📝

Draft article

This draft is visible to admins and superusers only. Sign in with an authorized account.

← लेखों की सूची पर वापस जाएँ
July 24, 2026
5 मिनट का पठन

स्लाइस के भीतर: आपके scheduler और exchange के बीच child-order tactics

स्लाइस के भीतर: आपके scheduler और exchange के बीच child-order tactics
#execution
#चाइल्ड ऑर्डर्स
#ऑर्डर टैक्टिक्स
#क्यू पोजीशन
#maker-taker
#आइसबर्ग ऑर्डर्स
#माइक्रोस्ट्रक्चर
#python

एक Almgren-Chriss trajectory आपको एक नंबर थमाती है: अगले पांच मिनट में 4.2 BTC बेचो। एक VWAP schedule उसी तरह का नंबर एक अलग तर्क के साथ थमाती है। दोनों में से कोई यह नहीं बताता कि आगे क्या होता है — क्या वो 4.2 BTC book में एक marketable order की तरह टकराएंगे, touch पर बैठकर maker fees इकट्ठा करेंगे, 0.3 BTC की display size के पीछे छुपेंगे, या किसी drifting quote का पीछा करते हुए ग्यारह बार reprice होंगे। यह दूसरी decision layer ही tactics layer है, और fee-dominated crypto books पर यह अक्सर उस पर बैठे scheduler के चुनाव से ज्यादा PnL प्रति slice हिलाती है। Scheduler के interval budgets TWAP और एक अच्छी tuned Almgren-Chriss के बीच पूरे parent order पर impact के कुछ ही bps अलग होते हैं; जिन slices को आप maker बना सकते थे उन पर taker fees चुकाना, या careless repricing से queue position गंवाना, प्रति घंटे उतना ही खर्च करा देता है। यह लेख उस layer के बारे में है जिसे हर कोई चलाता है और लगभग कोई भी लिखकर नहीं रखता: वह state machine जो तय करती है कि हर child order book को कैसे छूता है।

दो layers, एक संकरा interface

Lehalle और Laruelle की Market Microstructure in Practice (2nd ed., 2018) उस बात को औपचारिक रूप देती है जिस पर हर execution desk पहुंचता है: एक strategic layer (scheduler) जो समय के साथ quantity allocate करती है, और एक tactical layer (microtrader) जो हर allocation को live book के खिलाफ काम में लाती है। यह अलगाव केवल सौंदर्यबोध नहीं है — दोनों layers अलग-अलग clocks और अलग-अलग data पर जीती हैं। Scheduler मिनटों में सोचता है, volatility और volume forecasts consume करता है, और एक variational problem solve करता है। Tactics layer milliseconds-to-seconds में सोचती है, L2 deltas और queue estimates consume करती है, और छोटी stopping problems की एक series solve करती है।

Two-layer execution architecture: scheduler slice budget और urgency नीचे भेजता है, tactics layer fills और shortfall ऊपर लौटाती है

दोनों के बीच का interface संकरा होना चाहिए। नीचे की ओर, प्रति slice kk:

  • budget qkq_k — इस interval में execute करने की quantity (Almgren-Chriss का nkn_k, या VWAP का volume-curve increment);
  • window τk\tau_k — slice की लंबाई;
  • urgency — Almgren-Chriss के लिए स्वाभाविक candidate है κ=λσ2/η\kappa = \sqrt{\lambda\sigma^2/\eta}, जो risk aversion, volatility, और liquidity को पहले से ही एक rate में समेट देता है; VWAP scheduler के लिए यह आमतौर पर एक band-distance होता है ("हम target curve से 1.8% पीछे हैं")।

ऊपर की ओर: timestamps और fees के साथ fills, unfilled remainder, और interval arrival mid के मुकाबले slice-level implementation shortfall। यह आखिरी चीज़ मायने रखती है: scheduler का impact parameter η\eta पहले से ही यह price कर चुका है कि rate qk/τkq_k/\tau_k पर liquidity मांगने की कीमत क्या होनी चाहिए। Tactics layer का पूरा काम एक लाइन में है: η\eta-implied cost से बेहतर fills हासिल करना, parent order के अस्तित्व को leak किए बिना। अगर आपका measured slice shortfall लगातार model cost को मात देता है, तो आपका calibrated η\eta नीचे आ सकता है, scheduler तेज़ हो जाता है, और पूरा stack बेहतर होता है। अगर आप slice shortfall को schedule cost से अलग करके measure नहीं कर सकते, तो आप किसी भी layer को tune नहीं कर सकते — आपके पास एक धुंधला नंबर है और दो knobs।

Remainder policy भी इस contract का हिस्सा है। जब कोई slice unfilled quantity के साथ खत्म होती है, तो या तो tactics layer force-complete करती है (remainder को cross करना — deadline urgency के तहत default है) या इसे scheduler को re-amortization के लिए बाकी slices पर वापस लौटा देती है (low-κ\kappa schedule में शुरुआत में स्वीकार्य, deadline के पास ज़हरीला जहां re-amortization चुपचाप एक विशाल final slice में compound हो जाती है)।

Escalation ladder: पहले passive, deadline तक aggressive

इस क्षेत्र का सबसे पुराना नतीजा Harris (1998) का है, "Optimal dynamic order submission strategies in some stylized trading problems" (Financial Markets, Institutions & Instruments 7(2)): एक liquidity trader के लिए जिसे एक deadline तक trade पूरा करना है, optimal strategy dynamic है — जब समय सस्ता हो तो limit orders के साथ book में खड़े रहो, deadline करीब आने पर market की ओर reprice करो, और आखिर में cross करो। हर production tactics engine इसी shape की वंशज है: touch पर post करो, age out करो, escalate करो, cross करो। आधुनिक fee schedules और queue dynamics जो जोड़ते हैं वह यह अंकगणित है कि हर transition ठीक कब fire होता है।

Crossing के लिए break-even

Per unit काम, current mid के सापेक्ष prices, एक buy के लिए। अभी cross करने की कीमत है half-spread प्लस taker fee:

ctake=s2+ft.c_{\text{take}} = \frac{s}{2} + f_t.

Bid पर एक window τ\tau के दौरान post करना probability pp के साथ fill होता है; एक fill half-spread कमाता है और maker fee fmf_m चुकाता है (rebate होने पर negative)। No fill का मतलब है window के अंत में cross करना, जब price औसतन आपके खिलाफ δ(τ)=E[adverse mid moveno fill]>0\delta(\tau) = E[\,\text{adverse mid move} \mid \text{no fill}\,] > 0 जितना खिसक चुका होता है — strictly positive, क्योंकि non-fill और adverse drift एक ही event हैं: आपका bid तब hit नहीं होता जब market उससे दूर उठ जाता है। Expected posting cost:

cpost=p(s2+fm)+(1p)(s2+ft+δ).c_{\text{post}} = p\left(-\frac{s}{2} + f_m\right) + (1-p)\left(\frac{s}{2} + f_t + \delta\right).

Posting crossing को मात देती है अगर और केवल अगर

  p  >  p\*=δΠ+δ,Π=s+ftfm  \boxed{\; p \;>\; p^\* = \frac{\delta}{\Pi + \delta}, \qquad \Pi = s + f_t - f_m \;}

जहां Π\Pi prize है — वह पूरा round-trip जो आप taking की बजाय making करके capture करते हैं: spread प्लस fee differential। यही वह break-even है जो execution के पूरे maker-taker economics को चलाता है, एक ही slice में समेटा हुआ।

Numbers, BTCUSDT perp: mid $100,000, spread एक tick s = \0.10,VIP0जैसीfeesmaker2bps/taker5bps,तो, VIP0-जैसी fees maker 2 bps / taker 5 bps, तो f_m = $20,, f_t = $50प्रतिBTCPrizeप्रति BTC। Prize\Pi = 0.10 + 50 - 20 = $30.10 \approx 3bps—ध्यानदेंकिspreadलगभगकुछभीयोगदाननहींदेता;tightcryptomajorsपरprizeवहीfeedifferentialहै।3 bps — ध्यान दें कि spread लगभग कुछ भी योगदान नहीं देता; tight crypto majors पर prize *वही* fee differential है। 3% daily vol लें (\sigma_{\text{day}} = $3{,}000)और) और \delta(\tau) \approx 0.6,\sigma_{\text{day}}\sqrt{\tau/86400}$ (यह 0.6 एक adverse-selection haircut है जिसे आपको calibrate करना चाहिए, भरोसा नहीं):

  • τ=10\tau = 10 s: \delta \approx \19,तो, तो p^* = 19/49 \approx 0.39$। केवल तभी post करो अगर 10 सेकंड में कम से कम 39% fill की उम्मीद हो।
  • τ=60\tau = 60 s: \delta \approx \47,तो, तो p^* = 47/77 \approx 0.61$।
  • 2 bp fee की बजाय 1 bp के maker rebate के साथ (f_m = -\10):): \Pi = $60.10,और10sthresholdघटकर, और 10 s threshold घटकर p^* \approx 0.24$ हो जाता है।

दो structural facts यहां से निकलते हैं। पहला, δ\delta τ\sqrt{\tau} की तरह बढ़ता है जबकि Π\Pi constant रहता है, तो p\*(τ)1p^\*(\tau) \to 1: patience की एक hard expiry होती है, और age-out timer कोई heuristic नहीं बल्कि दो curves का crossing point है — आपका estimated p(τ)p(\tau) (concave, आपके आगे की queue drain होने के साथ saturate होता हुआ) बनाम p\*(τ)p^\*(\tau) (बढ़ता हुआ)। दूसरा, जिस fee tier पर आप trade करते हैं वह ladder को physically हिलाता है। एक tier upgrade जो taker fees घटाता है, आपकी optimal tactics को ज्यादा aggressive बना देता है — एक coupling जिसे ज़्यादातर लोग तभी discover करते हैं जब VIP re-tier के बाद उनके fill statistics शिफ्ट होते हैं।

Cont और Kukanov, "Optimal order placement in limit order markets" (Quantitative Finance 17(1), 2017; arXiv 2012), इसे एक period में rigorous बनाते हैं: SS units को market और limit orders के बीच split करके execute करने की expected cost minimize करना (एक या कई venues के across), shortfall के लिए एक penalty के साथ। Single-venue solution explicit है और इसमें एक newsvendor structure है: optimal limit-order size queue outflow के distribution से driven होती है — जब आगे की queue expected outflow के मुकाबले छोटी हो तो aggressively post size करो, और tail risk को market orders से cover करो। उनका multi-venue extension stochastic approximation से solve होता है और यह हर smart order router की passive-allocation logic का intellectual core है। एक tactics engine के लिए practical reading यह है: ऊपर के break-even में pp कोई constant नहीं है — यह queue position और drain rate का function है, यही कारण है कि tactics layer को queue-position estimator को first-class input के रूप में consume करना ही होगा।

Slice timeline जो touch पर passive post से लेकर repricing के जरिए escalation और deadline पर remainder cross होने तक दिखाती है

Urgency parameter इस पूरी ladder को compress कर देता है। Scheduler से high κ\kappa का मतलब है कि characteristic time θ=1/κ\theta = 1/\kappa छोटा है: windows सिकुड़ते हैं, p\*p^\* बढ़ता है, और engine सीधे crossing पर चला जाता है — सही ढंग से, क्योंकि scheduler पहले ही declare कर चुका है कि inventory risk fee savings पर हावी है। Low κ\kappa passive phase को खींच देता है। Tactics layer को कभी भी अपने market view से urgency दोबारा derive नहीं करनी चाहिए; वह scheduler का काम है, और उसे duplicate करना दो असहमत controllers बना देता है।

अपनी queue position जलाए बिना repricing

Post होने के बाद, quote drift करता है। इसे naively chase करना — cancel करो, नए touch पर repost करो, दोहराओ — यही वह तरीका है जिससे tactics engines चुपचाप उसी fill probability को नष्ट कर देते हैं जिसने posting को justify किया था। Queue position एक ऐसा asset है जिसकी measurable dollar value है (Moallemi और Yuan, 2016, इस पर एक price लगाते हैं: liquid FIFO books में front-of-queue positions spread के एक meaningful हिस्से के बराबर worth होते हैं), और हर reprice decision एक trade है: अपनी current queue position बेचो, किसी अलग price level की पिछली queue में एक खरीदो। यह trade तभी करने लायक है जब नए level की value पुराने वाले से messaging costs सहित ज्यादा हो। इसके लिए यह जानना ज़रूरी है कि हर venue का amend आपकी line में position के साथ असल में क्या करता है — और जवाब बेहद non-uniform है।

CME Globex सबसे साफ semantics document करता है: order quantity घटाने पर time priority बनी रहती है; quantity बढ़ाना या price बदलना आपको queue के पीछे भेज देता है। यह reference model है — quantity-down free है, बाकी सब कुछ एक re-queue है।

Binance spot ऐतिहासिक रूप से केवल POST /api/v3/order/cancelReplace offer करता था — एक atomic-दिखने वाला, explicitly non-transactional cancel-plus-new। दो modes: STOP_ON_FAILURE (default — अगर cancel fail होता है, तो कोई नया order नहीं) और ALLOW_FAILURE (cancel fail होने पर भी नया order place करो — accidental double exposure को हैलो कहिए)। Operation partially succeed भी कर सकता है, जिसका संकेत HTTP 409 देता है, इसलिए आपके OMS को दोनों legs अलग-अलग reconcile करने होंगे; और नया order हमेशा एक ताज़ा queue life शुरू करता है। फिर 2025 में Binance ने Order Amend Keep Priority (PUT /api/v3/order/amend/keepPriority) shipped किया: quantity को उसी जगह घटाओ, time priority रखो, वो भी zero unfilled-order-count cost पर। पंद्रह साल बाद CME semantics — और वो भी केवल quantity-down वाला आधा हिस्सा।

Binance USDT-M futures के पास एक true modify endpoint है (PUT /fapi/v1/order), लेकिन fine print पढ़िए: केवल LIMIT orders, price और quantity दोनों भेजने ज़रूरी हैं, और "modified orders will be reordered in the match queue" — docs pure quantity reductions के लिए भी priority retention का कोई वादा नहीं करते। हर futures modify को एक queue reset मानिए जो संयोगवश आपको एक message बचा देता है और order ID रख देता है। जानने लायक एक तीखा edge case: एक GTX (post-only) order को ऐसी price पर modify करना जो cross कर जाए, order को cancel कर देता है, reject-and-kept नहीं करता — एक peg implementation जो इसे check नहीं करता, कभी-कभी खुद को amend करके अस्तित्व से बाहर कर देगा।

OKX POST /api/v5/trade/amend-order (newPx, newSz, amend failure पर auto-cancel करने के लिए cxlOnFail के साथ) exposes करता है। यह एक single message है, order ID को preserve करता है, और asynchronously confirm करता है — sCode = 0 का मतलब है "request accepted", और असल outcome orders channel पर amendResult के रूप में आता है। जो चीज़ public docs स्पष्ट रूप से specify नहीं करते वह है queue-priority behavior। इस documentation gap को optimism से मत भरिए। Measure कीजिए: एक quiet level पर दो marker orders post करें, एक की size नीचे amend करें, और कुछ सौ trials में देखें कि कौन पहले fill होता है। जब तक आपके पास वो data न हो, conservative assumption — कोई भी price change हर जगह re-queue कर देता है, quantity-down priority केवल वहीं preserve करता है जहां explicitly documented हो — ही एकमात्र defensible assumption है।

Amend operations बनाम venues का matrix जो दिखाता है कौन-से operations queue priority preserve करते हैं और कौन-से इसे reset करते हैं

Policy के नतीजे:

  1. Hysteresis, pegging नहीं। केवल तभी reprice करें जब touch आपकी resting price से एक band bb ticks से ज्यादा drift कर चुका हो। Band के भीतर, drift noise है और आपकी queue position एक tick की price improvement से ज्यादा worth है। एक sensible starting band short-horizon vol से scaled 1–3 ticks है; सही band marginal reprice को EV-neutral बना देता है: VnewVcur=cmsgV_{\text{new}} - V_{\text{cur}} = c_{\text{msg}}, जहां VV Moallemi-Yuan-style queue value है और cmsgc_{\text{msg}} आपकी rate-limit shadow price। Amend/cancel-replace operations दोनों Binance venues पर order-rate budget consume करते हैं; जो tactics engine हर tick पर peg करती है वह आपके बाकी सिस्टम की message capacity भूखी मार देगी।
  2. नीचे amend करें, कभी नीचे cancel-repost न करें। जब scheduler mid-flight में एक slice budget काट दे (volume सूखता देखता एक POV scheduler, partial fills के बाद एक Almgren-Chriss re-solve), जहां भी priority-preserving path मौजूद हो उसका इस्तेमाल करें। पूरी layer में यही एक free lunch है।
  3. Reprice पर asymmetric urgency। Market की ओर (chasing) reprice करना आपकी queue को एक worse price पर reset करता है — यह केवल escalation logic से, अपने timer पर fire होना चाहिए। दूर की ओर (market आपके पास आया) reprice करना एक तोहफा है, इसे केवल passive band के जरिए लें, क्योंकि आपका current level वैसे भी fill होने वाला है।

Icebergs, display size, और क्या आपके intent को leak करता है

Display size तीसरा decision है, और यह एक genuine two-sided trade है, कोई free stealth button नहीं। Empirical record:

  • Frey और Sandås ("The Impact of Iceberg Orders in Limit Order Books", 2009 working paper; Quarterly Journal of Finance, 2017), Xetra data पर: iceberg orders ने submitted volume का 9.3% और executed volume का 15.9% carry किया, ordinary limit orders के 12–20x size के थे, और — punchline यह है — जब दूसरे participants एक iceberg detect करते हैं, तो वे matching market orders से respond करते हैं। छुपी हुई size, एक बार infer हो जाने पर, flow को attract करती है: latent liquidity search दोनों दिशाओं में काम करता है।
  • Bessembinder, Panayides और Venkataraman ("Hidden liquidity: an analysis of order exposure strategies in electronic stock markets", JFE 94(3), 2009), Euronext Paris पर, जहां hidden orders sample volume का 44% थे: hiding implementation shortfall घटाता है लेकिन full execution की probability भी घटाता है और time-to-completion बढ़ाता है। Exposure fills खरीदता है और उनके लिए impact में भुगतान करता है; यह option ठीक वैसे ही इस्तेमाल होता है जैसा theory predict करती है — aggressive orders counterparties को खींचने के लिए expose होते हैं, patient size छुपती है।
  • Esser और Mönch ("The navigation of an iceberg", Finance Research Letters 4(2), 2007) peak size को एक optimization के रूप में treat करते हैं: बड़ा display तेज़ fill होता है, छोटा display कम leak करता है, और optimum interior होता है।

पहले mechanics, क्योंकि वे optimization को bind करते हैं: लगभग हर venue पर जो native icebergs support करता है (Binance spot icebergQty के जरिए, OKX अपने iceberg algo orders के जरिए), visible peak का हर refill उस price पर queue के पीछे जाकर लगता है। एक iceberg इसलिए "hidden size वाला एक order" नहीं है — यह एक sequence of small orders है, हर एक पूरा queue-wait चुकाता हुआ, automatically fire होता हुआ। ऊपर के fee break-even पर, यह मायने रखता है: प्रति peak effective pp back-of-queue fill probability है, आपकी original position की नहीं। Deep queues छोटे peaks को दो बार सज़ा देती हैं — धीमी fills और ज़्यादा refills की adverse selection।

फिर signaling problem। Frey और Sandås का अपना detection method ही cautionary tale है: उनका frequentist detector दो सबसे common implementation laziness patterns पर key करता है — constant peak size और executing trade के timestamp के बिल्कुल बराबर refill timestamps। कोई भी participant जो वह detector चलाता है (और crypto venues पर, बहुत सारे चलाते हैं — exchange का अपना matching metadata colocated flow के लिए इसे और भी आसान बना देता है) चंद refills में आपकी hidden size reconstruct कर लेता है। Leak vectors, इस क्रम में कि मैं उन्हें असल में कितनी बार देखता हूं:

  1. Constant या round display sizes (0.5 BTC, हर बार)।
  2. Full-peak execution के बाद instant, deterministic refill — वही same-timestamp signature।
  3. Deterministic escalation timers: हर slice में ठीक 30 s पर cross करना, और tape एक metronome दिखाता है।
  4. Fixed reprice latency और band — आपकी amend cadence उतनी ही पहचानने लायक fingerprint है जितनी आपकी order sizes, जो digital fingerprints और trader identification का विषय है।

Detect होने की cost कोई काल्पनिक बात नहीं है। Van Kervel और Menkveld ("High-frequency trading around large institutional orders", Journal of Finance 74(3), 2019) दिखाते हैं कि HFTs शुरुआत में बड़े institutional metaorders के खिलाफ झुकते हैं — वह liquidity provide करते हुए जिसे आपकी passive tactics consume करती हैं — फिर एक बार जब order की persistence information reveal कर देती है तो order के साथ trade करने पर पलट जाते हैं, remainder को back-run करते हुए और parent की cost को materially बढ़ाते हुए। उनकी institutions ने speculative profit को detection risk के खिलाफ trade off करके response दिया। आपकी tactics layer ठीक वही जगह है जहां वह trade-off implement होता है: display size को randomize करें (एक vol-scaled base का uniform 30–70% ठीक काम करता है), हर timer को ±20–30% जिटर करें, कभी-कभी एक refill को wait करने दें, और कभी भी दो child orders को एक size, एक timer phase, और एक latency profile share न करने दें। इनमें से कुछ भी measurable fill quality की कीमत नहीं चुकाता; यह सब आपके flow पर detector fit करने वाले किसी भी व्यक्ति के लिए noise floor बढ़ा देता है।

एक न्यूनतम tactics engine

ऊपर की पूरी layer एक छोटी state machine में समा जाती है, प्रति slice: IDLE → POSTED → (reprice loop) → CROSSING → DONE, entry पर break-even gate के साथ, posted रहते हुए एक hysteresis band, और deadline escalation। नीचे का version जानबूझकर minimal है — कोई venue adapters नहीं, कोई iceberg management नहीं — लेकिन यह event-driven और side-effect-free है, तो यह fill-simulation ladder वाले rung-4 queue-aware simulator में सीधे fit हो जाता है: simulator on_tick/on_fill को call करता है, और actions को interpret करता है post → GTX/post-only, cross → IOC, cancel_replace/amend_down → ऊपर वाले matrix से venue के semantics।

import math
from dataclasses import dataclass
from enum import Enum, auto

class State(Enum):
    IDLE = auto(); POSTED = auto(); CROSSING = auto(); DONE = auto()

@dataclass
class Fees:
    maker: float          # $ per unit; negative = rebate
    taker: float          # $ per unit

@dataclass
class Cfg:
    tick: float
    sigma_1s: float       # $ per sqrt(second), from your live vol estimator
    adverse_frac: float = 0.6   # E[adverse move | no fill] ~ 0.6 * sigma; calibrate
    reprice_band: float = 2.0   # ticks of touch drift tolerated before repricing
    escalate_frac: float = 0.7  # cross the remainder at this fraction of the window

class SliceTactic:
    """One instance per scheduler slice. Drive it from a fill simulator or OMS."""

    def __init__(self, side: str, qty: float, window: float, fees: Fees, cfg: Cfg):
        self.side, self.qty, self.window = side, qty, window
        self.fees, self.cfg = fees, cfg
        self.filled, self.state, self.px, self.t0 = 0.0, State.IDLE, None, None

    def p_star(self, spread: float, tau: float) -> float:
        """Break-even fill probability for posting over a window tau."""
        delta = self.cfg.adverse_frac * self.cfg.sigma_1s * math.sqrt(tau)
        prize = spread + self.fees.taker - self.fees.maker
        return delta / (prize + delta)

    def p_fill(self, queue_ahead: float, drain: float, tau: float) -> float:
        """Crude queue-drain estimate; swap in your calibrated fill model."""
        if drain <= 0: return 0.0
        return min(1.0, drain * tau / max(queue_ahead + self.qty, 1e-9))

    def on_tick(self, t, bid, ask, queue_ahead, drain):
        if self.state == State.DONE: return []
        if self.t0 is None: self.t0 = t
        left = self.qty - self.filled
        elapsed, remain = t - self.t0, self.window - (t - self.t0)
        touch = bid if self.side == "buy" else ask

        if elapsed >= self.cfg.escalate_frac * self.window and left > 0:
            self.state = State.CROSSING          # deadline: pay up, finish
            return [("cross", left)]

        if self.state == State.IDLE:
            if self.p_fill(queue_ahead, drain, remain) >= self.p_star(ask - bid, remain):
                self.state, self.px = State.POSTED, touch
                return [("post", touch, left)]    # GTX / post-only
            self.state = State.CROSSING           # posting is -EV here
            return [("cross", left)]

        if self.state == State.POSTED:
            if abs(touch - self.px) / self.cfg.tick > self.cfg.reprice_band:
                self.px = touch                   # hysteresis breached:
                return [("cancel_replace", touch)]  # accept the queue reset
        return []

    def on_fill(self, t, fill_qty):
        self.filled += fill_qty
        if self.filled >= self.qty - 1e-9:
            self.state = State.DONE
            return [("slice_done", self.filled)]
        return []

    def on_budget_cut(self, new_qty):
        """Scheduler revised the slice down: amend-down keeps queue priority
        where documented (CME, Binance spot amend/keepPriority)."""
        self.qty = new_qty
        left = new_qty - self.filled
        return [("amend_down", left)] if left > 0 else [("cancel",)]

तीन ईमानदार caveats। यहां p_fill एक placeholder ratio है — production में यह fill-simulation article वाला bucketed, live-calibrated model होना चाहिए, क्योंकि पूरा post/cross gate उतना ही अच्छा है जितना वह estimate। adverse_frac article की सबसे मुश्किल quantity को छुपाता है (δ\delta regime-dependent है और ठीक तब spike करता है जब posting सबसे tempting होती है); इसे अपने खुद के no-fill outcomes से estimate करें, vol regime के हिसाब से bucketed। और ऊपर वाली engine unconditionally cancel-replace के जरिए reprice करती है — एक venue-aware version को quantity-down changes को priority-preserving path से route करना चाहिए और हर action को एक message budget के खिलाफ charge करना चाहिए।

किसी भी parameter पर भरोसा करने से पहले इसे एक replay tape के खिलाफ simulator के अंदर चलाएं। जो experiment मायने रखता है: scheduler को fix करें, escalate_frac और reprice_band को sweep करें, और slice shortfall को η\eta-implied model cost के मुकाबले plot करें। Surface में एक plateau होता है — near-optimal parameters की चौड़ी bands — और दो cliffs: बहुत देर से escalate करना (unfilled remainders momentum में cross होते हुए) और बहुत जल्दी reprice करना (सारी queue value जल जाना)। आपको यह जानना चाहिए कि आपके cliffs कहां हैं, इससे पहले कि production आपके लिए उन्हें ढूंढे।

क्या ले जाना है

  1. दो layers, एक contract। Scheduler तय करता है कितना और कब तक; tactics तय करती है कैसे। Interface है budget, window, urgency नीचे; fills और interval arrival के मुकाबले slice shortfall ऊपर। अगर आप shortfall को किसी layer से attribute नहीं कर सकते, तो आप किसी भी layer को tune नहीं कर सकते।
  2. Post/cross gate अंकगणित है, vibes नहीं। Post करें अगर और केवल अगर p>δ/(Π+δ)p > \delta/(\Pi + \delta), जहां Π=s+ftfm\Pi = s + f_t - f_m। Tight crypto books पर prize fee differential है, तो आपका fee tier आपकी tactics तय करता है — हर re-tier के बाद ladder को retune करें।
  3. Age-out timers दो curves का crossing point हैं — saturating fill probability बनाम τ\sqrt{\tau}-growing adverse selection — कोई folklore constants नहीं।
  4. Queue position एक asset है; इसे खर्च करने से पहले हर venue के amend semantics जानें। CME: quantity-down priority रखता है। Binance spot: cancelReplace हमेशा re-queue करता है, 2025 का amend-keepPriority quantity cuts के लिए इसे preserve करता है। Binance futures: हर modify re-queue करता है। OKX: undocumented — measure करें, और तब तक worst मान कर चलें।
  5. Icebergs back-of-queue orders की एक sequence हैं, और lazy वाले पढ़े जा सकते हैं। Constant peaks और same-timestamp refills एक published detection signature हैं; sizes और timers को randomize करें या back-run होने के लिए तैयार रहें।
  6. State machine को पहले अपने fill simulator में ship करें। Tactics layer वह हिस्सा है जहां backtest और production सबसे ज़्यादा अलग होते हैं — यही ठीक वह कारण है जिसकी वजह से यह simulator के अंदर होनी चाहिए, बाद में bolt-on नहीं।

उपयोगी लिंक

  1. Harris, L. — Optimal Dynamic Order Submission Strategies in Some Stylized Trading Problems, Financial Markets, Institutions & Instruments 7(2), 1-76 (1998)
  2. Cont, R., Kukanov, A. — Optimal Order Placement in Limit Order Markets, Quantitative Finance 17(1), 21-39 (2017)
  3. Frey, S., Sandås, P. — The Impact of Iceberg Orders in Limit Order Books (2009)
  4. Bessembinder, H., Panayides, M., Venkataraman, K. — Hidden Liquidity: An Analysis of Order Exposure Strategies in Electronic Stock Markets, Journal of Financial Economics 94(3), 361-383 (2009)
  5. van Kervel, V., Menkveld, A. — High-Frequency Trading around Large Institutional Orders, Journal of Finance 74(3), 1091-1137 (2019)
  6. Moallemi, C., Yuan, K. — A Model for Queue Position Valuation in a Limit Order Book (2016)
  7. Lehalle, C.-A. — Market Microstructure Knowledge Needed for Controlling an Intra-Day Trading Process (2011)
  8. Binance Spot API — Order Amend Keep Priority
  9. Binance Spot API — Trading endpoints (cancelReplace semantics)
  10. Binance USDT-M Futures API — Modify Order
  11. OKX API v5 — Amend order
  12. CME Group — Order Functionalities (modification and time priority)

Citation

@article{soloviov2026childordertactics,
  author = {Soloviov, Eugen},
  title = {Inside the slice: child-order tactics between your scheduler and the exchange},
  year = {2026},
  url = {https://marketmaker.cc/blog/child-order-execution-tactics},
  description = {The tactics layer between execution schedulers and the exchange: passive-then-aggressive escalation with maker-taker break-even math, amend vs cancel-replace queue semantics across venues, iceberg anti-signaling, and a per-slice Python state machine for fill simulators.}
}
blog.disclaimer

Authors

Eugen Soloviov
Eugen Soloviov

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.

Newsletter

बाज़ार से आगे रहें

AI ट्रेडिंग इनसाइट्स, मार्केट एनालिसिस और प्लेटफ़ॉर्म अपडेट के लिए हमारे न्यूज़लेटर को सब्सक्राइब करें।

हम आपकी गोपनीयता का सम्मान करते हैं। किसी भी समय अनसब्सक्राइब करें।