Бэктест-лайв паритети: бот эмне үчүн бэктесттен башкача сооданы жүргүзөт
Сиз стратегияны бэктест аркылуу иштеттиңиз. Sharpe 2.1, MaxDD -8%, PnL +67%. Ботту иштеттиңиз. Бир айдан кийин салыштырасыз: ошол эле сигналдар, ошол эле мезгил — бирок реалдуу PnL 40%га төмөн. Просадка бир жарым эсе тереңирээк. Он бүтүмдүн экөө таптакыр аткарылган жок.
Бул баг эмес. Бул — бэктест-лайв айырмачылыгы, башкача айтканда бэктест жыйынтыктары менен реалдуу соода ортосундагы системалуу айырмачылык. Бул баарында бар. Жалгыз суроо — сиз бул тууралуу билесизби жана аны көзөмөлдөй аласызбы.
Бул макала айырмачылыктардын толук таксономиясын, аларды азайтуу үчүн архитектуралык үлгүлөрдү жана өндүрүштө паритетти көзөмөлдөө үчүн практикалык текшерүү тизмесин сунуштайт.
"бэктесте иштеди" синдрому

Ар бир algotrader мына циклден өтөт:
- Jupyter notebook'то стратегия жазды
- Тарыхый CSV боюнча бэктест жүргүздү — жыйынтыктар сонун
- Логиканы бот түрүндө кайра жазды (көп учурда башка тилде же фреймворкто)
- Иштетти — жыйынтыктар дал келбейт
- Багды издеди, таппады — "рынок өзгөрдү"
Маселе рынокто эмес. Маселе — бэктест жана бот эки башка программалык продукт, алар бир эле реалдуулукту ар түрдүү моделдейт. Айырмачылыктар сөзсүз, бирок аларды системалаштырууга жана азайтууга болот.
Айырмачылыктардын таксономиясы

Айырмачылыктын бардык булактары төрт категорияга бөлүнөт. Ар бирине — оордук деңгээли (1ден 5ке чейин) жана PnL айырмачылыгына мүнөздүү салым.
1. Дайындар айырмачылыгы (оордугу: 3/5)
Бэктест көргөн дайындар менен бот реалдуу убакытта көргөн дайындар бирдей эмес.
Убакыт белгилери. Биржалар кэндлдерди убакыт белгисин дайындоонун ар түрдүү эрежелери менен жеткиришет. Бир биржа кэндлди мезгилдин башы менен, экинчиси аягы менен белгилейт. REST API реалдуу жабылуудан 1-3 секунддан кийин кэндл кайтарышы мүмкүн. Бэктест тарыхый файлдан алынган "идеалдуу" убакыт белгилери менен иштейт.
OHLCV агрегациясы. Тарыхый дайындарды провайдер көбүнчө биржа реалдуу убакытта жасаган ыкмадан башкача агрегациялайт. Айырма акыркы санда — бирок босого сигналдарында (MA кесилиши, деңгээл бузулушу) бул стратегия позицияга кирет же кирбейт дегенди чечет.
Боштуктар жана жетишпеген дайындар. Тарыхый дайындар адатта таза — жок кэндлдер интерполяция менен толтурулат. Реалдуу убакытта WebSocket үзүлүшү мүмкүн, бот 30 секунд дайынды өткөрүп жиберет.
PnL айырмачылыгына мүнөздүү салым: жылдык PnL'дин 2-5%.
2. Аткаруу айырмачылыгы (оордугу: 5/5)

Айырмачылыктын эң коркунучтуу классы. Бэктест аткарууну мыкты моделдейт — реалдуулук идеалдан алыс.
Слиппедж. Бэктест буйрукту жабылуу баасы (же сигнал баасы) менен толтурат. Чындыгында, рыноктук буйрук көлөм жана ликвиддүүлүккө көз каранды слиппеджи бар мыкты bid/ask боюнча аткарылат. Орточо ликвиддүүлүктөгү альткоинде $10K позиция үчүн слиппедж 0.05-0.3% болушу мүмкүн.
бүтүм боюнча топтолгон слиппедж формуласы:
мында — ордербуктун тереңдигине көз каранды -чи бүтүмдүн слиппеджи:
Кечигүү. Сигнал жаралган учурдан буйрукту аткарууга чейин убакыт өтөт: сигналды эсептөө (1-50 мс), суранышты жиберүү (10-200 мс), биржада дал келтирүү (1-10 мс). Бэктесте кечигүү = 0. Лайвда баа кыймылдашы мүмкүн.
Жарым-жартылай аткаруу. Бэктест буйруктун 100%ы дароо толтурулат деп эсептейт. Чындыгында, лимиттик буйрук жарым-жартылай толтурулушу мүмкүн — же баа кайра бурулса такыр толтурулбашы мүмкүн. Ликвиддүү эмес рынокто рыноктук буйрук үчүн ал бир нече ордербук деңгээлдери аркылуу "сыргалат".
Кезек артыкчылыгы. Мыкты bid баасына коюлган лимиттик буйрук дароо толтурулбайт — ал ошол деңгээлде мурда коюлган бардык буйруктардын артынан кезекке турат. "Баа тийди = буйрук толтурулду" деп эсептеген бэктест толтуруу деңгээлин системалуу түрдө ашыра баалайт.
PnL айырмачылыгына мүнөздүү салым: жылдык PnL'дин 10-30%.
3. Логика айырмачылыгы (оордугу: 4/5)
Булар бэктест жана бот ортосундагы стратегия кодунун өзүндөгү айырмачылыктар.
Өзүнчө код базалары. Классикалык антиүлгү: backtests/strategy_a.py жана bot/strategy_a.py — "бир эле нерсени жасаган" эки өзүнчө файл. Үч айлык өзгөртүүлөрдөн кийин алар сөзсүз айырмаланат. Бирөө бэктестке фильтр кошуп, ботто аны кайталоону унутуп калды. Же тескерисинче — ботто баг оңдолду, бирок бэктесте калды.
Ар түрдүү фреймворктор. Векторлоштурулган операциялары бар pandas'та бэктест, окуяга негизделген логикасы бар asyncio'до бот. Атүгүл бирдей стратегияда да чек ара учурлары ар түрдүү иштелет: тегеректөө, шарттарды текшерүү тартиби, NaN'ды иштетүү.
Абалды башкаруу. Бэктест адатта абалсыз — ал дайындар массиви боюнча кайталанат. Бот абалдуу — ал позицияларды, баланстарды, буйруктар тарыхын сактайт. Ботту кайра иштетүү, абалдын жоголушу, биржа менен десинхронизация — булардын баары айырмачылык булактары.
PnL айырмачылыгына мүнөздүү салым: жылдык PnL'дин 5-20%.
4. Чыгымдар айырмачылыгы (оордугу: 3/5)
Соода чыгымдарын моделдөөдөгү айырмачылыктар.
Фандинг мөлчөрлөмөлөрү. Түбөлүк фьючерстердин көбүнүн бэктесттери фандинг мөлчөрлөмөлөрүн такыр эсепке албайт. 10x левередж жана ар 8 сааттагы орточо 0.01% мөлчөрлөмөсүндө бул жылына түзөт — стратегиялардын көбүнүн PnL'инен көп. Толук талдоо Фандинг мөлчөрлөмөлөрү сиздин левереджиңизди өлтүрөт макаласында.
Комиссиялар. Maker/taker комиссиялары адатта моделденет, бирок көп учурда туура эмес мөлчөрлөмө менен. VIP деңгээлдер, BNB арзандатуулары, rebate'тер — булардын баары акыркы жыйынтыкка таасир этет.
Спред. Кэндлге негизделген бэктест bid-ask спредин көрбөйт. 1 мүнөттүк кэндлде close = 3000, бирок чындыгында bid = 2999.5 жана ask = 3000.5. Ар бир бүтүм спреддин жарымын "төлөйт".
PnL айырмачылыгына мүнөздүү салым: жылдык PnL'дин 5-15%.
Топтолгон эффект
Бардык төрт категория бир мезгилде жана адатта бир багытта — трейдерге каршы иштейт:
Тазаланбаган система үчүн бэктест PnL'инен 20-50% жалпы айырмачылык кадимки көрүнүш. Левередж менен эффект көбөйөт.
Паритет үчүн архитектуралык үлгүлөр
1-үлгү: Shared Core (жалпы өзөктү бөлүп чыгаруу)

Идея: стратегия өзөгүн — сигнал генерациясын жана аткаруу логикасын — бэктест да, бот да колдонгон өзүнчө модулга бөлүп чыгаруу. Айланадагы инфраструктура гана айырмаланат: дайын булагы жана буйруктарды жиберүү механизми.
┌─────────────────────────────────────┐
│ strategy_core.py │
│ ┌─────────────┐ ┌───────────────┐ │
│ │ SignalEngine │ │ OrderManager │ │
│ └──────┬──────┘ └──────┬────────┘ │
│ │ │ │
│ generate_signal() create_order()│
└─────────┬───────────────┬───────────┘
│ │
┌─────┴─────┐ ┌─────┴──────┐
│ Backtest │ │ Live │
│ DataFeed │ │ DataFeed │
│ FillModel │ │ Exchange │
└────────────┘ └────────────┘
from dataclasses import dataclass
from typing import Optional
import numpy as np
@dataclass
class Signal:
side: str # 'long' | 'short'
entry_price: float
sl_price: float
tp_price: float
size: float
timestamp: int
@dataclass
class OrderRequest:
side: str
order_type: str # 'market' | 'limit'
price: float
size: float
class StrategyCore:
"""
Strategy core. Identical code for backtest and live.
Depends only on data, not on infrastructure.
"""
def __init__(self, params: dict):
self.fast_period = params.get('fast_ma', 20)
self.slow_period = params.get('slow_ma', 50)
self.sl_pct = params.get('sl_pct', 0.02)
self.tp_pct = params.get('tp_pct', 0.04)
self.position: Optional[Signal] = None
self._closes: list[float] = []
def on_candle(self, timestamp: int, o: float, h: float,
l: float, c: float, v: float) -> Optional[OrderRequest]:
"""
Process a new candle. Returns an OrderRequest or None.
This method is called identically from the backtest and the bot.
"""
self._closes.append(c)
if len(self._closes) < self.slow_period:
return None
fast_ma = np.mean(self._closes[-self.fast_period:])
slow_ma = np.mean(self._closes[-self.slow_period:])
if self.position is not None:
exit_order = self._check_exit(h, l, c)
if exit_order:
self.position = None
return exit_order
if self.position is None:
if fast_ma > slow_ma and self._prev_fast_ma <= self._prev_slow_ma:
self.position = Signal(
side='long', entry_price=c,
sl_price=c * (1 - self.sl_pct),
tp_price=c * (1 + self.tp_pct),
size=1.0, timestamp=timestamp,
)
return OrderRequest('buy', 'market', c, 1.0)
self._prev_fast_ma = fast_ma
self._prev_slow_ma = slow_ma
return None
def _check_exit(self, high: float, low: float,
close: float) -> Optional[OrderRequest]:
pos = self.position
if pos.side == 'long':
if low <= pos.sl_price:
return OrderRequest('sell', 'market', pos.sl_price, pos.size)
if high >= pos.tp_price:
return OrderRequest('sell', 'market', pos.tp_price, pos.size)
return None
Эми бэктест жана бот бир эле StrategyCoreду колдонушат:
from strategy_core import StrategyCore
def run_backtest(candles, params, fill_model):
core = StrategyCore(params)
trades = []
for candle in candles:
order = core.on_candle(
candle['timestamp'], candle['open'], candle['high'],
candle['low'], candle['close'], candle['volume'],
)
if order:
fill_price = fill_model.simulate_fill(order, candle)
trades.append({'price': fill_price, 'side': order.side})
return trades
from strategy_core import StrategyCore
async def run_live(exchange, symbol, params):
core = StrategyCore(params)
async for candle in exchange.stream_candles(symbol, '1m'):
order = core.on_candle(
candle['timestamp'], candle['open'], candle['high'],
candle['low'], candle['close'], candle['volume'],
)
if order:
await exchange.place_order(symbol, order.side,
order.order_type, order.size)
Негизги эреже: StrategyCore дайындар кайдан келерин же буйруктар кайда жиберилерин билбейт. Ал OHLCV алат жана OrderRequest кайтарат. Калгандын баары инфраструктура катмарынын жоопкерчилиги.
2-үлгү: Окуяга негизделген бириктирүү (NautilusTrader ыкмасы)

NautilusTrader паритетти бирдиктүү NautilusKernel аркылуу ишке ашырат — детерминисттик окуяга негизделген өзөгү жана наносекунддук чечилиши бар Rust-native кыймылдаткыч. Бир стратегия ишке ашыруу бэктесте да, реалдуу соодада да иштейт.
Архитектура порттор жана адаптерлер үлгүсүнө (гексагоналдык архитектура) негизделген:
┌──────────────────────────────────┐
│ NautilusKernel │
│ ┌───────────┐ ┌─────────────┐ │
│ │ Strategy │ │ RiskEngine │ │
│ │ (Python) │ │ (Rust) │ │
│ └─────┬─────┘ └──────┬──────┘ │
│ │ │ │
│ ┌─────┴───────────────┴──────┐ │
│ │ Message Bus (Rust) │ │
│ └─────┬───────────────┬──────┘ │
└────────┼───────────────┼─────────┘
│ │
┌─────┴─────┐ ┌─────┴──────┐
│ Backtest │ │ Live │
│ Adapter │ │ Adapter │
│ FillModel │ │ Exchange │
│ (L2 book) │ │ Gateway │
└────────────┘ └────────────┘
Артыкчылыктары:
- Детерминисттик кайра ойнотуу. Окуялар катуу аныкталган тартипте иштелет — бэктест жыйынтыгы бит-биттеп кайра жаралат.
- Custom FillModel. Ар бир аткаруу үчүн L2 ордербук симуляциясы — слиппедж реалдуу ордербук тереңдигинин негизинде моделденет.
- Аткаруу натыйжалуулугу. Секундуна 5 миллионго чейин катар, RAMга батпаган дайындарды иштетүү.
- Redis + PostgreSQL. Redis аркылуу кэш жана билдирүүлөр шинасы, PostgreSQL аркылуу туруктуулук — бэктест жана лайв үчүн бирдей инфраструктура.
3-үлгү: Strategy Interface (Freqtrade ыкмасы)
Freqtrade бирдиктүү IStrategy интерфейсин колдонот: бир стратегия классы бэктесте да, лайвда да иштейт. Жалгыз айырма — туруктуулук катмары.
class IStrategy:
"""Unified interface — the implementation does not know if this is a backtest or live."""
def populate_indicators(self, dataframe, metadata):
"""Compute indicators."""
dataframe['fast_ma'] = dataframe['close'].rolling(20).mean()
dataframe['slow_ma'] = dataframe['close'].rolling(50).mean()
return dataframe
def populate_entry_trend(self, dataframe, metadata):
"""Determine entry signals."""
dataframe.loc[
(dataframe['fast_ma'] > dataframe['slow_ma']) &
(dataframe['fast_ma'].shift(1) <= dataframe['slow_ma'].shift(1)),
'enter_long'
] = 1
return dataframe
def populate_exit_trend(self, dataframe, metadata):
"""Determine exit signals."""
dataframe.loc[
(dataframe['fast_ma'] < dataframe['slow_ma']),
'exit_long'
] = 1
return dataframe
Freqtrade кошумча сунуштайт:
- Optuna аркылуу Hyperopt — стратегия параметрлерин оптималдаштыруу
--timeframe-detail— толтурууну тактоо үчүн майдараак убакыт кесимине терендетүү (адаптивдүү drill-downга окшош)
Үлгүлөрдү салыштыруу
| Shared Core | Окуяга негизделген (NautilusTrader) | Strategy Interface (Freqtrade) | |
|---|---|---|---|
| Ишке ашыруу татаалдыгы | Төмөн | Жогору | Орто |
| Паритет деңгээли | Орто | Максималдуу | Жогору |
| Толтуруу симуляциясы | Өзүнчө FillModel | L2 ордербук | --timeframe-detail |
| Өзөк тили | Python | Rust + Python | Python |
| Ылайыктуу | Custom кыймылдаткычтар | Институционалдык соода | Тез баштоо |
Толтуруу симуляциясынын тактыгы

Толтуруу симуляциясы аткаруу айырмачылыгынын негизги булагы. Тактыктын үч деңгээли:
1-деңгээл: Наивдуу (жабылуу баасы менен толтуруу)
fill_price = candle['close']
Ката: слиппеджди, спредди же жарым-жартылай толтурууну эсепке албайт. PnLды системалуу түрдө ашыра баалайт.
2-деңгээл: Слиппедж модели
def simulate_fill(order, candle, slippage_bps=5):
"""Fill with slippage."""
base_price = candle['close']
slip = base_price * slippage_bps / 10000
if order.side == 'buy':
return base_price + slip # Buy at a higher price
else:
return base_price - slip # Sell at a lower price
Ката: туруктуу слиппедж ликвиддүүлүктү жана буйрук көлөмүн эсепке албайт. Наивдуудан жакшыраак, бирок баары бир одоно модель.
3-деңгээл: 1с/100мс дайындары менен адаптивдүү drill-down
Эң жакшы варианты: SL/TP толтуруу тартибин так аныктоо үчүн реалдуу майда грануляциялуу дайындарды колдонуу. Толугураак Адаптивдүү drill-down: өзгөрмө грануляция менен бэктестинг макаласында сүрөттөлгөн.
class RealisticFillModel:
"""
Combined fill model: slippage + spread + volume impact.
"""
def __init__(self, avg_spread_bps=3, impact_coeff=0.1):
self.avg_spread_bps = avg_spread_bps
self.impact_coeff = impact_coeff
def simulate_fill(self, order, candle, order_size_usd):
base_price = candle['close']
spread_cost = base_price * self.avg_spread_bps / 20000
candle_volume_usd = candle['volume'] * candle['close']
participation_rate = order_size_usd / max(candle_volume_usd, 1)
impact = base_price * self.impact_coeff * np.sqrt(participation_rate)
if order.side == 'buy':
return base_price + spread_cost + impact
else:
return base_price - spread_cost - impact
Рынок таасир формуласы (жөнөкөйлөштүрүлгөн Almgren-Chriss модели):
мында — туруксуздук, — таасир коэффициенти, — буйрук көлөмү, ал эми — мезгил үчүн рынок көлөмү.
Практикалык паритет текшерүү тизмеси

Ботту лайвга иштетүүдөн мурун, ар бир пунктту текшериңиз:
Код:
- Стратегия shared core колдонот (бэктест жана лайв үчүн бир модуль)
- Сигнал логикасы эки жерде кайталанбайт
- Юнит-тесттер бирдей киргизүүлөр үчүн өзөктүн бирдей чыгуусун текшерет
- Шарттарды текшерүү тартиби бирдей (SL TPден мурунбу? TP SLден мурунбу?)
Дайындар:
- Убакыт белгисинин форматы бирдей (UTC, бирдей провайдер)
- OHLCV агрегациясы бирдей эрежелерди колдонот
- Жок кэндлдерди иштетүү бирдей
- Look-ahead bias жок — бэктест келечекке карабайт
Аткаруу:
- Слиппедж модели реалдуу дайындарда калибрленген
- Жарым-жартылай толтуруулар моделденген (же жок дегенде пессимисттик бааланган)
- Лимиттик буйруктарда кезек артыкчылык модели бар
- Кечигүү эсепке алынган (сигналдан толтурууга чейин 100-500 мс кечигүү)
Чыгымдар:
- Maker/taker комиссиялары учурдагы мөлчөрлөмө менен кошулган
- Түбөлүк фьючерстер менен фандинг мөлчөрлөмөлөрү эсепке алынган
- Спред моделденген (жок дегенде орточо)
Инфраструктура:
- Абал туруктуулугу: бот кайра иштетилгенден кийин позицияларды калыбына келтирет
- Кайра туташуу логикасы: WebSocket дайын жоготуусуз кайра туташат
- Логдоо: пост-мортем талдоо үчүн бардык буйруктар жана толтуруулар логдолот
Өндүрүштө айырмачылыкты көзөмөлдөө
Паритет бир жолку текшерүү эмес, тынымсыз процесс. Ботту иштеткенден кийин айырмачылыктарды реалдуу убакытта көзөмөлдөө керек.
Shadow режими (paper trading)

Ботту бэктест менен параллелдүү, бирдей дайындар боюнча иштетиңиз. Бот сигналдарды генерациялайт, бирок буйруктарды жибербейт — жөн гана логдойт. Ошол эле учурда бэктест бирдей дайындарды иштетет. Салыштырыңыз:
class DivergenceMonitor:
"""
Compares backtest and live bot signals in real time.
"""
def __init__(self, tolerance_pct=0.5):
self.tolerance = tolerance_pct / 100
self.divergences = []
def compare_signal(self, backtest_signal, live_signal, timestamp):
"""Compare backtest and live signals."""
if backtest_signal is None and live_signal is None:
return # Both silent — OK
if (backtest_signal is None) != (live_signal is None):
self.divergences.append({
'timestamp': timestamp,
'type': 'signal_mismatch',
'backtest': backtest_signal,
'live': live_signal,
'severity': 'HIGH',
})
return
price_diff = abs(
backtest_signal.entry_price - live_signal.entry_price
) / backtest_signal.entry_price
if price_diff > self.tolerance:
self.divergences.append({
'timestamp': timestamp,
'type': 'price_divergence',
'diff_pct': price_diff * 100,
'severity': 'MEDIUM',
})
def compare_fill(self, backtest_fill, live_fill, timestamp):
"""Compare execution."""
if backtest_fill and live_fill:
slippage = (live_fill['price'] - backtest_fill['price']
) / backtest_fill['price']
self.divergences.append({
'timestamp': timestamp,
'type': 'fill_divergence',
'slippage_bps': slippage * 10000,
'severity': 'LOW' if abs(slippage) < 0.001 else 'MEDIUM',
})
def report(self):
"""Weekly divergence report."""
from collections import Counter
severity_counts = Counter(d['severity'] for d in self.divergences)
return {
'total_divergences': len(self.divergences),
'by_severity': dict(severity_counts),
'avg_slippage_bps': np.mean([
d['slippage_bps'] for d in self.divergences
if d['type'] == 'fill_divergence'
]) if any(d['type'] == 'fill_divergence'
for d in self.divergences) else 0,
}
Дашборд метрикалары
| Метрика | Формула | Эскертүү чеги |
|---|---|---|
| Сигнал дал келүү деңгээли | < 95% | |
| Орточо слиппедж | (bps) | > 10 bps |
| Толтуруу деңгээли | < 90% | |
| PnL айырмачылыгы | > 20% | |
| Кечигүү p99 | Сигналдан толтурууга чейинки 99-персентиль | > 500 мс |
Слиппедж моделин калибрлөө

2-4 жума дайын топтогондон кийин, сиз бэктест слиппедж моделин реалдуу дайындарга калибрлей аласыз:
def calibrate_slippage(live_fills: list[dict]) -> dict:
"""
Calibrate slippage model using real fills.
live_fills: [{'expected_price': ..., 'actual_price': ..., 'size_usd': ..., 'volume_usd': ...}]
"""
slippages = []
participation_rates = []
for fill in live_fills:
slip = abs(fill['actual_price'] - fill['expected_price']
) / fill['expected_price']
part = fill['size_usd'] / max(fill['volume_usd'], 1)
slippages.append(slip)
participation_rates.append(part)
slippages = np.array(slippages)
participation_rates = np.array(participation_rates)
from scipy.optimize import curve_fit
def model(x, k, base):
return k * np.sqrt(x) + base
popt, _ = curve_fit(model, participation_rates, slippages,
p0=[0.1, 0.0001])
return {
'impact_coeff': popt[0],
'base_slippage': popt[1],
'mean_slippage_bps': np.mean(slippages) * 10000,
'p95_slippage_bps': np.percentile(slippages, 95) * 10000,
}
Башка куралдар менен байланыш
Бэктест-лайв паритети өзүнчө милдет эмес. Ал "Backtests Without Illusions" сериясынын башка куралдары менен кесилишет:
- Адаптивдүү drill-down — толтуруу симуляциясынын тактыгын жакшыртат, бул аткаруу паритетинин негизги компоненти.
- Фандинг мөлчөрлөмөлөрү — эгер бэктест фандингди моделдебесе, 3xтен жогору левередж менен паритет мүмкүн эмес.
- Parquet кэш — алдын ала эсептелген убакыт кесимдери жана индикаторлор бэктесттин ботко окшош дайындарды көрүшүн камсыз кылат. RunningCandleBuffer эмуляциясы = реалдуу убакытта жаңылоо.
- Polars vs Pandas — pandas'тан (бэктест) Polars'ка (лайв) өткөндө, сандык жыйынтыктардын дал келишин камсыз кылуу керек.
- Walk-Forward — үлгүдөн тышкаркы дайындардагы walk-forward стратегиянын кантип начарлаарын көрсөтөт — бул in-sample бэктестке караганда лайвга жакыныраак.
Сунуштар
-
Shared core милдеттүү. Сигнал генерациясы үчүн жалгыз код базасы — паритеттин минималдуу талабы. Бирдей логикасы бар эки файл бир ай ичинде айырмачылыкты кепилдейт.
-
Толтуруу моделин калибрлеңиз. Туруктуу 5 bps слиппедж эч нерседен жакшы. Реалдуу дайындарга калибрленген слиппедж модели алда канча жакшыраак.
-
Алгачкы 2-4 жума бою shadow режимин колдонуңуз. Сигнал дал келүү деңгээли 95%+ жеткенге чейин реалдуу акча менен соода кылбаңыз.
-
Фандинг мөлчөрлөмөлөрүн моделдеңиз. Түбөлүк фьючерстер үчүн бул тандоо эмес — бул милдеттүү. Фандинг 5xтен жогору левередж менен бардык PnLды жеп коюшу мүмкүн.
-
Баарын логдоңуз. Ар бир сигнал, ар бир буйрук, ар бир толтуруу — убакыт белгилери менен. Логдорсуз пост-мортем талдоо мүмкүн эмес.
-
Салыштырууну автоматташтырыңыз. Жумалык DivergenceMonitor отчету автоматтык түрдө келиши керек. PnL терс болгонго чейин күтпөңүз.
-
Демейки боюнча пессимисттик бэктест. Бэктесте күтүүлөрдү төмөн баалап, лайвда жагымдуу таңгалуу тескерисинче болгондон жакшыраак. Слиппедж модели консервативдүү болушу керек.
Корутунду

Бэктест-лайв паритети системанын касиети эмес, ал — процесс. Мыкаамат паритет жок: бэктест аныктамасы боюнча реалдуулуктун модели, ал эми модель дайыма жөнөкөйлөтөт. Бирок "модель 5%га башкача" жана "модель 50%га башкача" ортосундагы айырманы архитектура аныктайт.
Жетилүүнүн үч деңгээли:
- Негизги. Shared core, туруктуу слиппедж, комиссиялар. Айырмачылык: 10-20%.
- Өркүндөтүлгөн. Окуяга негизделген архитектура, адаптивдүү drill-down, фандинг модели, shadow режими. Айырмачылык: 5-10%.
- Институционалдык. L2 ордербук симуляциясы, калибрленген таасир модели, реалдуу убакыттагы айырмачылык мониторинги. Айырмачылык: 2-5%.
Сиздин милдетиңиз — кайсы деңгээлде экениңизди аныктоо жана позиция көлөмүңүз менен левереджиңиз үчүн кайсы айырмачылыкты кабыл алса боло турганын түшүнүү.
Пайдалуу шилтемелер
- NautilusTrader — High-Performance Algorithmic Trading Platform
- Freqtrade — Free, open source crypto trading bot
- Almgren, R., Chriss, N. — Optimal Execution of Portfolio Transactions (2001)
- Lopez de Prado — Advances in Financial Machine Learning, Chapter 12: Backtesting
- Ernest Chan — Quantitative Trading: How to Build Your Own Algorithmic Trading Business
- Hexagonal Architecture (Ports and Adapters) — Alistair Cockburn
- Optuna — Hyperparameter Optimization Framework
Цитата
@article{soloviov2026backtestliveparity,
author = {Soloviov, Eugen},
title = {Backtest-live parity: why your bot trades differently from the backtest},
year = {2026},
url = {https://marketmaker.cc/ru/blog/post/backtest-live-parity},
description = {Complete taxonomy of divergences between backtesting and live trading: from slippage and partial fills to codebase desynchronization. Architectural patterns for achieving parity and a production monitoring checklist.}
}
Authors
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.