Quattro numeri, tutti misurati sul nostro stack di paper trading, una strategia, segnali su perpetual BTCUSDT a 1-minuto, 31 giorni e 1,418 ordini. Tempo mediano dalla chiusura della barra all'ack dell'ordine da parte dell'exchange: 195 ms. 99° percentile: 2,970 ms. Mediana sull'1% dei minuti con la volatilità realizzata più alta: 840 ms. E la costante di latenza che è rimasta nella config del backtest per gran parte dell'anno precedente: 0.
Tre di questi numeri sono noiosi. Tutti sanno che lo zero è sbagliato, tutti prima o poi lo sostituiscono con qualcosa, e quel qualcosa è quasi sempre una costante che qualcuno ha scelto a naso. 100 ms, 250 ms, "stiamo conservativi, 500." Il numero che conta davvero è 840, perché dice che la tua latenza è una funzione dello stato di mercato, e gli stati di mercato in cui esplode sono gli stessi in cui il tuo segnale crede di aver trovato qualcosa.
Dove finiscono i 195 millisecondi
Ecco il budget completo, misurato fase per fase con timestamp di monotonic-clock scritti a ogni hop. Il box è un'istanza AWS in ap-northeast-1, stessa region degli endpoint del venue, che è pressappoco il meglio a cui può arrivare un setup di tipo retail non colocato.
| Fase | p50 | p95 | p99 |
|---|---|---|---|
| Chiusura barra → evento WS kline-closed ricevuto | 128 ms | 402 ms | 1,940 ms |
| Parse + aggiornamento stato feature | 3 ms | 9 ms | 28 ms |
| Decisione: eval del modello + controlli di rischio | 11 ms | 22 ms | 60 ms |
| Invio ordine → ack exchange | 47 ms | 180 ms | 1,100 ms |
| End-to-end (misurato, non sommato) | 195 ms | 690 ms | 2,970 ms |
Due cose da notare prima della parte interessante. Primo, le mediane non si sommano: 128 + 3 + 11 + 47 = 189, e la mediana end-to-end misurata è 195. I percentili non sono additivi, e se costruisci la stima di latenza sommando i p99 per fase ottieni 3,128 ms quando il p99 reale è 2,970. Abbastanza vicino qui, clamorosamente sbagliato quando le fasi sono correlate nell'altra direzione. Misura l'intero percorso.
Secondo, guarda la riga in cima. Due terzi del budget mediano se ne vanno ad aspettare che l'exchange ti dica che la barra è chiusa. Non la rete, non il tuo codice, non il routing degli ordini. Il venue aggrega i trade in una kline, decide che il minuto è finito, e fa push. Quel push ha una coda davanti, e la coda è condivisa con ogni altro subscriber su quello stream.
Gli 840
Metti in bucket ognuno di quei 1,418 ordini in base alla volatilità realizzata del minuto che ha prodotto il segnale, e la distribuzione si sfalda.
| Bucket di volatilità della barra-segnale | Ordini | p50 end-to-end | p99 end-to-end |
|---|---|---|---|
| Quartile inferiore | 201 | 141 ms | 488 ms |
| Due quartili centrali | 796 | 183 ms | 1,210 ms |
| Quartile superiore | 407 | 312 ms | 2,880 ms |
| Top 1% di tutti i minuti | 14 | 840 ms | 4,100 ms |
Tutte le fasi degradano insieme, ed è per questo che l'effetto si composta. La coda di aggregazione e broadcast del venue è alimentata dal carico del matching-engine, quindi un minuto con 11,000 trade viene pushato più tardi di un minuto con 600. Il tuo stesso processo sta gestendo più aggiornamenti di depth e più print di trade nella stessa finestra, quindi l'aggiornamento delle feature che di solito impiega 3 ms ne impiega 28. Il percorso REST dell'ordine compete con il panico di tutti gli altri, e inizi a vedere l'occasionale 503-and-retry che da solo ti costa un secondo intero. Il coefficiente di correlazione tra il conteggio dei trade sulla barra-segnale e la latenza end-to-end nel nostro campione era 0.41. Non enorme. Abbastanza da rovinare una costante.
E le strategie che superano uno screening di primo passaggio sono, in schiacciante maggioranza, quelle che operano su breakout, reversal, dislocazioni, cascate di liquidazione. Scattano esattamente nel bucket in cui la latenza è peggiore. Un segnale momentum che scatta solo quando il minuto si è mosso di 40 bps è un segnale che si è messo, strutturalmente, nelle condizioni di essere sempre servito dalla versione più lenta del tuo stack.
Una volta abbiamo passato un giorno a inseguire un outlier di 3.6 secondi che compariva più o meno alla stessa ora ogni notte. Era logrotate, in copy-truncate di un file da 2 GB sullo stesso volume EBS su cui il processo stava scrivendo, bloccando l'event loop. Il mercato era innocente. Prima misura, poi dai la colpa alla microstruttura.
Cosa fa a un fill
Il prezzo deriva mentre aspetti. Su un minuto a caso, il movimento avverso medio sui nostri 195 ms di mediana era circa 1.1 bps contro la direzione del segnale. Sui minuti del quartile superiore a 312 ms, 5.8 bps. Sui minuti top-1% a 840 ms, circa 14 bps di drift avverso prima ancora che l'ordine arrivi al book.
Sui perp BTC lo spread c'entra appena: un tick su una quotazione a 84,000 è 0.012 bps, quindi il danno è drift avverso piuttosto che costo di crossing. Sposta la stessa strategia su un perp mid-cap e il secondo termine si sveglia — lo spread al top-of-book nel nostro campione è passato da 1.4 bps nei minuti calmi a 6.2 bps nel quartile superiore, e la depth a quel touch si è assottigliata di più della metà. Paghi il drift e lo spread più largo e la depth peggiore, tutti insieme, tutti perché condividono una causa.
Quando abbiamo rieseguito gli stessi 31 giorni con latenza condizionale per barra invece di un 200 ms piatto, il prezzo medio di ingresso del backtest è peggiorato di 3.1 bps, concentrato quasi interamente nel 9% dei trade. La divergenza del prezzo di ingresso backtest-versus-paper è scesa da 4.2 bps a 0.9 bps. Lo Sharpe in-sample di quella strategia è passato da 1.7 a 1.1, che è il numero onesto e lo è sempre stato.
Quindi cosa metti davvero nella config
Non uno scalare. Quello che facciamo girare ora:
- Campiona, non impostare. Estrai la latenza di ogni ordine simulato da una distribuzione empirica condizionata sull'attività della barra stessa — il conteggio dei trade e il rendimento assoluto bastano, e entrambi sono già in una kline standard. Fittala una volta per venue per tipo di ordine, rifittala mensilmente.
- Tieni la coda. Non fittare una lognormale e dichiarare chiuso; il p99 vive nelle tempeste di retry e nelle pause GC che nessuna distribuzione liscia riproduce. Usiamo i quantili empirici con una coda ricampionata sopra il p95.
- La latenza vale anche per i cancel. Una sostituzione di stop o un cancel di hedge sono soggetti allo stesso ritardo, e nei mercati veloci il tuo cancel è in corsa contro un fill. Se il simulatore cancella all'istante, il tuo modello di rischio è finzione.
- Aggiungi un guard di staleness e simulalo. Il nostro scarta qualsiasi segnale la cui barra, all'arrivo, ha più di 1.5 secondi. È un comportamento reale con un costo reale — rimuove trade in silenzio, e deve rimuovere gli stessi nel backtest.
- Ricalibra contro il paper. Il paper trading è dove ottieni la ground truth. Logga i quattro timestamp di hop su ogni ordine e fai il diff delle distribuzioni rispetto a quello che il simulatore aveva assunto, settimanalmente.
Altre classi di asset, stessa malattia. Azioni USA: il consolidated tape aggiunge il proprio ritardo di aggregazione sopra quello del broker, e si allarga sotto pressione di message-rate per la stessa ragione strutturale. Prediction market: inserimento ordini solo REST sulla maggior parte dei venue, e abbiamo misurato mediane sub-100 ms che vanno a più secondi quando arriva un evento di risoluzione e tutti atterrano insieme. Opzioni crypto: la quotazione da cui stai prezzando può essere stantia di due secondi esattamente nel minuto in cui l'underlying si è mosso.
La forma generale dell'errore è trattare un parametro di esecuzione come una costante indipendente quando è una funzione della stessa variabile di stato che guida il tuo segnale. Le fee si comportano; il funding si comporta; la latenza no. Se da tutto questo ti porti dietro un numero in testa, portati il rapporto: il nostro p99 è quindici volte la nostra mediana, e il nostro segnale arriva in modo sproporzionato vicino al lato p99.
Vai a strumentare i quattro hop. È un pomeriggio di lavoro e ti dirà sulla tua strategia più di un'altra settimana di ricerca dei parametri.
← Tutti gli articoli


