Voorspellingsmarkten lijken het makkelijkste ter wereld om te backtesten. De prijs ligt tussen [0, 1]. De uitbetaling is een dollar of niets. Geen hefboom, geen funding, geen basis, geen gedoe met perpetual swaps om 00:00 UTC. We hadden al een backtester die crypto-perps met kosten, funding en impact aankon. Het plan was om daar twee dagen aan te sleutelen en daarna strategieën te gaan genereren.
Het werden er acht. Hier is het logboek, ongeveer in chronologische volgorde, inclusief de dag waarop de equitycurve er ongelooflijk uitzag — en dat ook was.
Dag 1: de adapter die eenvoudig had moeten zijn
De eerste mapping was één-op-één en voelde logisch. Een markt is een instrument. De YES-prijs is de prijs. YES kopen is long gaan, NO kopen is short gaan. Afwikkeling is een gedwongen sluiting op 1.00 of 0.00. Voer de uurlijkse prijsreeks in dezelfde eventloop in en klaar.
Die mapping hield het ongeveer negentig minuten vol met echte data. Het eerste dat sneuvelde was de rendementsreeks. Onze hele risicolaag — positiegrootte, vol targeting, de Sharpe-rapportage — ging uit van log-rendementen van een doorlopend instrument. Een markt die van 0.04 naar 0.00 gaat, heeft een ongedefinieerd log-rendement en een wel degelijk bepaald totaalverlies. En een markt die drie dagen voor afwikkeling op 0.04 staat, is een fundamenteel ander object dan een markt die vier minuten ervoor op 0.04 staat, ook al staat er in beide rijen 0.04.
Uiteindelijk hebben we de hele reeks opnieuw geparametriseerd op basis van de resterende tijd tot afwikkeling in plaats van de kloktijd, en PnL als terminaal behandeld in plaats van op marktwaarde. Dat was de juiste keuze, en daardoor moesten alle rapportagecode die erop voortbouwde op de schop.
Dag 2: de kostenformule is de strategie
Op Kalshi zijn de transactiekosten geen aftrek van een aantal basispunten. Ze zijn kwadratisch afhankelijk van de prijs: ongeveer 0.07 × contracts × P × (1−P), naar boven afgerond op de cent per order. Dat betekent dat de kosten het hoogst zijn precies waar een munt-opgooimarkt het interessantst is, en aan de uiteinden bijna niets kosten.
| Prijs | Kosten per contract | Benodigde edge (procentpunten kans) | Kosten als % van inzet |
|---|---|---|---|
| 5¢ | 0.33¢ | 0.33 | 6.7% |
| 10¢ | 0.63¢ | 0.63 | 6.3% |
| 25¢ | 1.31¢ | 1.31 | 5.3% |
| 50¢ | 1.75¢ | 1.75 | 3.5% |
| 75¢ | 1.31¢ | 1.31 | 1.8% |
| 90¢ | 0.63¢ | 0.63 | 0.7% |
| 95¢ | 0.33¢ | 0.33 | 0.35% |
Lees de derde kolom als het belangrijkste getal: om quitte te spelen als je op 50¢ koopt en aanhoudt tot de afwikkeling, moet je kansinschatting 1.75 punten hoger liggen dan die van de markt. Geen 1.75 procent relatief, maar absoluut. Als je uitstapt vóór de afwikkeling in plaats van aan te houden, betaal je die kosten twee keer, plus de spread.
De CLOB van Polymarket heeft historisch gezien een heel ander kostenprofiel gehad, met transactiekosten die dichter bij nul liggen. De volledige kosten verschuiven daardoor naar de spread en de diepte. Dezelfde strategielogica heeft dus heel andere economische gevolgen per handelsplatform. Elke vergelijking tussen platforms die één kostenmodel gebruikt, is fictie. We gebruiken nu een kostenfunctie per platform, geen enkele vaste waarde.
Als je maar één regel van een backtestrapport over voorspellingsmarkten leest, laat het dan de kostenregel in kanspunten zijn. Een strategie met een beweerde voorspellingsvoorsprong van 1.2 punten op markten van 50¢ levert op Kalshi verlies op, nog voordat er ook maar één andere kostenpost bijkomt. Dat moet op de eerste pagina staan, zodat de lezer het niet zelf hoeft af te leiden.
Dag 3: het orderboek is een trap en is kort
Ons impactmodel was een wortelfunctie die was gekalibreerd op orderboeken van BTC-perps. Dat is de verkeerde vorm. Met een tick van 1¢ op een instrument van $1 zijn er maar 99 mogelijke prijsniveaus in het hele orderboek. In een markt met gemiddelde liquiditeit liggen er misschien een paar honderd contracten op het beste niveau, gevolgd door een gat.
Hier is een momentopname van een markt voor economische cijfers die we bemonsterden, aan de YES-kant, ongeveer 30 uur voor afwikkeling:
| Niveau | Omvang (contracten) | Cumulatieve koopkosten |
|---|---|---|
| 42¢ | 310 | 310 @ gem. 42.0¢ |
| 43¢ | 85 | 395 @ gem. 42.2¢ |
| 45¢ | 140 | 535 @ gem. 42.9¢ |
| 49¢ | 600 | 1,135 @ gem. 46.1¢ |
Een order van 1,000 contracten — vijfhonderd dollar risico, een afrondingsfout in crypto — verschuift de effectieve prijs met vier cent. Vier cent is meer dan twee keer de kosten. Hier valt geen vloeiende functie op aan te passen; je loopt het orderboek niveau voor niveau af, of je verzint maar wat. We hebben het sqrt-model voor deze activaklasse geschrapt en een letterlijke orderboekdoorloop geschreven. Die is trager en klopt.
Ergens hierbij betrapte ik mezelf erop dat ik me ergerde aan het feit dat deze markten "te klein zijn om ertoe te doen". Ze zijn klein omdat de prijs wordt bepaald voor één concrete vraag uit de echte wereld, met een deadline, en er maar zoveel mensen zijn die een mening hebben over de eerste aanvragen voor een werkloosheidsuitkering in de VS op een woensdag. De omvang is de markt. Erover klagen is alsof je klaagt dat er maar negen mensen aan een pokertafel passen.
Dag 4: de dag waarop de equitycurve prachtig was
Sharpe 4.1 op 1,400 markten. Vloeiend. Iedere onderzoeker zou hiervan buikpijn moeten krijgen; bij mij kwam die uiteindelijk ook, zo'n veertig minuten nadat ik er al een screenshot van had gemaakt.
De bug zat in de resampler. Prijshistorie voor illiquide markten komt terug met onregelmatige tijdstempels, dus zetten we de index om naar een regelmatig uurraster. Het laatste punt van elke gearchiveerde reeks is de afwikkelingswaarde, 1.00 of 0.00. Bij het herindexeren gebruikten we een nearest-neighbour-vulling zonder richtingbeperking. Daardoor werd bij markten waarvan de laatste transactie uren voor afwikkeling plaatsvond de afwikkelingswaarde achterwaarts over het gat verspreid. Het model las het antwoord van morgen in de rij van vandaag, precies bij de illiquide markten waar het zijn positie kon vergroten zonder tegen dieptelimieten aan te lopen.
Een nearest-neighbour-vulling is prima bij een doorlopend instrument. Bij een instrument waarvan de laatste waarneming de werkelijkheid is, wordt het een machine die vooruitkijkt. We controleren nu met een assert dat elke vulling alleen vooruitgaat en dat de afwikkelingsrij een label krijgt en wordt uitgesloten van alle featureberekeningen. Die assert is negen regels lang en het is de waardevolste code die we die hele week hebben geschreven.
Dag 5–6: 1,412 markten, ongeveer 180 weddenschappen
De steekproefgrootte is bij voorspellingsmarkten een valstrik met een vriendelijk gezicht. Je rekent 1,412 markten af, hebt het gevoel dat je 1,412 waarnemingen hebt en berekent een t-statistiek die daarbij past. Maar veertien NFL-wedstrijden op dezelfde zondag delen hetzelfde weer, dezelfde blessurerapporten en dezelfde geldstroom van gokkers. Eenenvijftig verkiezingsmarkten per staat delen één nationale verschuiving. "Gebeuren vóór 31 maart" en "gebeuren vóór 30 juni" zijn dezelfde weddenschap met een andere afloopdatum, en ze worden samen afgerekend.
We hebben de markten geclusterd op onderliggende gebeurtenisbron en afwikkelingsdatum en kwamen uit op een effectief aantal onafhankelijke waarnemingen van ongeveer 180. Dat is niet genoeg om bij de effectgroottes waar we naar keken een echte edge van ruis te onderscheiden. En per markt bootstrappen lost dit niet op, want de bootstrap moet clusters bemonsteren in plaats van rijen. Als je dit verkeerd doet, overschat je de significantie stilletjes met een factor twee of drie.
Dag 7: afwikkeling is ook een kansverdeling
De dingen die we helemaal niet hadden gemodelleerd en op de harde manier ontdekten:
- Vervroegde afwikkeling. Een markt met de looptijd "vóór 31 december" kan op 4 augustus al worden afgerekend als de gebeurtenis dan plaatsvindt. Je kapitaal komt eerder vrij en de houdperiode was nooit wat de contractnaam suggereerde.
- Betwistingen. Markten die door een oracle worden afgerekend, hebben een bezwaartermijn. Een positie kan dagen na de gebeurtenis nog onbeslist blijven, en in een klein aantal gevallen draait de uitkomst om ten opzichte van wat voor de hand lag.
- Ongeldigverklaringen. Bij onduidelijke brondata wordt een markt geannuleerd en krijgt iedereen zijn geld terug. In onze steekproef geldt dit voor minder dan 1% van de markten, maar ze clusteren juist rond de ambigue vragen die een model als verkeerd geprijsd aanmerkt.
- Vastgezet kapitaal. Een edge van 3 punten die in 90 dagen wordt gerealiseerd en een edge van 3 punten die in 6 uur wordt gerealiseerd, zijn niet vergelijkbaar. Een backtest die de totale edge rapporteert zonder die af te zetten tegen de tijd dat het kapitaal vastzat, zal altijd de langzame variant verkiezen.
We hebben een term voor kapitaalkosten en willekeurige variatie in de afwikkelingsdatum aan de simulator toegevoegd. Geen van beide is nauwkeurig. Allebei zijn ze beter dan de stilzwijgende aanname dat de afwikkeling zeker precies op de opgegeven datum plaatsvindt.
Dag 8: wat we zouden overslaan en waarmee we zouden beginnen
- Sla de volledige infrastructuur op basis van rendementen over. Pas geen risicolaag met vol targeting aan voor een instrument met een terminale uitbetaling. Schrijf een laag voor positiegrootte die werkt met kansen en inzetten. We verloren twee dagen met pogingen om de oude aanpak passend te maken.
- Bouw de kostenfunctie vóór de strategie. Breng voor elk handelsplatform dat je wilt gebruiken de break-even-edgecurve in beeld en hang die boven je bureau. Zo sneuvelt ongeveer de helft van de ideeën nog voordat ze je een backtestrun kosten.
- Loop vanaf dag 1 door het orderboek. Elk parametrisch impactmodel uit een doorlopende markt zal op een manier fout zijn die in jouw voordeel uitpakt.
- Cluster vóór je telt. Bepaal de clust sleutel voor de effectieve steekproefgrootte tegelijk met de keuze van je universum, niet pas nadat je een Sharpe hebt gevonden die je bevalt.
- Voer een assert uit op de vulrichting. Eén regel per join. Als een reeks eindigt met de werkelijkheid, behandel achterwaarts vullen dan per definitie als een bug, in plaats van iets waarvan je hoopt dat je het bij review opmerkt.
Die acht dagen waren de moeite waard, vooral omdat voorspellingsmarkten de ambiguïteit wegnemen die het zo makkelijk maakt om jezelf voor de gek te houden met crypto-backtests. Er is geen funding rate om weg te wuiven en geen discussie over de mark-prijsconventie. Alleen een vraag, een deadline en een antwoord. Als de backtest hier fout zit, kun je precies aanwijzen waar.
← Alle artikelen


