From 3501d7a37bee9f862cd8eb735eef7dd3bcab5a72 Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Tue, 31 Mar 2026 11:26:45 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20proper=20MBP-10=20integration=20test=20w?= =?UTF-8?q?ith=20real=20data=20=E2=80=94=20no=20silent=20failures?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace if-let-Ok pattern with #[ignore] test that asserts on results. Uses CARGO_MANIFEST_DIR to resolve workspace root. Validates bar ordering, positive volume, valid OHLC. Produces 654 imbalance bars from Q1+Q2 2024 ES MBP-10 data (448s load time). Co-Authored-By: Claude Opus 4.6 (1M context) --- crates/ml-features/src/mbp10_loader.rs | 57 +++++++++++++++++--------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/crates/ml-features/src/mbp10_loader.rs b/crates/ml-features/src/mbp10_loader.rs index 6b9472397..ab5f503e9 100644 --- a/crates/ml-features/src/mbp10_loader.rs +++ b/crates/ml-features/src/mbp10_loader.rs @@ -886,27 +886,44 @@ mod tests { assert!(err_msg.contains("MBP-10 directory not found"), "Error: {err_msg}"); } + /// Integration test: loads real MBP-10 data and produces imbalance bars. + /// Requires test_data/futures-baseline-mbp10/ES.FUT/ with .dbn.zst files. + /// Run with: cargo test -p ml-features --lib -- test_mbp10_to_imbalance_bars_real --ignored --nocapture #[test] - fn test_mbp10_to_imbalance_bars_from_test_data() { - // This test depends on test_data/mbp10/ES.FUT/ existing. - // If not available (CI), it will fail with a descriptive error — that's OK. - let bars = mbp10_to_imbalance_bars( - Path::new("../../test_data/mbp10"), - "ES.FUT", - 100.0, - 0.1, - ); - if let Ok(bars) = bars { - assert!(!bars.is_empty(), "Expected at least one imbalance bar"); - for w in bars.windows(2) { - assert!( - w[0].timestamp <= w[1].timestamp, - "Bars must be time-ordered: {:?} > {:?}", - w[0].timestamp, - w[1].timestamp - ); - } + #[ignore] + fn test_mbp10_to_imbalance_bars_real() { + // Resolve workspace root from CARGO_MANIFEST_DIR + let manifest = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + let workspace = std::path::Path::new(&manifest) + .parent() // crates/ + .and_then(|p| p.parent()) // repo root + .expect("Failed to find workspace root"); + let mbp10_dir = workspace.join("test_data/futures-baseline-mbp10"); + assert!(mbp10_dir.exists(), "MBP-10 test data not found at {}", mbp10_dir.display()); + + let bars = mbp10_to_imbalance_bars(&mbp10_dir, "ES.FUT", 100.0, 0.1) + .expect("mbp10_to_imbalance_bars must succeed with real data"); + + assert!(!bars.is_empty(), "Must produce imbalance bars from MBP-10 data"); + println!("Produced {} imbalance bars from MBP-10 data", bars.len()); + println!(" First bar: {:?}", bars.first().unwrap().timestamp); + println!(" Last bar: {:?}", bars.last().unwrap().timestamp); + + // Verify time-ordering + for w in bars.windows(2) { + assert!( + w[0].timestamp <= w[1].timestamp, + "Bars must be time-ordered: {:?} > {:?}", + w[0].timestamp, w[1].timestamp + ); } - // If Err, that's fine — test data may not be present + + // Verify reasonable bar properties + for bar in &bars { + assert!(bar.high >= bar.low, "high must >= low"); + assert!(bar.volume > 0.0, "volume must be positive"); + assert!(bar.close > 0.0, "close must be positive"); + } + println!("All {} bars valid: time-ordered, positive volume, valid OHLC", bars.len()); } }