We herstartten een papieren strategie halverwege een transactie en kregen een andere reeks orders dan vóór de herstart. Dezelfde marktgegevens, dezelfde strategieversie, hetzelfde rekeningsaldo. De signaalberekening kwam overeen. De herinnering van de strategie aan haar positie en openstaande orders niet.
We brachten de afwijking in kaart tijdens een dag replaywerk. De nuttige les was eenvoudig: voor je software is een herstart een marktgebeurtenis. Als je niet test hoe de strategie haar status opnieuw opbouwt, kan een schone backtest verhullen dat een papieren systeem vergeet wat het in bezit heeft.
09:10 — We kozen een saaie positie
De teststrategie handelde in een liquide perpetual: long gaan wanneer een kort voortschrijdend gemiddelde boven een langer gemiddelde kruiste, en uitstappen bij de omgekeerde kruising. We begonnen de replay met een kleine open positie en een reduce-only limietorder die klaarstond om die af te bouwen. Zo moest het herstel 2 feiten reconstrueren: wat we in bezit hadden en wat we de beurs al hadden gevraagd te doen.
Op het controlepunt stond er 0.04 contract op de rekening. De order stond open voor 0.01. Het strategieproces had beide waarden in het geheugen gecachet, maar haalde bij het opstarten alleen de positie op. Het ging ervan uit dat de gecachete order verdwenen was.
09:25 — De eerste dubbele order verscheen
Na de herstart zag de strategie de bestaande longpositie, voerde de signaallogica uit en plaatste nog een trimorder van 0.01. De papieren beurs had nu 2 actieve orders. Op zichzelf was geen van beide orders verkeerd. Samen konden ze de beoogde hoeveelheid dubbel verkopen als ze allebei werden uitgevoerd.
Eerst gaven we de signaallus de schuld. Die was het niet; de momentopname was onvolledig. De strategie vroeg: “Welke positie heb ik?” maar vroeg nooit: “Welke orders staan nog open?”
| Status na herstart | Wat het proces dacht | Wat de rekening bevatte |
|---|---|---|
| Positie | Long 0.04 | Long 0.04 |
| Open trimorders | Geen | 2 van elk 0.01 |
| Beoogde blootstelling na 1 uitvoering | Long 0.03 | Kan long 0.02 worden |
10:00 — We herstelden het opstarten en vonden toen een timingprobleem
We pasten het opstarten aan zodat de status opnieuw werd opgebouwd aan de hand van de posities en openstaande orders op de rekening, voordat nieuwe beslissingen werden toegestaan. Daarmee verdween de dubbele order. Daarna maakten we de verbinding minder netjes: één order werd uitgevoerd terwijl de strategie offline was, en de melding van de uitvoering kwam pas na het opnieuw verbinden binnen.
De momentopname van de rekening bevatte de uitvoering al. De vertraagde melding verlaagde vervolgens de lokale positie nog een keer. Een paar seconden lang dacht de strategie dat ze 0.02 contracten had, terwijl de rekening er 0.03 had. De volgende herbalancering was gebaseerd op een fictief tekort.
We voegden reconciliatieregels toe: neem de momentopname van de rekening als uitgangspunt, gebruik gebeurtenis-ID's om uitvoeringen te negeren die daarin al verwerkt zijn, en verstuur geen orders voordat de eerste synchronisatie is voltooid. Een melding kan te laat of dubbel binnenkomen. Herstel moet beide situaties aankunnen.
13:40 — De replay ving een subtiele afwijking op
We speelden hetzelfde koersverloop opnieuw af voor de oorspronkelijke run en de herstartte run. Een vergelijking van de uiteindelijke P&L had het probleem gemist: na de omkering van de markt eindigden beide versies met dezelfde positie. De ordergebeurtenissen vergelijken bracht het aan het licht.
We logden elke beslissing samen met de status die ervoor werd gebruikt: positie, openstaande orders, ID van de laatst verwerkte uitvoering, signaalwaarde en strategieversie. Zo was de eerste afwijkende gebeurtenis te verklaren. De ene run zag een openstaande order; de andere zag een lege lijst. Later verwerkte de ene een uitvoering dubbel.
Een gelijk eindsaldo bewijst niet dat het gedrag overeenkwam. Vergelijk de reeks beslissingen en orders, vooral rond momenten waarop de strategie herstelt.
16:20 — Wat we de volgende keer anders zouden doen
We hadden te lang koersgegevens opnieuw afgespeeld voordat we de statusovergangen van de rekening controleerden. De volgende keer zouden we eerst de faalscenario's simuleren en het marktverloop vrijwel vlak houden. Zo valt de softwarefout goed op, zonder dat een volatiele beweging de diagnose vertroebelt.
- Herstart met een positie en een gedeeltelijk uitgevoerde order.
- Verbreek de verbinding na het plaatsen van een order en verbind opnieuw voordat de uitvoeringsmelding binnenkomt.
- Lever dezelfde uitvoeringsgebeurtenis 2 keer aan en controleer of de status maar 1 keer verandert.
- Blokkeer nieuwe orders totdat zowel posities als openstaande orders zijn gereconcilieerd.
- Vergelijk beslissings- en orderlogs van ononderbroken runs met die van runs na een herstart.
We leerden ook om naast de strategieversie en het gebeurtenissenlog een herstelmomentopname op te slaan. Daardoor konden we de fout binnen enkele minuten reproduceren, zonder afhankelijk te zijn van iemands herinnering aan de exacte volgorde van opnieuw verbinden.
Een papieren strategie die alleen correct werkt zolang het proces actief blijft, heeft de volledige repetitie niet doorstaan. Herstart haar midden in een positie, laat uitvoeringen vertraagd binnenkomen en controleer elke order die ze daarna verstuurt. Het doel is niet bewijzen dat ze nooit faalt. Het doel is haar herstel zichtbaar te maken voordat de papieren rekening je onverwacht dezelfde les leert.
← Alle artikelen


