स्लिपेज कर्व्स, न कि स्लिपेज कॉन्स्टेंट्स: कॉस्ट मॉडल जो लाइव ट्रेडिंग में टिक सकें
ज़्यादातर बैकटेस्ट में सबसे महंगी लाइन होती है slippage_bps = 5। इसलिए नहीं कि 5 गलत संख्या है — एक साल के फिल्स पर औसत निकालें तो शायद यह सही भी हो — बल्कि इसलिए कि कॉन्स्टेंट कंडीशनली गलत है, और आपकी स्ट्रैटेजी सिलेक्शन प्रक्रिया एक ऐसी मशीन है जो कंडीशनल एरर्स को ढूंढकर उनका फायदा उठाती है। स्लिपेज ऑर्डर साइज़, स्प्रेड, वोलैटिलिटी और उपलब्ध लिक्विडिटी का फंक्शन है। कॉन्स्टेंट उसी फंक्शन का एक बिंदु पर निकाला गया मान है जिसे फिर हर जगह एक्सट्रापोलेट कर दिया जाता है — यहां तक कि रात 3 बजे की लिक्विडेशन कैस्केड तक भी, जहां आपका मीन-रिवर्शन सिग्नल सबसे तेज़ फायर होता है और बुक अपनी सामान्य डेप्थ का दसवां हिस्सा रह जाती है। बैकटेस्ट वहां भी 5 bps चार्ज करता है। लाइव ट्रेडिंग नहीं करेगी।
यह लेख बैकटेस्ट लूप के अंदर के कॉस्ट मॉडल के बारे में है: वह फंक्शन cost(size, market_state) जो हर सिम्युलेटेड ट्रेड से घटाया जाता है। यह जानबूझकर एक्सीक्यूशन शेड्यूल करने के लिए पहले से इम्पैक्ट का अनुमान लगाने के बारे में नहीं है — वह एक साथी समस्या है, जिसे मॉडल की ओर से price impact modeling में और ऑप्टिमल-शेड्यूलिंग की ओर से Almgren-Chriss में कवर किया गया है। यहां सवाल संकरा है और, जो भी बैकटेस्ट से स्ट्रैटेजी चुनता है उसके लिए ज़्यादा ज़रूरी है: आपके कॉन्स्टेंट की जगह कौन-सा फंक्शन खड़ा होना चाहिए, आपके पास मौजूद असली डेटा से इसे कैसे फिट करें, और इस जवाब से आप आखिर में कौन-सी स्ट्रैटेजी चलाते हैं यह कितना बदलता है। आखिरी हिस्से का एक तीखा एम्पिरिकल जवाब है: एक स्ट्रैटेजी फैमिली के 20 वेरिएंट्स को चार कॉस्ट मॉडलों के तहत फिर से रैंक करें और देखें कि लीडरबोर्ड उलट जाता है।
कॉस्ट-मॉडल सीढ़ी

fill simulation ladder की तरह, कॉस्ट मॉडल भी एक फिडेलिटी सीढ़ी बनाते हैं जहां हर पायदान को ज़्यादा डेटा चाहिए और एक खास सिस्टेमैटिक बायस हटाता है। पायदान संचयी हैं: हर एक नीचे वाले के टर्म्स रखता है और एक जोड़ता है।
M0: कॉन्स्टेंट bps
एक संख्या, हर ट्रेड पर लागू। बढ़ते नुकसान के क्रम में तीन फेल्यर मोड:
- साइज़-ब्लाइंड। 5M का पैरेंट ऑर्डर एक ही चीज़ चुकाते हैं। कैपेसिटी लेवल्स के आर-पार कोई भी स्ट्रैटेजी तुलना बेमानी हो जाती है।
- रीजीम-ब्लाइंड। शांत मंगलवार दोपहर और FTX का पतन एक ही चीज़ चुकाते हैं। यह एरर नॉइज़ नहीं है; यह ठीक उन्हीं स्टेट्स के साथ एंटी-करिलेटेड है जहां इवेंट-ड्रिवन स्ट्रैटेजीज़ अपनी ट्रेडिंग कंसंट्रेट करती हैं।
- सिलेक्शन-टॉक्सिक। जब आप 200 पैरामीटर कॉम्बिनेशन स्वीप करते हैं, तो ऑप्टिमाइज़र पाता है कि फ्लैट कॉस्ट के तहत, टर्नओवर वास्तविकता की तुलना में सस्ता है, और पूरी सर्च को हाई-फ्रीक्वेंसी वेरिएंट्स की ओर ड्रिफ्ट कर देता है। कॉस्ट एरर PnL पर एक सिमेट्रिक फोर्स नहीं, बल्कि मॉडल सिलेक्शन पर एक डायरेक्शनल फोर्स बन जाता है।
M1: स्प्रेड-प्रोपोर्शनल
डिसिज़न टाइमस्टैम्प पर मापा गया हाफ-स्प्रेड चार्ज करें (साथ ही फीस, जो डिटरमिनिस्टिक है और हमेशा अपनी अलग लाइन-आइटम होनी चाहिए)। यह पहला मॉडल है जो मार्केट के प्रति किसी भी तरह रिस्पॉन्ड करता है: स्प्रेड न्यूज़ पर, सेशन ओपन पर, पतले altcoins में चौड़े होते हैं, तो कॉस्ट अब कम-से-कम एक लिक्विडिटी वेरिएबल के साथ को-मूव करता है। यह अब भी क्या मिस करता है: स्प्रेड टॉप-ऑफ-बुक के एक क्लिप की फिल की कीमत बताता है। इससे बड़ा कुछ भी बुक में चलता है, और वह वॉक के लिए अदृश्य है।
M2: वोलैटिलिटी-स्केल्ड
शॉर्ट-होराइज़न वोलैटिलिटी के प्रोपोर्शनल एक टर्म जोड़ें। इसका औचित्य एम्पिरिकल भी है और स्ट्रक्चरल भी: स्प्रेड और डेप्थ मार्केट मेकर्स तय करते हैं जिनका एडवर्स-सिलेक्शन और इन्वेंटरी रिस्क के साथ स्केल करता है (Avellaneda-Stoikov की क्वोटिंग लॉजिक उल्टी चलाई गई), इसलिए लिक्विडिटी मांगने की कॉस्ट स्वाभाविक रूप से वोलैटिलिटी की यूनिट्स में डिनॉमिनेट होती है। जब आपके पास बुक डेटा बिल्कुल न हो — डेली बार्स, लंबी हिस्ट्री — तो जिसमें डेली वोल का लगभग 0.05–0.1 हो, किसी भी कॉन्स्टेंट से पहले ही नाटकीय रूप से बेहतर मॉडल है, क्योंकि यह कम-से-कम रीजीम के साथ सांस लेता है।
M3: पार्टिसिपेशन में स्क्वायर-रूट
साइज़ टर्म। आपका ऑर्डर साइज़ है, संबंधित विंडो में मार्केट वॉल्यूम, उसी विंडो में वोलैटिलिटी। यह फंक्शनल फॉर्म कोई सुविधा-भर नहीं है; यह मार्केट माइक्रोस्ट्रक्चर के सबसे ज़्यादा दोहराए गए एम्पिरिकल रिज़ल्ट्स में से एक है, और यह समझना ज़रूरी है कि यह कहां से आता है।
थियोरेटिकल शुरुआती बिंदु है Kyle (1985), "Continuous auctions and insider trading" (Econometrica 53(6), 1315–1335)। Kyle के मॉडल में एक मार्केट मेकर कीमत को नेट ऑर्डर फ्लो के लीनियर फंक्शन के रूप में सेट करता है, , जिसमें
— फ्लो की प्रति यूनिट इम्पैक्ट, नॉइज़-ट्रेडिंग वॉल्यूम पर वैल्यू अनसर्टेनिटी के प्रोपोर्शनल। Kyle के lambda ने इस फील्ड को लिक्विडिटी की यूनिट दी (डेप्थ है ) और अपना पहला टेस्टेबल दावा: प्रति ट्रेडेड डॉलर कॉस्ट लिक्विडिटी के मुकाबले इन्फॉर्मेशन के अनुपात पर निर्भर करती है, किसी कॉन्स्टेंट पर नहीं। पर मॉडल साइज़ में लीनियर है, और डेटा कुछ और कहता है।
डेटा कहता है कॉन्केव। Almgren, Thum, Hauptmann and Li (2005), "Direct estimation of equity market impact" (Risk, July 2005), ने Citigroup के डेस्क्स से लगभग 700,000 US इक्विटी ऑर्डर्स फिट किए और पाया कि टेम्पररी इम्पैक्ट पार्टिसिपेशन की पावर के साथ बढ़ता है — उन्होंने लीनियर और शुद्ध स्क्वायर-रूट दोनों को स्पष्ट रूप से टेस्ट किया और के पक्ष में रिजेक्ट कर दिया — जबकि परमानेंट इम्पैक्ट निकला, जो स्टैटिस्टिकली लीनियर से अलग नहीं पहचाना जा सका (जो राहत की बात है, क्योंकि Huberman and Stanzl (2004) ने दिखाया था कि नॉनलीनियर परमानेंट इम्पैक्ट मैनिपुलेशन को जगह देता है)। Tóth et al. (2011), "Anomalous price impact and the critical nature of liquidity in financial markets" (Physical Review X 1, 021006), ने Capital Fund Management के फ्यूचर्स मार्केट्स से लगभग 500,000 मेटाऑर्डर्स का इस्तेमाल करते हुए पाया जिसमें ऑर्डर वन का — और अब-मानक व्याख्या दी: विज़िबल बुक लेटेंट लिक्विडिटी का एक नगण्य-सा अंश है, जो मिड के आसपास लोकली लीनियर होती है, जिससे उसमें से खा जाने की कॉस्ट स्क्वायर रूट के रूप में स्केल होती है। बाद के काम ने किनारों को परिष्कृत किया: Zarinelli, Treccani, Farmer and Lillo (2015), "Beyond the square root" (Market Microstructure and Liquidity 1(2)), ने सत्तर लाख ANcerno इंस्टीट्यूशनल मेटाऑर्डर्स पर दिखाया कि स्क्वायर रूट ऑर्डर साइज़ के लगभग दो दशकों में अच्छी तरह फिट होता है पर लॉगारिथमिक फॉर्म पांच दशकों तक फैलता है; Bucci et al. (2019, Physical Review Letters 122, 108302) ने बहुत छोटे पार्टिसिपेशन पर लीनियर (Kyle-जैसे) इम्पैक्ट से इससे ऊपर स्क्वायर-रूट तक के क्रॉसओवर को दस्तावेज़ किया। और Frazzini, Israel and Moskowitz (2018), "Trading Costs" (SSRN 3229719), ने AQR से 19 साल में $1.7 ट्रिलियन के लाइव एक्सीक्यूशंस का इस्तेमाल करते हुए पाया कि रियलाइज़्ड कॉस्ट पहले के एकेडमिक अनुमानों से एक ऑर्डर ऑफ मैग्नीट्यूड छोटे थे — एक चेतावनी कि दूसरों के फ्लो पर फिट किए गए कोएफिशिएंट्स, अलग अर्जेंसी और अलग इन्फॉर्मेशन कंटेंट के साथ, आपके फ्लो पर ट्रांसफर नहीं होते।
बैकटेस्ट लूप के लिए, व्यावहारिक सारांश तीन बातों में है। इम्पैक्ट वोलैटिलिटी के साथ स्केल करता है। इम्पैक्ट साइज़ में कॉन्केव है, एक ऐसे एक्सपोनेंट के साथ जिसे आपको मानना चाहिए जब तक आपका अपना डेटा के पक्ष में दलील न दे। प्रीफैक्टर ऑर्डर वन का है पर वेन्यू, एसेट, और — सबसे अहम — आपकी अपनी ट्रेडिंग स्टाइल के हिसाब से बदलता है, इसलिए अगला सेक्शन इसे कॉपी करने के बजाय फिट करने के बारे में है। गहरी कैलिब्रेशन (डिके कर्नल, ट्रांज़िएंट बनाम परमानेंट डीकंपोज़िशन, क्रॉस-इम्पैक्ट) impact modeling article की चीज़ है; बैकटेस्ट को सिर्फ कर्व चाहिए।
मैग्नीट्यूड तय करने के लिए एक काम की संख्या। BTC perp, डेली वोल bps, वेन्यू डेली वॉल्यूम V_d = \6Y = 0.75\delta = 0.5$:
| ऑर्डर साइज़ | इम्पैक्ट टर्म | + हाफ-स्प्रेड (0.5 bp) | ||
|---|---|---|---|---|
| $50k | 0.0008% | 0.0029 | 0.5 bp | 1.0 bp |
| $500k | 0.008% | 0.0091 | 1.7 bp | 2.2 bp |
| $5M | 0.083% | 0.0289 | 5.4 bp | 5.9 bp |
| $50M | 0.83% | 0.0913 | 17.1 bp | 17.6 bp |
साइज़ में तीन ऑर्डर ऑफ मैग्नीट्यूड कॉस्ट में लगभग 18 के फैक्टर तक फैलते हैं। कोई भी कॉन्स्टेंट उस टेबल को कवर नहीं करता, और हर वह स्ट्रैटेजी तुलना जो पोज़िशन साइज़ को बदलती है जबकि slippage_bps को स्थिर रखती है, चुपचाप 5M पर संतरों से तुलना कर रही है।
कर्व फिट करना: आपके फिल्स, या किसी के नहीं
आपके अपने फिल्स से
सही डेटा आपका अपना TCA रिकॉर्ड है: प्रति पैरेंट ऑर्डर एक पंक्ति जिसमें अराइवल मिड, रियलाइज़्ड फिल VWAP, ऑर्डर साइज़, और डिसिज़न टाइम पर मार्केट स्टेट हो — ठीक वही डेटासेट जो implementation shortfall measurement एक बाय-प्रोडक्ट के रूप में देता है। अराइवल के मुकाबले bps में शॉर्टफॉल, समकालीन वोलैटिलिटी से नॉर्मलाइज़्ड, पार्टिसिपेशन पर रिग्रेस्ड, आपको सीधे और देता है।
जाल है नॉइज़। एक अकेले ऑर्डर का शॉर्टफॉल इम्पैक्ट प्लस एक्सीक्यूशन विंडो में प्राइस नॉइज़ है, और नॉइज़ हावी रहता है: 250 bps डेली वोल पर 10-मिनट के एक्सीक्यूशन के लिए, नॉइज़ टर्म bps है, जो लगभग 3 bps के इम्पैक्ट सिग्नल के मुकाबले है। प्रति ऑब्ज़र्वेशन 0.15 का सिग्नल-टु-नॉइज़ ही वजह है कि Almgren et al. को 700k ऑर्डर्स चाहिए थे और क्यों आपको बकेट मीडियन पर फिट करना चाहिए, कच्चे पॉइंट्स पर कभी नहीं:
import numpy as np
import pandas as pd
def fit_sqrt_curve(orders: pd.DataFrame) -> tuple[float, float]:
"""orders: one row per parent order.
is_bps -- implementation shortfall vs arrival mid, bps, cost-positive
sigma_bps -- volatility at arrival (same window used at simulation time)
q_over_v -- parent size / market volume over the execution window
Fits I = Y * sigma * (Q/V)^delta on participation-bucket medians."""
df = orders.query("q_over_v > 0 and sigma_bps > 0").copy()
df["i_norm"] = df.is_bps / df.sigma_bps # impact in vol units
df["bucket"] = pd.qcut(np.log10(df.q_over_v), 12, duplicates="drop")
b = (df.groupby("bucket", observed=True)
.agg(i=("i_norm", "median"), qv=("q_over_v", "median")))
b = b[b.i > 0] # noisy buckets can go negative; drop, don't clip
delta, log_y = np.polyfit(np.log(b.qv), np.log(b.i), 1)
return float(np.exp(log_y)), float(delta)
कुछ हज़ार क्रिप्टो पैरेंट ऑर्डर्स पर यह फिट पहले से ही पर लगभग ±30% और पर ±0.1 तक स्थिर है — मोटा-मोटा, पर फिट किए गए कर्व और अंदाज़ लगाए गए कॉन्स्टेंट के बीच का फर्क 30% नहीं है, वह पूरा शेप है। हर तिमाही रीफिट करें; में ड्रिफ्ट खुद एक डायग्नोस्टिक है (कॉन्स्टेंट पार्टिसिपेशन पर बढ़ता यानी या तो वेन्यू का लिक्विडिटी रीजीम बदल गया या आपका ऑर्डर फ्लो ज़्यादा इन्फॉर्म्ड/ज़्यादा डिटेक्टेबल हो गया)।
कोल्ड स्टार्ट: अभी तक कोई फिल नहीं
पहले लाइव ऑर्डर से पहले आपके पास सिर्फ पब्लिक डेटा है, और दो ईमानदार विकल्प हैं।
बुक को डेप्थ-वॉक करें। हर साइज़ पर L2 स्नैपशॉट्स को वॉक करने की कॉस्ट का औसत निकालें, ठीक जैसे fill simulator प्रति-ट्रेड करता है, पर एक कर्व में एग्रीगेट किया हुआ। यह एक ज्ञात दिशा वाला लोअर बाउंड है: स्नैपशॉट वह लिक्विडिटी दिखाता है जो बाकी सबके फ्लो से बच गई, रीफिल डायनामिक्स अदृश्य हैं, और आपके अपने पहले वाले चाइल्ड ऑर्डर्स आपके बाद वालों के आने से पहले बुक को हिला चुके होंगे।
def curve_from_book(snapshots, sizes_usd, safety=1.75):
"""snapshots: iterable of (mid, asks), asks = [(price, qty), ...] best-first.
Depth-walk cost is a LOWER bound on realized cost -- scale it."""
rows = []
for q_usd in sizes_usd:
costs = []
for mid, asks in snapshots:
rem, paid, got = q_usd / mid, 0.0, 0.0
for p, q in asks:
x = min(q, rem)
paid += x * (p - mid); got += x; rem -= x
if rem <= 0:
break
if rem <= 0:
costs.append(paid / got / mid * 1e4)
rows.append((q_usd, safety * float(np.median(costs))))
return pd.DataFrame(rows, columns=["q_usd", "cost_bps"])
पब्लिक ट्रेड्स को फुटप्रिंट करें। एग्रेसर ट्रेड्स को साइज़ के हिसाब से बिन करें, हर एक के कुछ सेकंड बाद के मिड मूव को मापें, और एक एम्पिरिकल इम्पैक्ट कर्व निकालें। यह कॉन्केव शेप और लगभग सही -स्केलिंग रिकवर करता है, पर लेवल एक ऐसी दिशा में बायस्ड है जिसे आप पहले से तय नहीं कर सकते: पब्लिक प्रिंट्स दूसरे ट्रेडर्स के फैसले हैं, इसलिए बड़े प्रिंट्स कंडीशनली इन्फॉर्म्ड होते हैं (आपके अनइन्फॉर्म्ड रीबैलेंस के मुकाबले मापे गए इम्पैक्ट को ऊपर बायस करते हुए) जबकि सबसे लिक्विडिटी-सेंसिटिव ट्रेडर्स ठीक छिपने के लिए ऑर्डर्स को स्प्लिट करते हैं (उसे नीचे बायस करते हुए)। इसे शेप के लिए इस्तेमाल करें, लेवल के लिए नहीं।
किसी भी तरह, कोल्ड-स्टार्ट प्रोटोकॉल है: पब्लिक-डेटा कर्व लें, 1.5–2 का सेफ्टी फैक्टर लगाएं, छोटा ट्रेड करें, और उस TCA टेबल को भरना शुरू करें जो इसे रिप्लेस करेगी। पब्लिक कर्व स्कैफोल्डिंग है, लोड-बेयरिंग दीवार नहीं।
रीजीम डिपेंडेंस: वही ऑर्डर, पांच गुना कॉस्ट

में हर टर्म स्टेट-डिपेंडेंट है, और वोलैटिलिटी स्पाइक में वे सब एक साथ आपके खिलाफ चलते हैं। स्प्रेड शॉर्ट-होराइज़न वोल के प्रोपोर्शनल होते हैं, इसलिए 5–10x चौड़ा हो जाता है। सीधे इम्पैक्ट टर्म में जाता है। वॉल्यूम भी बढ़ता है — जो सतही तौर पर पार्टिसिपेशन को घटाता है — पर यह न्यूमरेटर में से कम बढ़ता है, और यह ऑफसेट एक ज़्यादा खराब असर छुपाता है: मिड के पास क्वोटेड डेप्थ ट्रेडेड वॉल्यूम से बहुत तेज़ी से गिरती है, इसलिए रियलाइज़्ड कर्व फिट किए गए फॉर्मूले की अकेले स्ट्रेस्ड इनपुट्स से की गई भविष्यवाणी से आगे निकलकर और तीखा हो जाता है।
ठोस रूप में, ऊपर फिट किए गए कर्व के साथ, एक $3M BTC ऑर्डर:
- शांत दिन: bps, स्प्रेड 1 bp, V_d = \6= 0.5 + 0.75 \times 150 \times \sqrt{0.0005} = 0.5 + 2.5 = 3.0$ bps।
- क्राइसिस दिन (LUNA, FTX ग्रेड): bps, स्प्रेड 6 bps, V_d = \18= 3.0 + 0.75 \times 700 \times \sqrt{0.000167} = 3.0 + 6.8 = 9.8$ bps।
फॉर्मूला कहता है 3.3x। स्ट्रेस दिनों पर रियलाइज़्ड TCA लगातार फॉर्मूले से ऊपर आता है — डेप्थ कोलैप्स जिसे sqrt टर्म नहीं देखता — यहीं एक मापा गया स्ट्रेस मल्टीप्लायर काम आता है। हमारे फिल्स में क्राइसिस-बकेट रेज़िड्यूअल स्ट्रेस्ड-इनपुट फॉर्मूले के ऊपर 1.4–1.8x चलता है, जिससे उसी ऑर्डर के लिए कुल स्ट्रेस कॉस्ट शांत-दिन कॉस्ट का 4.5–6x पर पहुंच जाता है। यही "वही ऑर्डर वोल स्पाइक में 5x ज़्यादा कॉस्ट करता है" का ईमानदार मूल है: वॉल्यूम के मुकाबले नेट से लगभग 2x, स्प्रेड से 2x, और बाकी वॉल्यूम स्टैटिस्टिक्स के अनुमान से तेज़ी से गायब होती डेप्थ से।
इम्प्लीमेंटेशन एक कंडीशनल कॉस्ट मॉडल है: कर्व को हर रीजीम बकेट के हिसाब से फिट करें, या इसके बराबर एक कर्व और डिसिज़न टाइम पर (सिर्फ ट्रेलिंग विंडो — फुल सैंपल पर कंप्यूट किया गया रीजीम लेबल कॉस्ट मॉडल के ज़रिए घुसाया गया लुक-अहेड है) कंप्यूट किए गए रियलाइज़्ड-वोल क्वांटाइल पर की-ड किया गया मल्टीप्लायर टेबल फिट करें:
| रीजीम (ट्रेलिंग 1h वोल क्वांटाइल) | फ्रीक्वेंसी | स्प्रेड मल्ट | कर्व मल्ट (मापा गया) |
|---|---|---|---|
| शांत (< p25) | 25% | 0.6x | 0.7x |
| सामान्य (p25–p75) | 50% | 1.0x | 1.0x |
| उभरता (p75–p95) | 20% | 1.8x | 1.6x |
| स्ट्रेस (> p95) | 5% | 5–10x | 3–6x |
Frazzini, Israel and Moskowitz (2018) अपने इंस्टीट्यूशनल डेटा में वही फेनोमेनन दस्तावेज़ करते हैं: रियलाइज़्ड कॉस्ट समकालीन वोलैटिलिटी के साथ मज़बूती से को-मूव करती है, और टाइम-वेरींग वोल टर्म के बिना कॉस्ट मॉडल ठीक टेल्स की गलत कीमत लगाता है। यह टेबल अपनी 5% स्ट्रेस रो के संकेत से ज़्यादा क्यों मायने रखती है इसकी वजह करिलेशन है: स्ट्रैटेजीज़ इन रो को यूनिफॉर्मली सैंपल नहीं करतीं। एक वोल-ब्रेकआउट सिस्टम अपनी ज़्यादातर ट्रेडिंग सबसे नीचे की दो रो में करता है। एक शांत-मार्केट मेकर सबसे ऊपर की रो में कमाता है और सबसे नीचे वाली से बाहर निकल जाता है। हर स्ट्रैटेजी के ट्रेड्स को उसके खुद के रीजीम हिस्टोग्राम से वेट करना — बजाय सबको अनकंडीशनल एवरेज चार्ज करने के — इस पूरे पन्ने पर इवेंट-ड्रिवन सिस्टम्स के लिए सबसे बड़ा PnL करेक्शन है, सीढ़ी के किन्हीं भी दो सटे हुए पायदानों के फर्क से ज़्यादा कीमती।
सेंसिटिविटी एक्सपेरिमेंट: चार कॉस्ट मॉडल, एक उलटा हुआ लीडरबोर्ड
अगर कॉस्ट मॉडल PnL को एक कॉन्स्टेंट ऑफसेट से बदलता, तो सिलेक्शन के लिए इनमें से कुछ भी मायने नहीं रखता — हर वेरिएंट बराबर शिफ्ट होता और argmax बच जाता। ऐसा नहीं होता, क्योंकि वेरिएंट्स के बीच कॉस्ट सेंसिटिविटी एक ऑर्डर ऑफ मैग्नीट्यूड तक बदलती है। यह एक्सपेरिमेंट इसे ठोस बनाता है:
सेटअप। एक स्ट्रैटेजी फैमिली — BTC और ETH perps पर z-score मीन रिवर्शन और Donchian ब्रेकआउट, 1-मिनट बार्स, 18 महीने — होल्डिंग होराइज़न (15m / 1h / 4h / 24h) और एंट्री थ्रेशोल्ड पर एक ग्रिड के साथ: 20 वेरिएंट्स, वन-साइडेड टर्नओवर प्रति दिन 0.4x से 11x बुक तक, $250k क्लिप्स 5 मिनट में एक्सीक्यूट। हर वेरिएंट को हर कॉस्ट मॉडल के साथ एक बार बैकटेस्ट किया गया:
- M0: सिर्फ फीस;
- M1: फीस + 5 bps कॉन्स्टेंट;
- M2: फीस + हाफ-स्प्रेड + ;
- M3: फीस + फिट किया गया कर्व , ऊपर वाले रीजीम मल्टीप्लायर टेबल के साथ।
वही फिल्स, वही सिग्नल्स, वही कोड पाथ — कॉस्ट मॉडल बैकटेस्टर में एक कंस्ट्रक्टर आर्ग्युमेंट के रूप में पास किया जाता है, जैसे कोई भी फर्स्ट-क्लास पैरामीटर होता है:
from dataclasses import dataclass
@dataclass(frozen=True)
class SqrtCost:
y: float = 0.75 # fitted impact coefficient
delta: float = 0.5 # fitted exponent
fee_bps: float = 2.5 # taker fee, always separate
def cost_bps(self, q_usd: float, st) -> float:
part = q_usd / st.window_volume_usd
return (self.fee_bps + st.stress_mult *
(st.spread_bps / 2 + self.y * st.sigma_bps * part ** self.delta))
for model in [ZeroCost(), ConstCost(5.0), VolCost(0.08), SqrtCost()]:
for variant in grid:
results[(model, variant)] = backtest(variant, cost_model=model)
नतीजे (प्रतिनिधि रन; वार्षिक नेट रिटर्न):
| वेरिएंट | टर्नओवर/दिन | M0 | M1 (5 bp) | M2 | M3 (कर्व) | रैंक M1 → M3 |
|---|---|---|---|---|---|---|
| MR-15m, z=1.0 | 11.4x | +187% | +61% | +9% | −14% | 1 → 17 |
| MR-15m, z=1.5 | 7.9x | +141% | +52% | +15% | −2% | 2 → 13 |
| BO-1h, k=2 | 3.1x | +74% | +43% | +28% | +19% | 3 → 4 |
| MR-1h, z=2.0 | 2.4x | +58% | +38% | +25% | +21% | 4 → 2 |
| BO-4h, k=3 | 0.9x | +39% | +33% | +29% | +26% | 7 → 1 |

लीडरबोर्ड्स के बीच रैंक करिलेशन (Kendall ): — एक कॉन्स्टेंट मुश्किल से कुछ भी दोबारा ऑर्डर करता है, यह एक टैक्स है, मॉडल नहीं। — M1 के टॉप टेन में से छह M3 के तहत टॉप टेन छोड़ देते हैं, और M1 का चैंपियन +61% से नेगेटिव पर चला जाता है। — अकेला वोल टर्म ज़्यादातर रीऑर्डरिंग रिकवर कर लेता है; साइज़ टर्म उन वेरिएंट्स के लिए काम पूरा करता है जो विंडो वॉल्यूम के मुकाबले बड़ा ट्रेड करते हैं। मैकेनिज़्म ठीक पायदान M0 वाली सिलेक्शन टॉक्सिसिटी है: एक फ्लैट 5 bps उन ट्रेड्स को सब्सिडाइज़ करता है जिनकी असली कॉस्ट 15 bps है (बड़े, तेज़, स्ट्रेस में) और उन्हें ओवरटैक्स करता है जिनकी कॉस्ट 2 है (छोटे, धैर्यवान, शांत में), तो M1 से रैंकिंग सिस्टेमैटिक रूप से उन वेरिएंट्स को प्रमोट करती है जिनकी असली कॉस्ट सबसे ज़्यादा कम आंकी गई है। ऑप्टिमाइज़र ने अल्फा नहीं ढूंढा; उसने आपके कॉस्ट मॉडल का एरर टर्म ढूंढ लिया।
यही वजह है कि कॉस्ट मॉडल को वॉक-फॉरवर्ड स्प्लिट या ऑब्जेक्टिव फंक्शन की ही मानसिक श्रेणी में होना चाहिए: एक फर्स्ट-क्लास बैकटेस्ट पैरामीटर जिसे आप बदलते हैं, न कि कोई एनवायरनमेंटल कॉन्स्टेंट जिसे आप एक बार सेट कर देते हैं। अगर किसी वेरिएंट की रैंक M2 और M3 के आर-पार स्थिर है, तो उसका एज कॉस्ट के मुकाबले असली है। अगर उसकी रैंक सीढ़ी ऊपर जाते हुए ढह जाती है, तो आपने सीखा कि यह एक कॉस्ट-मॉडल आर्टिफैक्ट था — walk-forward optimization में आउट-ऑफ-सैंपल मरती एक स्ट्रैटेजी जैसा ही एपिस्टेमिक इवेंट, और इसे वैसी ही प्रतिक्रिया मिलनी चाहिए। और अगर आपने M1 के तहत 200 वेरिएंट्स का argmax चुना, तो deflated Sharpe logic एक ट्विस्ट के साथ लागू होता है: आपने एक मल्टीपल-टेस्टिंग सर्च चलाई जहां टेस्ट स्टैटिस्टिक खुद हाई-टर्नओवर एंट्रीज़ के पक्ष में बायस्ड था।
ईमानदार बाउंड्स: PnL एक बैंड के रूप में
आखिरी अनुशासन इस स्वीकृति से आता है कि फिट करने के बाद भी कॉस्ट मॉडल अनिश्चित है। का एक कॉन्फिडेंस इंटरवल है, स्ट्रेस मल्टीप्लायर्स कुछ मुट्ठी भर टेल दिनों से अनुमानित हैं, और भविष्य अपने खुद के रीजीम खींचता है। तो नेट PnL को एक संख्या के रूप में रिपोर्ट करना बंद करें। इसे नामित कॉस्ट सिनारियोज़ के आर-पार एक बैंड के रूप में रिपोर्ट करें:
- ऑप्टिमिस्टिक: डेप्थ-वॉक लोअर बाउंड, कोई स्ट्रेस मल्टीप्लायर नहीं। कभी अकेले रिपोर्ट न करें; इसका इकलौता काम बेस्ट केस को बाउंड करना है।
- रियलिस्टिक: फिट किया गया कर्व, फिट किए गए रीजीम मल्टीप्लायर्स — आपका सेंट्रल एस्टिमेट।
- पेसिमिस्टिक: , स्प्रेड , स्ट्रेस रो हमेशा उसके p75 वैल्यू पर या उससे ज़्यादा लागू। मोटे तौर पर: फिट किया गया कर्व हर पैरामीटर के कॉन्फिडेंस इंटरवल के अनफ्रेंडली किनारे पर इवैल्युएट किया गया।
दो डिसिज़न रूल्स बैंड को ऑपरेशनल बनाते हैं। पहला: पेसिमिस्टिक पर अलोकेट करें, रियलिस्टिक रिपोर्ट करें। एक स्ट्रैटेजी जो सिर्फ रियलिस्टिक मॉडल के तहत बचती है वह एक ऐसा दांव है कि आपके कॉस्ट फिट में महंगी दिशा में कोई एरर नहीं है — एक ऐसा दांव जो आपने सचेत होकर नहीं लगाया। दूसरा: फ्रैजिलिटी रेशियो ट्रैक करें — ग्रॉस PnL पर बैंड की चौड़ाई। ऊपर के एक्सपेरिमेंट से: BO-4h 0.9x टर्नओवर पर ग्रॉस +39% दिखाता है, बैंड [+22%, +29%], फ्रैजिलिटी 0.44। MR-15m 11.4x पर ग्रॉस +187% दिखाता है, बैंड [−31%, +34%] — फ्रैजिलिटी 2.2, और स्ट्रैटेजी का साइन बैंड के अंदर ही पलट जाता है। उस दूसरी स्ट्रैटेजी का आपके मौजूदा कॉस्ट-नॉलेज स्टेट पर कोई निर्धारणीय साइन नहीं है; ईमानदार बयान हैं "हमें नहीं पता" और "जब तक हमें पता न चले तब तक टर्नओवर घटाएं।" एक बैकटेस्ट जो +34% छापता है और बैंड के −31% किनारे को छोड़ देता है वह ऑप्टिमिस्टिक नहीं है, वह अनफॉल्सिफायबल है।
बैंड बनाने में कुछ खर्च नहीं होता — कॉस्ट-मॉडल स्वीप में तीन और एंट्रीज़ जो आप वैसे भी अब चला रहे हैं — और यह बातचीत बदल देता है। "यह स्ट्रैटेजी 20% कमाती है" विश्वास को न्योता देता है। "यह स्ट्रैटेजी हमारे कॉस्ट सिनारियोज़ में 11–19% कमाती है, और पेसिमिस्टिक के तहत भी पॉज़िटिव रहती है" अलोकेशन को न्योता देता है।
यह कहां फिट होता है
बैकटेस्ट इंजन में, कॉस्ट मॉडल ठीक वहां बैठता है जहां fill simulator एक एक्सीक्यूटेड क्वांटिटी वापस देता है: फिल्स तय करते हैं आपको क्या मिला, कॉस्ट कर्व तय करता है उसके लिए आपने क्या चुकाया, और उस सीढ़ी पर L2 से ऊपर के पायदान (डेप्थ-वॉक, क्यू मॉडल) धीरे-धीरे कॉस्ट मॉडल को फिल मॉडल में ही समाहित कर लेते हैं — कर्व वह पैरामेट्रिक स्टैंड-इन है जिसे आप तब इस्तेमाल करते हैं जब आप बुक को सीधे सिम्युलेट नहीं कर रहे होते। पैरामीटर्स आपके अपने TCA record से आते हैं जब आपके पास एक हो और सेफ्टी-स्केल्ड पब्लिक डेटा से जब न हो। फंक्शनल फॉर्म चालीस साल की थियरी और मेज़रमेंट से आता है — Kyle (1985) यह बताने के लिए कि प्रति डॉलर कॉस्ट लिक्विडिटी पर बिल्कुल क्यों निर्भर करती है, Almgren et al. (2005) और Tóth et al. (2011) खुद कॉन्केव लॉ के लिए, Almgren-Chriss शेड्यूलिंग काउंटरपार्ट के रूप में और neural impact models प्रेडिक्शन फ्रंटियर के रूप में। यह लेख जो जोड़ता है वह है वर्कफ्लो: कर्व फिट करें, इसे रीजीम पर कंडीशन करें, इसे एक पैरामीटर की तरह स्वीप करें, और बैंड रिपोर्ट करें। इसमें से कुछ भी ग्लैमरस नहीं है। यह सब लाइव में यह पता लगाने से सस्ता है कि आपकी स्ट्रैटेजी असल में slippage_bps = 5 के किस तरफ थी।
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.