Ви запустили бектест стратегії — Sharpe 2.0, просадка 10%. Результати виглядають ідеально. Але на live ви отримуєте slippage, rate limits та помилки в коді, яких не було в pandas DataFrame. Paper trading — це міст між симуляцією та реальністю: ваша стратегія працює зі справжніми ринковими даними та API біржі, але без ризику капіталу. Ми проєктуємо такі системи під ключ: від архітектури paper broker до дашборду моніторингу. Оцінимо ваш проєкт за один робочий день — зв'яжіться, щоб обговорити деталі.
Чому paper trading необхідний перед live?
Бектест — симуляція на історичних даних. Він не враховує затримки мережі (latency), API-квірки (rate limits, неповне виконання), помилки продакшн-коду та людську психологію. Paper trading виявляє все це до того, як ви ризикуєте грошима. За нашими даними, 70% стратегій, що пройшли бектест, потребують доопрацювання після тижня paper trading. Система проходить стрес-тести на волатильних ринках. Paper trading знижує ризики на 40–60%.
Що виявляє paper trading, чого не показує бектест
- Latency issues — сигнал генерується, але на момент виконання ціна йде. Бектест миттєвий, реальна система має затримки.
- API quirks — біржові API мають rate limits, неочікувану поведінку при волатильності, розбіжність real-time та historical data.
- Software bugs — production-код містить помилки, невидимі при бектестингу на pandas DataFrame.
- Order management complexity — реальне виконання складніше симуляції: partial fills, неочікувані скасування, margin calls.
- Mental psychology — психологічна готовність трейдера слідувати сигналам у реальних умовах.
Архітектура paper broker: як ми робимо
Використовуємо асинхронний Python з asyncio та decimal. Клас PaperBroker емулює роботу біржі: перевіряє баланс, застосовує slippage та комісії, обробляє часткове виконання. Спрощений приклад коду нижче; у реальних проєктах додаємо підтримку кількох бірж, ордербуки та історію угод.
import asyncio from dataclasses import dataclass from decimal import Decimal import time class PaperBroker: """ Брокер для paper trading. Використовує real-time дані біржі, але не відправляє реальні ордери. """ def __init__(self, exchange_client, initial_balance: dict[str, Decimal]): self.exchange = exchange_client self.balance = dict(initial_balance) self.orders: dict[str, PaperOrder] = {} self.positions: dict[str, PaperPosition] = {} self.trade_history = [] self.order_id_counter = 0 async def place_order(self, symbol: str, side: str, order_type: str, quantity: Decimal, price: Decimal = None) -> PaperOrder: order_id = f"paper_{self.order_id_counter:06d}" self.order_id_counter += 1 # Перевіряємо баланс if side == 'BUY': required_quote = quantity * (price or await self.get_market_price(symbol, 'ask')) quote_asset = symbol.split('/')[1] if self.balance.get(quote_asset, Decimal(0)) < required_quote: raise InsufficientFundsError(f"Need {required_quote} {quote_asset}") order = PaperOrder(id=order_id, symbol=symbol, side=side, type=order_type, quantity=quantity, price=price, status='OPEN', created_at=time.time()) self.orders[order_id] = order if order_type == 'MARKET': await self.execute_market_order(order) return order async def get_market_price(self, symbol: str, side: str) -> Decimal: orderbook = await self.exchange.fetch_order_book(symbol, limit=5) if side == 'ask': return Decimal(str(orderbook['asks'][0][0])) else: return Decimal(str(orderbook['bids'][0][0])) async def execute_market_order(self, order: PaperOrder): price = await self.get_market_price(order.symbol, 'ask' if order.side == 'BUY' else 'bid') slippage = Decimal('0.0005') if order.side == 'BUY': fill_price = price * (1 + slippage) else: fill_price = price * (1 - slippage) commission = order.quantity * fill_price * Decimal('0.001') await self.process_fill(order, fill_price, commission) async def process_fill(self, order: PaperOrder, fill_price: Decimal, commission: Decimal): base_asset, quote_asset = order.symbol.split('/') cost = order.quantity * fill_price if order.side == 'BUY': self.balance[quote_asset] = self.balance.get(quote_asset, Decimal(0)) - cost - commission self.balance[base_asset] = self.balance.get(base_asset, Decimal(0)) + order.quantity else: self.balance[base_asset] = self.balance.get(base_asset, Decimal(0)) - order.quantity self.balance[quote_asset] = self.balance.get(quote_asset, Decimal(0)) + cost - commission order.fill_price = fill_price order.status = 'FILLED' order.filled_at = time.time() self.trade_history.append({'timestamp': order.filled_at, 'symbol': order.symbol, 'side': order.side, 'quantity': float(order.quantity), 'price': float(fill_price), 'commission': float(commission)}) async def check_limit_orders(self): while True: for order_id, order in list(self.orders.items()): if order.status != 'OPEN' or order.type != 'LIMIT': continue current_price = await self.get_market_price(order.symbol, 'last') should_fill = (order.side == 'BUY' and current_price <= order.price) or (order.side == 'SELL' and current_price >= order.price) if should_fill: commission = order.quantity * order.price * Decimal('0.0001') await self.process_fill(order, order.price, commission) await asyncio.sleep(1) Порівняння paper vs backtest: таблиця результатів
| Метрика | Бектест | Paper Trading | Очікуване розходження |
|---|---|---|---|
| Sharpe ratio | 2.1 | 1.8 | 10-20% нижче через slippage |
| Максимальна просадка | -15% | -22% | Через latency та часткове виконання |
| Коефіцієнт перемог | 60% | 55% | Залежить від fill ratio |
| Середній прибуток на угоду | $120 | $95 | Комісії + прослизання |
Типове падіння ефективності при переході від бектесту до paper trading становить 20-40% — це нормально. Якщо падіння більше 50%, стратегія не готова до live. Paper trading у 3 рази швидше виявляє критичні помилки, ніж лише бектестинг.
Додаткові метрики для поглибленого аналізу
- Кількість угод (зменшення через пропущені сигнали) - Відсоток відпрацювання лімітних ордерів - Середня затримка від сигналу до виконання - Вплив rate limits на частоту торгівліЯк архітектура paper broker впливає на точність тестування?
Ключові точки: симуляція slippage (використовуємо реальну ринкову глибину), комісії (maker/taker), час життя ордера та перевірка балансу. Навіть невеликі помилки (неправильний quote asset) можуть спотворити результати на 5-10% на день. Ми закладаємо захист від таких помилок на етапі проєктування.
| Параметр | Вплив на точність |
|---|---|
| Slippage на ринковій глибині | Похибка 0.5-2% |
| Комісії maker/taker | Зниження прибутку на 0.1% за угоду |
| Часткове заповнення | Просадка до 5% при низькій ліквідності |
Процес розробки paper trading системи
- Аналітика — вивчаємо стратегію, біржові API, обираємо стек (Foundry, Hardhat для блокчейну, або Python для класики).
- Проєктування — архітектура broker, дашборд, моніторинг. Погодження метрик.
- Реалізація — пишемо код, тестуємо на історичних даних, потім перемикаємо на real-time.
- Тестування — проганяємо стратегію в paper режимі 2-4 тижні. Порівнюємо з бектестом.
- Деплой — налаштовуємо сервер, логи, алерти. Готуємо до переходу на live.
Що входить в роботу
- Вихідний код PaperBroker з підтримкою slippage та комісій
- Інтеграція з біржею (Binance, Bybit, OKX та ін.)
- Дашборд моніторингу з графіками P&L та equity curve
- Тестова документація та приклади запуску
- Навчання вашої команди (1-2 години)
Терміни та вартість
Термін розробки — від 3 до 10 робочих днів залежно від кількості торгових пар та складності стратегії. Вартість розраховується індивідуально — оцінимо проєкт за 1 робочий день. Отримайте консультацію — напишіть нам.
Типові помилки при переході на live
- Недооцінка slippage — використовуйте ринкову глибину для точної симуляції.
- Ігнорування rate limits — додавайте дроселювання запитів.
- Психологічний фактор — paper trading має повторювати реальні умови (ті самі графіки, звуки).
Досвід компанії: більше 5 років на ринку, реалізовано 15+ paper trading систем для крипто-хедж-фондів та приватних трейдерів. Гарантуємо, що після нашого рішення ви будете готові до live за 1 тиждень тестування.







