When to Use
Use this skill when sizing the quote reprice interval for an automated market making or algorithmic execution strategy that shares a venue session subject to a message rate ceiling. Repricing on every price flick preserves queue priority but burns the session's message budget; inserting a large reprice delay leaves stale quotes exposed to being picked off ($\tau_{\text{exposure}}$). This module derives the smallest reprice delay ($\Delta t_{\text{optimal_ms}}$) that keeps the projected session message rate inside a configured safety buffer, and refuses to certify a configuration it cannot bring inside that budget.
Under MiFID II RTS 6 Art. 15(1)(d) an EU investment firm engaged in algorithmic trading must operate "maximum messages limits, which prevent sending an excessive number of messages to order books pertaining to the submission, modification or cancellation of an order." This skill sizes that limit; it does not enforce it.
When NOT to Use
- As the enforcement mechanism. This is an offline/periodic parameter calculator, not a runtime throttle. RTS 6 Art. 15(1)(d) requires a control that actually blocks excess messages in the order path — pair this with
matching-engine-throttle-and-message-gapping-detection. A recommended delay that nothing enforces is not a pre-trade control. - For burst control. The model is steady-state: it reasons about an average rate, not the sub-second bursts that venues measure over a rolling window (CME evaluates administrative message thresholds as an average over a three-second window). A configuration that passes here can still trip a burst threshold on a tick storm.
- To derive the price threshold.
price_threshold_bpsis an operator-supplied input echoed into the audit notes. The engine does not compute an optimal quote-suppression threshold — deriving one requires a tick-size and price-move distribution this module does not take. - As an adverse-selection cost model.
adverse_selection_exposure_scoreis an ordinal staleness heuristic in bps-milliseconds, not a currency cost and not a calibrated pick-off probability. See Common Pitfalls. - For order-to-trade ratio economics. Staying under an MPS ceiling does not keep you under a message-efficiency benchmark; those are separate regimes with separate penalties — see
order-to-trade-ratio-fee-penalty-avoidance.
Prerequisites
- The venue's actual published limit for the session in question (
exchange_max_mps). This is not a universal constant — seereferences/standards.md. Where a venue publishes both a reject and a terminate threshold, configure the lower (reject) one. - Tuning configuration (
symbol,target_safety_buffer_pctin $(0, 100]$,min_reprice_delay_ms,max_reprice_delay_ms,price_threshold_bps). - Real-time market state (
ticks_per_sec,price_volatility_bps,active_quoting_pairs, andbaseline_session_mpsfor any co-resident flow on the same session).
Workflow
- Target Rate & Unthrottled Velocity Calculation:
- Compute target MPS limit: $R_{\text{target_mps}} = R_{\text{max_mps}} \times \frac{\text{safety_pct}}{100.0}$.
- Compute unthrottled message velocity: $R_{\text{unthrottled}} = \text{TicksPerSec} \times \text{ActiveQuotingPairs}$.
- Deduct co-resident flow to get the repricing budget: $R_{\text{available}} = R_{\text{target_mps}} - R_{\text{baseline}}$. Tuning is required when $R_{\text{unthrottled}} + R_{\text{baseline}} > R_{\text{target_mps}}$.
- Optimal Quote Reprice Delay Tuning:
- Compute required reprice delay, rounded up to the reported precision — rounding a throttle delay to nearest puts the realised rate back above the target: $$\Delta t_{\text{optimal_ms}} = \text{clamp}\left( \left\lceil \frac{1{,}000.0 \times \text{ActiveQuotingPairs}}{R_{\text{available}}} \right\rceil_{0.01},\ \Delta t_{\text{min_ms}},\ \Delta t_{\text{max_ms}} \right)$$
- Feasibility Gate — do not skip:
- Project the session rate: $R_{\text{projected}} = \min\left(R_{\text{unthrottled}},\ \frac{1{,}000.0 \times \text{ActiveQuotingPairs}}{\Delta t_{\text{optimal_ms}}}\right) + R_{\text{baseline}}$.
- If $R_{\text{projected}} > R_{\text{target_mps}}$ the delay ceiling (or baseline flow) binds and no delay can meet the budget. Emit
RATE_LIMIT_TARGET_UNREACHABLEwithis_target_achievable = False. Do not deploy these parameters — reduceactive_quoting_pairs, widenprice_threshold_bps, or split the flow across sessions. Capping the delay and shipping anyway is what terminates the session.
- Adverse Selection Exposure Audit:
- Calculate the staleness heuristic: $\text{Score} = \Delta t_{\text{optimal_ms}} \times \text{VolatilityBps}$, and compare it across candidate configurations only.
- Audit Report Generation: Output structured
TuningReport.
Full procedure: see
references/workflows.md. Standards reference: seereferences/standards.md. Printable pre-flight checklist: seeassets/checklist.md.
Common Pitfalls
- Repricing Quotes on Minor Noise: Updating resting limit orders for sub-tick price fluctuations, consuming the whole message budget during quiet markets.
price_threshold_bpsis the suppression knob — this engine reports it but will not choose it for you. - Ignoring High-Volatility Spikes: Holding a static reprice delay through a crash, so the quote is stale exactly when informed flow is fastest. Re-run the tuner on the current
price_volatility_bps, not a calm-market default. - No Safety Buffer: Sizing for 100% of the exchange limit, leaving no headroom for tick bursts, retransmissions, or the cancels that unwind the position.
- Sizing Against the Terminate Threshold: Venues that publish two levels reject messages at the lower one and drop the session at the higher one. Budgeting against the terminate threshold means the strategy operates permanently inside the reject band, silently losing quotes.
- Counting Only Quote Traffic: RTS 6 Art. 15(2) requires all orders sent to the venue to count against the pre-trade limit. Hedges, cancels, and other strategies on the same session consume the same budget — pass them as
baseline_session_mpsor the projection is fiction. - Assuming One Message Per Reprice:
active_quoting_pairsassumes one cancel/replace amendment per side. A strategy that sends a separate cancel and a separate new order emits two messages per side and must double the value, or it will under-project the rate by 2×. - Reading the Exposure Score as a Cost: The score is linear in delay, but pick-off risk is not. A resting quote is a free option written to the market (Copeland & Galai, 1983); under a driftless diffusion the expected absolute mid displacement over a staleness window $\Delta t$ grows with $\sigma\sqrt{\Delta t}$, not $\Delta t$. Use the score to rank candidate delays, never to size a spread or book a P&L expectation.
- Trusting a Capped Delay: Always branch on
is_target_achievable, not onstatus != "DIRECT_PASS_NO_TUNING_REQUIRED". A configuration whose required delay exceedsmax_reprice_delay_msis reported as unreachable precisely so it cannot be mistaken for a tuned pass.
Verification
- Instantiate
MessageRateLatencyTunerEngine. Audit a high-frequency stream ($100\text{ ticks/sec}$, $5\text{ quoting pairs}$, unthrottled rate $= 500\text{ MPS}$, session limit $= 500\text{ MPS}$, target buffer $= 80% \implies 400\text{ MPS}$) $\implies$ verify the engine tunes the optimal reprice delay to $\Delta t_{\text{optimal}} = 12.5\text{ ms}$, projects rate $= 400\text{ MPS}$, and approvesRATE_LIMIT_TUNING_APPLIED. - Feasibility gate: $1{,}000\text{ quoting pairs}$ against the same $400\text{ MPS}$ target requires a $2{,}500\text{ ms}$ delay, beyond the $500\text{ ms}$ ceiling $\implies$ verify
RATE_LIMIT_TARGET_UNREACHABLE,is_target_achievable = False, and projected rate $= 2{,}000\text{ MPS}$ (4× the exchange ceiling). - Rounding direction: session limit $375\text{ MPS}$ at $80%$ gives a $300\text{ MPS}$ target; the required delay $1000/300 = 3.\overline{3}\text{ ms}$ must round up to $3.34\text{ ms}$ ($299.4\text{ MPS}$), not to nearest ($3.33\text{ ms} \implies 300.3\text{ MPS}$, over budget).
- Shared session: $50\text{ ticks/sec} \times 2\text{ pairs} = 100\text{ MPS}$ passes alone, but with $380\text{ MPS}$ of
baseline_session_mps$\implies$ verify tuning to a $100\text{ ms}$ delay and a projected $400\text{ MPS}$. - Invalid budgets (
target_safety_buffer_pctof $0$, negative, or $> 100$; NaN/negativeticks_per_sec) must raiseValueErrorat construction, never produce a report. - Run
python -m unittest discover -s skills/message-rate-limit-vs-latency-tradeoff-tuning/scripts.