Există o întrebare pe care orice backtest o ocolește: același cod, hrănit live cu aceeași piață, ar fi făcut același lucru? Nu poți răspunde cu și mai mult backtesting. Poți răspunde doar rulând strategia pe date live, cu semantică reală de execuție, și verificând apoi — tranzacție cu tranzacție — că cele două lumi se potrivesc. Facem verificarea asta în fiecare zi, automat, și a fost de departe cel mai productiv vânător de bug-uri din platformă.
Ziua întâi: construiește oglinda
Fiecare strategie promovată rulează într-un nod live izolat, care consumă fluxuri reale de la exchange: cotații live pentru execuții, spread-uri reale, ore reale de sesiune. Fără stare partajată între strategii (asta am învățat-o pe pielea noastră — un nod comun lăsa interogările de poziții ale unei strategii să se scurgă în alta). Fiecare execuție este înregistrată împreună cu valoarea semnalului care a generat-o.
În fiecare dimineață: replay și diff
Un job zilnic ia fereastra de paper a fiecărei strategii, rulează cod identic prin motorul de backtest pe aceeași perioadă, folosind datele din catalog, și potrivește execuțiile una la una: aceeași direcție, aceeași toleranță de timestamp, aceeași dimensiune. Rezultatul nu e o corelație sau o impresie. E un tabel: potrivite, doar-în-paper, doar-în-replay. O strategie sănătoasă stă la 54 din 55 potrivite. Una bolnavă îți spune exact care tranzacție a divergat și când.
Ce s-a stricat, în ordinea în care s-a stricat
- Execuții în timpul warmup-ului. Nodul live alimenta istoric ca să încălzească indicatorii — iar strategiile cu handlere proprii de bare tranzacționau vesel pe el. Backtesturile nu vedeau niciodată acele intrări fantomă. Soluția a fost o protecție la nivelul stratului de submitere, nu o corecție în strategie, pentru că altfel fiecare strategie moștenește bug-ul.
- Warmup secvențial pe mai multe picioare. O strategie cross-secțională își încălzea instrumentele pe rând; fiecare picior vedea frații goi, iar ancora nu se inițializa niciodată. Live nu tranzacționa nimic; în replay mergea perfect. Zero tranzacții potrivite — dar doar diff-ul a spus-o cu voce tare.
- Crash loop din precizia tick-urilor. Tick-urile aggTrade live sosesc cu o precizie diferită față de cea așteptată de instrumentul din sandbox. Nodul intra în crash loop pe o aserțiune pe care backtestul nu ar fi putut-o declanșa vreodată, pentru că barele din catalog sunt deja normalizate.
- Amnezie la restart. Repornirile procesului re-declanșau logica de intrare pe poziții care existau deja — pentru o strategie de rebalansare, un restart devenea, discret, o rebalansare. În tranzacționarea live asta nu e o notă de subsol despre paritate; e un semnal de alarmă cu bani în joc.
Observați tiparul: niciunul dintre ele nu e un bug de semnal. Toate sunt bug-uri la granița de execuție — warmup, stare, precizie, reporniri. Exact clasa de defecte la care backtesturile sunt structural oarbe, pentru că într-un backtest motorul este granița de execuție.
Asimetriile pe care le păstrăm intenționat
Cele două lumi nu sunt identice, și asta e voit. Backtestul taxează în PnL un half-spread modelat plus impact după legea rădăcinii pătrate; paper plătește spread-ul real în prețul de execuție și nu are model de impact. Adăugarea spread-ului modelat în paper (sau a celui real în backtest) ar însemna dublă contorizare. Paritate înseamnă aceleași decizii, aceleași execuții în limita toleranței — nu PnL identic bit cu bit. Să știi care diferențe sunt principiale și care sunt bug-uri: în asta stă mare parte din disciplină.
Un backtest e o ipoteză. Paper trading e experimentul. Paritatea prin replay e caietul de laborator care te prinde când te amăgești singur.
Dacă rulezi strategii și nu compari periodic comportamentul live cu cel din replay, ai o categorie întreagă de bug-uri pe care nu ai văzut-o niciodată. Noi găsim cam unul la două săptămâni, și fiecare era invizibil din interiorul backtestului.
← Toate articolele
