Files
foxhunt/crates/ml/src/features/extraction_wave_d_impl.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

75 lines
2.7 KiB
Rust

/// WAVE 8 AGENT 37: Extract Wave D regime detection features (24 total)
///
/// ## Feature Breakdown (Indices 201-224)
/// - 201-210: CUSUM features (10)
/// - 211-215: ADX & directional indicators (5)
/// - 216-220: Transition probabilities (5)
/// - 221-224: Adaptive position/stop-loss (4)
fn extract_wave_d_features(&mut self, out: &mut [f64]) -> Result<()> {
let bar = self.bars.back().context("No current bar")?;
let mut idx = 0;
// Features 201-210: CUSUM regime detection (10 features)
let return_value = if self.bars.len() > 1 {
let prev = &self.bars[self.bars.len() - 2];
safe_log_return(bar.close, prev.close)
} else {
0.0
};
let cusum_features = self.regime_cusum.update(return_value);
out[idx..idx + 10].copy_from_slice(&cusum_features);
idx += 10;
// Features 211-215: ADX & directional indicators (5 features)
// Convert OHLCVBar to regime_adx OHLCVBar format
let adx_bar = crate::features::regime_adx::OHLCVBar {
timestamp: bar.timestamp.timestamp(),
open: bar.open,
high: bar.high,
low: bar.low,
close: bar.close,
volume: bar.volume,
};
let adx_features = self.regime_adx.update(&adx_bar);
out[idx..idx + 5].copy_from_slice(&adx_features);
idx += 5;
// Features 216-220: Transition probabilities (5 features)
// Determine current regime based on ADX and CUSUM
let adx_value = adx_features[0]; // ADX strength
let cusum_direction = cusum_features[3]; // Direction feature
let current_regime = if adx_value > 25.0 {
if cusum_direction > 0.5 {
MarketRegime::Bull
} else if cusum_direction < -0.5 {
MarketRegime::Bear
} else {
MarketRegime::Trending
}
} else if adx_value < 20.0 {
MarketRegime::Sideways
} else {
MarketRegime::Normal
};
let transition_features = self.regime_transition.update(current_regime);
out[idx..idx + 5].copy_from_slice(&transition_features);
idx += 5;
// Features 221-224: Adaptive position sizing & stop-loss (4 features)
// Convert bars to regime_adaptive format
let adaptive_bars: Vec<crate::features::regime_adaptive::OHLCVBar> = self.bars.iter().map(|b| {
crate::features::regime_adaptive::OHLCVBar {
timestamp: b.timestamp,
open: b.open,
high: b.high,
low: b.low,
close: b.close,
volume: b.volume,
}
}).collect();
let adaptive_features = self.regime_adaptive.update(current_regime, return_value, 0.0, &adaptive_bars);
out[idx..idx + 4].copy_from_slice(&adaptive_features);
Ok(())
}