Trade Classification When You Have No Side Flag: Tick, Quote, Lee-Ready, BVC
Алдымен микроқұрылым оқулықтарының көбі бастайтын бұл мәселенің нұсқасын жоққа шығарайық. Бұл блог нақты сауда жасайтын алаңдарда сауда бағытын болжаудың қажеті жоқ — ол дайын өріс ретінде келеді. Binance aggTrades арнасында isBuyerMaker; Bybit сауда ағынында side беріледі. Барларды құру мақаласы агрессор жағын осы белгіден тікелей алады және ешқандай классификатор қолданбайды:
def on_trade(self, timestamp: int, price: float, qty: float, is_buyer_maker: bool):
side = -1 if is_buyer_maker else 1
Бұл — наносекундтық ажыратымдылықтағы тегін ақиқат. Егер заманауи крипто CEX ағынынан таңбаланған ордер ағынын құрып жатсаңыз, бұл мақала сізге қажет емес.
Ол төрт жағдайда керек, әрі олардың маңызы жеткілікті:
- Сізде тек барлар бар. Тарихи OHLCV — сатушылардың көбі ұсынатын және бэктестердің көбі пайдаланатын дерек; сауда ағыны мұрағатталмаған немесе оны жинау зерттеу құнын ақтамайды. Төмендегі BVC мәселесі осы.
- Алаң қапталды белгілемейді. Кіші CEX-тер, акцияларға арналған TAQ тәрізді деректер және 2017 жылға дейінгі мұрағаттардың дерлік бәрі сізге тек баға мен көлемді береді.
- DEX және ончейн ағыны. Swap оқиғасы қай токеннің қай бағытта қозғалғанын айтады, бірақ маршрутталған көп-hop сауда немесе агрегатор ішіндегі агрессияны анықтауға сүйенетін белгі жоқ.
- Жарияланған зерттеуді қайталайсыз. Kyle лямбдасының бағалары, VPIN, спред декомпозициялары — микроқұрылым әдебиетінің дерлік бәрі Lee-Ready арқылы классификацияланған дерекке сүйенеді, сондықтан салыстырмалылық үшін нақты қапталды оқудың орнына олардың классификаторын іске қосу керек.
Төменде ережелер жиыны, ең маңызды істен шығу режимі, көлемді жаппай классификациялау қысқартуы және бәрін өлшеу протоколы берілген — өйткені крипто акциялар әдебиетінде болмаған белгілерді береді.
Tick тесті

Ағымдағы сауда бағасы мен алдыңғы бағаны салыстырыңыз:
Интуициясы мынадай: сатып алушы бастаған сауда ask-ті көтеріп, бағаны өсіреді; сатушы бастаған сауда bid-ті ұрып, бағаны түсіреді. Нөлдік тиктер алдыңғы таңбаны алға тасымалдайды, қателіктің көбі осы жерде: бір тиктік спреді бар өтімді құралда қатар тұрған саудалардың басым бөлігі бір бағада орындалады.
sign = np.sign(np.diff(prices, prepend=prices[0]))
sign[sign == 0] = np.nan
directions = pd.Series(sign).ffill().fillna(1).astype(int).values
Дәл осы алға тасымалдау семантикасы бар өндірістік іске асыру уақыт барларынан кейінгі тик және көлем дисбалансы барларының генераторларындағы _tick_sign() ішінде бар — екінші көшірмені қолдағанша соны қайта пайдаланыңыз.
Quote ережесі

Қатар тұрған саудаларды салыстырудың орнына сауда бағасын ағымдағы орта нүктемен салыстырыңыз: :
def quote_rule(trade_prices: np.ndarray,
bid_prices: np.ndarray,
ask_prices: np.ndarray) -> np.ndarray:
"""Classify trades using the quote rule.
Returns +1 (buy), -1 (sell), or 0 (unclassified) for midpoint trades.
"""
midpoints = (bid_prices + ask_prices) / 2.0
directions = np.zeros(len(trade_prices), dtype=int)
directions[trade_prices > midpoints] = 1
directions[trade_prices < midpoints] = -1
return directions
Quote ережесі tick тестіне қарағанда көбірек ақпарат пайдаланады, бірақ басқа жерде істен шығады: дәл орта нүктеде орындалған саудалар туралы ештеңе айтпайды. Спреді тар, тик өлшемімен шектелген құралда бұл шеткі жағдай емес — таспаның үлкен бөлігі осындай. Ережеге қосымша fallback керек, оны Lee-Ready береді.
Lee-Ready: гибрид және ескірген quote болжамы

Lee мен Ready (1991) екеуін біріктірді: quote ережесін қолданып, орта нүктедегі сауда үшін tick тестіне қайта оралады.
def lee_ready(trade_prices: np.ndarray,
bid_prices: np.ndarray,
ask_prices: np.ndarray,
quote_lag: int = 0) -> np.ndarray:
"""Lee-Ready classification.
quote_lag : number of quote observations to lag (0 = contemporaneous).
Set > 0 only if your quote feed is known to trail the trade
feed; see the discussion of the 5-second rule below.
Depends on tick_test() with carry-forward semantics — the `_tick_sign()`
implementation from /blog/beyond-time-bars-candle-construction.
"""
if quote_lag > 0:
bid = np.concatenate([bid_prices[:quote_lag], bid_prices[:-quote_lag]])
ask = np.concatenate([ask_prices[:quote_lag], ask_prices[:-quote_lag]])
else:
bid, ask = bid_prices, ask_prices
directions = quote_rule(trade_prices, bid, ask)
unclassified = directions == 0
if unclassified.any():
directions[unclassified] = tick_test(trade_prices)[unclassified]
return directions
Мақаланың қызығырақ жартысы — әдетте негіздемесіз көшірілетін бөлігі. Lee мен Ready жай ғана гибрид ұсынған жоқ; олар әр сауданы бес секунд бұрынғы quote-пен салыстыруды ұсынды. Бұл сан нарық туралы модельдік таңдау емес. Ол есеп беру артефактісін түзету үшін қажет болды: 1980-жылдардағы NYSE біріктірілген таспасында сауда мен quote әртүрлі кідірісі бар бөлек жолдармен таралып, quote-тар өздері тиесілі саудадан бұрын жетуге бейім еді. Сондықтан сауданы сол сәттегі басылған quote-пен салыстыру оны әлдеқашан көрсетіп қойған quote-пен салыстырды — нарықты қозғаған дәл саудаларда таңбаны кері аударды.
Бұл криптоға көшіретіндер үшін екі қорытынды береді.
Бес секунд ережесі ескірді және оны қолдану зиянды. Ол қазір жоқ тарату кідірісін түзетеді. Акция нарықтары бұл алшақтықты 1990-жылдардың ортасына қарай жойды; крипто алаңының сауда және order-book delta ағындары бір sequence кеңістігін бөлісіп, бір matching engine арқылы микросекундтық ажыратымдылықта таңбаланады. BTCUSDT үшін бес секунд синхрондау төзімділігі емес, жүздеген кітап жаңартуы. Quote-ты бес секундқа кідірту ескі quote-ты түзетпейді, оны жасайды. Өз capture-іңізде нақты ығысуды өлшемейінше quote_lag=0 қолданыңыз.
Бірақ негізгі мәселе жаңа түрде сақталды. Енді quote-тың ескіруіне биржа емес, сіздің конвейеріңіз кінәлі. Кітапты WebSocket delta ағынынан қайта құрып, саудаларды қабырға сағатының timestamp-і бойынша қоссаңыз, буферлеуіңізге, snapshot-ты қайта синхрондау саясатына және сағатыңызға тәуелді кідіріс енгізіледі. Кітапты оқитын кез келген классификаторға сенбес бұрын оны өлшеңіз: бір терезені қайта ойнатып, саудаларды кітап күйіне қосыңыз да, қосылған [bid, ask] сыртында қалғандарының үлесін тексеріңіз. Қосылған ask-тен жоғары орындалған сауда оған сәйкестендірілген кітаптың ескіргенін дәлелдейді.
Түзету Lee мен Ready ұсынғаннан бөлек, ал істен шығу режимі бірдей.
Bulk Volume Classification

Easley, Lopez de Prado және O'Hara (2012) басқа мәселеге шабуыл жасайды: жеке саудаларды мүлде көрмесеңіз не болады? BVC бар ішіндегі жиынтық көлемді стандартталған баға өзгерісінің стандартты қалыпты CDF-і арқылы бөледі:
мұнда , ал — бардағы баға өзгерістерінің стандартты ауытқуы.
from scipy.stats import norm
def bulk_volume_classification(open_prices: np.ndarray,
close_prices: np.ndarray,
volumes: np.ndarray,
sigma: float | None = None) -> tuple:
"""Split bar volume into buy/sell using the BVC rule.
Returns (buy_volume, sell_volume) as continuous, not integer, splits.
"""
delta_p = close_prices - open_prices
if sigma is None:
sigma = max(float(np.std(delta_p)), 1e-8)
buy_fraction = norm.cdf(delta_p / sigma)
return volumes * buy_fraction, volumes * (1.0 - buy_fraction)
BVC — нашарлау емес, басқа құрал; мұны үш қасиет түсіндіреді. Ол саудаларды классификацияламайды — үлес шығарады, сондықтан өзгеріссіз жабылған бар оның ішіндегі әр саудаға тиын лақтырғандай емес, 50/50 болып бөлінеді; егер тұтынушыға әр саудаға таңба керек болса, BVC оны бере алмайды. Ол таспаның орнына барларда жұмыс істейді, мәні де осында: сауда деңгейіндегі дерек жоқ кезде жұмыс істейтін осы жердегі жалғыз әдіс. Ал — нәтижені өзгертетін еркін параметр: бүкіл үлгі бойынша есептеу lookahead, ал қысқа жылжымалы бағалау функциясын қанықтырып, әр барды 0/100 жағына итереді. Бұл таңдау әдепкі мәнді қабылдауды емес, сезімталдықты тексеруді қажет етеді.
Бастапқы мақала BVC-ның сауда деңгейіндегі классификацияны VPIN бағалауына жеткілікті жақын бақылайтынын көрсетеді. Нақты дәлдік сандары бар өлшеміне, инструментке және бағалауышына қатты тәуелді, ал екінші дереккөздердегі сандар үшеуін де сирек атайды. Акциялар зерттеуіндегі бір санды көшірмеңіз — өзіңіз өлшеңіз.
Классификацияға тән жалғыз белгі

Ереже іске қосудың орнына мұны модельге үйретсеңіз, белгілер жиынының көп бөлігі бұрын жарияланған: спред, тереңдік дисбалансы, сауда ағынының дисбалансы және жылжымалы іске асқан волатилдік ML көмегімен спредті модельдеу материалында кестеленіп, іске асырылған, ал көп деңгейлі ордер кітабы белгілері DeepLOB мақаласында бар. Соларды пайдаланыңыз.
Осы мәселеге ғана тән және екі материалда да жоқ белгі — сауданың спред ішіндегі орны:
Bid-тегі сауда 0-ге, ask-тегі 1-ге, орта нүктедегі сауда 0,5-ке бейнеленеді. Бұл quote ережесінің үздіксіз жалпылауы: орта нүктеде шек қоюдың орнына модельге қашықтықты береді, сонда модель 0,95-тегі сауданың сатып алу екеніне дерлік сенімді, ал 0,55-тегі сауданың ақпараты аз екенін үйрене алады. сыртындағы мәндер — алдыңғы бөлімдегі ескірген quote диагностикасы; оларды қиып тастағаннан гөрі журналға жазған дұрыс.
Осы белгілер үшін boosting базасын құрғанда, конвейер ML көмегімен спредті модельдеу материалында жарияланған күйінде қалады, тек мақсат binary болады — оның purge және embargo бар walk-forward CV-сын да қоса. Микроқұрылым классификаторын қарапайым TimeSeriesSplit арқылы бағаламаңыз; сол мақала мен walk-forward оңтайландыру нәтижедегі санның неге оптимистік екенін түсіндіреді. Кітап snapshot-тары бойынша sequence модельдері үшін DeepLOB — анықтамалық архитектура, ал ондағы оқыту туралы ескерулер өзгеріссіз қолданылады.
Мұны дұрыс өлшеу: крипто сізге белгілерді береді

Акциялардағы сауда классификациясы әдебиетіндегі әр дәлдік көрсеткіші ақиқаттың проксиіне қарсы бағаланады — TORQ, audit-trail ішкі үлгілері немесе бір алаңның ішкі жазбалары — өйткені шын агрессор жағы ешқашан жарияланбаған. Крипто оны жариялайды. Binance aggTrades ішіндегі isBuyerMaker әр сауда үшін тегін белгі береді. Демек эксперимент кез келген адамға қолжетімді, ал оның крипто үшін жарияланғанын кездестірмедім. Протокол:
Дерек. Бір айлық BTCUSDT aggTrades және book ticker ағыны; әр сауда оның дәл алдындағы bid пен ask-ті алып жүруі үшін оларды біріктіріңіз. Спред кең болғанда не болатынын көру үшін жұқа альткоинде де қайталаңыз.
Белгі. direction = -1 if is_buyer_maker else +1. Содан кейін белгіні тастап, әр әдісті тек баға мен quote деректеріне іске қосыңыз.
Әдістер. Tick тесті, quote ережесі, quote_lag=0 кезіндегі Lee-Ready, ескірген ереженің зиянын өлшеу үшін тарихи бес секундтық lag кезіндегі Lee-Ready және шын әр бардағы buy-volume үлесіне қарсы бірнеше бар өлшеміндегі BVC.
Бөліктер. Жалпы дәлдік — ең қызықсыз сан. Спред режимі бойынша бөліңіз (бір тикке қарсы кең спред — tick тестінің алға тасымалдауы спред бекітілген жерде күйреуі керек), сауда орта нүктеде орындалды ма соған қарай (quote ережесі қай жерде қалыс қалатынын және Lee-Ready fallback-ы қай жерде барлық жұмысты істейтінін бөлу), сауда көлемі бойынша (aggTrades жазбалары — шыпырулар; ірі саудалар әсерді анықтайды және қате таңбаланса ең көп шығын әкеледі) және волатилдік режимі бойынша (BVC мәнін бағалайды, сондықтан оның қатесі құрылымдық түрде режимге тәуелді).
| Әдіс | Жалпы | Орта нүктеде | Тар спред | Кең спред | Ірі сауда |
|---|---|---|---|---|---|
| Tick тесті | — | — | — | — | — |
| Quote ережесі | — | — | — | — | — |
| Lee-Ready (lag 0) | — | — | — | — | — |
| Lee-Ready (5s lag) | — | — | — | — | — |
| BVC (бардағы үлес) | — | n/a | — | — | n/a |
Дәлдік — мақсат емес

DeepLOB ұсынған құрылымдық тәртіпті ұстанайық: классификация дәлдігі нәтиже емес, нәтижеге кіретін дерек. Ешкім сауда таңбасын жеке сатпайды — таңбалардың толық ағынынан есептелген нәрсені сатады, ал қателер оған бейтарап түрде таралмайды. Саудалардың 10%-ында кездейсоқ қате жіберетін классификатор мен бағаны қозғайтын ірі саудалардың 10%-ында жүйелі түрде қате жіберетін классификатор дәлдігі бірдей болса да, таңбаланған ордер ағынын мүлде өзгеше береді. Tick тестінің алға тасымалдау қатесі flat бағаға — таңбаланған ағын ақпаратты болуы тиіс режимге — арнайы корреляцияланған. Сондықтан жоғарыдағы бөліктер, тақырыптағы сан емес, нақты нәтиже.
Ақиқат белгілері бар кезде кейінгі сұрақты тікелей өлшеуге болады: сізге керек шаманы шын таңбалардан есептеңіз, әр классификатордың таңбаларынан қайта есептеңіз де, айырманы есеп беріңіз.
- Баға әсері. Бекітілген терезелердегі таңбаланған таза taker ағынына орта баға өзгерістерін регрессиялаңыз — бағалаушы сырғу құны модельдерінде анықталған, ал Binance-тің ашық деректеріндегі жұмыс істейтін іске асыру Almgren-Chriss оңтайлы орындауында бар. Мұнда оны қайта анықтамаңыз; екі рет іске қосып, бағаланған коэффициентті салыстырыңыз.
- Болжаушы ретінде ордер ағынының дисбалансы. Шын таңбалардағы OFI мен алдағы кірістердің корреляциясын және классификацияланған таңбалардағы корреляцияны есептеңіз. Сол корреляцияның нашарлауы — маңызды жалғыз бірлікте көрсетілген классификация қатесінің бағасы.
- Уыттылық метрикалары. VPIN және сауда ағыны дисбалансының белгілері классификацияланған көлемді тұтынады; екеуі де ML көмегімен спредті модельдеу материалында қамтылған. Олардың классификация қатесіне сезімталдығын дәл осы жолмен өлшеуге болады.
Бұл сізді қайда әкеледі

Егер алаңыңыз агрессор белгісін берсе, соны пайдаланыңыз. Криптоның көп бөлігі көбіне осылай істейді.
Егер бермесе, қатардағы quote-пен Lee-Ready — дәлдігі үшін емес, стандарт болғаны үшін дұрыс әдепкі нұсқа, ал жарияланған бағалаулардың үш онжылдығымен салыстырмалылық тексеру мүмкін емес бірнеше дәлдік пунктінен қымбат. Бес секунд ережесі — 1980-жылдардағы таспа кідірісінің қазбасы; оны заманауи деректе қайталау жою үшін жасалған ескірудің өзін енгізеді. Егер сізде тек барлар болса, BVC — мүлде жұмыс істейтін жалғыз нұсқа және ол басқа сұраққа жауап береді: сауда таңбасы емес, көлемнің бөлінуі.
Қай жағдайда да крипто тегін беретін белгілермен салыстырыңыз, нәтижені спред режимі мен сауда көлемі бойынша бөліңіз және дұрыс болған пайызды емес, қателіктің downstream шығынын есеп беріңіз.
Authors
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.