Розробка системи алертів за технічними індикаторами

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Розробка системи алертів за технічними індикаторами
Середній
~3-5 днів
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1288
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1198
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    902
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1122
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    589
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    859

Розробка платформи соціального трейдингу

Соціальний трейдинг — це копіювання сделок успішних трейдерів у реальному часі. eToro зробила це mainstream у традиційних фінансах, потім з'явились крипто-аналоги: Bybit Copy Trading, Bitget Copy Trade, OKX Copy Trading. Розробка власної платформи — складна задача з унікальними викликами синхронізації ордерів та розподілу комісій.

Архітектура платформи

Ролі учасників

Provider (мастер-трейдер) — досвідчений трейдер, чиї сделки копіюються. Заробляє profit share (зазвичай 5–30% від прибутку копировщиків) або фіксовану підписку.

Follower (копировщик) — користувач, виділяючий частину капіталу на копіювання. Вибирає провайдера за статистикою, встановлює ліміти.

Platform — отримує комісію з кожної скопійованої сделки або з profit share.

Копіювання ордерів

Ключова технічна задача: коли провайдер розміщує ордер, потрібно синхронно розмістити пропорційні ордери для всіх активних копировщиків.

type CopyEngine struct {
    orderEngine *OrderEngine
    db          *DB
    mu          sync.RWMutex
}

func (ce *CopyEngine) OnProviderOrder(providerOrder Order) {
    followers := ce.getActiveFollowers(providerOrder.UserID)
    
    if len(followers) == 0 {
        return
    }
    
    // Паралельне розміщення ордерів для всіх копировщиків
    var wg sync.WaitGroup
    errors := make(chan error, len(followers))
    
    for _, follower := range followers {
        wg.Add(1)
        go func(f Follower) {
            defer wg.Done()
            
            copyOrder, err := ce.buildCopyOrder(providerOrder, f)
            if err != nil {
                errors <- fmt.Errorf("follower %d: %w", f.UserID, err)
                return
            }
            
            _, err = ce.orderEngine.PlaceOrder(copyOrder)
            if err != nil {
                errors <- fmt.Errorf("follower %d order failed: %w", f.UserID, err)
            }
        }(follower)
    }
    
    wg.Wait()
    close(errors)
    
    // Логуємо неудачні копіювання
    for err := range errors {
        log.Error("Copy order failed", "error", err)
    }
}

Розрахунок розміру позиції копировщика

У провайдера може бути $100k, у копировщика — $500. Потрібна пропорційна адаптація:

type PositionSizer struct{}

func (ps *PositionSizer) Calculate(
    providerOrder Order,
    providerBalance Decimal,
    follower Follower,
) (Decimal, error) {
    // Який % від баланса використовує провайдер
    providerUsagePct := providerOrder.Quantity.Mul(providerOrder.Price).
        Div(providerBalance).Mul(Decimal("100"))
    
    // Три режими копіювання
    switch follower.CopyMode {
    case "fixed_amount":
        // Завжди копіюємо фіксовану суму
        return follower.FixedAmount.Div(providerOrder.Price), nil
        
    case "proportional":
        // Такий же % від баланса копировщика
        copyAmount := follower.AllocatedBalance.Mul(providerUsagePct).Div(Decimal("100"))
        return copyAmount.Div(providerOrder.Price), nil
        
    case "multiplier":
        // X-кратне умноження відносного розміру
        copyAmount := follower.AllocatedBalance.Mul(providerUsagePct).
            Mul(follower.Multiplier).Div(Decimal("100"))
        return copyAmount.Div(providerOrder.Price), nil
    }
    
    return Decimal("0"), ErrUnknownCopyMode
}

Важливі перевірки перед копіюванням:

  • Достатньо ли вільного баланса у копировщика
  • Не перевищує ли позиція max risk limit копировщика
  • Не виходить ли позиція за межі max open positions настройки

Синхронізація закриття позицій

Коли провайдер закриває позицію — закриємо всі копійовані позиції:

func (ce *CopyEngine) OnProviderPositionClose(providerTradeID string) {
    // Знаходимо всі відкриті копійовані ордери пов'язані з цією сделкою
    copyOrders := ce.db.GetCopyOrdersByProviderTrade(providerTradeID)
    
    for _, copyOrder := range copyOrders {
        if copyOrder.Status == OrderStatusOpen {
            // Закриваємо рыночним ордером немедленно
            closeOrder := Order{
                UserID: copyOrder.FollowerID,
                Pair:   copyOrder.Pair,
                Side:   copyOrder.Side.Opposite(),
                Type:   Market,
                Quantity: copyOrder.RemainingQty,
            }
            ce.orderEngine.PlaceOrder(closeOrder)
        }
    }
}

Статистика провайдерів

Статистика — головний інструмент вибору провайдера. Повинна бути чесною та верифікованою сервером (розраховується сервером, не передається провайдером).

CREATE MATERIALIZED VIEW provider_stats AS
SELECT
    p.user_id,
    p.display_name,
    -- Основні метрики
    COUNT(DISTINCT t.id) AS total_trades,
    COUNT(CASE WHEN t.pnl > 0 THEN 1 END)::float / 
        NULLIF(COUNT(DISTINCT t.id), 0) * 100 AS win_rate,
    SUM(t.pnl) AS total_pnl_usd,
    -- ROI за періодами
    SUM(CASE WHEN t.closed_at >= NOW() - INTERVAL '7 days' 
        THEN t.pnl_pct ELSE 0 END) AS roi_7d,
    SUM(CASE WHEN t.closed_at >= NOW() - INTERVAL '30 days' 
        THEN t.pnl_pct ELSE 0 END) AS roi_30d,
    -- Риск-метрики
    MIN(t.pnl_pct) AS max_loss_single_trade,
    MAX(dd.drawdown) AS max_drawdown,
    -- Sharpe Ratio (упрощённий)
    AVG(t.pnl_pct) / NULLIF(STDDEV(t.pnl_pct), 0) AS sharpe,
    -- Активність
    COUNT(DISTINCT f.user_id) AS active_followers,
    SUM(f.allocated_balance) AS total_aum
FROM providers p
JOIN trades t ON t.user_id = p.user_id AND t.is_copy_trade = false
LEFT JOIN drawdowns dd ON dd.provider_id = p.user_id
LEFT JOIN copy_relationships f ON f.provider_id = p.user_id AND f.status = 'active'
GROUP BY p.user_id, p.display_name;

REFRESH MATERIALIZED VIEW CONCURRENTLY provider_stats;  -- кожні 5 хвилин

Equity Curve

Для кожного провайдера розраховується equity curve — історія зростання $10,000 гіпотетичного депозиту. Це найкращий візуальний індикатор стабільності результатів.

def calculate_equity_curve(trades: list[Trade], initial_equity: float = 10000) -> list[dict]:
    equity = initial_equity
    curve = [{'date': trades[0].opened_at.date(), 'equity': equity}]
    
    for trade in sorted(trades, key=lambda t: t.closed_at):
        pnl_usd = equity * (trade.pnl_pct / 100)
        equity += pnl_usd
        curve.append({
            'date': trade.closed_at.date(),
            'equity': round(equity, 2),
            'pnl_pct': round(trade.pnl_pct, 2),
        })
    
    return curve

Модель монетизації та розподіл прибутку

Profit Share Розрахунок (High Watermark)

High Watermark — стандартна модель для хедж-фондів та copy trading: провайдер отримує profit share тільки з нових рекордних значень прибутку. Якщо капітал просів і відновився до старого максимуму — profit share не починається.

class ProfitShareCalculator:
    def calculate(self, follower_id: int, provider_id: int) -> Decimal:
        hwm = self.get_high_watermark(follower_id, provider_id)
        current_equity = self.get_follower_equity_for_provider(follower_id, provider_id)
        
        if current_equity <= hwm:
            return Decimal('0')  # немає нової прибутку — немає profit share
        
        new_profit = current_equity - hwm
        provider_share_pct = self.get_provider_share_pct(provider_id)  # наприклад 20%
        platform_fee_pct = Decimal('2')  # 2% платформа бере з profit share
        
        provider_earnings = new_profit * (provider_share_pct / 100)
        platform_earnings = provider_earnings * (platform_fee_pct / 100)
        
        # Оновлюємо high watermark
        self.update_high_watermark(follower_id, provider_id, current_equity)
        
        return provider_earnings - platform_earnings

Settlement розписання

Profit share розраховується щотижня або щомісяця. Settlement workflow:

  1. Snapshot всіх equity позицій на дату розрахунку
  2. Розрахунок profit share для кожної пари (follower, provider)
  3. Передача комісій: у follower списується, у provider нараховується
  4. Сповіщення обом сторонам
  5. Оновлення high watermark

Risk controls для копировщиків

type CopyRiskControls struct {
    MaxLoss         Decimal  // -20%: автоотключение при просадці
    MaxOpenTrades   int      // максимум відкритих сделок
    MaxPerTrade     Decimal  // % від allocated balance на одну сделку
    StopCopyOnClose bool     //停止ли копіювання при виході?
}

func (ce *CopyEngine) CheckFollowerRisk(follower Follower, newOrder Order) error {
    // Перевіряємо просадку
    currentDrawdown := ce.calculateCurrentDrawdown(follower.ID)
    if currentDrawdown.GreaterThan(follower.RiskControls.MaxLoss.Abs()) {
        ce.stopCopying(follower.ID, "max_loss_reached")
        return ErrMaxLossReached
    }
    
    // Перевіряємо кількість відкритих позицій
    openTrades := ce.countOpenCopyTrades(follower.ID)
    if openTrades >= follower.RiskControls.MaxOpenTrades {
        return ErrMaxOpenTradesReached
    }
    
    return nil
}

Лідерборд та Discovery

Сторінка вибору провайдерів — критична для конверсії:

// Фільтри лідерборду
interface LeaderboardFilters {
  period: '7d' | '30d' | '90d' | 'all';
  minAUM: number;
  minFollowers: number;
  maxDrawdown: number;
  riskLevel: 'low' | 'medium' | 'high';
  strategy: 'spot' | 'futures' | 'mixed';
}

// Карточка провайдера
interface ProviderCard {
  userId: string;
  displayName: string;
  avatar: string;
  roi30d: number;
  winRate: number;
  maxDrawdown: number;
  followers: number;
  aum: number;
  profitSharePct: number;
  equityCurve: EquityPoint[];  // мініатюрний sparkline
}

Регуляторні аспекти

Соціальний трейдинг попадає під регулювання в багатьох юрисдикціях (провайдер де-факто управляє чужими коштами). Важливо:

  • Юридична консультація по цільовій юрисдикції
  • Disclaimers: прошлі результати не гарантують майбутніх
  • Обмеження по сумам для нерегульованих платформ

Сроки та вартість

Компонент Термін
Copy engine (order routing) 4–6 тижнів
Position sizing алгоритми 2–3 тижні
Статистика провайдерів 3–4 тижні
Profit share розрахунок 2–3 тижні
Лідерборд та discovery 3–4 тижні
Risk controls для копировщиків 2–3 тижні

Повна платформа соціального трейдингу: 4–6 місяців.