Source migration: - crates/ml-backtesting/src/lob/mod.rs:5 + policy/mod.rs:18: local const N_HORIZONS 5→3 via re-export from ml_alpha::heads::N_HORIZONS (single source of truth across crates) - crates/ml-backtesting/src/sim/mod.rs:1751,1773,1784: [IsvKellyStateHost; 5] array literals → ; N_HORIZONS] - crates/ml-backtesting/cuda/lob_state.cuh:9: #define N_HORIZONS 5→3 (this triggers cubin rebuild of decision_policy + 4 other ml-backtesting kernels that #include this header) Test migration (8 test files + 2 JSON fixtures): - threshold_and_cost.rs, decision_floor_coldstart.rs, parallel_sim_ correctness.rs, stop_controller.rs (37+10+1 broadcast_alpha calls), lob_sim_integrated_fuzz.rs, lob_sim_fixtures.rs: hardcoded [f32; 5] alpha-probs and [IsvKellyStateHost; 5] arrays → N_HORIZONS-sized via std::array::from_fn or [v; N_HORIZONS] literals - trainer_parity.rs:34 + ring3_replay.rs:47: horizons literal [30,100,300,1000,6000] → ml_alpha::heads::HORIZONS - fixtures/decision_alpha_buy_close.json + decision_program_h4_only.json: 5-element warm_start_isv_kelly / alpha_probs / expected_isv_kelly_after trimmed to 3 elements; active horizon relocated to N_HORIZONS-1 Library lib-test rewrite (per pearl_tests_must_prove_not_lock_observations): - crates/ml-backtesting/src/policy/mod.rs:197-233: lib tests default_strategy_has_5_horizon_leaves + ..._flattens_to_5_emits... renamed to N_HORIZONS-parametric form (observed-value 5 and 7 were bug-locks). cargo check -p ml-backtesting --all-targets: clean. cargo test -p ml-backtesting --lib: 33 passed. cargo test -p ml-backtesting --tests (non-CUDA, non-fixture-data): 2 passed, 53 ignored (CUDA-gated or FOXHUNT_TEST_DATA-gated). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
85 lines
3.7 KiB
Plaintext
85 lines
3.7 KiB
Plaintext
// Per-block shared-mem layout for the LOB simulator.
|
||
// One block = one parallel backtest. See spec §2 + §5b.
|
||
//
|
||
// MUST stay in sync with crates/ml-backtesting/src/lob/mod.rs's host mirrors.
|
||
|
||
#ifndef LOB_STATE_CUH
|
||
#define LOB_STATE_CUH
|
||
|
||
// Must stay in sync with crates/ml-alpha/src/heads.rs::N_HORIZONS and
|
||
// crates/ml-backtesting/src/lob/mod.rs::N_HORIZONS.
|
||
#define N_HORIZONS 3
|
||
#define MAX_LIMITS 32
|
||
#define MAX_STOPS 16
|
||
|
||
struct Book {
|
||
float bid_px[10];
|
||
float bid_sz[10];
|
||
float ask_px[10];
|
||
float ask_sz[10];
|
||
};
|
||
|
||
// Per-backtest position + cumulative P&L. See spec §2 (CUDA shared-mem layout).
|
||
// Host mirror in crates/ml-backtesting/src/lob/mod.rs::PosFlat — MUST stay in sync.
|
||
struct Pos {
|
||
int position_lots; // signed (+ long, − short)
|
||
float vwap_entry; // running entry-price VWAP for current open position
|
||
float realized_pnl; // cumulative realized P&L in price-units × lots
|
||
float peak_equity; // for drawdown tracking
|
||
unsigned int submission_overflow; // diagnostic counter
|
||
unsigned int open_horizon_mask; // bit h set if currently open position was authorized by horizon h
|
||
};
|
||
|
||
// Per-horizon adaptive Kelly state. Lives per (backtest, horizon).
|
||
// See spec §5 (per-horizon ISV-Kelly).
|
||
struct IsvKellyState {
|
||
float pnl_ema_win; // Wiener-α blended EMA of winning trade returns (price units)
|
||
float pnl_ema_loss; // EMA of losing trade returns (positive magnitude)
|
||
float win_rate_ema;
|
||
unsigned int n_trades_seen;
|
||
float realised_return_var; // Welford running variance over per-trade returns
|
||
float recent_sharpe; // composite: (μ × win_rate − μ_loss × (1−win_rate)) / sqrt(var)
|
||
};
|
||
|
||
// Resting-order slots. See spec §2 (CUDA shared-mem layout) and §3
|
||
// (order types). Host mirror in src/lob/mod.rs::{LimitSlotFlat,StopSlotFlat}.
|
||
// LimitSlot.kind / StopSlot.kind values mirror OrderEventKind:
|
||
// Limit=1, Ioc=2, Fok=3 for LimitSlot
|
||
// StopMarket=4, StopLimit=5 for StopSlot
|
||
struct LimitSlot {
|
||
unsigned char active; // 0=free, 1=resting, 2=in-flight (latency)
|
||
unsigned char side; // 0=buy, 1=sell
|
||
unsigned char kind; // 1=Limit, 2=Ioc, 3=Fok
|
||
unsigned char oco_pair; // 0xFF=no pair, else paired-slot global index
|
||
// (limits: 0..31; stops: 32..47)
|
||
float price; // limit price in price-units (e.g. 5500.25)
|
||
float size_remaining; // contracts left unfilled
|
||
float queue_position; // contracts ahead of us at this level (queue decay)
|
||
unsigned long long arrival_ts_ns; // when in-flight order becomes resting
|
||
unsigned short gen_counter; // bumped on each slot allocation for SlotTag freshness
|
||
unsigned char _pad[6]; // pad-to-8 for u64-aligned arrays of this struct
|
||
}; // 32 bytes
|
||
|
||
struct StopSlot {
|
||
unsigned char active; // 0=free, 1=armed, 2=in-flight
|
||
unsigned char side; // 0=buy, 1=sell
|
||
unsigned char kind; // 4=StopMarket, 5=StopLimit
|
||
unsigned char oco_pair; // 0xFF=no pair, else paired-slot global index
|
||
float trigger_price;
|
||
float limit_price; // 0.0 for StopMarket; price for StopLimit
|
||
float size;
|
||
unsigned long long arrival_ts_ns;
|
||
unsigned short gen_counter;
|
||
unsigned char _pad[6]; // pad-to-8 for u64-aligned arrays
|
||
}; // 32 bytes
|
||
|
||
#define MAX_LIMITS 32
|
||
#define MAX_STOPS 16
|
||
|
||
struct Orders {
|
||
LimitSlot limits[MAX_LIMITS]; // 32 × 32 = 1024 B
|
||
StopSlot stops[MAX_STOPS]; // 16 × 32 = 512 B
|
||
}; // 1536 B total
|
||
|
||
#endif // LOB_STATE_CUH
|