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>
134 lines
4.4 KiB
Rust
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");
|
|
}
|