26 Agosto 2026 · dati di mercato

Anatomia di una barra da 1 minuto: tutto ciò che gli OHLCV non dicono al tuo backtest

Anatomia di una barra da 1 minuto: tutto ciò che gli OHLCV non dicono al tuo backtest

Ecco una barra. Binance USDⓈ-M perpetual, BTCUSDT, il minuto che inizia alle 13:46:00 UTC. È arrivata dall'endpoint delle klines come un semplice array di dodici valori, ed è l'unità di input più comune nella ricerca quant retail e adiacente. Quasi ogni strategia che generiamo tocca qualcosa con questa forma.

Quindi smontiamola, indice per indice, e vediamo quanto di essa un backtest interpreta male.

IndiceValoreNome
01773495960000orario di apertura (ms)
1"84120.50"apertura
2"84177.90"massimo
3"84098.10"minimo
4"84163.40"chiusura
5"38.417"volume base (BTC)
61773496019999orario di chiusura (ms)
7"3232108.94"volume in quote (USDT)
81204numero di operazioni
9"21.883"volume base acquisti taker
10"1841203.55"volume quote acquisti taker
11"0"ignora

[0] e [6]: di quale minuto si tratta, e l'orologio di chi lo dice

Orario di apertura 1773495960000, orario di chiusura 1773496019999. Nota il secondo: termina in 19999, un millisecondo prima dell'apertura della barra successiva. La finestra è semiaperta, e l'exchange te lo dice esplicitamente. Metà dei bug sui dati che ho inseguito iniziavano con qualcuno che trattava entrambi gli estremi come inclusivi, contando due volte un'operazione al confine, oppure allineando un ricampionamento in modo che ogni barra da 5 minuti prendesse in prestito un millisecondo dalla vicina.

I timestamp sono l'orario del matching engine dell'exchange. Non il tuo orologio, non l'orologio di ingestione del tuo vendor, e nemmeno lo stesso orologio usato dallo snapshot del funding. Quando fai un join tra una serie di klines e una serie di funding rate o open interest presa da un endpoint diverso, stai unendo fonti che concordano entro circa un secondo, la maggior parte delle volte. Per una strategia a 1 minuto questo è un errore di temporizzazione dell'1,7% su ogni riga unita. Per qualsiasi cosa sub-minuto è fatale.

E questa barra è timbrata alla sua apertura. L'informazione che contiene non è conoscibile fino alle 13:46:59.999. Ogni questione di convenzione sull'indicizzazione — se traslare di uno, se usare i timestamp di chiusura o di apertura della barra come tempo dell'evento — è in realtà la stessa domanda sul lookahead travestita.

[1] "84120.50": l'apertura che non puoi tradare

L'apertura è il prezzo della prima operazione stampata all'interno della finestra. È una transazione già conclusa tra altre due persone. Nel momento in cui la barra esiste come riga nel tuo dataframe, quel prezzo ha già sessanta secondi.

La barra precedente si è chiusa a 84109.80, quindi ci sono 10,70$ di movimento di prezzo nel divario tra due barre adiacenti da 1 minuto. Sono 1,3 basis point, invisibili su un grafico, e circa un quarto della fee taker. Va bene. Ma vai a guardare la stessa serie su un alt perp durante un dato CPI USA e questi divari tra barre corrono tra 15 e 40 bps. Un backtest che genera segnale alla chiusura della barra ed esegue all'apertura della barra successiva sta silenziosamente assumendo che il divario sia zero, ed è zero esattamente quando non conta.

[2] e [3]: "84177.90" massimo, "84098.10" minimo

Questi due sono dove muoiono la maggior parte dei motori di esecuzione, quindi questa è la sezione più lunga.

Massimo e minimo sono prezzi estremi toccati. Non portano informazioni su size o durata. Dal tape delle operazioni grezzo per questo stesso minuto, tutto ciò che è stato scambiato a 84100.00 o sotto è stato 0,62 BTC su nove stampe in una finestra di 1,4 secondi. Quindi uno stop di backtest a 84100 "si esegue" — e se la tua posizione è 3 BTC, hai divorato l'intero book visibile sulla via giù e il resto della tua size è stato eseguito da qualche parte nel rimbalzo 84105–84130. La barra dice che il minimo era 84098.10. La barra non dice che lì si sono scambiati solo 52.000$ di nozionale.

1204operazioni nel minuto
0.032 BTCdimensione media della stampa (~2,7k$)
0.62 BTCtotale scambiato al minimo o sotto
57%del volume è stato iniziato dall'acquirente

L'altra direzione è peggiore, perché ti lusinga. Supponi di avere un limit sell in attesa a 84175. Il massimo della barra è 84177.90, quindi un motore ingenuo ti esegue a 84175 e registra un rebate maker invece di un costo taker. Se quella esecuzione sia effettivamente avvenuta dipende dalla posizione in coda a quel livello di prezzo, cosa che la barra non può sapere e che tu probabilmente non hai mai registrato. Toccato non significa eseguito.

La regola su cui ci siamo assestati nel nostro motore di esecuzione: un limit in attesa si esegue solo se la barra attraversa il livello, non semplicemente lo tocca. Le esecuzioni al tick estremo esatto richiedono evidenza di volume-a-prezzo dal tape delle operazioni, altrimenti vengono rifiutate. Ha rimosso circa il 6% delle operazioni da un tipico book di mean-reversion e ha tagliato lo Sharpe di backtest di un candidato da 1,9 a 1,1. Quel candidato non è mai stato reale; la regola di esecuzione è stata solo la prima cosa abbastanza onesta da dirlo.

Trappola correlata: il percorso intrabarra. Se il range di una barra copre sia il tuo stop che il tuo take-profit, gli OHLCV non possono dirti quale è arrivato prima. Ogni motore deve scegliere una convenzione. Il nostro assume sempre stop-prima, il che è pessimistico e occasionalmente sbagliato, ma non genera mai una vincita falsa. Se il tuo motore assume take-profit-prima, le barre a range ampio genereranno profitto dall'ambiguità, e le barre a range ampio sono esattamente quelle che dominano la distribuzione del tuo PnL.

[4] "84163.40": il numero meno robusto della barra

La chiusura è l'ultima stampa nella finestra. Tutto qui. Potrebbe essere un lotto spaiato di 0,002 BTC da un bot che arrotonda una posizione alle 13:46:59.8. Questo singolo tick, strutturalmente arbitrario, è ciò che la maggior parte delle pipeline di ricerca usa per calcolare ogni segnale, marcare ogni posizione e valutare ogni uscita.

Sui perp BTC conta a malapena; su un perp altcoin illiquido alle 04:00 UTC conta enormemente, e la differenza tra le chiusure di due venue per lo stesso minuto può superare l'intero tuo edge per operazione. Quando il PnL di una strategia dipende specificamente dalla chiusura, la rieseguiamo marcando invece al mark price dell'exchange, che è derivato dall'indice e molto più difficile da manipolare. Se i risultati divergono, la strategia stava tradando l'artefatto.

[5] e [7]: "38.417" e "3232108.94", volume in unità di cosa

Il volume base è in BTC; il volume quote è in USDT. Entrambi qui, il che è una cortesia che non tutti i venue offrono. Il motivo per cui contarlo è l'aggregazione tra venue. I contratti coin-margined sono quotati in contratti da 100$ di nozionale. Alcuni feed azionari riportano lotti tondi. I venue di prediction market riportano conteggi di share dove una share è una rivendicazione binaria denominata in dollari. Sommare il "volume" tra un universo misto senza normalizzare a un'unica unità di nozionale produce un ranking di liquidità puro nonsense, e sarà nonsense in un modo apparentemente stabile che sopravvive alla revisione.

Normalizza tutto al nozionale in quote all'ingestione. Conserva anche il campo grezzo, ma non lasciare mai che una strategia lo veda.

[8] 1204: il campo che dovrebbe impostare il tuo modello di impatto

Il numero di operazioni diviso il volume base dà una stampa media di 0,032 BTC, circa 2.700$. Se la tua strategia candidata vuole entrare con 250.000$ in una volta, sta chiedendo di essere circa 92 volte la size tipica della transazione in quel minuto. Quel numero, non una generica costante di slippage di 5 bps, è ciò che dovrebbe guidare il tuo termine di impatto a radice quadrata. Calcoliamo il tasso di partecipazione per barra come colonna di prima classe e respingiamo le strategie il cui ingresso mediano supera qualche punto percentuale del nozionale della barra, perché tutto ciò che segue è finzione.

Il numero di operazioni segnala anche i minuti strani a basso costo. Volume normale, numero di operazioni crollato a 11? Qualcuno ha fatto un blocco. Volume normale, numero di operazioni a 9.000? È una cascata di liquidazioni masticata in pezzi minuscoli.

[9] e [10]: "21.883", il campo che tutti buttano via

Volume base acquisti taker. 21,883 su 38,417 BTC in questa barra sono stati iniziati dall'acquirente, quindi il delta di volume segnato è +5,349 BTC e la ripartizione degli aggressori è 57/43 verso gli acquirenti. L'exchange ti sta consegnando lo squilibrio del flusso d'ordini, gratis, in un campo che la maggior parte delle persone non legge mai perché pandas non ha dato loro il nome della colonna.

Non sto dicendo che predica i rendimenti da solo; le strategie di delta ingenue sono tra i modi più affidabili per donare al registro delle fee. Ma è una misura genuinamente diversa dal prezzo, è disponibile nella stessa richiesta che stavi già facendo, e ti permette di distinguere un rally comprato da un rally accaduto perché i venditori si sono ritirati. Le due cose sembrano identiche in OHLC e si comportano diversamente dieci minuti dopo. Il nostro agente di ricerca tratta un'ipotesi che ignora la ripartizione taker su un venue che la pubblica come lasciare prove sul tavolo.

[11] "0": ignora — e tutto il resto che non c'è

L'indice 11 è un campo deprecato, permanentemente zero. Più interessante è la lista delle cose che questa barra non contiene: nessun bid, nessun ask, nessuno spread, nessuna profondità del book, nessun funding rate, nessun open interest, nessuna liquidazione, nessun mark price, nessun index price. E, cosa cruciale, nessun modo per sapere se il tuo ordine sarebbe stato maker o taker, che è la differenza tra pagare lo 0,045% e guadagnare lo 0,01% su questo venue.

Quindi qualsiasi modello di fee costruito solo su klines è un'assunzione travestita da numero. Lo risolviamo obbligando ogni strategia a dichiarare in anticipo il proprio stile di esecuzione, e poi addebitando taker su tutto ciò che non può dimostrare il contrario.

La barra che non si è mai presentata

Ultimo pezzo, e quello che morde più forte fuori dai major. Un minuto con zero operazioni non produce alcuna kline. Vendor e librerie comunemente la riempiono in avanti (forward-fill): apertura = massimo = minimo = chiusura = chiusura precedente, volume 0. Il tuo indicatore calcola felicemente. La tua strategia vede una riga valida e può generare un segnale su un minuto in cui nessuno al mondo ha tradato quello strumento.

Su un perp mid-cap che abbiamo ingerito, il 4,1% delle barre da 1 minuto in una finestra di dodici mesi aveva zero operazioni. Una strategia candidata di mean-reversion su quel simbolo stava piazzando il 38% dei suoi ingressi su barre sintetiche, perché i prezzi sintetici piatti sono catnip per qualsiasi cosa misuri la deviazione da una media mobile. Il backtest era bellissimo. Stava tradando i buchi nei dati.

Motivo per cui il livello di ingestione ora porta un booleano synthetic per barra, propagato attraverso ogni ricampionamento, e la gauntlet di verifica boccia qualsiasi strategia le cui operazioni si concentrano su di esso. Colonna economica. Ha ucciso più candidati di qualsiasi indicatore che abbiamo mai scritto.

Dodici valori. Quattro di essi interpretati male di routine, due di essi scartati di routine, e un'intera categoria di essi assente dalla riga e immaginata dal motore. Prima del tuo prossimo backtest, vai a prendere una barra grezza dal tuo store e leggi ogni campo ad alta voce confrontandolo con ciò che la tua logica di esecuzione presuppone su di esso. È un esercizio di venti minuti e non ho mai visto nessuno farlo e non trovare nulla.

ohlcvmicrostruttura di mercatoingegneria dei datibacktestingfuture crypto
← Tutti gli articoli