feat(alpha): fitted FillModel coefficients from 500K ES.FUT snapshots

Phase E.0 Task 5c. Ran phase_e_fit_fill_model on the ES.FUT 2024-Q1 MBP-10
+ trade tape (5.2M trades, 3.9M MBP-10 events, 500K snapshots accumulated
at snapshot_interval=50 over a ~24-minute window). Total runtime ~80s.

Empirical fill rates within 60s window:
  - bid_l1: 4.97%   (matches L1 maker-side activity in trending market)
  - ask_l1: 71.34%  (high — most 60s windows see an aggressive buy)

Fitted L1 cloglog coefficients (all 5 features):
  BID L1: β_0=-0.213  β_spread=-2.064  β_imbal=-0.099  β_ofi=-0.006  β_logτ=-0.286
  ASK L1: β_0=+0.016  β_spread=-40.336 β_imbal=+0.041  β_ofi=+0.652  β_logτ=-0.055

Sanity (sign checks all pass):
  - β_spread < 0 both sides   (wider spread → fewer fills) ✓
  - bid β_imbal < 0           (more bid stack → harder to get hit by sell) ✓
  - ask β_ofi > 0             (buying pressure correlates with ask fills) ✓
  - β_logτ < 0 both sides     (quieter markets → slower execution) ✓

L1-only limitation: as documented in the binary header, the parser only
populates levels[0]; L2/L3 in the JSON are L1 with β_0 -= ln(L+1) attenuation.

Default --out-path bumped to config/ml/phase_e_fill_coeffs.json so future
re-runs land in the same committed location.
This commit is contained in:
jgrusewski
2026-05-15 13:26:21 +02:00
parent 3bdf74018d
commit 12151ccf6a
2 changed files with 61 additions and 1 deletions

View File

@@ -0,0 +1,60 @@
{
"ask_coeffs": [
[
0.015584787353873253,
-40.335906982421875,
0.041306495666503906,
0.6524077653884888,
-0.055438391864299774
],
[
-0.677562415599823,
-40.335906982421875,
0.041306495666503906,
0.6524077653884888,
-0.055438391864299774
],
[
-1.0830274820327759,
-40.335906982421875,
0.041306495666503906,
0.6524077653884888,
-0.055438391864299774
]
],
"bid_coeffs": [
[
-0.21279112994670868,
-2.063631057739258,
-0.09875621646642685,
-0.006330371834337711,
-0.28642183542251587
],
[
-0.9059383273124695,
-2.063631057739258,
-0.09875621646642685,
-0.006330371834337711,
-0.28642183542251587
],
[
-1.3114033937454224,
-2.063631057739258,
-0.09875621646642685,
-0.006330371834337711,
-0.28642183542251587
]
],
"empirical_ask_l1_rate": 0.713424,
"empirical_bid_l1_rate": 0.049668,
"fit_iters": 1000,
"fit_lr": 0.009999999776482582,
"l1_only_limitation": true,
"l1_only_limitation_reason": "parse_mbp10_streaming ignores Mbp10Msg.levels[1..10]; L2/L3 coefficients are L1 with attenuated β_0 (-ln(L+1))",
"n_degenerate_skipped": 138941,
"n_snapshots": 500000,
"n_trades": 5198778,
"phase": "E.0 Task 5",
"snapshot_interval": 50,
"window_seconds": 60.0
}

View File

@@ -74,7 +74,7 @@ struct Cli {
#[arg(long, default_value_t = 60.0)]
window_seconds: f32,
/// Output JSON path.
#[arg(long, default_value = "phase_e_fill_coeffs.json")]
#[arg(long, default_value = "config/ml/phase_e_fill_coeffs.json")]
out_path: PathBuf,
/// MBP-10 events between snapshot emissions (denser = larger sample).
#[arg(long, default_value_t = 10)]