Oto jeden wiersz z dziennego pliku z danymi akcji. NVDA, piątek 7 czerwca 2024, ostatnia sesja przed wejściem w życie splitu 10 za 1.
| Kolumna | Wartość |
|---|---|
| date | 2024-06-07 |
| close | 1208.88 |
| volume | 42,800,000 (zaokrąglone) |
| split_factor | 1.0 |
| dividend | 0.00 |
| adj_close | 120.8781 |
Celowo pominąłem tu kolumny OHLC. Wrócimy do nich pod koniec — to właśnie one po cichu powodują problemy.
Wszystko, co ciekawe w tym wierszu, kryje się w różnicy między kolumną drugą a szóstą. 7 czerwca notowania pokazywały 1208.88. Nikt już nigdy nie zawrze transakcji po tej cenie w tym sensie, że akcja, do której się odnosiła, nie istnieje już jako jednostka. Wartość 120.8781 to rekonstrukcja i nie wynika po prostu z podzielenia 1208.88 przez 10. Przyjrzyjmy się kolumnom po kolei.
date: 2024-06-07 oraz 2 inne daty, które mają większe znaczenie
Split ogłoszono 22 maja 2024 wraz z wynikami finansowymi. Dniem ustalenia
prawa do udziału w splicie był 6 czerwca. Handel po uwzględnieniu splitu
rozpoczął się w poniedziałek 10 czerwca. Są 3 daty, a kolumna
split_factor dostawcy danych odpowiada dokładnie jednej z nich,
zwykle pierwszej sesji po splicie. Błąd o jeden dzień to najczęstszy błąd w
obsłudze działań korporacyjnych, jaki widuję, i nie widać go w ujęciu
zbiorczym: krzywa kapitału zalicza jednodniowy spadek o 90% albo wzrost o
900%. Sharpe liczony za 2,000 dni ledwie to odnotuje, ale maksymalne
obsunięcie kapitału czy reguła stop-loss już tak.
Dywidenda ma własny problem z datą, a w 2024 zmieniła się ona wszystkim pod nosem. Dzień ustalenia prawa do kwartalnej dywidendy NVDA w wysokości 0.01 USD po splicie przypadał 11 czerwca. W USA rozrachunek skrócono do T+1 28 maja 2024, co oznacza, że teraz dzień bez prawa do dywidendy i dzień ustalenia prawa przypadają tego samego dnia. Każdy loader, który wyznacza dzień bez prawa jako „dzień roboczy przed dniem ustalenia prawa” — co przez dekady było poprawne — zaczął w czerwcu 2024 po cichu stosować korektę dywidendową o jedną sesję za wcześnie. Nic nie zgłasza błędu. Współczynnik trafia po prostu do niewłaściwego wiersza.
Błąd w kodzie obsługującym działania korporacyjne nigdy nie objawia się wyjątkiem. To liczba przesunięta o dzień, która wygląda całkiem wiarygodnie.
close: 1208.88 — cena, której nie ma w pliku
To surowa cena transakcyjna i w większości potoków badawczych istnieje
wyłącznie jako kolumna, której nikt nie czyta. Sygnały oblicza się na
podstawie adj_close. Każda reguła odwołująca się do poziomu ceny
za akcję w dolarach używa teraz liczby, której nie widział żaden uczestnik
rynku.
Wiosną 2024 NVDA naprawdę zbliżała się do 1,000 USD, a za tym ruchem stały realne zlecenia: okrągłe poziomy przyciągały ceny, strike'i opcji skupiały się przy 950 i 1000, a każde zbliżenie niosło ryzyko związane z nagłówkami. W danych po korekcie cały ten epizod rozgrywa się przy 100 USD. Jeśli testujesz zachowanie przy psychologicznych poziomach cenowych, logikę domykania luk w pobliżu okrągłych poziomów albo cechę opartą na odległości od strike'u, testujesz ją na szeregu cenowym przeskalowanym przez zdarzenie, które jeszcze wtedy nie nastąpiło.
To samo dotyczy filtrów uniwersum. „Wyklucz akcje poniżej 5 USD” to uzasadniony przybliżony wskaźnik rzeczywistych problemów mikrostrukturalnych: szerokich spreadów względnych, zasad dotyczących akceptowania papierów jako zabezpieczenia i reżimów wielkości kroku cenowego. Zastosuj ten filtr do skorygowanej historii, a wykluczysz spółki w okresach, gdy ich akcje kosztowały 30 USD, a później przeszły reverse split. Ustaw filtr „cena powyżej 500 USD”, a po cichu usuniesz NVDA z każdego roku przed czerwcem 2024. Filtry cenowe powinny korzystać z surowych cen transakcyjnych. Kropka.
split_factor: 1.0 — i 0.1 w następnym wierszu
Współczynnik to iloczyn skumulowany liczony wstecz od dziś. Każdy wiersz sprzed 10 czerwca 2024 zawiera 0.1 z tego splitu, pomnożone przez 0.25 ze splitu 4 za 1 w 2021, a także przez wcześniejsze współczynniki. Historia NVDA sprzed 2021 jest przeskalowana przez 0.025, więc świeca, która w 2019 zamknęła się przy 200 USD, pokazuje 5.00 USD.
Warto pamiętać o 2 konsekwencjach. Po pierwsze, skorygowana historia zmienia się za każdym razem, gdy pojawia się nowe działanie korporacyjne. Backtest przeprowadzony w maju 2024 i ten uruchomiony dziś dadzą różne wyniki, mimo identycznego kodu i identycznego zakresu dat. Jeśli buforowaliśmy cechy według symbolu i daty, bez oznaczenia wersji danych, mamy teraz bufor zawierający dane w 2 różnych skalach. Właśnie dlatego uwzględniamy epokę korekty w kluczu cechy; nauczyło nas tego jedno bardzo mylące popołudnie.
Po drugie, przy skali 0.025 akcje, które były notowane z krokiem 0.01 USD, poruszają się teraz w przyrostach po 0.00025 USD. Logika zaokrąglania do kroku cenowego, porównania typu „czy to nowe maksimum” i sprawdzanie równości liczb zmiennoprzecinkowych — wszystko to działa teraz z dokładnością znacznie większą niż rozdzielczość, z jaką faktycznie notowano akcje.
dividend: 0.01 — liczba, która rozbija siatkę cenową we wszystkich wcześniejszych danych
Jeden cent. Wygląda jak szum i właśnie dlatego adj_close pokazuje
120.8781 zamiast równego 120.888.
Kurs zamknięcia z 10 czerwca wyniósł 121.79. Współczynnik korekty o dywidendę to (121.79 − 0.01) / 121.79 = 0.99991789. Mnoży on każdą cenę sprzed 11 czerwca, więc skorygowana o split wartość 120.888 zmienia się w 120.878074. To niewielka, trwała zmiana, stosowana ponownie przy każdej z ponad 60 dat bez prawa do dywidendy w historii NVDA. Liczy się efekt składany: patrząc na 2015, widzisz cenę pomnożoną przez dziesiątki czynników, z których każdy jest w pewnym sensie nieracjonalny. Żadna historyczna cena po korekcie nie leży na siatce co cent.
Oznacza to, że każde porównanie == z okrągłym poziomem jest
fałszywe, każde sprawdzenie „czy cena dotknęła limitu” wymaga tolerancji, a
odtworzone dane OHLC nie spełniają już warunku low ≤ open ≤ high po naiwnym
zaokrągleniu do 4 miejsc po przecinku. Oznacza to również, że
adj_close jest szeregiem całkowitej stopy zwrotu, podczas gdy
close to szereg stopy zwrotu z ceny; jeśli obliczasz stopy zwrotu
z jednego, a obsunięcia kapitału z drugiego, mieszasz 2 różne definicje tego,
co się wydarzyło.
volume: 42,800,000 — dzielnik, którego nie wszyscy stosują tak samo
Aby porównać wolumen akcji z sesjami po splicie, trzeba go pomnożyć przez 10. Niektórzy dostawcy danych to robią. Inni nie. Niektórzy korygują OHLC, ale zostawiają surowy wolumen. To najgorszy z tych 3 wariantów, bo plik wygląda na wewnętrznie spójny, dopóki nie pomnożysz ceny przez wolumen.
Najrozsądniej przestać używać wolumenu akcji jako cechy i korzystać z wolumenu w ujęciu wartościowym, który z definicji nie zmienia się przy splitach. Filtr płynności oparty na 20-dniowej średniej wartości obrotu nie wymaga żadnej logiki korekt i nie może zostać zepsuty przez działanie korporacyjne. Niezmienność cech jest lepsza niż poprawny kod korekt, bo o poprawność tego kodu trzeba dbać bez przerwy.
3 formaty plików od dostawców, 3 rodzaje błędów.
| Co dostajemy | Co się psuje |
|---|---|
| Skorygowany kurs zamknięcia, surowe OHLC | Luka i logika śródsesyjna obliczane są na 2 różnych skalach cenowych |
| Skorygowane OHLC, surowy wolumen | Wartość obrotu odbiega o współczynnik splitu; filtry ADV działają błędnie |
| Surowe OHLCV wraz z kolumnami współczynników | Nic, jeśli je stosujesz. Wszystko, jeśli stosujesz je do niewłaściwego wiersza |
Brakujące kolumny: adj_open, adj_high, adj_low
Przywróćmy teraz kolumny OHLC. Jeśli źródło koryguje tylko kurs zamknięcia, a
strategia oblicza lukę nocną jako open / prev_adj_close − 1, to
10 czerwca 2024 oblicza 120.37 / 120.8781 − 1, co daje prawidłowy wynik, mniej
więcej −0.4%. Przenieś ten sam kod do 7 czerwca 2024, a obliczy kurs otwarcia
z surowego pliku (około 1207) względem kursu zamknięcia skorygowanego o 0.025
ze względu na wcześniejsze splity i zwróci lukę rzędu kilku tysięcy procent.
Każda operacja łącząca surową kolumnę ze skorygowaną wykonuje obliczenia na danych z 2 różnych układów współrzędnych. Traktuję teraz odczyt danych z niespójnym poziomem korekty jako warunek sprawdzany przez loader, zamiast polegać na tym, że badacz o tym pamięta — bo nie będzie pamiętał. Ja też nie.
Czego nie zdradza żadna kolumna: ile akcji naprawdę byśmy kupili
To właśnie ten element kosztuje w modelu kosztów backtestu i dlatego w ogóle piszę o splicie akcji.
Prowizje za obrót akcjami w USA często nalicza się za każdą akcję. Załóżmy 0.005 USD, przy minimalnej prowizji za zlecenie wynoszącej 1.00 USD. To popularna stała stawka u brokerów detalicznych. Teraz przeprowadź backtest pozycji w NVDA o wartości 400,000 USD rok przed splitem, gdy surowa cena wynosiła około 400 USD, a cena po korekcie to 40 USD.
| Liczba akcji | Prowizja | |
|---|---|---|
| Rzeczywisty przebieg (surowa cena 400 USD) | 1,000 | 5.00 USD |
| Dane widziane przez backtest (skorygowana cena 40 USD) | 10,000 | 50.00 USD |
Ta sama ekspozycja, ta sama transakcja, 10 razy wyższy modelowany koszt. To 45 USD fikcyjnego kosztu na każdą stronę transakcji, 90 USD za pełną transakcję kupna i sprzedaży, a strategia dokonująca codziennie obrotu generuje około 22,000 USD rocznych kosztów, które nigdy nie istniały. Przy portfelu o wartości 400k to 5.6 punktu procentowego rocznej stopy zwrotu — w całości wymyślone przez dzielnik. W tym przypadku backtest pokazuje wynik gorszy niż w rzeczywistości, co da się przeżyć.
Reverse splity działają w drugą stronę, a to już niebezpieczny kierunek. Reverse split 1 za 10 oznacza, że skorygowana historia pokazuje ceny 10 razy wyższe, a liczbę akcji 10 razy niższą niż w rzeczywistym obrocie. Model kosztów po cichu dzieli prowizję za akcję przez 10. Reverse splity są częste wśród spółek o małej kapitalizacji, których akcje kosztują poniżej 5 USD i mają szerokie spready — właśnie tam opłaty za akcję stanowią największą pozycję w kosztach transakcyjnych. Backtest zawyża atrakcyjność dokładnie tych spółek, które powinien karać.
Rozwiązanie jest proste i systemowe: ustalaj wielkość pozycji w dolarach, przeliczaj ją na akcje według nieskorygowanej ceny z danego dnia i naliczaj opłaty za akcję od tej liczby. Surowa kolumna cenowa powinna na stałe pozostać w loaderze — nie jako materiał do audytu, lecz jako bieżące wejście dla silnika realizacji zleceń.
- Sygnały i stopy zwrotu: szeregi skorygowane.
- Liczba akcji, opłaty za akcję, zaokrąglanie do kroku cenowego, filtry poziomu ceny: szeregi nieskorygowane.
- Płynność i zdolność do absorpcji kapitału: wolumen w ujęciu wartościowym, który nie wymaga żadnej z tych korekt.
6 kolumn, 1 wiersz i dość zwyczajne działanie korporacyjne, ogłoszone 3 tygodnie wcześniej, które nikogo nie zaskoczyło. Rynek uporał się z nim w ciągu poranka. Wierne odtworzenie go w potoku badawczym jest znacznie trudniejsze, a oznaką, że potok sobie z tym nie poradził, prawie nigdy nie jest komunikat o błędzie.
← Wszystkie wpisy


