Un test util pentru backtest nu are nimic de-a face cu găsirea unui parametru mai bun: oprește procesul la jumătate, restaurează-l și termină aceeași reluare. Cu intrări identice și un simulator de execuție controlat, deciziile, ordinele și capitalul propriu ar trebui să coincidă cu o rulare neîntreruptă.
Dacă nu coincid, ai găsit o problemă de gestionare a stării. Strategia depinde de ceva ce nu ai salvat sau nu ai putut reconstrui. Această dependență contează ori de câte ori reluăm rulări de cercetare, înlocuim lucrători sau implementăm cod nou într-un serviciu de paper trading.
Îmi place testul acesta fiindcă răspunsul așteptat este neobișnuit de clar. Nu există loc de dispută despre schimbarea pieței. Ambele rulări primesc aceeași piață.
Iată 3 moduri greșite de a reporni. Numerele sunt ilustrative; fiecare defecțiune poate apărea într-un sistem altminteri determinist.
1. Reîncarci câteva bare și consideri indicatorii încălziți
Să presupunem că strategia folosește o medie mobilă exponențială pe 100 de perioade. Actualizarea ei este:
alpha = 2 / 101
ema_next = alpha * close + (1 - alpha) * ema_previous
Procesul neîntrerupt duce mai departe EMA acumulată. Procesul repornit preia 100 de bare, inițializează EMA cu prima închidere și presupune că un indicator pe 100 de perioade are nevoie de 100 de observații.
Această presupunere confundă parametrul de netezire al indicatorului cu o fereastră finită de memorie. O EMA păstrează o contribuție descrescătoare din starea inițială. Dacă două versiuni pornesc cu o diferență de 10 unități de preț între valorile EMA, prețurile ulterioare identice reduc diferența astfel:
| Actualizări de la inițializare | Diferența rămasă | Proporția din eroarea inițială |
|---|---|---|
| 100 | 1.353 | 13.53% |
| 250 | 0.0674 | 0.674% |
| 500 | 0.000454 | 0.00454% |
Calculul este 10 * (99 / 101)^k. Preluarea a 100 de bare îți oferă doar 99 de actualizări dacă prima observație este folosită ca valoare inițială.
Dezastrul apare de obicei în apropierea unui prag de decizie. O rulare vede prețul deasupra EMA, cealaltă îl vede dedesubt. O mică diferență numerică generează o tranzacție în plus. După aceea, perioadele de așteptare, numerarul disponibil și deciziile ulterioare pot ajunge și ele să difere.
Salvează starea recursivă a indicatorului, starea inițializării și ultimul eveniment procesat. Ca alternativă, reia rularea de la o stare inițială cunoscută. O perioadă mai lungă de încălzire poate oferi o aproximație acceptabilă, dar alege-i durata pornind de la o toleranță explicită la eroare și verifică dacă acea toleranță poate schimba deciziile. „De 5 ori perioada” este o convenție, nu o demonstrație.
Iar indicatorii nu sunt tot istoricul. O percentilă mobilă are nevoie de fereastra ei. Un model online poate avea nevoie de starea optimizatorului. O regulă care așteaptă 3 bare după o pierdere trebuie să-și amintească pierderea și contorul.
2. Salvezi pozițiile și uiți ordinele încă active
Poziția-țintă este de 10 unități. Un ordin de cumpărare pentru 10 s-a executat în proporție de 4, iar 6 au rămas în așteptare. Salvezi la checkpoint poziția de 4, repornești și trimiți încă un ordin de cumpărare pentru cele 6 lipsă.
Dacă se execută atât cantitatea rămasă din ordinul inițial, cât și ordinul de înlocuire, ajungi să deții 16.
În backtest, această eroare rămâne adesea ascunsă fiindcă repornirea motorului de executare șterge în tăcere ordinele active. În paper trading, simulatorul sau serviciul extern le poate păstra. Același cod de recuperare produce apoi o expunere diferită, în funcție de componenta care a supraviețuit.
| La repornire | Starea reală | Ce vede recuperarea bazată doar pe poziție |
|---|---|---|
| Poziția-țintă | 10 | 10 |
| Poziția executată | 4 | 4 |
| Cantitatea ordinului de cumpărare rămasă în așteptare | 6 | 0 |
| Cantitatea suplimentară necesară | 0 | 6 |
Dezastrul se vede ca un val inexplicabil de ordine imediat după recuperare. Uneori dublează expunerea. Alteori închide o poziție pentru care ordinul de protecție este încă activ, lăsând acel ordin să deschidă o poziție nouă mai târziu.
Un checkpoint trebuie să păstreze identitatea ordinelor și starea ciclului lor de viață alături de poziții. Înainte de a genera acțiuni noi, recuperarea trebuie să reconcilieze acele înregistrări cu sistemul de execuție. Un ordin cu rezultat necunoscut trebuie investigat; a considera că „nu s-a salvat nicio confirmare” înseamnă „nu a fost trimis niciodată” este rețeta pentru ordine duplicate.
Identificatorii stabili ai ordinelor client te ajută să afli ce s-a întâmplat. Ei previn duplicatele doar dacă sistemul receptor aplică efectiv regulile necesare de unicitate sau idempotență. Salvează și identificatorii execuțiilor procesate, astfel încât o executare reluată să nu mărească poziția de două ori.
Am o slăbiciune pentru banalul ecran cu starea ordinelor. În ziua repornirii, rândurile lui mărunte devin brusc cea mai interesantă interfață din clădire.
3. Restaurezi poziția și începi un registru P&L nou
Să luăm un exemplu spot fără levier și fără comisioane. Pornim cu $10,000 numerar, cumpărăm 10 unități la $100 și salvăm starea la checkpoint când prețul de evaluare ajunge la $110.
Starea corectă este $9,000 numerar plus o poziție în valoare de $1,100: capital propriu de $10,100. Dacă recuperarea restaurează cele 10 unități, dar readuce numerarul la valoarea inițială de $10,000, raportează $11,100. Ai creat $1,000 prin simpla repornire a unui proces.
Alte variante sunt mai puțin spectaculoase. Recuperarea păstrează capitalul propriu intact, dar resetează prețul de intrare la $110. Capitalul propriu total poate rămâne corect, în timp ce repartizarea între profitul realizat și cel nerealizat se schimbă. Dacă un stop sau o condiție de ieșire folosește prețul de intrare, scurtătura contabilă schimbă acum comportamentul de tranzacționare.
Sau sistemul uită maximul anterior al capitalului propriu. Să presupunem că acesta a atins un vârf de $10,600 înainte să scadă la $10,100. Drawdown-ul este de aproximativ 4.72%. Resetează maximul istoric la recuperare, iar strategia crede brusc că drawdown-ul este zero. Orice control al riscului bazat pe drawdown tocmai a fost resetat fără autorizare.
Dezastrul poate lua, așadar, forma unei discontinuități a capitalului propriu, a unui drawdown suspect de mic sau a unei reguli de risc care încetează să se declanșeze după implementări. Păstrează registrul și starea strategiei dependentă de contabilitate: mișcările de numerar, pozițiile, baza de cost aplicabilă, taxele acumulate și memoria controlului riscului. Reconciliază capitalul propriu restaurat cu registrul la același moment de evaluare.
Un checkpoint are nevoie de un punct de referință coerent. Dacă salvezi numerarul după o executare și cantitatea poziției înaintea acelei executări, obții o stare care nu a existat niciodată. Salvează împreună stările corelate sau înregistrează o secvență persistentă de evenimente din care le poți reconstrui. Păstrează și cursorul evenimentelor împreună cu starea, astfel încât recuperarea să nu sară peste executare și nici să nu o aplice de două ori.
În cadrul de cercetare, aș păstra un test care rulează o reluare de referință neîntreruptă, apoi repornește o a doua rulare în puncte alese intenționat pentru că sunt delicate: în timpul inițializării indicatorilor, după o executare parțială și cât timp este activă o limită de risc. Folosește aceeași ordine a evenimentelor și păstrează orice stare aleatorie a simulatorului. Compară prima decizie după recuperare, înregistrările ordinelor și executărilor, precum și evoluția capitalului propriu. Un sold final identic poate ascunde erori care se compensează reciproc.
Pentru o cădere după trimiterea ordinului, dar înainte de confirmare, cadrul de test trebuie să păstreze și starea serviciului de execuție, independent de procesul strategiei. Altfel, șterge chiar incertitudinea pe care încerci s-o testezi.
Specificația unei strategii include ceea ce își amintește. Fă-i memoria suficient de explicită încât să poți opri procesul la jumătatea unei reluări și să arăți exact cum își reia activitatea.
← Toate articolele


