13. september 2026 · eksekvering

Hvor meget latenstid bør du lægge ind i en backtest? Vi målte hvert millisekund af vores

Hvor meget latenstid bør du lægge ind i en backtest? Vi målte hvert millisekund af vores

Fire tal, alle målt på vores egen paper-trading-stack, én strategi, 1-minuts BTCUSDT perpetual-signaler, 31 dage og 1,418 ordrer. Mediantid fra bar-luk til ordre bekræftet af børsen: 195 ms. 99-percentilen: 2,970 ms. Median på den 1% af minutterne med den højeste realiserede volatilitet: 840 ms. Og den latenstidskonstant, der sad i backtest-configen det meste af det foregående år: 0.

195 msmedian bar-luk → ordre-ack
2,970 msp99, samme sti
840 msmedian i top-1%-volatilitetsminutter

Tre af de tal er kedelige. Alle ved, at nullet er forkert, alle erstatter det før eller siden med et eller andet, og det et eller andet er næsten altid en konstant, nogen har valgt på mavefornemmelse. 100 ms, 250 ms, "lad os være konservative, 500." Det tal, der faktisk betyder noget, er 840, fordi det siger, at din latenstid er en funktion af markedstilstanden, og de markedstilstande, hvor den stikker af, er de samme markedstilstande, hvor dit signal synes, det har fundet noget.

Hvor de 195 millisekunder bliver af

Her er det fulde budget, målt trin for trin med monotonic-clock-tidsstempler skrevet ved hvert hop. Boksen er en AWS-instans i ap-northeast-1, samme region som venueets endpoints, hvilket er omtrent så godt, som et ikke-kolokeret, retail-agtigt setup kan blive.

Trinp50p95p99
Bar-luk → WS kline-closed-event modtaget128 ms402 ms1,940 ms
Parse + feature-state-opdatering3 ms9 ms28 ms
Beslutning: model-eval + risikotjek11 ms22 ms60 ms
Ordreafsendelse → exchange-ack47 ms180 ms1,100 ms
End-to-end (målt, ikke summeret)195 ms690 ms2,970 ms

To ting at bemærke, før den interessante del. For det første lægger medianerne ikke sammen: 128 + 3 + 11 + 47 = 189, og den målte end-to-end-median er 195. Percentiler er ikke additive, og hvis du bygger dit latenstidsestimat ved at summere p99 pr. trin, får du 3,128 ms, når den reelle p99 er 2,970. Tæt nok her, vildt forkert, når trinene er korrelerede den anden vej. Mål hele stien.

For det andet: se på den øverste række. To tredjedele af medianbudgettet går med at vente på, at børsen fortæller dig, at barren er lukket. Ikke netværk, ikke din kode, ikke ordrerouting. Venueet aggregerer handler til en kline, beslutter at minuttet er ovre, og pusher. Det push har en kø foran sig, og køen er fælles for alle andre subscribers på den stream.

De 840

Inddel hver eneste af de 1,418 ordrer i buckets efter den realiserede volatilitet i det minut, der producerede signalet, og fordelingen falder fra hinanden.

Signal-bar-volatilitetsbucketOrdrerp50 end-to-endp99 end-to-end
Nederste kvartil201141 ms488 ms
De to midterste kvartiler796183 ms1,210 ms
Øverste kvartil407312 ms2,880 ms
Top 1% af alle minutter14840 ms4,100 ms

Hvert trin forringes samtidig, og det er derfor, det tårner sig op. Venueets aggregerings- og broadcast-kø fodres af matching-engine-load, så et minut med 11,000 handler pusher senere end et minut med 600. Din egen proces håndterer flere dybdeopdateringer og flere trade prints i samme vindue, så den feature-opdatering, der normalt tager 3 ms, tager 28. REST-ordrestien konkurrerer med alle andres panik, og du begynder at se den lejlighedsvise 503-and-retry, der alene koster dig et helt sekund. Korrelationskoefficienten mellem antal handler i signal-baren og end-to-end-latenstid i vores stikprøve var 0.41. Ikke enorm. Nok til at ødelægge en konstant.

Og de strategier, der overlever en første screening, er i overvældende grad dem, der handler breakouts, reversals, dislocations, likvidationskaskader. De udløses præcis i den bucket, hvor latenstiden er værst. Et momentumsignal, der kun udløses, når minuttet bevægede sig 40 bps, er et signal, der strukturelt har indrettet sig til altid at blive betjent af den langsomste version af din stack.

Vi brugte engang en dag på at jage en 3.6-sekunders outlier, der dukkede op på omtrent samme tidspunkt hver nat. Det var logrotate, der kørte copy-truncate på en 2 GB-fil på samme EBS-volume, som processen skrev til, og satte event loopet i stå. Markedet var uskyldigt. Mål først, bebrejd så mikrostrukturen.

Hvad det gør ved et fill

Prisen driver, mens du venter. På et tilfældigt minut var den gennemsnitlige adverse bevægelse over vores 195 ms-median cirka 1.1 bps imod signalretningen. På øverste-kvartil-minutterne ved 312 ms, 5.8 bps. På top-1%-minutterne ved 840 ms, groft sagt 14 bps adverse drift, før ordren overhovedet når bogen.

På BTC-perps deltager spreadet næsten ikke i dette: ét tick på et 84,000-quote er 0.012 bps, så skaden er adverse drift snarere end crossing cost. Flyt den samme strategi til en mid-cap-perp, og det andet led vågner — top-of-book-spreadet i vores stikprøve gik fra 1.4 bps i rolige minutter til 6.2 bps i den øverste kvartil, og dybden på det touch blev mere end halveret. Du betaler driften og det bredere spread og den dårligere dybde, alt sammen på én gang, alt sammen fordi de deler en årsag.

Da vi afspillede de samme 31 dage med per-bar betinget latenstid i stedet for en flad 200 ms, flyttede backtestens gennemsnitlige entry-pris sig 3.1 bps dårligere, koncentreret næsten udelukkende i 9% af handlerne. Backtest-versus-paper-divergensen i entry-pris faldt fra 4.2 bps til 0.9 bps. In-sample Sharpe på den strategi gik fra 1.7 til 1.1, hvilket er det ærlige tal og altid har været det.

Så hvad putter du egentlig i configen

Ikke en skalar. Det, vi kører nu:

  1. Sample, sæt ikke. Træk latenstiden for hver simuleret ordre fra en empirisk fordeling betinget på den pågældende bars egen aktivitet — antal handler og absolut afkast er nok, og begge ligger allerede i en standard-kline. Fit den én gang pr. venue pr. ordretype, refit månedligt.
  2. Behold halen. Fit ikke en lognormal og kald det færdigt; p99 lever i retry-storme og GC-pauser, som ingen glat fordeling gengiver. Vi bruger de empiriske kvantiler med en resamplet hale over p95.
  3. Latenstid gælder også for cancels. En stop-replacement eller en hedge-cancel er underlagt den samme forsinkelse, og i hurtige markeder racer din cancel et fill. Hvis din simulator canceler øjeblikkeligt, er din risikomodel fiktion.
  4. Tilføj en staleness-guard og simulér den. Vores dropper ethvert signal, hvis bar er mere end 1.5 sekunder gammel ved ankomst. Det er en reel adfærd med en reel omkostning — den fjerner handler i det stille, og den skal fjerne de samme i backtesten.
  5. Rekalibrér mod paper. Paper trading er der, du får ground truth. Log de fire hop-tidsstempler på hver ordre, og diff fordelingene mod det, simulatoren antog, ugentligt.

Andre aktivklasser, samme sygdom. US-aktier: den consolidated tape lægger sin egen aggregeringsforsinkelse oven på din brokers, og den udvider sig under message-rate-pres af samme strukturelle grund. Forudsigelsesmarkeder: REST-only ordreindlæggelse på de fleste venues, og vi har målt sub-100 ms-medianer, der går til flere sekunder, når en resolution-event rammer, og alle ankommer samtidig. Kryptooptioner: det quote, du priser ud fra, kan være to sekunder stale i netop det minut, det underliggende bevægede sig.

Den generelle form på fejlen er at behandle en eksekveringsparameter som en uafhængig konstant, når den er en funktion af den samme tilstandsvariabel, der driver dit signal. Gebyrer opfører sig; funding opfører sig; latenstid gør ikke. Hvis du skal bære ét tal med i hovedet fra alt dette, så bær ratioen: vores p99 er femten gange vores median, og vores signal ankommer uforholdsmæssigt tæt på p99-enden.

Gå ud og instrumentér de fire hops. Det er en eftermiddags arbejde, og det fortæller dig mere om din strategi end endnu en uge med parametersøgning.

latenstidbacktestingpaper tradingeksekveringkrypto-futures
← Alle indlæg