Ecco una riga tratta da un file giornaliero di azioni. NVDA, venerdì 7 giugno 2024, l'ultima seduta prima che lo split 10-for-1 entrasse in vigore.
| Colonna | Valore |
|---|---|
| date | 2024-06-07 |
| close | 1208.88 |
| volume | 42,800,000 (arrotondato) |
| split_factor | 1.0 |
| dividend | 0.00 |
| adj_close | 120.8781 |
Ho lasciato deliberatamente le colonne OHLC fuori da questa vista. Tornano verso la fine, e sono quelle che si rompono in silenzio.
Tutto ciò che è interessante in questa riga vive nello scarto tra la seconda e la sesta colonna. Il nastro del 7 giugno ha stampato 1208.88. Nessuno scambierà mai più a quel prezzo, nel senso che l'azione a cui si riferiva non esiste più come unità. Il 120.8781 è una ricostruzione, e non è semplicemente 1208.88 diviso dieci. Andiamo colonna per colonna.
date: 2024-06-07, e le altre due date che contano di più
Lo split è stato annunciato il 22 maggio 2024 insieme agli earnings. La record date era il 6 giugno. Le negoziazioni su base rettificata per split sono iniziate lunedì 10 giugno. Tre date, e la colonna split_factor del tuo vendor sta esattamente su una sola di esse, di solito la prima seduta rettificata per split. Un off-by-one qui è il singolo bug sulle corporate action più comune che veda, ed è invisibile in aggregato: la tua equity curve prende un gap-down del 90% o un gap-up del 900% in un singolo giorno, che uno Sharpe calcolato su 2,000 giorni registra a malapena, ma un max-drawdown o una regola di stop-loss registrano assolutamente.
Il dividendo ha un suo problema di date, e nel 2024 è cambiato sotto i piedi di tutti. Il dividendo trimestrale post-split di $0.01 di NVDA aveva record date l'11 giugno. Il settlement USA è passato a T+1 il 28 maggio 2024, il che significa che ex-date e record date coincidono ora nello stesso giorno. Qualsiasi loader che deriva l'ex-date come "record date meno un giorno lavorativo", cosa corretta per decenni, ha iniziato a produrre in silenzio rettifiche da dividendo una seduta in anticipo nel giugno 2024. Non viene lanciata nessuna eccezione. Il fattore atterra semplicemente sulla riga sbagliata.
Il failure mode del codice sulle corporate action non è mai un'eccezione. È un numero sfasato di un giorno che sembra del tutto plausibile.
close: 1208.88 — il prezzo che non sta nel file
Questo è il print grezzo, e nella maggior parte delle pipeline di ricerca esiste solo come una colonna che nessuno legge. I segnali vengono calcolati su adj_close. E qualsiasi regola che fa riferimento a un livello di prezzo per azione in dollari sta ora puntando a un numero che nessun partecipante al mercato ha mai visto.
La marcia di NVDA verso i $1,000 nella primavera del 2024 era una cosa vera, con vero order flow alle spalle: magneti sui numeri tondi, strike delle opzioni raggruppati a 950 e 1000, rischio da headline a ogni avvicinamento. Nei dati rettificati l'intero episodio accade a $100. Se stai testando il comportamento sui livelli psicologici, la logica di gap-fill vicino ai numeri tondi, o una feature di prossimità allo strike, la stai testando su una serie di prezzi riscalata da un evento che non era ancora accaduto.
Lo stesso vale per i filtri sull'universo. "Escludi i titoli sotto i $5" è un proxy legittimo di un vero cluster di problemi di microstruttura: spread relativi ampi, regole di marginabilità, regimi di tick. Applicalo alla storia rettificata e escludi società per periodi in cui trattavano a $30 e sono poi state oggetto di reverse split. Applica "prezzo sopra i $500" e toglierai in silenzio NVDA da ogni anno precedente al giugno 2024. I filtri di prezzo stanno sui print non rettificati. Punto.
split_factor: 1.0 — e lo 0.1 sulla riga successiva
Il fattore è un prodotto cumulativo che corre all'indietro da oggi. Ogni riga precedente al 10 giugno 2024 porta uno 0.1 da questo split, moltiplicato per lo 0.25 dello split 4-for-1 del 2021, moltiplicato per qualunque cosa sia venuta prima. La storia pre-2021 di NVDA è scalata di 0.025, quindi una barra che ha stampato a $200 nel 2019 compare come $5.00.
Due conseguenze da tenere a mente. Prima: la storia rettificata cambia ogni volta che atterra una nuova corporate action. Un backtest che hai lanciato a maggio 2024 e uno che lanci oggi producono numeri diversi su codice identico su date identiche, e se hai messo in cache delle feature con chiave su simbolo e data senza uno stamp di versione dei dati, ora hai una cache che mescola due scale. Noi versioniamo l'epoca di rettifica nella chiave della feature proprio per questo; ci è costato un pomeriggio molto confuso per impararlo.
Seconda: con uno scaling di 0.025, un titolo che trattava in tick da $0.01 ora si muove a incrementi di $0.00025. La tua logica di arrotondamento al tick, i tuoi confronti "è un nuovo massimo", i tuoi check di uguaglianza sui float: tutti operano ora ben al di sotto della risoluzione che il mercato aveva davvero.
dividend: 0.01 — il numero che sgriglia ogni prezzo alle sue spalle
Un centesimo. Sembra rumore, ed è il motivo per cui adj_close legge 120.8781 invece di un pulito 120.888.
Il close del 10 giugno era 121.79. Il fattore ex-dividend è (121.79 − 0.01) / 121.79 = 0.99991789. Quel fattore moltiplica ogni prezzo precedente all'11 giugno, così il 120.888 rettificato per split diventa 120.878074. Piccolo, e permanente, e applicato di nuovo a ciascuna della sessantina di ex-date che risalgono la storia di NVDA. È il compounding che conta: quando arrivi al 2015, stai guardando un prezzo moltiplicato per decine di fattori più o meno irrazionali. Non un solo prezzo storico rettificato siede sulla griglia del penny.
Il che significa che ogni confronto == contro un livello tondo è falso, ogni check "abbiamo toccato il limit price" ha bisogno di una tolleranza, e il tuo OHLC ricostruito non soddisfa più l'invariante low ≤ open ≤ high dopo un arrotondamento ingenuo a 4 decimali. Significa anche che adj_close è una serie di total-return mentre close è una serie di price-return, e se calcoli i rendimenti da una e i drawdown dall'altra hai mescolato due definizioni diverse di ciò che è successo.
volume: 42,800,000 — il divisore che nessuno applica in modo coerente
Il volume in azioni va moltiplicato per 10 per essere confrontabile con le sedute post-split. Alcuni vendor lo fanno. Altri no. Alcuni rettificano l'OHLC e lasciano il volume grezzo, che è il peggiore dei tre perché il file sembra internamente coerente finché non moltiplichi prezzo per volume.
La mossa onesta è smettere di usare il volume in azioni come feature e usare il dollar volume, che è invariante agli split per costruzione. Un filtro di liquidità sul dollar volume medio a 20 giorni non ha bisogno di alcuna logica di rettifica e non può essere rotto da una corporate action. L'invarianza della feature batte il codice di rettifica corretto, perché il codice di rettifica corretto è una cosa su cui devi continuare ad avere ragione.
Tre forme di file del vendor, tre failure mode.
| Cosa arriva | Cosa si rompe |
|---|---|
| Solo close rettificato, OHLC grezzo | La logica di gap e intrabar calcola attraverso due scale di prezzo |
| OHLC rettificato, volume grezzo | Dollar volume sbagliato del rapporto di split; i filtri ADV scattano a vuoto |
| OHLCV grezzo più colonne di fattore | Niente, se le applichi. Tutto, se le applichi sulla riga sbagliata |
Le colonne che non ci sono: adj_open, adj_high, adj_low
Ora rimetti l'OHLC. Se un feed rettifica solo il close e la tua strategia calcola un gap overnight come open / prev_adj_close − 1, allora il 10 giugno 2024 calcola 120.37 / 120.8781 − 1, che è un numero onesto, circa −0.4%. Spingi lo stesso codice indietro al 7 giugno 2024 e calcola l'open dal file grezzo (circa 1207) contro un close rettificato di 0.025 da split precedenti, e produce un gap di diverse migliaia di percento.
Qualsiasi cosa mescoli una colonna grezza con una rettificata è aritmetica tra due sistemi di coordinate. Ora tratto le letture a rettifica mista come un'asserzione a livello di loader, non come qualcosa che un ricercatore deve ricordare, perché i ricercatori non lo faranno, me compreso.
Quello che nessuna colonna ti dice: quante azioni avresti davvero comprato
Questo è quello che costa soldi nel modello di costi del backtest, ed è il motivo per cui sto scrivendo di uno stock split.
Le commissioni sulle azioni USA sono spesso per azione. Diciamo $0.005 con un minimo d'ordine di $1.00, un tier fisso comune presso i broker retail. Ora fai il backtest di una posizione NVDA da $400,000 un anno prima dello split, quando il prezzo grezzo era vicino a $400 e il prezzo rettificato compare come $40.
| Azioni | Commissione | |
|---|---|---|
| Cosa è successo davvero (grezzo $400) | 1,000 | $5.00 |
| Cosa vede il backtest (rettificato $40) | 10,000 | $50.00 |
Stessa esposizione, stesso trade, 10x il costo modellato. Sono $45 di finzione per leg, $90 per round trip, e una strategia che ruota ogni giorno si mangia circa $22,000 all'anno di costi mai esistiti. Su un book da $400k, 5.6 punti percentuali di rendimento annuale, interamente fabbricati da un divisore. Qui ti fa sembrare peggiore della realtà, il che è sopravvivibile.
I reverse split vanno nell'altra direzione, ed è quella pericolosa. Un reverse split 1-for-10 significa che la storia rettificata mostra prezzi 10x più alti e conteggi di azioni 10x più bassi di quelli che avresti negoziato. Il tuo modello di costi divide in silenzio per dieci la commissione per azione. L'universo in cui i reverse split sono comuni è l'universo small-cap, sub-$5, a spread ampi, dove le fee per azione sono la voce più grande nello stack dei costi. Il backtest lusinga esattamente i nomi che dovrebbe punire.
Quindi la correzione è noiosa e strutturale: dimensiona le posizioni in dollari, converti in azioni usando il prezzo non rettificato di quella data, e addebita le fee per azione su quel conteggio. Tieni la colonna del prezzo grezzo nel loader per sempre, non come artefatto di audit ma come input vivo al fill engine.
- Segnali e rendimenti: serie rettificate.
- Conteggi di azioni, fee per azione, arrotondamento al tick, filtri sui livelli di prezzo: serie non rettificate.
- Liquidità e capacity: dollar volume, che non ha bisogno di nessuno dei due.
Sei colonne, una riga, una corporate action abbastanza ordinaria, annunciata con tre settimane di anticipo e che non ha sorpreso nessuno. Il mercato l'ha gestita in una mattina. Ricostruirla fedelmente in una pipeline di ricerca è assai più difficile di così, e il segnale rivelatore che una pipeline non l'ha fatto è quasi mai un messaggio di errore.
← Tutti gli articoli


