Files
foxhunt/crates/common/tests/test_sharedml_225_features.rs
jgrusewski 9c3d741a08 refactor: restructure repo — crates/, bin/, testing/ layout
Move 17 library crates into crates/, CLI binary into bin/fxt,
consolidate 10 test crates into testing/, split config crate
from deployment config files.

Root directory reduced from 38+ to ~17 directories.
All Cargo.toml paths and build.rs proto refs updated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 11:56:00 +01:00

134 lines
4.4 KiB
Rust

//! VALIDATION 1/8: Test that SharedMLStrategy extracts 225 features
//!
//! This test validates that the Wave D implementation correctly extracts
//! all 225 features (201 Wave C + 24 Wave D regime detection features).
use chrono::Utc;
use common::ml_strategy::SharedMLStrategy;
use ml::features::ProductionFeatureExtractorAdapter;
#[tokio::test]
async fn test_sharedml_extracts_225_features() {
// Create SharedMLStrategy with production feature extractor (225 features)
let extractor = Box::new(ProductionFeatureExtractorAdapter::new());
let strategy = SharedMLStrategy::new_with_production_extractor(extractor, 0.5);
// Warm up the feature extractor with some historical data
// (needed to properly compute indicators like EMAs, RSI, etc.)
for i in 0..100 {
let price = 100.0 + (i as f64 * 0.1);
let volume = 1000.0 + (i as f64 * 10.0);
let _ = strategy
.get_ensemble_prediction(price, volume, Utc::now())
.await;
}
// Extract features from the strategy
let predictions = strategy
.get_ensemble_prediction(100.0, 1000.0, Utc::now())
.await
.expect("Should extract features successfully");
// Get features from the first prediction (all models use same features)
assert!(
!predictions.is_empty(),
"Should have at least one prediction"
);
let features = &predictions[0].features;
// VALIDATION 1: Verify feature count is exactly 225
assert_eq!(
features.len(),
225,
"SharedMLStrategy must extract exactly 225 features (201 Wave C + 24 Wave D), but got {}",
features.len()
);
// VALIDATION 2: Verify no NaN values
for (i, f) in features.iter().enumerate() {
assert!(
!f.is_nan(),
"Feature at index {} is NaN (value: {})",
i,
f
);
}
// VALIDATION 3: Verify no Inf values
for (i, f) in features.iter().enumerate() {
assert!(
f.is_finite(),
"Feature at index {} is not finite (value: {}). All features must be finite numbers.",
i,
f
);
}
println!("✅ VALIDATION 1/8 PASSED");
println!(" - Feature count: {} (expected 225)", features.len());
println!(" - All features are finite");
println!(" - No NaN or Inf values detected");
}
#[tokio::test]
async fn test_feature_extraction_wave_d_breakdown() {
// Create SharedMLStrategy with production feature extractor (225 features)
let extractor = Box::new(ProductionFeatureExtractorAdapter::new());
let strategy = SharedMLStrategy::new_with_production_extractor(extractor, 0.5);
// Warm up the feature extractor
for i in 0..100 {
let price = 100.0 + (i as f64 * 0.1);
let volume = 1000.0 + (i as f64 * 10.0);
let _ = strategy
.get_ensemble_prediction(price, volume, Utc::now())
.await;
}
// Extract features
let predictions = strategy
.get_ensemble_prediction(100.0, 1000.0, Utc::now())
.await
.expect("Should extract features successfully");
let features = &predictions[0].features;
// Verify feature breakdown (expected from Wave D documentation):
// - Wave A: 26 features (indices 0-25)
// - Wave B: 10 features (indices 26-35) [alternative bar sampling]
// - Wave C: 165 features (indices 36-200) [advanced feature engineering]
// - Wave D: 24 features (indices 201-224) [regime detection]
// Total: 225 features
assert_eq!(
features.len(),
225,
"Expected 225 total features (26 Wave A + 10 Wave B + 165 Wave C + 24 Wave D)"
);
// Verify Wave D features (indices 201-224) are present
for i in 201..225 {
let feature_value = features.get(i);
assert!(
feature_value.is_some(),
"Wave D feature at index {} is missing",
i
);
let value = feature_value.unwrap();
assert!(
value.is_finite(),
"Wave D feature at index {} is not finite: {}",
i,
value
);
}
println!("✅ Wave D feature breakdown validated");
println!(" - Wave A features (0-25): present");
println!(" - Wave B features (26-35): present");
println!(" - Wave C features (36-200): present");
println!(" - Wave D features (201-224): present");
}