malkhut: conditional slippage (Fable)

This commit is contained in:
Codex
2026-07-15 17:05:16 +02:00
parent 619966605e
commit c03d914e7a
3 changed files with 41 additions and 4 deletions

View File

@@ -483,11 +483,28 @@ class HftBacktestCWM:
mid = prev_book.mid if prev_book.bids and prev_book.asks else 0.0
spread_bps = prev_book.spread_bps if prev_book.bids and prev_book.asks else 0.0
# Slippage: how far from mid did we fill?
# ── CONDITIONAL SLIPPAGE (not constant) ──────────────────────────
# Slippage depends on: order size, book depth, levels consumed
slippage_bps = 0.0
expected_slippage_bps = 0.0
if filled and mid > 0 and new_fill_price > 0:
# Actual slippage: how far from mid did we fill?
slippage_bps = abs(new_fill_price - mid) / mid * 10_000
# Expected slippage from book depth model (power-law)
# Walk levels until we accumulate fill_qty
book_depth = prev_book.asks if action.side == Side.BUY else prev_book.bids
cumulative_usd = 0.0
cumulative_levels = 0
for level in (book_depth or ()):
level_usd = level.price * level.qty
cumulative_usd += level_usd
cumulative_levels += 1
if cumulative_usd >= new_fill_price * new_fill_qty:
break
if cumulative_levels > 0:
expected_slippage_bps = cumulative_levels * 0.1 # ~0.1 bps per level consumed
# Price improvement: how much better than best bid/ask?
price_improvement_bps = 0.0
if filled and action.post_only and action.side:
@@ -525,11 +542,13 @@ class HftBacktestCWM:
else:
rolling_fill_rate = 0.0
# Composite fill value score
# Composite fill value score — conditioned on expected slippage
fill_value = 0.0
if filled:
quality = price_improvement_bps if is_maker else max(0.0, spread_bps - slippage_bps)
fill_value = quality - abs(post_fill_adverse) * 0.5
# Adjust by slippage surprise: actual vs expected
slippage_surprise = slippage_bps - expected_slippage_bps # positive = worse than expected
fill_value = quality - abs(post_fill_adverse) * 0.5 - max(0.0, slippage_surprise) * 0.3
return FillQuality(
filled=filled,
@@ -537,6 +556,7 @@ class HftBacktestCWM:
fill_price=new_fill_price,
requested_qty=action.qty_fraction * prev_state.account.available_balance / max(mid, 1e-12) if action.qty_fraction > 0 and mid > 0 else 0.0,
slippage_bps=slippage_bps,
expected_slippage_bps=expected_slippage_bps,
price_improvement_bps=price_improvement_bps,
levels_consumed=levels_consumed,
is_maker_fill=is_maker,