From ef831ba598000de1509e3868a35d1126c4b4b520 Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Tue, 19 May 2026 22:29:52 +0200 Subject: [PATCH] obs(ml-backtesting): trades=N on progress line for intra-run firing visibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds LobSimCuda::read_total_trade_count (cheap n_backtests*4 byte DtoH of the trade-log head counters) and emits the sum on each PROGRESS_EVERY eprintln. Lets future smokes (Q2 CBSW validation, P7 sweep) see trade firing mid-run instead of waiting for write_artifacts at harness end. Heads count kernel writes (clamped to ring cap), so the sum is a monotone trade counter across the sweep โ€” drops back only on harness reset which doesn't happen mid-run. Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/ml-backtesting/src/harness.rs | 5 +++-- crates/ml-backtesting/src/sim/mod.rs | 11 +++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/crates/ml-backtesting/src/harness.rs b/crates/ml-backtesting/src/harness.rs index ec2e01c30..aafc3021f 100644 --- a/crates/ml-backtesting/src/harness.rs +++ b/crates/ml-backtesting/src/harness.rs @@ -301,9 +301,10 @@ impl BacktestHarness { if self.event_count >= next_progress_event { let elapsed = started.elapsed().as_secs_f32(); let rate = self.event_count as f32 / elapsed.max(1e-3); + let trades = self.sim.read_total_trade_count().unwrap_or(0); eprintln!( - "progress: events={} decisions={} elapsed={:.0}s rate={:.0}ev/s", - self.event_count, total_decisions, elapsed, rate, + "progress: events={} decisions={} trades={} elapsed={:.0}s rate={:.0}ev/s", + self.event_count, total_decisions, trades, elapsed, rate, ); next_progress_event += PROGRESS_EVERY; } diff --git a/crates/ml-backtesting/src/sim/mod.rs b/crates/ml-backtesting/src/sim/mod.rs index 7c46cc506..28db6b867 100644 --- a/crates/ml-backtesting/src/sim/mod.rs +++ b/crates/ml-backtesting/src/sim/mod.rs @@ -390,6 +390,17 @@ impl LobSimCuda { self.n_backtests } + /// Sum of per-backtest trade-log head counters. Cheap DtoH copy of + /// `n_backtests * 4` bytes โ€” used by the harness progress line to + /// surface intra-run trade firing without reading the full ring. + /// Heads count writes (clamped to ring cap inside the kernel), so the + /// sum is a reliable monotone trade counter across the sweep. + pub fn read_total_trade_count(&self) -> Result { + let mut heads = vec![0u32; self.n_backtests]; + self.stream.memcpy_dtoh(&self.trade_log_head_d, heads.as_mut_slice())?; + Ok(heads.iter().map(|&h| h as u64).sum()) + } + /// Apply one MBP-10 snapshot's top-10 levels to every backtest's book. /// v1 inputs are single-snapshot broadcast (same market data to all /// parallel backtests โ€” see spec ยง7 inference scope, policy sweeps only).