Сигнали Copy-Trading в мобільному додатку
Copy-trading — це коли угоди майстер-трейдера автоматично копіюються на рахунках підписників. Мобільний додаток тут вирішує два принципово різні завдання: для майстра — публікація угод та управління підписниками, для копіювача — отримання сигналів, налаштування параметрів копіювання та моніторинг результатів.
Архітектура сигналів
Сигнал — це не просто сповіщення «купи BTC». Це структурований об'єкт з достатнім контекстом для автоматичного виконання:
struct TradingSignal: Codable {
let id: UUID
let masterId: String
let pair: String // "BTC/USDT"
let side: TradeSide // .long, .short
let entryPrice: Decimal? // nil для market ордера
let takeProfit: [Decimal] // кілька рівнів TP
let stopLoss: Decimal
let leverage: Int? // для фьючерсів
let riskPercent: Decimal // % від депозиту підписника
let comment: String?
let publishedAt: Date
let validUntil: Date? // сигнал застарівається
}
riskPercent замість фіксованої суми — тому що підписники мають різні депозити. 2% від $1,000 та 2% від $50,000 — різні суми, але однаковий ризик.
Доставка сигналів: latency має значення
Сигнал входу в позицію — часочутливий об'єкт. Ціна рухається, поки сигнал літить. Вимоги до latency залежать від стратегії майстра: для swing-трейдингу (позиції на дні) достатньо push із затримкою 5–10 секунд. Для скальпінгу — WebSocket обов'язковий, push занадто повільний.
WebSocket для активних користувачів у додатку. Backend розповсюджує сигнал усім підключеним підписникам майстра одночасно.
FCM/APNs push для фонових сповіщень. Важливий нюанс: push — не гарантована доставка, FCM може буферизувати. Для торгових сигналів це неприйнятно. Тому при відкритті додатку — завжди синхронізуємо пропущені сигнали через GET /signals?since={lastReceivedAt}.
// Android — отримання та обробка сигналу
class SignalReceiver @Inject constructor(
private val signalRepository: SignalRepository,
private val orderExecutor: OrderExecutor,
private val notificationManager: AppNotificationManager,
) {
suspend fun handle(signal: TradingSignal) {
signalRepository.save(signal)
val subscription = signalRepository.getSubscription(signal.masterId) ?: return
if (!subscription.autoExecute) {
// Лише сповіщення, користувач вирішує вручну
notificationManager.showSignal(signal)
return
}
// Автоисполнення з перевірками
val account = accountRepository.getCurrent()
val orderSize = account.balance * subscription.riskPercent / 100
if (orderSize < exchange.minimumOrderSize(signal.pair)) {
notificationManager.showError("Недостатньо балансу для виконання сигналу")
return
}
val result = orderExecutor.execute(signal, orderSize)
notificationManager.showExecutionResult(signal, result)
}
}
Налаштування копіювання
Кожен підписник налаштовує параметри окремо для кожного майстра:
Розмір позиції:
- Фіксований % від депозиту (слідувати ризику майстра)
- Фіксована сума в USDT
- Множник від розміру майстра (наприклад, 0.5x якщо обсяг майстра занадто великий)
Фільтри сигналів:
- Лише long / лише short / обидва напрями
- Пари (дозволити лише BTC, ETH; ігнорувати альткоїни)
- Максимальне плече (не копіювати, якщо майстер використовує > 10x)
- Максимальна кількість одночасних позицій
Режим виконання:
- Авто (одразу при отриманні сигналу)
- З підтвердженням (push → користувач натискає «Виконати»)
- Лише сповіщення (без виконання, моніторинг стратегії майстра)
Форма налаштувань — ключовий UX-елемент. Користувач повинен розуміти наслідки кожного параметра. Для % від депозиту — показуємо розрахунок: «При депозиті $2,000 та ризику 2% — $40 на угоду».
Екран майстра: що бачить підписник
Профіль майстра — це показники його торгівлі, а не маркетинговий текст:
| Метрика | Значення |
|---|---|
| Win Rate | 64% |
| Profit Factor | 1.87 |
| Max Drawdown | −18.4% |
| Sharpe Ratio | 1.31 |
| Угод (30д) | 142 |
| Підписників | 2,840 |
| Monthly PnL | +12.3% |
Графік equity curve майстра — обов'язковий. Підписник повинен бачити не просто «+30% за рік», а як саме: було довге просадочне плато? Різкий ріст на початку та стагнація потім?
Мої результати як копіювача
Окремий екран — PnL від копіювання конкретного майстра. Дані відрізняються від майстра: різні ціни виконання (slippage), різний час входу (затримка доставки сигналу), різні розміри позицій.
Порівняння: equity curve майстра проти моїх результатів на одному графіку. Якщо розбіжність велика — аналіз причин (slippage, пропущені сигнали, ліміти за фільтрами).
// iOS, SwiftUI — порівняння кривих
Chart {
ForEach(masterEquity) { point in
LineMark(
x: .value("Дата", point.date),
y: .value("PnL", point.pnl),
series: .value("Тип", "Майстер")
)
.foregroundStyle(.blue)
}
ForEach(myEquity) { point in
LineMark(
x: .value("Дата", point.date),
y: .value("PnL", point.pnl),
series: .value("Тип", "Мої результати")
)
.foregroundStyle(.green)
}
}
.chartLegend(.visible)
Пошук та рейтинг майстрів
Каталог майстрів із фільтрами: за win rate, за просадкою, за кількістю угод, за періодом роботи (мінімум 3 місяці активної торгівлі). Сортування за Sharpe Ratio за замовчуванням — єдина метрика, яка враховує дохід та ризик одночасно.
Картка майстра в списку — компактно: аватар, ник, 3 ключові метрики, мініатюра equity curve, кнопка «Підписатися».
Що входить до роботи
- Доставка сигналів через WebSocket + FCM/APNs із синхронізацією пропущених
- Форма налаштування копіювання з фільтрами та розрахунком розміру позиції
- Профіль майстра з метриками та equity curve
- Екран моїх результатів зі порівнянням із майстром
- Каталог майстрів із фільтрацією та рейтингом
- Історія сигналів: отримано, виконано, пропущено (з причиною)
Терміни
| Роль | Функції | Тривалість |
|---|---|---|
| Копіювач (підписник) | Сигнали, налаштування, результати | 10–14 днів |
| Майстер | Публікація, підписники, аналітика | 7–10 днів |
| Повна система | Каталог, рейтинги, обидві ролі | 20–28 днів |
Вартість розраховується індивідуально після аналізу вимог.







