Dapat may 525,600 row ang isang taon ng 1-minute bar. 525,557 ang nakuha namin sa 2025 pull ng BTCUSDT perps — kulang ng 43 minuto, na may 99.992% completeness rate. Sa isang mid-cap alt perp sa parehong venue, parehong pull, at parehong code path, kulang ito ng 1,247: 99.76%. At ang minute series ng isang US equity para sa parehong taon ay may humigit-kumulang 427,000 row na mas kaunti kaysa sa crypto, na hindi naman puwang—sarado lang ang market.
Walang gaanong saysay ang 3 sa mga bilang na iyan. Ang 43 ang sulit pag-usapan nang mahaba.
Apat na magkaibang bagay na lahat ay mukhang butas sa dataframe mo
Bago pag-usapan ang 43, linawin muna natin ang mga uri nito, dahil mali na agad ang karamihan sa gap-handling code pagdating sa bahaging ito. Kapag walang row sa lokal mong parquet, hindi mo alam kung alin sa mga ito ang dahilan, at magkakaiba ang tamang tugon sa bawat isa.
| Uri | Ano talaga ang nangyari | Paano ito lumilitaw | Tamang tugon |
|---|---|---|---|
| Walang trade | Bukas ang market; walang tumawid sa spread sa minutong iyon | Zero-volume bar (magkakapantay ang OHLC, trades=0) sa ilang endpoint, pero walang row sa iba | Panatilihin ito. Tunay itong impormasyon: walang gustong makipagkalakalan. |
| Down ang venue | Offline ang matching engine, nakaiskedyul man o hindi | Walang row, minsan sunod-sunod na ilang row | Markahang stale. Huwag makipagkalakalan habang nangyayari ito. |
| Nasuspinde ang instrumento | Paglabag sa LULD band, hinihintay ang balita, abiso ng pag-delist | Walang row, saka may print sa reopening auction | Markahang stale, at ituring na discontinuity ang muling pagbubukas. |
| Kasalanan mo | Na-rate-limit na pagination, retry na may nalaktawang page, o bug sa timezone boundary ng loop | Walang row, at hindi ito maihihiwalay sa mga naunang uri | Tuklasin at kuning muli ang datos. Ito ang puwede mong ayusin. |
Hindi pare-pareho ang ginagawa ng mga venue sa unang row ng talahanayang iyon, at doon nagkakaproblema. Lubusang nilalaktawan ng candles endpoint ng Coinbase ang mga walang lamang bucket, kaya punô ng literal na butas ang history ng isang illiquid na pares. Karaniwang nagbibigay ang klines ng Binance ng synthetic bar na may volume na 0 at open=high=low=close na nakapirmi sa huling trade. Iisa ang pinagbabatayang pangyayari pero magkaiba ang anyo, at kapag ni-reindex ng loader mo sa buong minute grid, napapalitan ang isa ng isa nang hindi ka sinasabihan. Alamin muna kung ano ang ginagawa ng venue mo bago ka gumawa ng gap-filler.
Halos lahat ng 1,247 nawawalang minuto sa alt ay kabilang sa unang kategorya: manipis ang order book nang 04:00 UTC ng Linggo at walang nakikipagkalakalan. Nakakainis pero madaling unawain, at halos walang pinsala dahil hindi rin naman makikipagkalakalan ang strategy noon. Kaya tumigil na ako sa pagtingin doon at binalikan ko ang 43.
Hindi nakakalat ang 43 minuto
Kung pantay-pantay ang pagkakawala ng mga minuto, ang 43 minuto sa loob ng isang taon ay lalabas bilang 43 magkakahiwalay na minuto, tig-isa kada walo't kalahating araw, at bawat isa'y maliit na pagkakaiba lang. Hindi iyon ang nangyari. Dumating ang mga ito sa anim na sunod-sunod na takbo: isa na may 19 magkakasunod na minuto, isa na may 11, dalawa na may 4, at dalawang pares. Anim na insidente, hindi 43 aksidente.
At nakadepende ang mga insidente sa mismong bagay na mahalaga sa iyo. Nagda-down ang mga venue kapag mabigat ang load, at mabigat ang load kapag gumagalaw ang presyo. Hinati ko sa mga bucket ayon sa realized volatility ang bawat oras ng taon at sinuri kung saan lumitaw ang mga nawawalang minuto: 61% sa mga ito ay nasa pinakamataas na decile. Ang walang-kondisyong posibilidad na mawalan ang isang minuto ay 0.008%. Kapag nasa oras ito na kabilang sa pinakamataas na decile ng volatility, humigit-kumulang 0.05% — anim na ulit na mas mataas, bukod pa sa pagkakakumpulan ng mga ito.
Kaya maling bagay ang sinusukat ng completeness metric sa data-quality dashboard mo. Mukhang dataset na hindi mo na kailangang pag-isipan ang 99.992%. Ang inilalarawan talaga nito ay isang series na kumpleto sa mga oras na walang ginagawa ang strategy mo, pero may mga butas sa mga oras na aktibo ito. Mas mataas nang malaki kaysa ipinahihiwatig ng headline na bilang ang tsansa ng isang momentum system na tumataya sa pagbilis ng volatility na tamaan ng puwang, at tinatamaan ito habang may bukas na trade.
Ang ginagawa ng forward-fill makalipas ang 3 linya
Ito ang problemang nagtulak sa akin na isulat ito. Kunin natin ang takbong may 19 minuto. Karaniwang paglilinis: i-reindex sa buong minute grid, i-forward-fill ang OHLC mula sa huling close, at itakda sa zero ang volume. Tuloy-tuloy na ngayon ang series at tatakbo ang mga indicator mo nang walang makikitang NaN.
Magkakapantay ang high, low, at close ng 19 bar na iyon. Zero ang true range ng bawat isa. Ang ATR(14) na kinalkula sa panahong iyon, mula sa pre-outage reading na humigit-kumulang 240 USDT, ay bababa sa mga 34 pagbalik ng venue — ang 5 totoong bar na natira sa panahong iyon ang bumubuo sa buong average. Ipasok mo iyon sa volatility-scaled position sizer na karaniwan, tulad ng size = risk_budget / ATR. Pitong ulit ang laki ng posisyon.
Ang susunod na totoong bar ay ang print sa muling pagbubukas, at hindi ito tahimik na bar. Sa kaso namin, nagbukas ito nang 1.8% ang layo sa huling close bago ang outage. Masayang pumasok ang backtest sa posisyong 7x ang laki habang may 1.8% na puwang, sa fill na imposibleng mangyari at sa presyong walang sinumang nag-quote. Mas malaki ang halaga ng nag-iisang synthetic trade na iyon kaysa sa isang buwang lehitimong P&L sa equity curve, at maling direksiyon pa — at nagmula ito sa isang linya lang ng paglilinis ng datos na isinulat para luminis tingnan ang dataframe.
Hindi rin solusyon ang pagbura sa mga row sa halip na punan ang mga ito; pareho lang itong bug na nag-iba ng anyo. Kapag binura mo ang mga ito, nagsisinungaling ang mga lookback mo na naka-index sa integer: ang "20-bar EMA" ay sasaklaw na ngayon sa 39 minuto sa totoong oras sa kabila ng outage, ituturing ang buong 1.8% na pagtalon sa boundary bilang galaw sa loob ng isang minuto ang bar-to-bar return, at babasahin ng anumang per-bar volatility estimate ang pagtalon bilang 60-sigma na kaganapan. Walang magbababala sa iyo. Monotonic pa rin ang index.
Dito nagiging hindi na nakikita ang problema sa resampling
Karamihan sa research ay hindi gumagamit ng 1-minute bar; aggregated na data ang ginagamit, at itinatago ng aggregation ang problema. Kapag nag-resample sa 5-minute, nagiging 4 na bar ang puwang na 19 minuto, at partial ang una at huli. Makakalkula ang Pandas ng mukhang makatwirang OHLC mula sa 2 natitirang minuto at lalagyan iyon ng label na kapareho ng bar na binuo mula sa 5 minuto. Walang anumang magtatangi sa mga ito sa output.
Ang pinakasimpleng pag-aayos na alam ko: isama ang column na bars_in_window sa bawat resample at huwag itong itapon kailanman. Isang integer kada row, at masasagot na ang bawat kasunod na tanong kung mapagkakatiwalaan ba ang isang bar. Isinasama rin namin ang seconds_since_last_real_print, na naglalaman ng kaparehong impormasyon sa anyong magagamit ng execution layer.
Ang patakaran namin
Ganito na ang sunod-sunod na ginagawa ng aming mga agent:
- Huwag kailanman mag-reindex nang hindi ipinapaalam. Naglalabas ang loader ng gap manifest — simula, wakas, haba, at kung alin sa 4 na kategorya sa tingin nito ang dahilan. Kung mas maikli sa 3 bar ang takbo ng nawawalang minuto at manipis ang volume sa mga nakapaligid na bar, minutong walang trade iyon. Itinuturing na outage ang anumang mas mahaba rito sa mga aktibong oras hangga't walang katibayang nagsasabing iba.
- Kunin muli ang datos bago magbigay-kahulugan. Kalahati ng mga unang puwang namin ay dulot ng mga bug sa pagination. Nalulutas ng pangalawang pull mula sa ibang endpoint o ibang vendor ang kategorya 4 at pinapaliit ang problema bago pa kailangang magpasya ng anuman.
- Gumamit ng staleness gate, huwag mag-fill ng puwang. Tumatanggap ang strategy ng input na
data_ageat may mahigpit na tuntunin: walang bagong entry kapag lampas na sa N bar ang huling totoong print, at isinasara ang mga bukas na posisyon sa muling pagbubukas gamit lang ang market order na may tahasang bawas para sa panganib ng puwang sa pagpepresyo. Mas masama ang mga fill na imposibleng mangyari kaysa sa mga trade na hindi nangyari. - NaN ang nakikita ng mga indicator, hindi kathang-isip. Hindi kailanman nakakarating sa feature layer ang mga presyong ni-forward-fill. Kung hindi makalkula ang ATR, undefined ito; at kapag undefined, flat ang posisyon. Mas mabuti ang malinaw na pagkabigo kaysa sa tahimik na 7x.
- Iulat ang performance ayon sa kondisyon ng puwang. Ipinapakita ng bawat backtest na inilalabas namin ang P&L na hindi kasama ang mga trade malapit sa outage, kasabay ng pangunahing resulta. Kung ang mga trade na iyon ang nagpapaganda sa resulta, artifact ito ng datos.
Mabilis na pagsusuring puwede mong gawin ngayon: pagsama-samahin sa magkakasunod na takbo ang mga nawawalang minuto, saka tingnan kung anong bahagi ng mga trade sa backtest mo ang nagbubukas o nagsasara sa loob ng 30 minuto mula sa hangganan ng isang takbo. Kung mas mababa sa 1%, malamang na walang gaanong epekto ang mga puwang. Kung 5% o higit pa, bahagi ng kuwento sa equity curve ang downtime ng exchange.
Mas pinagkakatiwalaan ko na ngayon ang anyo ng mga nawawalang minuto kaysa sa dami ng mga ito. Karaniwang ayos lang ang dataset na may libo-libong nakakalat na butas sa mga oras na walang gaanong galaw. Kapag iilang magkakadikit na kumpol ang nasa dataset, sinasabi nitong may pumapalya kapag mabigat ang load, at sa mismong bahaging iyon kumikilos ang strategy mo.
← Lahat ng post
