Uruchomiliśmy ponownie strategię paper trading w połowie transakcji i otrzymaliśmy inną sekwencję zleceń niż przed restartem. Te same dane rynkowe, ta sama wersja strategii, to samo saldo rachunku. Obliczenie sygnału było zgodne. Pamięć strategii dotycząca pozycji i oczekujących zleceń — już nie.
Przez cały dzień odtwarzaliśmy przebieg, by znaleźć źródło rozbieżności. Wniosek był prosty: restart jest dla oprogramowania wydarzeniem rynkowym. Jeśli nie testujesz, jak strategia odbudowuje swój stan, czysty backtest może ukryć system paper trading, który zapomina, co ma na rachunku.
09:10 — Wybraliśmy mało ekscytującą pozycję
Strategia testowa handlowała płynnym kontraktem perpetual: otwierała pozycję długą, gdy krótka średnia krocząca przecinała dłuższą od dołu, a zamykała ją przy przeciwnym przecięciu. Odtwarzanie rozpoczęliśmy z niewielką, już otwartą pozycją i oczekującym zleceniem limit zamykającym pozycję (reduce-only), które miało ją zmniejszyć. Odzyskiwanie stanu musiało więc odtworzyć dwie informacje: co mieliśmy na rachunku i jakie zlecenie zdążyliśmy już wysłać do giełdy.
W punkcie kontrolnym rachunek miał 0.04 kontraktu. Zlecenie na 0.01 pozostawało otwarte. Proces strategii przechowywał obie wartości w pamięci, ale podczas uruchamiania pobierał tylko pozycję. Uznał, że zapamiętane zlecenie już nie istnieje.
09:25 — Pojawiło się pierwsze zduplikowane zlecenie
Po restarcie strategia wykryła istniejącą pozycję długą, uruchomiła logikę sygnałów i wysłała kolejne zlecenie zmniejszające pozycję o 0.01. Na rachunku paper trading były teraz 2 aktywne zlecenia. Każde z osobna było poprawne. Razem mogły sprzedać dwukrotność zamierzonej ilości, gdyby oba zostały zrealizowane.
Początkowo obwinialiśmy pętlę sygnałów. To nie ona zawiniła, lecz niepełny obraz stanu. Strategia zapytała: „Jaką mam pozycję?”, ale nie sprawdziła: „Które zlecenia nadal są aktywne?”.
| Stan po restarcie | Stan widziany przez proces | Stan rachunku |
|---|---|---|
| Pozycja | Długa 0.04 | Długa 0.04 |
| Otwarte zlecenia zmniejszające pozycję | Brak | 2 po 0.01 każde |
| Docelowa ekspozycja po realizacji jednego zlecenia | Długa 0.03 | Może spaść do długiej 0.02 |
10:00 — Naprawiliśmy odzyskiwanie stanu, a potem znaleźliśmy problem z synchronizacją
Zmieniliśmy procedurę startową tak, by przed włączeniem nowych decyzji odbudowywała stan na podstawie pozycji na rachunku i otwartych zleceń. To usunęło duplikat. Potem skomplikowaliśmy przerwę w połączeniu: jedno zlecenie zostało zrealizowane, gdy strategia była offline, a powiadomienie o realizacji dotarło dopiero po ponownym połączeniu.
Migawka rachunku uwzględniała już tę realizację. Opóźnione powiadomienie ponownie zmniejszyło lokalną pozycję. Przez kilka sekund strategia uważała, że ma 0.02 kontraktu, choć rachunek miał 0.03. Kolejne równoważenie opierało się na nieistniejącym niedoborze.
Dodaliśmy reguły uzgadniania stanu: za punkt wyjścia przyjmujemy migawkę rachunku, identyfikatorami zdarzeń odrzucamy realizacje już w niej uwzględnione i nie wysyłamy zleceń, dopóki początkowa synchronizacja się nie zakończy. Powiadomienie może dotrzeć z opóźnieniem albo dwa razy. Odzyskiwanie stanu musi radzić sobie z obiema sytuacjami.
13:40 — Odtwarzanie ujawniło subtelną rozbieżność
Odtworzyliśmy tę samą ścieżkę cenową dla pierwotnego i ponownie uruchomionego przebiegu. Porównanie końcowego P&L nie ujawniłoby problemu: po odwróceniu rynku obie wersje zakończyły z taką samą pozycją. Rozbieżność wyszła na jaw dopiero przy porównaniu zdarzeń zleceń.
Rejestrowaliśmy każdą decyzję wraz ze stanem, z którego korzystała: pozycją, otwartymi zleceniami, identyfikatorem ostatniej przetworzonej realizacji, wartością sygnału i wersją strategii. Pierwsze rozbieżne zdarzenie miało jasne wyjaśnienie. W jednym przebiegu strategia widziała aktywne zlecenie, w drugim — pustą listę. Później jeden przebieg dwukrotnie uwzględnił tę samą realizację.
Zgodne saldo końcowe nie dowodzi, że przebiegi zachowywały się tak samo. Porównuj sekwencje decyzji i zleceń, zwłaszcza w momentach odzyskiwania stanu.
16:20 — Co zrobilibyśmy inaczej następnym razem
Zbyt długo odtwarzaliśmy dane cenowe, zanim sprawdziliśmy zmiany stanu rachunku. Następnym razem najpierw zasymulowalibyśmy sytuacje awaryjne i utrzymali niemal płaską ścieżkę rynku. Błąd w oprogramowaniu byłby wtedy łatwy do zauważenia, bez zmienności utrudniającej diagnozę.
- Uruchom ponownie strategię z otwartą pozycją i częściowo zrealizowanym zleceniem.
- Rozłącz się po wysłaniu zlecenia, a następnie połącz ponownie, zanim dotrze powiadomienie o realizacji.
- Dostarcz to samo zdarzenie realizacji 2 razy i sprawdź, czy stan zmieni się tylko raz.
- Wstrzymaj nowe zlecenia, dopóki pozycje i otwarte zlecenia nie zostaną uzgodnione.
- Porównaj logi decyzji i zleceń z przebiegów ciągłych oraz po restarcie.
Nauczyliśmy się też zapisywać migawkę do odzyskiwania stanu razem z wersją strategii i logiem zdarzeń. Dzięki temu mogliśmy odtworzyć błąd w kilka minut, bez polegania na czyjejś pamięci o dokładnej sekwencji ponownego łączenia.
Strategia paper trading, która działa poprawnie tylko wtedy, gdy jej proces pozostaje uruchomiony, nie przeszła pełnej próby. Uruchom ją ponownie w trakcie pozycji, opóźnij dostarczenie informacji o realizacji i sprawdź każde wysłane potem zlecenie. Nie chodzi o udowodnienie, że nigdy nie zawiedzie. Chodzi o to, by zobaczyć, jak odzyskuje stan, zanim rachunek paper trading niespodziewanie udzieli tej samej lekcji.
← Wszystkie wpisy


