Een 20-daagse Donchian oogt onschuldig in een spec. De agent schrijft een rolling max van 20 bars, de backtest start op de eerste rij van het parquet-bestand, en de eerste twee weken is de "20-daagse high" gewoon de running max van de bars die er toevallig zijn. Op dag vier is het een vierdaagse high. De strategie waarvan je dacht dat je die testte, is niet degene die het eerste dozijn fills produceerde.
Ik heb een notebook met dagelijkse ETHUSDT-bars waar de full-sample-Sharpe 1.4 is. Knip de eerste 20 sessies weg en hij zakt naar 0.6. Houd die 20 en gooi de rest van jaar één weg, en hij print 3.1. Niemand heeft morgen gelekt. De strategie gebruikte het verleden, alleen niet genoeg ervan, en het rapport behandelde die onaffe trades als bewijs.
Laat het venster traden terwijl het nog aan het vullen is
De gebruikelijke ravage is min_periods=1. Pandas berekent een rolling mean op een enkele bar als je het toelaat. Agents doen dit voortdurend, omdat een NaN bovenaan het frame voelt als een bug, en hem opvullen maakt de unit test groen.
Een 20-daags realized-vol-target met twee return-observaties is een size-explosie. De variantie van twee getallen is een muntworp, je inverteert hem, en de eerste positie is meerdere keren het beoogde risico. Een z-score tegen een standaarddeviatie die bijna nul is, doet dezelfde truc met een teken: de strategie lijkt een razor-scherpe entry te hebben die nooit meer opduikt zodra het venster eerlijk is.
Breakouts zijn erger, omdat ze op de echte regel lijken. Een 20-bar-kanaal op bar zes is een zes-bar-kanaal. Je krijgt pal aan het begin een cluster trades, vaak in een rustige periode die de afgewerkte indicator niet zou hebben getriggerd. Rustige markten drijven een beetje. Een krap kanaal vuurt. De equity curve krijgt een voorsprong die geen later jaar herhaalt.
Zero-fill en forward-fill verzinnen een andere leugen. RSI op 0 leest als oververkocht. Een ontbrekende ATR van 0 blaast de unit size op, en de backtest koopt braaf een magazijn. Ik heb liever dat een NaN de order doodt dan dat een 0 er een verzint.
Ik betrap mezelf er nog steeds op dat ik vanaf rij 0 plot, omdat een lege maand links op de chart onaf oogt. De lege maand is het eerlijke deel.
Knip de equity curve bij, houd de positie
Deze overleeft de code review. Je berekent de 20-daagse features keurig, gooit de eerste 20 rijen van de geplotte curve weg, en publiceert vanaf 21 januari. De positie op 21 januari is geopend op 14 januari. De high-water van de trailing stop, de pyramid-count, de cash na die burns: het liep allemaal het "schone" sample binnen.
De ravage is een paper-strategie die je niet kunt starten op de datum in het stuk. Herstart vanaf flat op de gerapporteerde start en de orders van de eerste week komen niet overeen. Soms zit de backtest al in een trade die het papersysteem geen reden heeft om in te gaan. Soms gaat het papersysteem in omdat zijn lookback koud is, en de backtest blijft buiten omdat zijn verborgen maand de breakout al heeft genomen. Twee openingsboeken, één gepubliceerde startdatum.
Walk-forward-folds doen dit stilletjes. Elk testvenster heeft een lookback-staart die je niet plot. Sla het simuleren van die staart over en de eerste test-trades zijn opnieuw trades van een onafgemaakt venster. Simuleer hem wel en rapporteer alleen de testdagen, en de positie van de testdag is conditioneel op fills die je niet toont. Die tweede versie kan een legitieme onderzoekskeuze zijn. De eerste ochtend van de fold een cold start noemen, terwijl een trailing stop al live is vanuit de staart, is hoe twee onderzoekers twee Sharpes uit één config halen.
Warm op in kalenderdagen wanneer de feature geen dag is
"Geef het 30 dagen" laat de feature ondergespecificeerd. 30 kalenderdagen op een 5-minuten-Donchian is duizenden bars voorbij een 20-periode-lookback. 30 dagen op een dagelijkse feature die 20 sessies nodig heeft, is ofwel te vet of te dun, afhankelijk van weekenden en gaten.
Een funding-rate-z-score op een van onze perp-venues kreeg een 30-daagse warmup omdat de spec 30 periodes zei en iemand periodes in kalender vertaalde. Funding print daar elke acht uur. 30 dagen is ongeveer 90 settlements. 30 periodes is tien dagen. De extra twee maanden burn-in bevatten toevallig een depeg-week. Die weglaten maakte het live-venster kalmer dan de echte geschiedenis van de strategie. Mensen gaven de schuld aan startdatum-gevoeligheid. De warmup had het regime opgegeten.
En crypto versus equity laat hetzelfde getal van betekenis veranderen zonder dat iemand een parameter aanpast. 20 "dagen" ETH omvatten zaterdagen. 20 equity-sessies is bijna een kalendermaand. Kopieer een 20-daagse lookback van een aandelen-notebook naar uurlijkse perpetual-candles en je hebt een 20-uurskanaal met een 20-daagse naam. De eerste geldige bar is dan ofwel 20 uur erin, of 20 dagen erin als een latere functie resamplet, en ik heb beide gezien in dezelfde agent-diff.
Zet het eerste verhandelbare tijdstip vast
De warmup is een datavereiste, geen bonus-sample. Elke feature noemt het aantal voltooide observaties dat hij nodig heeft, in de eenheden waarin hij wordt berekend. Het eerste verhandelbare tijdstip is de eerste bar waarop dat allemaal waar is en een flat account een order had mogen versturen.
| Feature | Wat de spec meestal zegt | Wat er daadwerkelijk moet bestaan | Stille vervanger |
|---|---|---|---|
| 20-daagse Donchian | 20 dagelijkse highs | 20 voltooide sessies | Running max met min_periods=1 |
| 30-daagse realized vol | 30-daags venster | 30 close-to-close returns | Twee-daagse variantie, geïnverteerd tot size |
| 20-print funding-z-score | 20 dagen | 20 funding-settlements | 20 kalenderdagen (~90 prints), of 20 bars van de verkeerde timeframe |
| 14-periode-RSI op 5m | 14 periodes | 14 gesloten 5-minuten-bars | 14 dagen, of 14 bars met gaten forward-filled |
P&L vóór dat tijdstip blijft buiten het track record. De state vóór dat tijdstip moet mogelijk nog worden gesimuleerd, zodat een trailing stop of een cooldown echt is wanneer de klok de eerste verhandelbare bar raakt, maar die fills gaan niet in de Sharpe, het aantal trades of de capacity-berekening. Draai dan de lelijke check: herstart vanaf flat op dat tijdstip, met de lookback alleen beschikbaar als data. Als de orders veranderen, leverde je verborgen trades mee.
Paper trading start op hetzelfde contract. Elk walk-forward-testvenster ook. Als de chart eruitziet alsof er een maand ontbreekt, laat hem ontbreken.
← Alle artikelen


