Implementation shortfall және DIY TCA: орындаудың сізге шын мәнінде қанша тұратынын өлшеу
Әрбір институционалдық үстелде транзакция шығындарын талдау (TCA) конвейері бар. Крипто-бот жүргізетіндердің ешқайсысында дерлік ол жоқ. Әдеттегі конфигурация fill-дерді журналдайды, комиссияларды қосады және бэктест PnL мен нақты PnL арасындағы айырманы "slippage" деп атайды — латенттілікті, spread-ті, әсерді, adverse selection-ды және баға кетіп қалғанша толмаған әрбір тапсырысты сіңіретін жалғыз түсіндірілмеген қалдық. Сіз бір санмен өлшеген шығынды түзете алмайсыз. Оны дұрыс өлшейтін механизм 1988 жылдан бері бар, ол меншікті емес, ал өз fill журналдарыңыздың үстінен ол шамамен 200 жол Python коды. Осы мақала оны құрады.
Пайда — әдемірек дашборд емес. Сіздің бэктестіңізде шығын моделі бар — slippage тұрақтысы, fill ықтималдығы, әсер коэффициенті — және ондағы әрбір параметр қазір болжам ғана. Нақты fill-дер үстіндегі TCA — сол параметрлерді калибрлеуге болатын жалғыз шынайы шындық. Біз бұл циклдің симуляция жағын Fill симуляциясы: жабылу-бағасы фантазиясынан кезек-хабардар шындыққа дейінгі баспалдақ мақаласында құрдық; осы мақала өлшеу жағын құрады.
Қағаз бен шындық: Perold шын мәнінде нені өлшеді
Іргелі трюк André Perold-қа тиесілі (1988, "The Implementation Shortfall: Paper Versus Reality," Journal of Portfolio Management 14(3), 4–9). Қатар екі портфель жүргізіңіз. Қағаз портфелі әрбір шешімді бірден, шектеусіз көлемде, нөлдік шығынмен, шешім қабылданған сәтте үстемдік еткен бағамен орындайды. Нақты портфель — сіздің ботыңыздың шын мәнінде жасағаны: ішінара fill-дер, қуалаған котировкалар, күшін жойған қалдықтар, комиссиялар. Implementation shortfall — олардың кірістерінің айырмасы.
Анықтама маңызды, өйткені ол нені жасыруға бас тартады. Комиссия туралы есеп комиссияларды көрсетеді. Fill-мен-лимит-бағасы есебі мүлдем ештеңе көрсетпейді (сіз лимитіңізден нашар ешқашан толмайсыз — құрылысы бойынша). Қағаз портфелі сізден бәрі үшін ақы алады: шешім мен келу арасындағы дрейфке, сіз кесіп өткен spread-ке, сіз тудырған әсерге және — ең бастысы — баға кетіп бара жатқанда ешқашан толмаған тапсырыстарға. Wagner мен Edwards (1993, "Best Execution," Financial Analysts Journal 49(1), 65–71) көрінетін комиссияларды мұзтаудың ұшы деп атады; айналымы бар кез келген нәрсе үшін су астындағы бөлік басым болады.
Белгілеулерді бекітейік. Ата-тапсырыс: тарап (сатып алу/сату), көлем . Шешім бағасы — сигнал жанғанда стратегияңыз көрген mid. Fill-дер түрінде келеді, толған жалпы саны . Горизонтта (ата-тапсырыс аяқталды, күшін жойды немесе уақыты бітті) mid болады. Айқын комиссиялар . Валюталық тұрғыдан implementation shortfall:
қағаз ноционалы -ге бөлу арқылы базистік пунктке нормаланады. Оң мән — сіз төледіңіз дегенді білдіреді. Бірінші мүше — қағаз портфеліне қатысты fill-деріңіз қанша тұрғаны; екіншісі — Perold-тың opportunity cost-ы — толмаған қалдық кетіп қалған бағамен белгіленген; үшіншісі — сіздің биржа есебіңіз мойындайтын жалғыз бөлік.
Бір конвенция ескертпесі: сала "arrival price" дейді, ал көптеген үлестік TCA-да arrival тапсырыс нарыққа жеткен сәттегі mid-ті білдіреді. Бот үшін шешім уақыты мен келу уақыты сіздің өз ішкі латенттілігіңіз плюс rate-limit кезегі бойынша ерекшеленеді — нақты, өлшенетін шығын. Сондықтан біз екі уақыт белгісін де, екі бағаны да сақтаймыз және ыдырауға оларды бөлуге мүмкіндік береміз.
Ыдырау: кідіріс, әсер, тайминг, opportunity, комиссиялар
Жалғыз IS саны сізге орындаудың қымбат екенін айтады. Ол сізге неге екенін айтпайды, ал әртүрлі компоненттердің шешімдері мүлдем басқаша — кідіріс шығыны мен әсер шығынын бір өзгеріспен шешпейсіз. Robert Kissell-дің кеңейтілген implementation shortfall-ы (Kissell, 2006, "The Expanded Implementation Shortfall: Understanding Transaction Cost Components," Journal of Trading 1(3), 6–16; кітап көлемінде The Science of Algorithmic Trading and Portfolio Management, Academic Press, 2013-те дамытылған) жалпы шаманы компоненттерге бөледі, олардың әрқайсысы тапсырыс өмірлік циклінің жеке кезеңіне жатқызылады. Практиктің нұсқасы, arrival mid -ды қолдана отырып (бірінші биржа растауындағы mid):
Тепе-теңдік Perold-тың анықтамасына дәл телескоптанады — мүшелерді жайыңыз да қысқарады. Әрбір бөліктің жеке иесі бар:
Delay cost : сигнал жанғаны мен сіздің бірінші бала-тапсырысыңыздың биржада тірі болуы арасындағы баға дрейфі. Бұл сіздің инфрақұрылымыңыз — сериализация, желі, rate-limit кезектері, тәуекел тексерулері. Егер сигналыңызда шынайы қысқа горизонтты alpha болса, delay cost — ол алдымен ағып кететін жер; тұрақты оң орташа мән нарық сіз келгенге дейін сіздің пайдаңызға қарай жылжитынын айтады — сөнетін momentum alpha немесе сол сигналды сатушы сізден жылдам біреу.
Trading cost : сіздің fill-деріңіз arrival-ға қатысты қанша төлегені — кесіп өткен spread плюс нарық әсері плюс кесте ішіндегі дрейф. Бұл орындау алгоритмінің табелі және орындау зерттеулері шын мәнінде модельдейтін шама. Almgren, Thum, Hauptmann мен Li (2005, "Direct Estimation of Equity Market Impact," Risk 18(7), 58–62) оны Citigroup үстелдерінен шамамен 700,000 АҚШ үлестік тапсырысының үстінде (2001 жылғы желтоқсан–2003 жылғы маусым) өлшеп, trading cost күнделікті құбылмалылық пен қатысу коэффициентіне қарай масштабталатынын тапты — уақытша әсер сауда жылдамдығына степень заңымен экспоненті 3/5-ке жақын, тұрақты әсер көлемге сызықтыға жақын ілеседі. Калибрлеу кезінде біз олардың функционалдық түрін қайта қолданамыз.
Timing risk: орташа ыдырауда мүше емес, бірақ оның айналасындағы дисперсия. Ата-тапсырысты уақыт бойынша тарату күтілетін әсерді азайтады және сізді құбылмалылыққа әшкерелейді; қалған позициясы болатын кесте үшін шығынның стандартты ауытқуы ретінде масштабталады. Бұл дәл Almgren–Chriss фреймворкі оңтайландыратын айырбас. Сіздің TCA есебіңізде ол ата-тапсырыстар арасындағы IS-тың дисперсиясы ретінде көрінеді — әрбір орташа мәннің қасында стандартты ауытқуды хабарлаңыз, әйтпесе орташа мән барлық назарды алады, ал құйрықтар барлық ақшаңызды алады.
Opportunity cost : терминалдық бағамен белгіленген толмаған көлем. Пассив стратегиялар үшін бұл әдетте ең үлкен және ең аз зерттелген компонент, әрі бұл — бүкіл фреймворкті адал ететін мүше — бұл туралы толығырақ тұзақтар бөлімінде, өйткені оны түсіріп қалу — адамдардың TCA-мен өздерін алдайтын ең кең таралған тәсілі.
Fees : айқын бөлік. Крипто-да комиссияларды жеңілдіктерден кейін журналдаңыз (VIP деңгейлер, fill-уақыты бағасымен айырбасталған токен рибейттер) және maker рибейттерін таңбамен сақтаңыз — теріс комиссия — бұл шу емес, дерек.
Толық талданған мысал
BTC сатып алу. Сигнал -де жанады; қағаз ноционалы $600,000. Бірінші бала-тапсырыс mid -мен расталды. Келесі екі минут ішінде 8 BTC VWAP 60,072-мен толады; баға кетіп бара жатыр, алгоритм лимитін сақтайды, ал қалған 2 BTC mid-те күшін жояды. Толған ноционалда араласқан комиссиялар 2.5 bps.
| Компонент | Формула | USD | қағаздың bps |
|---|---|---|---|
| Delay | 120 | 2.0 | |
| Trading cost | 480 | 8.0 | |
| Opportunity | 456 | 7.6 | |
| Fees | 120 | 2.0 | |
| Жалпы IS | 1,176 | 19.6 |
Биржа есебі $120 көрсетеді. Шешімді іске асырудың нақты шығыны $1,176 болды — он есе, әрі ең үлкен екі компонент комиссияға негізделген есептеуге көрінбейді. Оның шамамен 40%-ы ешқашан сатылмаған көлемнен келді. Тек fill-дерді талдайтын TCA есебі бұл ата-тапсырысты 8 bps деп бағалап, оны жақсы деп атаған болар еді.

Markout-тар: adverse selection-ды бағалау
Implementation shortfall ата-тапсырысты бағалайды. Ол жеке fill-дердің сапасы туралы ештеңе айтпайды — атап айтқанда, сіз жүйелі түрде сіз білмейтін бірнәрсені білетін контрагенттермен сауда жасайсыз ба, соны. Мұны markout-тар өлшейді: әрбір fill-ді ол болғаннан кейін тұрақты горизонттағы mid-ке белгілеңіз.
мұнда — уақытындағы fill бағасы, ал — уақытындағы mid. Бұл — горизонтындағы fill-дің бірлікке шаққандағы mark-to-market PnL-і, әрі -де оның таза анатомиясы бар: maker fill жарты-spread-тан басталады (сіз bid-те сатып алдыңыз, mid сіздің үстіңізде); taker fill жарты-spread-тан басталады. өскен сайын не болатыны — сауданың ақпараттық мазмұны:
- s снайпингті және ескірген котировкаға тап болуды оқшаулайды. Егер сіздің maker fill-деріңіз толғаннан кейін бір секунд ішінде-ақ судың астында болса, жылдамырақ қатысушылар сіздің котировкаларыңыз дұрыс емес бағаланған сәтте оларды соғып жатыр — сіздің котировканы жаңарту циклыңыз олардың триггер циклынан баяу. Бұл markout — латенттілік диагностикасы, стратегия диагностикасы емес.
- s классикалық adverse selection-ды өлшейді: сіздің бағаңыз арқылы қозғалыс жалғасатын fill-дер. Нарық жасаушы үшін бұл — spread ұстауы жеңуі керек шығын; үлестік микроқұрылым осыған қатысты шаманы realized spread деп атайды, ол SEC Rule 605 есептілігінде 5-минуттық горизонтта институционалданған. Крипто тезірек қозғалады; 10–60s — баламалы диапазон.
- s сізге fill-дер микроқұрылым горизонтынан тыс сізге қарсы momentum алып жүре ме, соны айтады — taker стратегиялары үшін сіздің сигналыңыздың 60s-тегі alpha-сы сіз кіру үшін төлеген spread-плюс-әсерден асып түсе ме, соны. bps-тан басталып, нөлді ешқашан кесіп өтпейтін taker markout қисығы — alpha-сы қаржыландыра алмайтын кірулер үшін төлейтін стратегия.
Maker/taker асимметриясы — пассив сауданың бүкіл экономикасы екі қисықта. bps-тан (жарты-spread) басталып, 60s-ке қарай bps-қа сөнетін maker қисығы былай дейді: сіз spread-ті ұстайсыз да, көбірек қайтарасыз, әрі ешқандай рибейт деңгейі оны түзетпейді. Дәл сол қисық bps-те тұрақталса, котировкалау қозғалтқышы өз орнын ақтайды дейді. Бұл дәл наив touch-fill бэктестері елемейтін нәрсе — сізді баға лимитіңізге тигенде толтыратын симулятор толу дұрыс еместікпен корреляцияланғанын елемейді, сол себепті fill-симуляция баспалдағының кезек-хабардар сатысына болжам емес, өлшенген markout-тар кіріс ретінде керек.

Есептеу — өз mid ағыныңыз үстіндегі merge_asof:
import pandas as pd
def markouts(fills: pd.DataFrame, mids: pd.DataFrame,
horizons=("1s", "10s", "60s")) -> pd.DataFrame:
"""fills: [ts, price, qty, side, liquidity]; mids: [ts, mid].
Both UTC-indexed and sorted. Mid stream must be from YOUR captured
feed, not candles reconstructed later."""
fills = fills.sort_values("ts").reset_index(drop=True)
mids = mids.sort_values("ts")
out = fills.copy()
for h in horizons:
probe = fills[["ts"]].copy()
probe["ts"] = probe["ts"] + pd.Timedelta(h)
m = pd.merge_asof(probe, mids, on="ts", direction="backward")
out[f"mo_{h}"] = (fills["side"] * (m["mid"].values - fills["price"])
/ fills["price"] * 1e4)
return out
def markout_report(mo: pd.DataFrame) -> pd.DataFrame:
"""Qty-weighted markouts by liquidity flag. Weighting matters:
a 0.001 BTC fill and a 2 BTC fill are not equal evidence."""
cols = [c for c in mo.columns if c.startswith("mo_")]
def agg(g):
w = g["qty"] / g["qty"].sum()
return pd.Series({c: (g[c] * w).sum() for c in cols}
| {"n": len(g), "qty": g["qty"].sum()})
return mo.groupby("liquidity").apply(agg)
Есепті одан әрі символ, тәуліктің сағаты және mid-тен котировка қашықтығы бойынша тіліңіз. Maker стратегиясы үшін ең әрекетке жарамды кесік — толу кезіндегі кезек позициясы бойынша markout: жаңа кезектің басындағы fill-дер деңгей сіз арқылы сыпырылған fill-дерден мүлдем басқаша бағаланады.
Конвейер: нені журналдау керек
TCA математика қабатында емес, журналдау қабатында өледі. Жоғарыдағы математикаға көптеген боттар лақтырып тастайтын сандар керек, әрі олардың ешқайсысын биржа тарихынан кейін қалпына келтіру мүмкін емес. Келіссіздіктер:
- Шешім mid-і, өз fide-іңізден, сигнал уақытында. Биржа шамының жабылуы емес, кейінгі қалпына келтіру емес. Бенчмарк — "стратегиям шешім қабылдағанда сенген баға" — оны тек сол сәттегі процесіңіз біледі.
- Екі уақыт белгісі: шешім уақыты және бірінші-растау уақыты, әйтпесе delay cost өлшенбейді және үнсіз trading cost-қа қосылады.
- Биржа уақыт белгісі, комиссиясы және maker/taker жалаушасы бар әрбір fill — сіздің жергілікті қабылдау уақытыңыз өз кіріс латенттілігіңізбен ластанған.
- Күшін жойған және мерзімі біткен ата-тапсырыстар, бәрі сияқты журналданған. Нөлдік fill-і бар ата-тапсырыстар — кестедегі ең қымбат жолдар.
- Тұрақты mid ағыны (немесе L1 ағыны) 100–250ms түйіршіктілікте, markout-тарды есептеуге жеткілікті ұзақ сақталған. Егер сіз fill симуляторы үшін кітаптарды жазып алсаңыз, бұл тегін.
Екі жалпақ кесте жеткілікті:
PARENTS = {
"parent_id": "str",
"strategy": "str",
"symbol": "str",
"venue": "str",
"algo": "str", # twap | pov | sniper | quote | ...
"side": "int8", # +1 buy, -1 sell
"qty": "float64", # parent size, base units
"limit_px": "float64", # NaN for unconstrained
"decision_ts": "datetime64[ns, UTC]",
"decision_mid": "float64", # mid your feed showed at decision_ts
"arrival_ts": "datetime64[ns, UTC]", # first exchange ack
"arrival_mid": "float64",
"end_ts": "datetime64[ns, UTC]", # filled / cancelled / expired
"terminal_mid": "float64",
"mkt_volume": "float64", # market volume over [arrival_ts, end_ts]
"sigma_bps": "float64", # realized vol estimate at decision time
}
FILLS = {
"parent_id": "str",
"ts": "datetime64[ns, UTC]", # exchange timestamp
"price": "float64",
"qty": "float64",
"fee": "float64", # quote ccy, post-discount, signed
"liquidity": "str", # maker | taker
"venue": "str",
}
Атрибуция функциясы — ыдыраудың тікелей транскрипциясы:
import numpy as np
def is_decomposition(p: pd.Series, fills: pd.DataFrame) -> dict:
"""Expanded implementation shortfall for one parent, bps of paper
notional. Sign convention: positive = cost."""
s, X = p["side"], p["qty"]
paper = X * p["decision_mid"]
x = fills["qty"].sum()
delay = s * X * (p["arrival_mid"] - p["decision_mid"])
trade = s * ((fills["price"] - p["arrival_mid"]) * fills["qty"]).sum()
oppty = s * (X - x) * (p["terminal_mid"] - p["arrival_mid"])
fees = fills["fee"].sum()
bps = lambda v: 1e4 * v / paper
return {
"parent_id": p["parent_id"],
"delay_bps": bps(delay), "trade_bps": bps(trade),
"oppty_bps": bps(oppty), "fees_bps": bps(fees),
"is_bps": bps(delay + trade + oppty + fees),
"fill_ratio": x / X,
"participation": x / max(p["mkt_volume"], x),
}
def tca_table(parents: pd.DataFrame, fills: pd.DataFrame) -> pd.DataFrame:
fg = dict(tuple(fills.groupby("parent_id")))
empty = fills.iloc[0:0]
rows = [is_decomposition(p, fg.get(p["parent_id"], empty))
for _, p in parents.iterrows()]
return parents.merge(pd.DataFrame(rows), on="parent_id")
Ал атрибуция сұраулары — дәл TCA есептеу болудан тоқтап, зерттеу болуды бастайтын жер:
tca = tca_table(parents, fills)
def wavg(g: pd.DataFrame, col: str) -> float:
w = g["qty"] * g["decision_mid"] # notional weights
return (g[col] * w).sum() / w.sum()
comp = ["delay_bps", "trade_bps", "oppty_bps", "fees_bps", "is_bps"]
by_strat = tca.groupby("strategy").apply(
lambda g: pd.Series({c: wavg(g, c) for c in comp}
| {"is_std": g["is_bps"].std(), "n": len(g)}))
done = tca[tca["fill_ratio"] > 0.99]
done["pov_bin"] = pd.qcut(done["participation"], 6)
impact_curve = done.groupby("pov_bin").apply(lambda g: wavg(g, "trade_bps"))
tca["hour"] = tca["arrival_ts"].dt.hour
by_hour = tca.groupby("hour").apply(lambda g: wavg(g, "is_bps"))
by_venue = tca.groupby("venue").apply(
lambda g: pd.Series({"is_bps": wavg(g, "is_bps"),
"is_std": g["is_bps"].std(),
"fill_ratio": g["fill_ratio"].mean(), "n": len(g)}))
4-сұрау — smart order router оңтайландыратын кіріс кестесі — venue-бойынша TCA-сыз маршруттау комиссия кестесі бойынша, яғни ең кіші шығын компоненті бойынша маршруттау (Крипто-дағы smart order routing осы кестені бастау нүктесі ретінде алады). Markout модулімен бірге бұл — уәде етілген ~200 жол.
Циклды жабу: бэктест шығын моделін калибрлеу
Міне, осы жерде конвейер өзін ақтайды. Сіздің бэктестіңіз сандарды бекітеді: slippage_bps = 5, fill ықтималдық қисығы, әсер коэффициенті. Олардың әрқайсысы — нақты орындау туралы тұжырым, ал TCA кестесі — нақты орындау. Цикл: TCA-мен өлшеу, шығын моделін тұрғызу, тұрғызылған моделмен бэктест жүргізу, сауда жасау, қайта өлшеу.

Taker шығыны үшін өзіңіз ойлап таппай, Almgren et al. (2005) функционалдық түрін алыңыз. Олардың нәтижесі — шығын күнделікті құбылмалылыққа көбейтілген қатысу коэффициентінің степеніне пропорционалды — екі параметрлі модель береді:
үлестік бағалау приор ретінде. Оны шикі ата-тапсырыстарда емес, топталған орташалар бойынша тұрғызыңыз — жеке ата-тапсырыс шығындарында шу басым (бұл — timing-risk мүшесі), ал шикі деректегі log-log регрессия шуды қуана-қуана тұрғызады:
done = tca[(tca["fill_ratio"] > 0.99) & (tca["participation"] > 0)]
done["norm_cost"] = done["trade_bps"] / done["sigma_bps"]
bins = done.groupby(pd.qcut(done["participation"], 8)).agg(
pov=("participation", "mean"), cost=("norm_cost", "mean"))
bins = bins[bins["cost"] > 0] # can't log a negative bin
b, log_a = np.polyfit(np.log(bins["pov"]), np.log(bins["cost"]), 1)
def taker_cost_bps(participation, sigma_bps, a=np.exp(log_a), b=b):
return a * sigma_bps * participation ** b
Содан кейін қателік жолағы туралы адал болыңыз. Almgren тобында 700,000 тапсырыс болды, әрі олар уақытша-әсер экспонентін бәрібір деп хабарлады; 2,000 ата-тапсырысы бар бот символ бойынша -ны еркін бағалауға құқылы емес. Практикалық режим: бойынша нормалаудан кейін символдар арасында біріктіріңіз, -ны 0.6-ға қарай қатты сығыңыз (немесе оны бекітіп, тек -ны тұрғызыңыз) және айына қайта тұрғызыңыз. Егер тұрғызылған -ңыз жоғары ауытқыса, сіздің ізіңіз өсті немесе нарық жұқарды — қалай болғанда да бэктестке мұны білу қажет еді.
Maker стратегиялары үшін калибрлеу мақсаттары басқа және басқа екі модульден келеді:
- Fill ықтималдығы: fill симуляторының кезек моделі әрбір (spread-қашықтығы, кезек-позициясы) ұяшығы үшін -ды болжайды; сіздің ата-тапсырыс журналыңыз әрбір ұяшық үшін нақты fill коэффициенттерін береді. Келіспеушілік — тор сілтемесі бекітілген симулятор багы.
- Adverse selection: симулятордың айқын емес "fill-дер алмастырылады" болжамын өлшенген markout кестесімен алмастырыңыз — сағатында қашықтығындағы симуляцияланған maker fill бірден mark-to-market шегерімі ретінде өлшенген -ды алып жүреді. Дәл осы бір өзгеріс — галлюцинация жасайтын maker бэктесті мен ізге түсетін бэктест арасындағы айырма; бұл fill-симуляция мақаласында белгіленген жоғалған калибрлеу кірісі болды.
- Шығын дисперсиясы: бэктестке IS-тың орташа мәнін емес, таралуын беріңіз. Тек орташа мәнді ығыстыратын шығын моделі timing risk тудыратын drawdown-дарды қайталай алмайды; тіпті ата-тапсырыс бойынша IS-қа тұрғызылған лог-нормаль де тұрақтыдан жақсы.
Толық slippage-қисық талдауы — функционалдық түрлер, режимге шарттау, степень заңы бұзылғанда — жеке мақала: Бэктестер үшін slippage қисықтары мен шығын моделдері. Мұндағы мәселе — архитектуралық: сол мақаланың моделдері осы мақаланың кестелерісіз тұрғызылмайды.
Тұзақтар
TCA әдебиеті ондаған жылдық, оны алдау тәсілдері де сондай. Үш ақаулық режимі өзін-өзі алдаудың көбін құрайды.
Бенчмаркты алдау. Arrival price-тан басқа кез келген бенчмаркты құшақтауға болады. Классикасы — VWAP: интервалдық VWAP-қа қарсы бағаланатын алгоритм оны базистік пункт ішінде ұстай алады, ал позиция arrival-ға қарсы жиырма ағып жатады, өйткені бенчмарк сіз итеретін бағамен дрейфтейді — әрі елеулі қатысуда сіздің өз prints-теріңіз дәл сол VWAP болады, сондықтан оны ұстау — өзін-өзі бағалайтын үй тапсырмасы. Біз бенчмарк саясатын TWAP vs VWAP vs POV мақаласында талдадық; TCA жағындағы ереже қарапайымырақ: бенчмарктар сауда алдында таңдалады, ал IS-қа-қарсы-arrival жоспарлаушы өзінің жоспарлау бенчмаркіне қарсы бағаланғанда да әрқашан есептеледі. Нәзігірек нұсқасы — arrival-ды алдау: егер decision_ts-ті орнататын компонент қысқа мерзімді momentum-ды көре алса, ол delay мүшесін жеңілдету үшін "шешімдерді" таймдай алады. Шешім уақыт белгілері сигнал қабатына тиесілі, кез келген орындау логикасы жұмыс істемес бұрын журналданады.
Тек-толғандарды талдаудағы survivorship bias. Шығын талдауыңызды fill-дерге шарттаңыз, сонда пассив орындау тегін болып көрінеді. Нақтырақ: 100 пассив buy ата-тапсырысы, mid-тен бір тик төмен. Алпысы толады, әрі — пассив бола тұрып — arrival-дан орта есеппен 3 bps жақсы бағамен толады: өлшенген "шығын" bps, мақтануға тұратын есеп. Ешқашан толмаған қырқы — дәл баға көтеріліп кеткендер; оларды бас тарту кезінде 25 bps қолайсыз деп белгілеңіз, сонда адал сан bps. Тек-толғандар есебі мен шынайы есеп 11 bps және таңбамен ерекшеленеді. Бұл — бұрыштық жағдай емес — бұл пассив сауданың механизмі: толу баға сіз арқылы өтуімен корреляцияланады, ал бұл touch-fill бэктестерін фантазия ететін дәл сол шарттау. Opportunity cost — IS-тың міндетті емес нақтылауы емес; ол — бүкіл өлшеуді selection-нан қорғайтын мүше. Дәл сол bias-тың taker нұсқасы бар: тап болмаған IOC тапсырыстары, rate limit немесе тәуекел тексерулерімен қабылданбаған тапсырыстар — егер жіберіп алулар журналданбаса, жіберіп алу шығыны өлшенбейді, әрі ол дәл сіздің стратегияңыз саудаға ең зәру болған жылдам нарықтарда ең үлкен.
Түрлі аяққа ату қаупі, қысқаша: биржа шамдарынан қалпына келтірілген arrival mid-тер (сіздің fide-іңіз бен шам маңызды болғанда дәл келіспейді); ноционал салмағынсыз ата-тапсырыс бойынша bps орташалау (мың тозаң fill бір нақты тапсырыстан асып дауыс беруі); жеңілдіктерге дейін журналданған комиссиялар; fill-ден басқа venue-ден алынған markout mid-тер (adverse selection болып көрінетін кросс-venue базис); ал perp-терде funding есептелуін орындау терезесіне ағызуға жол беру — funding — шығын, бірақ орындау шығыны емес, әрі оларды араластыру екі талдауды да улайды.
Осы аптада не істеу керек
Ботыңызға екі журнал кестесін қосыңыз — жоғарыдағы схема — жоба емес, баған тізімі. Ештеңені кейінге қайта толтырмаңыз; екі апталық адал журналдар бір жылдық қалпына келтіруден жақсы. Ыдырауды және үш markout горизонтын жүргізіңіз. Сіз қай компонент басым болатынын (комиссия дерлік ешқашан емес), пассив fill-деріңіз spread ұстауынан тыс adverse selection-ға ұшырай ма және бэктестіңіздің шығын тұрақтысы өлшенген қисықтан қаншалықты алшақ тұрғанын білесіз. Содан кейін тұрғызылған қисықты симуляторға қайта жалғап, бастапқыда бұл стратегияны жүргізуге кеңес берген бэктестті қайта жүргізіңіз. Perold-тың қағаз портфелі, отыз сегіз жылдан кейін де, сіздің нақты портфеліңіздің жалғыз адал қарсыласы болып қала береді.
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.