# Wave D Code References and Integration Guide ## Overview This document provides exact file locations, code snippets, and integration points for all Wave D technical indicators and structural break detection components. --- ## Part 1: Already Implemented Components (Ready to Use) ### 1. RSI (Relative Strength Index) **File**: `/home/jgrusewski/Work/foxhunt/ml/src/features/feature_extraction.rs` **Lines**: 132-177 **Integration**: Already used in Wave A features (index 23) **Function Signature**: ```rust fn calculate_rsi(&self, bars: &[OHLCVBar]) -> Vec ``` **Key Parameters**: - Period: 14 (hardcoded in `rsi_period` field, configurable via FeatureExtractor) - Output: Vector of RSI values (0-100 scale) - Warmup: 14 bars minimum **Usage Example**: ```rust use ml::features::feature_extraction::{FeatureExtractor, OHLCVBar}; let extractor = FeatureExtractor::new(); let rsi_values = extractor.calculate_rsi(&bars); let current_rsi = rsi_values.last().unwrap(); // For Wave D: Use for regime confirmation if *current_rsi > 70.0 { // Overbought (potential selling pressure) } else if *current_rsi < 30.0 { // Oversold (potential buying pressure) } ``` **How to Integrate into Wave D**: 1. Import from `ml::features::feature_extraction` 2. Call in regime classification logic 3. Combine with Hurst exponent for regime confirmation 4. Example: Trending confirmation = (Hurst > 0.6) AND (RSI trending upward) --- ### 2. ATR (Average True Range) **File**: `/home/jgrusewski/Work/foxhunt/ml/src/features/feature_extraction.rs` **Lines**: 267-300 **Integration**: Feature 18 in Wave A, used for dynamic stops **Function Signature**: ```rust fn calculate_atr(&self, bars: &[OHLCVBar]) -> Vec ``` **Key Parameters**: - Period: 14 (hardcoded, configurable) - True Range Components: - High - Low - Absolute(High - Close[i-1]) - Absolute(Low - Close[i-1]) - Smoothing: EMA-based - Output: ATR values for each bar **Usage Example**: ```rust use ml::features::feature_extraction::FeatureExtractor; let extractor = FeatureExtractor::new(); let atr_values = extractor.calculate_atr(&bars); let current_atr = atr_values.last().unwrap(); // For Wave D: Dynamic position sizing let base_position = 100; let position_size = base_position / (*current_atr as i32 + 1); // For Wave D: Adaptive stops let stop_loss = current_price - (current_atr * 2.0); // Trending regime let stop_loss = current_price - (current_atr * 0.8); // Ranging regime ``` **How to Integrate into Wave D**: 1. Use in `position_sizer.rs` for dynamic position sizing 2. Scale position inversely with ATR (higher ATR = smaller position) 3. Use in `dynamic_stops.rs` for regime-dependent stop widths 4. Trending: stops wider (ATR × 1.5-2.0) 5. Ranging: stops tighter (ATR × 0.5-0.8) 6. Volatile: stops dynamic (ATR × volatility_multiplier) --- ### 3. Bollinger Bands **File**: `/home/jgrusewski/Work/foxhunt/ml/src/features/feature_extraction.rs` **Lines**: 234-266 **Integration**: Feature 19 (Bollinger position) in Wave A **Function Signature**: ```rust fn calculate_bollinger_bands(&self, bars: &[OHLCVBar]) -> (Vec, Vec, Vec) ``` **Key Parameters**: - Period: 20 (SMA window) - Std Dev Multiplier: 2.0 (for bands at mean ± 2σ) - Output: (upper_bands, middle_bands, lower_bands) - Bollinger Position: (close - lower) / (upper - lower) ∈ [0, 1] **Usage Example**: ```rust use ml::features::feature_extraction::FeatureExtractor; let extractor = FeatureExtractor::new(); let (bb_upper, bb_middle, bb_lower) = extractor.calculate_bollinger_bands(&bars); let current_close = bars.last().unwrap().close; let upper = bb_upper.last().unwrap(); let lower = bb_lower.last().unwrap(); // Bollinger position (0-1 scale, 0.5 = middle) let bb_position = (current_close - lower) / (upper - lower); // For Wave D: Regime classification if bb_position > 0.8 { // Near upper band = potential uptrend } else if bb_position < 0.2 { // Near lower band = potential downtrend } else if 0.3 < bb_position && bb_position < 0.7 { // Middle band = ranging regime } ``` **How to Integrate into Wave D**: 1. Use in `ranging.rs` for ranging regime classification 2. Bollinger position ∈ [0.3, 0.7] indicates ranging 3. Bollinger squeeze (upper - lower < threshold) indicates low volatility 4. Break above/below bands signals regime transition 5. Combine with Hurst for confirmation --- ### 4. Hurst Exponent **File**: `/home/jgrusewski/Work/foxhunt/ml/src/features/price_features.rs` **Lines**: 286-337 **Integration**: Feature 13 in Wave C price features **Function Signature**: ```rust pub fn compute_hurst_exponent(bars: &VecDeque, period: usize) -> f64 ``` **Key Parameters**: - `bars`: VecDeque of OHLCV bars (minimum 50 for rolling analysis) - `period`: Window size for R/S analysis (default 20) - Output: Hurst exponent ∈ [0, 1] - H ≈ 0.5: Random walk - H > 0.6: Trending (persistent) - H < 0.4: Mean-reverting **Algorithm**: 1. Calculate log returns from prices 2. Compute mean-centered cumulative deviations 3. Calculate range (max - min) and standard deviation 4. R/S statistic = range / std 5. H = log(R/S) / log(N) **Usage Example**: ```rust use ml::features::price_features::PriceFeatureExtractor; use std::collections::VecDeque; let hurst = PriceFeatureExtractor::compute_hurst_exponent(&bars, 20); // For Wave D: Primary regime classifier match () { _ if hurst > 0.6 => { // Trending regime regime = MarketRegime::Trending; strategy = "DQN_with_trend_bias"; position_multiplier = 1.2; // Larger positions stop_width = atr * 2.0; // Wider stops }, _ if hurst > 0.4 && hurst < 0.6 => { // Ranging regime regime = MarketRegime::Ranging; strategy = "PPO_with_reversion_bias"; position_multiplier = 0.9; // Smaller positions stop_width = atr * 0.8; // Tighter stops }, _ => { // Mean-reverting/volatile regime = MarketRegime::MeanReverting; strategy = "MarketMaking"; position_multiplier = 0.7; // Risk-managed stop_width = atr * 0.6; // Tight stops } } ``` **How to Integrate into Wave D**: 1. **PRIMARY** regime classifier in `trending.rs`, `ranging.rs`, `volatile.rs` 2. Compute Hurst every bar (or every N bars for efficiency) 3. Use as input to regime classification ensemble 4. High Hurst persistence: confirmation signal for regime (prevent whipsaw) 5. Hurst changes gradually: smooth regime transitions **Tests Available**: - `test_hurst_exponent_random_walk`: Expect H ≈ 0.5 - `test_hurst_exponent_trending`: Expect H > 0.6 - `test_hurst_exponent_insufficient_data`: Edge case handling --- ### 5. Autocorrelation **File**: Three implementations available #### Implementation 1: Feature Extraction **File**: `/home/jgrusewski/Work/foxhunt/ml/src/features/extraction.rs` **Lines**: 904-918 ```rust fn compute_autocorr(&self, lag: usize) -> f64 { if self.bars.len() <= lag { return 0.0; } let n = self.bars.len() - lag; let mean: f64 = self.bars.iter().map(|b| b.close).sum::() / self.bars.len() as f64; let mut numerator = 0.0; let mut denominator = 0.0; for i in 0..n { numerator += (self.bars[i].close - mean) * (self.bars[i + lag].close - mean); } for bar in self.bars.iter() { denominator += (bar.close - mean).powi(2); } numerator / (denominator + 1e-8) } ``` #### Implementation 2: Statistical Features **File**: `/home/jgrusewski/Work/foxhunt/ml/src/features/statistical_features.rs` **Lines**: 334-400 ```rust pub fn compute_autocorrelation(bars: &VecDeque, period: usize) -> f64 ``` This is the recommended implementation with: - Proper edge case handling - Full test suite - Optimized performance **Usage Example**: ```rust use ml::features::statistical_features::StatisticalFeatureExtractor; let autocorr_lag1 = StatisticalFeatureExtractor::compute_autocorrelation(&bars, 1); let autocorr_lag5 = StatisticalFeatureExtractor::compute_autocorrelation(&bars, 5); // For Wave D: Regime and persistence detection if autocorr_lag1 > 0.6 { // Strong positive correlation: trending (persistent) persistence = "High"; regime_hint = "Trending"; } else if autocorr_lag1 > 0.3 { // Moderate positive: somewhat persistent persistence = "Medium"; } else if autocorr_lag1 < -0.2 { // Negative correlation: mean-reverting persistence = "Low (Mean-reverting)"; regime_hint = "Ranging"; } else { // Near zero: random walk persistence = "None (Random)"; } // Combine with Hurst for confirmation if (hurst > 0.6) && (autocorr_lag1 > 0.5) { // STRONG trending confirmation confidence = 0.95; } else if (0.4 < hurst < 0.6) && (autocorr_lag1 < 0.2) { // STRONG ranging confirmation confidence = 0.95; } ``` **How to Integrate into Wave D**: 1. Use in regime classification ensemble 2. Compare multiple lags (1, 5, 10) to detect regime changes 3. Autocorr spike = changepoint signal (complement CUSUM) 4. Positive → trending, Negative/Near-zero → ranging 5. Lag > 5 with high correlation = strong trend **Tests Available**: - `test_autocorrelation_constant` - `test_autocorrelation_trending` - `test_autocorrelation_mean_reverting` --- ## Part 2: Components to Build for Wave D ### 1. CUSUM (Cumulative Sum Control Chart) **File to Create**: `/adaptive-strategy/src/regime/cusum.rs` **Estimated Size**: 500-600 lines **Key Algorithms**: - Mean shift detection - Variance change detection - Two-sided CUSUM - Adaptive thresholding **Pseudo-code**: ```rust pub struct CUSUMDetector { /// Positive cumulative sum (for upward shifts) cumsum_pos: f64, /// Negative cumulative sum (for downward shifts) cumsum_neg: f64, /// Decision boundary (detection threshold) threshold: f64, /// Mean baseline (for deviations) baseline_mean: f64, /// Variance baseline baseline_var: f64, /// Number of bars since last reset bars_since_reset: usize, } impl CUSUMDetector { pub fn new(threshold: f64, baseline_mean: f64, baseline_var: f64) -> Self { Self { cumsum_pos: 0.0, cumsum_neg: 0.0, threshold, baseline_mean, baseline_var, bars_since_reset: 0, } } /// Update CUSUM with new price, return true if changepoint detected pub fn update(&mut self, price: f64) -> bool { let deviation = price - self.baseline_mean; // Update cumsums (reset to 0 if go negative) self.cumsum_pos = (self.cumsum_pos + deviation).max(0.0); self.cumsum_neg = (self.cumsum_neg + deviation).min(0.0); self.bars_since_reset += 1; // Signal if either threshold exceeded if self.cumsum_pos > self.threshold || self.cumsum_neg.abs() > self.threshold { // Changepoint detected self.reset(); return true; } false } /// Reset cumsums (after changepoint detected) fn reset(&mut self) { self.cumsum_pos = 0.0; self.cumsum_neg = 0.0; self.bars_since_reset = 0; } } ``` **Integration Points**: 1. Call from `RegimeDetector::detect_regime()` 2. Input: Current price or returns 3. Output: Changepoint signal (boolean) 4. Use in regime classification as "transition detected" flag --- ### 2. Regime Classification Framework **Files to Create**: 1. `trending.rs` (200 lines) 2. `ranging.rs` (200 lines) 3. `volatile.rs` (200 lines) 4. `transition_matrix.rs` (300 lines) **trending.rs Pseudo-code**: ```rust pub struct TrendingRegimeClassifier; impl TrendingRegimeClassifier { pub fn classify(hurst: f64, autocorr: f64, rsi: f64, bb_position: f64, atr: f64) -> Option<(MarketRegime, f64)> { let mut score = 0.0; let mut weight = 0.0; // Hurst: weight 40% if hurst > 0.6 { score += 1.0 * 0.4; weight += 0.4; } // Autocorrelation: weight 30% if autocorr > 0.5 { score += 1.0 * 0.3; weight += 0.3; } // RSI: weight 15% (confirmation) if rsi > 55.0 || rsi < 45.0 { // Not neutral score += 1.0 * 0.15; weight += 0.15; } // Bollinger position: weight 15% if bb_position > 0.7 || bb_position < 0.3 { // Extremes score += 1.0 * 0.15; weight += 0.15; } let confidence = score / weight; if confidence > 0.65 { Some((MarketRegime::Trending, confidence)) } else { None } } } ``` --- ### 3. Adaptive Position Sizer **File to Create**: `/adaptive-strategy/src/regime/position_sizer.rs` **Estimated Size**: 400 lines **Pseudo-code**: ```rust pub struct AdaptivePositionSizer { base_position: f64, hurst_exponent: f64, volatility: f64, regime: MarketRegime, } impl AdaptivePositionSizer { pub fn calculate_position(&self) -> f64 { match self.regime { MarketRegime::Trending => { // Larger positions in trends // Scale by Hurst: higher Hurst = stronger trend = bigger position self.base_position * (1.0 + (self.hurst_exponent - 0.5) * 0.5) }, MarketRegime::Ranging => { // Smaller positions in ranges (less room to move) self.base_position * 0.75 }, MarketRegime::HighVolatility => { // Risk-managed in volatility self.base_position * (1.0 / (1.0 + self.volatility)) }, _ => self.base_position, } } } ``` --- ## Part 3: Integration Workflow for Wave D ### Data Flow Diagram ``` ┌─────────────────────────────────────────────────────────┐ │ Input: OHLCV Bars (from real_data_loader) │ └──────────────────────┬──────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ Feature Extraction (Wave C) │ │ ├─ RSI (14-period) │ │ ├─ ATR (14-period) │ │ ├─ Bollinger Bands (20-period) │ │ ├─ Hurst Exponent (20-period) ← PRIMARY │ │ ├─ Autocorrelation (lag 1-5) ← PRIMARY │ │ └─ 55+ other features │ └──────────────────────┬──────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ Structural Break Detection (Wave D Phase 1) │ │ ├─ CUSUM (mean change) │ │ ├─ CUSUM (variance change) │ │ ├─ Bayesian changepoint │ │ └─ Multi-CUSUM (joint detection) │ └──────────────────────┬──────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ Regime Classification (Wave D Phase 2) │ │ ├─ Trending Classifier │ │ ├─ Ranging Classifier │ │ ├─ Volatile Classifier │ │ ├─ Transition Matrix │ │ └─ Ensemble Voting │ │ Output: (Regime, Confidence) ∈ {T,R,V} × [0,1] │ └──────────────────────┬──────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ Adaptive Strategy (Wave D Phase 3) │ │ ├─ Position Sizer │ │ │ └─ Output: position_multiplier │ │ ├─ Dynamic Stops │ │ │ └─ Output: stop_loss_level │ │ ├─ Strategy Selector │ │ │ └─ Output: model (DQN | PPO | MAMBA2) │ │ └─ Performance Tracker │ │ └─ Output: regime_sharpe, attribution │ └──────────────────────┬──────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ Output: Trading Decision │ │ ├─ Signal: (BUY | SELL | HOLD) │ │ ├─ Position size: scaled by regime_multiplier │ │ ├─ Stop loss: regime-dependent │ │ ├─ Strategy: regime-matched │ │ └─ Confidence: ensemble voting │ └─────────────────────────────────────────────────────────┘ ``` --- ## Part 4: Testing Strategy for Wave D ### Unit Test Template ```rust #[cfg(test)] mod tests { use super::*; #[test] fn test_cusum_mean_shift_detection() { let mut detector = CUSUMDetector::new(5.0, 100.0, 1.0); // Normal prices (no shift) for p in [100.0, 101.0, 99.0, 100.5].iter() { assert!(!detector.update(*p)); } // Mean shift (prices jump up) detector.baseline_mean = 105.0; for p in [110.0, 111.0, 112.0, 113.0].iter() { if detector.update(*p) { // Changepoint should be detected return; } } panic!("Mean shift not detected"); } #[test] fn test_regime_classification_trending() { let hurst = 0.65; let autocorr = 0.55; let rsi = 65.0; let bb_position = 0.8; let atr = 1.5; let (regime, confidence) = TrendingRegimeClassifier::classify( hurst, autocorr, rsi, bb_position, atr ).unwrap(); assert_eq!(regime, MarketRegime::Trending); assert!(confidence > 0.65); } #[test] fn test_position_sizing_scales_with_hurst() { let sizer = AdaptivePositionSizer { base_position: 100.0, hurst_exponent: 0.7, volatility: 0.02, regime: MarketRegime::Trending, }; let position = sizer.calculate_position(); assert!(position > 100.0); // Should be larger in trends } } ``` --- ## Part 5: Performance Targets ### Per-Component Latency | Component | Target | Notes | |-----------|--------|-------| | RSI | <50μs | Already meets target | | ATR | <50μs | Already meets target | | Hurst | <200μs | Acceptable for 20-bar window | | Autocorr | <100μs | Already meets target | | CUSUM | <100μs | Per update | | Regime Classification | <500μs | Per bar | | Position Sizing | <10μs | Lookup + multiply | | Dynamic Stops | <10μs | Lookup + calculate | | **Total Per Bar** | **<1ms** | Combined workflow | ### Accuracy Targets | Metric | Target | Measurement | |--------|--------|-------------| | Trending Detection | 85%+ | vs labeled data | | Ranging Detection | 85%+ | vs labeled data | | Changepoint Delay | 1-5 bars | bars after actual break | | Regime Persistence | >10 bars | min duration | | False Positive Rate | <5% | regime flips per 100 bars | --- ## Summary **To implement Wave D:** 1. **Use existing code** for RSI, ATR, Bollinger, Hurst, Autocorr (no rebuilding) 2. **Import from** `ml::features::feature_extraction` and `ml::features::price_features` 3. **Create new files** for CUSUM, regime classifiers, adaptive strategies 4. **Follow TDD**: Tests before implementation 5. **Measure**: Latency targets per component 6. **Integrate**: Link changepoint → regime → strategy **Files Already Available**: - `/home/jgrusewski/Work/foxhunt/ml/src/features/feature_extraction.rs` (RSI, ATR, Bollinger) - `/home/jgrusewski/Work/foxhunt/ml/src/features/price_features.rs` (Hurst) - `/home/jgrusewski/Work/foxhunt/ml/src/features/statistical_features.rs` (Autocorr) - `/home/jgrusewski/Work/foxhunt/adaptive-strategy/src/regime/mod.rs` (Framework) **Files to Create** (11 files, ~3,600 lines): - cusum.rs, bayesian_changepoint.rs, multi_cusum.rs - trending.rs, ranging.rs, volatile.rs, transition_matrix.rs - position_sizer.rs, dynamic_stops.rs, performance_tracker.rs, ensemble.rs