# BLOCKER 1 Investigation Report: MLFeatureExtractor Analysis **Date**: 2025-10-19 **Investigator**: Agent using Zen MCP + Task Tool **Status**: Investigation Complete **Verdict**: MLFeatureExtractor is NOT obsolete - needs careful update --- ## Executive Summary **VERDICT: Option B - Careful Update Required** `common::MLFeatureExtractor` is **NOT obsolete** and is **actively used in production paths**. However, it is critically outdated and extracting only **30 features instead of 225**. The `ml::features::extraction` module serves a **different purpose** (training-time batch feature extraction) while `MLFeatureExtractor` serves **inference-time streaming** feature extraction in production trading. **Critical Finding**: This is a **HIGH-RISK BLOCKER** affecting live trading decisions. All 5 ML models are receiving incomplete feature vectors (30/225 = 13.3% completeness), potentially causing severely degraded predictions. --- ## Comparison: MLFeatureExtractor vs ml::features::extraction | Aspect | `common::MLFeatureExtractor` | `ml::features::extraction` | |---|---|---| | **Purpose** | Inference-time streaming (online) | Training-time batch processing (offline) | | **Input** | Single price/volume/timestamp | Array of OHLCV bars | | **Output** | `Vec` (variable length) | `Vec<[f64; 256]>` (fixed 256-dim) | | **State** | Stateful (maintains rolling windows) | Stateless (processes entire bar array) | | **Features** | 30 (Wave A + 4 Wave C) | 256 (full feature set) | | **Usage** | Production trading (real-time) | Model training (batch) | | **Location** | `common/src/ml_strategy.rs` | `ml/src/features/extraction.rs` | | **Dependencies** | None (self-contained) | Requires 50+ bars warmup | | **Architecture** | Streaming feature extraction | Batch feature extraction | **Key Difference**: These are **NOT interchangeable**. They serve different architectural purposes. --- ## Production Usage Confirmed **File**: `common/src/ml_strategy.rs:1423` ```rust pub fn new(lookback_periods: usize, min_confidence_threshold: f64) -> Self { Self { models: Arc::new(RwLock::new(models)), feature_extractor: Arc::new(RwLock::new(MLFeatureExtractor::new_wave_d(lookback_periods))), // ← PRODUCTION USE model_performance: Arc::new(RwLock::new(HashMap::new())), min_confidence_threshold, } } ``` **Production Call Sites**: 1. Trading Agent Service → AssetSelector → MLFeatureExtractor (assets.rs:136) 2. Trading Service → SharedMLStrategy → MLFeatureExtractor (ml_strategy.rs:1423) --- ## Current vs Expected State **Current State** (30 features): - Wave A: 26 features (5 OHLCV + 21 technical) - Wave C: 4 features (OBV Momentum, Volume Oscillator, A/D Line, EMA Ratio) - **Total: 30 features** **Expected State** (225 features): - Wave A: 26 features - Wave C Initial: 4 features - Wave C Advanced: 175 features (3 microstructure + 10 alternative bars + 162 fractional diff) - Wave D: 24 features (10 CUSUM + 5 ADX + 5 Transition Probs + 4 Adaptive Metrics) - **Total: 229 features** (or 225 if we optimize) **Missing: 195 features (86.7% gap)** --- ## Risk Assessment ### What Breaks If We Change It? 1. **Model Dimension Mismatch**: - All trained models expect 256 features (as per Wave D spec) - Current inference provides 30 features - Gap: 226 features (88% missing) - Impact: Models are either zero-padding (degraded accuracy) or throwing errors 2. **Test Dependencies**: - 31 tests in `common/tests/` depend on 30-feature output - Tests explicitly assert: `assert_eq!(features.len(), 30)` - All tests currently passing (false security) 3. **Production Services**: - SharedMLStrategy used in Trading Service and Trading Agent Service - Change affects ALL live trading decisions --- ## Recommendation: Safe Migration Path ### Phase 1: Extend MLFeatureExtractor (2-3 hours) Add Wave C Advanced Features (175 features): - Microstructure (3) - Alternative bars (10) - Fractional differentiation (162) Add Wave D Regime Features (24 features): - CUSUM statistics (10) - ADX directional (5) - Transition probabilities (5) - Adaptive metrics (4) ### Phase 2: Update Model Adapters (1 hour) Extend SimpleDQNAdapter to support 225 features: ```rust pub fn with_feature_count(model_id: String, feature_count: usize) -> Self { let weights = match feature_count { 26 => vec![0.02; 26], // Wave A 30 => vec![0.02; 30], // Wave A + 4 Wave C 36 => vec![0.02; 36], // Wave B 65 => vec![0.02; 65], // Wave C partial 225 => vec![0.01; 225], // Wave D (NEW) _ => panic!("Unsupported feature count: {}", feature_count), }; // ... } ``` ### Phase 3: Test Migration (2 hours) Update tests to expect 225 features: ```rust #[test] fn test_wave_d_feature_extraction() { let mut extractor = MLFeatureExtractor::new_wave_d(20); let features = extractor.extract_features(100.0, 1000.0, Utc::now()); assert_eq!(features.len(), 225, "Wave D must extract 225 features"); } ``` ### Phase 4: Gradual Rollout (1 hour) 1. Keep legacy constructor (`MLFeatureExtractor::new()` → 30 features) 2. Use new constructor (`MLFeatureExtractor::new_wave_d()` → 225 features) in SharedMLStrategy 3. Monitor production prediction quality --- ## Final Verdict **DO NOT REPLACE MLFeatureExtractor with ml::features::extraction** **REASON**: They serve fundamentally different purposes: - **MLFeatureExtractor**: Streaming inference (real-time trading) - **ml::features::extraction**: Batch training (offline model training) **CORRECT ACTION**: **Update MLFeatureExtractor** to extract all 225 Wave D features while maintaining its streaming architecture. **ESTIMATED EFFORT**: 6-8 hours total - 2-3 hours: Implementation - 2 hours: Testing - 2-3 hours: Validation **PRIORITY**: **CRITICAL** - This blocker prevents Wave D regime detection from functioning correctly in production. --- ## Next Steps Based on this investigation, we should proceed with: 1. Implementing Wave C advanced features in MLFeatureExtractor 2. Implementing Wave D regime features in MLFeatureExtractor 3. Updating model adapters to support 225 features 4. Updating tests to validate 225-feature extraction 5. Gradual rollout with production monitoring **DO NOT** attempt to replace MLFeatureExtractor with ml::features::extraction - they are fundamentally incompatible.