malkhut: Flight9 learnings — markout=quality, queue×flow, depth-for-size
Fable's Flight9/BLUE generalizable features incorporated: 1. Slippage model gains trade_flow_intensity parameter: - Estimated from book imbalance (proxy for trade arrivals) - More flow → better fills (lower slippage) - Fable: 'fill = queue position × trade-flow intensity' 2. Markout = quality concept documented: - Score fills by post-fill markout, not just fill/no-fill - Maker fills are adversely selected 3. Depth-for-size documented: - Spread lies; key on depth-within-K-bps vs order notional 4. Measured fees: - BingX maker=2.00bp, taker=5.016bp (over 1,455 fills) - BingX commission = NEGATIVE (debit) 5. OB study updated with Flight9 learnings
This commit is contained in:
@@ -392,3 +392,55 @@ The OB microstructure directly determines fill quality:
|
|||||||
The PerformanceMatrix tracks `avg_fill_value_score` per (regime, strategy, venue),
|
The PerformanceMatrix tracks `avg_fill_value_score` per (regime, strategy, venue),
|
||||||
enabling the system to learn: "In this regime, on this venue, this strategy
|
enabling the system to learn: "In this regime, on this venue, this strategy
|
||||||
achieves the best fill quality."
|
achieves the best fill quality."
|
||||||
|
|
||||||
|
## 14. Flight9/BLUE Fill Learnings (Fable, 2026-07-16)
|
||||||
|
|
||||||
|
Real FLIGHT9/BLUE fill backfill — generalizable features, not hardcoded thresholds.
|
||||||
|
|
||||||
|
### Markout = Quality
|
||||||
|
|
||||||
|
Fill quality is measured by **post-fill markout** (price move N ticks after fill),
|
||||||
|
not just fill/no-fill. A maker fill at a good quoted price can still be a bad fill
|
||||||
|
if the market moves adversely after execution. The system scores fills by markout.
|
||||||
|
|
||||||
|
**Generalizable:** score fills by post-fill markout. Model fill-CONDITIONAL-on-adverse-flow.
|
||||||
|
|
||||||
|
### Fill = Queue × Flow Intensity
|
||||||
|
|
||||||
|
Fill probability is driven by **trade-arrival intensity** (the tape), not the static book.
|
||||||
|
A resting maker fills only when trades print through its level for enough volume to clear
|
||||||
|
the queue ahead. The HftBacktestCWM queue model is the right substrate — it needs real
|
||||||
|
trade-flow intensity as input.
|
||||||
|
|
||||||
|
**On testnet:** maker fill-rate ~0% (no flow). This is an artifact, not a signal.
|
||||||
|
|
||||||
|
### Depth-for-Size, Not Spread
|
||||||
|
|
||||||
|
Spread alone LIES: an asset with 1.5bp spread behind ~$977 of depth is unfillable at any
|
||||||
|
size. Generalizable: key fill viability on **depth-within-K-bps** relative to order
|
||||||
|
notional, not spread.
|
||||||
|
|
||||||
|
### Measured Fees (Venue-Parameterized)
|
||||||
|
|
||||||
|
| Venue | Maker | Taker | Sign |
|
||||||
|
|-------|-------|-------|------|
|
||||||
|
| BingX | 2.00 bp | 5.016 bp | NEGATIVE = DEBIT |
|
||||||
|
|
||||||
|
Generalize: parameterize fee + sign per venue from measurement, never assume.
|
||||||
|
|
||||||
|
### Realized Friction (F9 VST Fills)
|
||||||
|
|
||||||
|
- Taker: ~20-27 bp adverse on thin/mid books
|
||||||
|
- Maker: saves ~3-4 bp WHEN it fills
|
||||||
|
- Maker fill-rate: ~0% on VST (no flow — testnet artifact)
|
||||||
|
|
||||||
|
### Counterfactual Maker Fill (Real Binance Book)
|
||||||
|
|
||||||
|
- ~50% fill on liquid books (at-touch upper bound)
|
||||||
|
- Queue + venue-thinness reduce it
|
||||||
|
|
||||||
|
### Validation Methodology
|
||||||
|
|
||||||
|
When validating against a crude fill sim, optimize on **RELATIVE lift** between two policies
|
||||||
|
through the SAME sim — fidelity bias cancels in the difference. Trust the ordering of
|
||||||
|
policies even when absolute fill rates are approximate.
|
||||||
|
|||||||
@@ -583,9 +583,15 @@ class MinimalCryptoLOBCWM:
|
|||||||
if cumulative_levels > 0:
|
if cumulative_levels > 0:
|
||||||
from malkhut.training.slippage_calibration import expected_slippage_bps as _esb
|
from malkhut.training.slippage_calibration import expected_slippage_bps as _esb
|
||||||
total_book_usd = sum(l.price * l.qty for l in (book_depth or ()))
|
total_book_usd = sum(l.price * l.qty for l in (book_depth or ()))
|
||||||
|
bid_vol = sum(l.qty for l in (state.book.bids or ()))
|
||||||
|
ask_vol = sum(l.qty for l in (state.book.asks or ()))
|
||||||
|
total_vol = bid_vol + ask_vol
|
||||||
|
imbalance = abs(bid_vol - ask_vol) / max(total_vol, 1e-12)
|
||||||
|
flow_intensity = min(imbalance * 2.0, 1.0)
|
||||||
expected_slippage_bps = _esb(
|
expected_slippage_bps = _esb(
|
||||||
state.venue.symbol, cumulative_levels,
|
state.venue.symbol, cumulative_levels,
|
||||||
new_fill_price * new_fill_qty, total_book_usd,
|
new_fill_price * new_fill_qty, total_book_usd,
|
||||||
|
trade_flow_intensity=flow_intensity,
|
||||||
)
|
)
|
||||||
is_maker_fill = (our_action.order_type and our_action.order_type.value == "LIMIT") or our_action.post_only if isinstance(our_action, FulfilmentAction) else False
|
is_maker_fill = (our_action.order_type and our_action.order_type.value == "LIMIT") or our_action.post_only if isinstance(our_action, FulfilmentAction) else False
|
||||||
price_improvement_bps = 0.0
|
price_improvement_bps = 0.0
|
||||||
|
|||||||
@@ -503,12 +503,19 @@ class HftBacktestCWM:
|
|||||||
if cumulative_usd >= new_fill_price * new_fill_qty:
|
if cumulative_usd >= new_fill_price * new_fill_qty:
|
||||||
break
|
break
|
||||||
if cumulative_levels > 0:
|
if cumulative_levels > 0:
|
||||||
# Calibrated slippage: per-asset model from VST data
|
# Calibrated slippage: per-asset model with flow intensity (Fable Flight9)
|
||||||
from malkhut.training.slippage_calibration import expected_slippage_bps as _esb
|
from malkhut.training.slippage_calibration import expected_slippage_bps as _esb
|
||||||
total_book_usd = sum(l.price * l.qty for l in (book_depth or ()))
|
total_book_usd = sum(l.price * l.qty for l in (book_depth or ()))
|
||||||
|
# Estimate flow intensity from book imbalance (proxy for trade arrivals)
|
||||||
|
bid_vol = sum(l.qty for l in (prev_book.bids or ()))
|
||||||
|
ask_vol = sum(l.qty for l in (prev_book.asks or ()))
|
||||||
|
total_vol = bid_vol + ask_vol
|
||||||
|
imbalance = abs(bid_vol - ask_vol) / max(total_vol, 1e-12)
|
||||||
|
flow_intensity = min(imbalance * 2.0, 1.0) # high imbalance = more flow
|
||||||
expected_slippage_bps = _esb(
|
expected_slippage_bps = _esb(
|
||||||
prev_state.venue.symbol, cumulative_levels,
|
prev_state.venue.symbol, cumulative_levels,
|
||||||
new_fill_price * new_fill_qty, total_book_usd,
|
new_fill_price * new_fill_qty, total_book_usd,
|
||||||
|
trade_flow_intensity=flow_intensity,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Price improvement: how much better than best bid/ask?
|
# Price improvement: how much better than best bid/ask?
|
||||||
|
|||||||
@@ -64,8 +64,18 @@ class SlippageCalibration:
|
|||||||
order_usd: float = 0.0,
|
order_usd: float = 0.0,
|
||||||
book_depth_usd: float = 1.0,
|
book_depth_usd: float = 1.0,
|
||||||
is_mainnet: bool = False,
|
is_mainnet: bool = False,
|
||||||
|
trade_flow_intensity: float = 0.0,
|
||||||
) -> float:
|
) -> float:
|
||||||
"""Predict slippage. Switches model based on book depth."""
|
"""Predict slippage. Switches model based on book depth.
|
||||||
|
|
||||||
|
Generalizable features (Fable, Flight9/BLUE):
|
||||||
|
1. Fill = queue position × trade-flow intensity (not just book snapshot)
|
||||||
|
2. Depth-for-size > spread (spread lies — unfillable behind $977)
|
||||||
|
3. Markout = quality (post-fill adverse selection)
|
||||||
|
"""
|
||||||
|
# Flow intensity boost: more trade arrivals → higher fill probability
|
||||||
|
flow_boost = 1.0 + trade_flow_intensity * 0.1
|
||||||
|
|
||||||
if book_depth_usd < self.thin_book_threshold_usd:
|
if book_depth_usd < self.thin_book_threshold_usd:
|
||||||
# THIN BOOK: intercept-dominant (alts, meme coins)
|
# THIN BOOK: intercept-dominant (alts, meme coins)
|
||||||
# The fill walks the entire book in 1-2 levels.
|
# The fill walks the entire book in 1-2 levels.
|
||||||
@@ -77,6 +87,9 @@ class SlippageCalibration:
|
|||||||
depth_ratio = order_usd / max(book_depth_usd, 1.0)
|
depth_ratio = order_usd / max(book_depth_usd, 1.0)
|
||||||
base = self.alpha * levels_consumed + self.beta * depth_ratio
|
base = self.alpha * levels_consumed + self.beta * depth_ratio
|
||||||
|
|
||||||
|
# Adjust for flow intensity: more flow = better fills (lower slippage)
|
||||||
|
base /= max(flow_boost, 0.5)
|
||||||
|
|
||||||
if is_mainnet:
|
if is_mainnet:
|
||||||
base *= self.testnet_to_mainnet
|
base *= self.testnet_to_mainnet
|
||||||
return base
|
return base
|
||||||
@@ -123,10 +136,11 @@ class SlippageRegistry:
|
|||||||
order_usd: float = 0.0,
|
order_usd: float = 0.0,
|
||||||
book_depth_usd: float = 1.0,
|
book_depth_usd: float = 1.0,
|
||||||
is_mainnet: bool = False,
|
is_mainnet: bool = False,
|
||||||
|
trade_flow_intensity: float = 0.0,
|
||||||
) -> float:
|
) -> float:
|
||||||
"""Predict slippage using the appropriate model."""
|
"""Predict slippage using the appropriate model."""
|
||||||
model = self.get(symbol)
|
model = self.get(symbol)
|
||||||
return model.expected_slippage_bps(levels_consumed, order_usd, book_depth_usd, is_mainnet)
|
return model.expected_slippage_bps(levels_consumed, order_usd, book_depth_usd, is_mainnet, trade_flow_intensity)
|
||||||
|
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
@@ -219,6 +233,7 @@ def expected_slippage_bps(
|
|||||||
order_usd: float = 0.0,
|
order_usd: float = 0.0,
|
||||||
book_depth_usd: float = 1.0,
|
book_depth_usd: float = 1.0,
|
||||||
is_mainnet: bool = False,
|
is_mainnet: bool = False,
|
||||||
|
trade_flow_intensity: float = 0.0,
|
||||||
) -> float:
|
) -> float:
|
||||||
"""Predict slippage using Flight7-calibrated model."""
|
"""Predict slippage using Flight7-calibrated model."""
|
||||||
return REGISTRY.expected_slippage_bps(symbol, levels_consumed, order_usd, book_depth_usd, is_mainnet)
|
return REGISTRY.expected_slippage_bps(symbol, levels_consumed, order_usd, book_depth_usd, is_mainnet, trade_flow_intensity)
|
||||||
|
|||||||
Reference in New Issue
Block a user