CRITICAL FINDING: RegimeAdaptiveFeatures (Features 221-224) are fully implemented but NOT integrated into trading decision flow. Analysis Results: - ✅ RegimeAdaptiveFeatures: 644 lines, 12/12 tests passing - ✅ Database schema: regime_states, regime_transitions, adaptive_strategy_metrics - ✅ gRPC endpoints: GetRegimeState, GetRegimeTransitions defined - ❌ Trading Agent Service: NO regime integration in allocation.rs - ❌ Order Generation: NO stop-loss multiplier application Impact: - ML models train with regime features - Production trading IGNORES regime state - Position sizes remain STATIC (no 0.2x-1.5x adjustment) - Expected Sharpe improvement: 0% (instead of +25-50%) Integration Plan (11 hours): 1. Phase 1: Database query layer (2h) - regime.rs 2. Phase 2: Allocation integration (3h) - RegimeAdaptive method 3. Phase 3: Service wiring (2h) - RegimeDetector in service 4. Phase 4: Order generation (1h) - stop-loss multipliers 5. Phase 5: Testing (3h) - regime allocation tests Code Changes: - New files: regime.rs (200 lines), tests (300 lines) - Modified: allocation.rs (+100), service.rs (+50), orders.rs (+30) - Total: ~500 new lines, ~180 modified lines Performance: +3ms latency (acceptable for +25-50% Sharpe) Risk: Low (feature flag + 3-level rollback plan) Recommendation: PROCEED before 225-feature ML retraining Files: - AGENT_WIRE02_ADAPTIVE_SIZER_INTEGRATION.md (full analysis) - AGENT_WIRE02_QUICK_SUMMARY.md (executive summary) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
14 KiB
AGENT WIRE-14: Paper Trading Executor Wave D Integration Status
Agent: WIRE-14 Mission: Verify paper trading executor uses Wave D features and adaptive sizing Status: ⚠️ PARTIAL INTEGRATION - Missing Wave D Features Priority: HIGH - Paper trading must test Wave D before live deployment Date: 2025-10-19
Executive Summary
The paper trading executor (services/trading_service/src/paper_trading_executor.rs) currently uses SharedMLStrategy but is NOT configured for Wave D features. Critical gaps identified:
- ✅ Uses
SharedMLStrategy(ONE SINGLE SYSTEM architecture) - ❌ NO Wave D feature configuration - Uses hardcoded defaults (20 lookback, 0.6 confidence)
- ❌ NO regime state queries - Does not check
regime_statestable - ❌ NO adaptive position sizing - Uses fixed 1.0 contract size
- ⚠️ Kelly Criterion mentioned but not implemented (line 569 comment only)
Risk: Paper trading will test Wave C baseline (201 features) instead of Wave D (225 features + regime detection).
Code Analysis
1. ML Strategy Initialization
File: services/trading_service/src/paper_trading_executor.rs
Lines: 154-157
pub fn new(db_pool: PgPool, config: PaperTradingConfig) -> Self {
// Initialize with shared ML strategy (default configuration)
let ml_strategy = SharedMLStrategy::new(20, 0.6);
// ^^^ HARDCODED: 20 lookback, 0.6 confidence - NO Wave D config
Issue: SharedMLStrategy::new() does NOT accept FeatureConfig parameter. The constructor signature is:
pub fn new(lookback_periods: usize, min_confidence_threshold: f64) -> Self
Missing: No way to pass FeatureConfig::wave_d() to enable 225-feature extraction.
2. Position Sizing Logic
File: services/trading_service/src/paper_trading_executor.rs
Lines: 567-575
fn calculate_position_size(&self, _prediction: &PendingPrediction) -> Result<f64> {
// Simple fixed position size for paper trading
// In production, this could use Kelly Criterion or volatility-adjusted sizing
let position_size = 1.0; // 1 contract
// ^^^ FIXED SIZE: No adaptive sizing based on regime or confidence
if position_size > self.config.max_position_size {
return Err(anyhow!("Position size {} exceeds maximum {}", position_size, self.config.max_position_size));
}
Ok(position_size)
}
Missing Wave D Adaptive Logic:
- No regime state queries (
SELECT regime FROM regime_states) - No adaptive multipliers (0.2x-1.5x based on regime)
- No Kelly Criterion position sizing
- No volatility-adjusted sizing
Expected Behavior (from Wave D design):
// Query regime state
let regime = sqlx::query!("SELECT regime FROM get_latest_regime($1)", symbol)
.fetch_one(&self.db_pool).await?;
// Apply regime-adaptive multiplier
let base_size = 1.0;
let regime_multiplier = match regime.regime.as_str() {
"Trending" => 1.5, // Increase size in trending markets
"Ranging" => 0.8, // Reduce size in ranging markets
"Volatile" => 0.5, // Minimize size in volatile markets
"Transition" => 0.2, // Avoid trading during transitions
_ => 1.0, // Normal sizing for unknown regimes
};
let position_size = base_size * regime_multiplier * confidence_factor;
3. Regime State Integration
Search Results: ❌ NO regime queries found in paper_trading_executor.rs
$ grep -rn "regime_states\|regime_transitions\|get_latest_regime" \
services/trading_service/src/paper_trading_executor.rs
# Result: 0 matches
Contrast with trading.rs (Trading Service):
// services/trading_service/src/services/trading.rs:992-1023
async fn get_regime_state(&self, req: Request<GetRegimeStateRequest>) -> Result<Response<GetRegimeStateResponse>, Status> {
let regime_state = sqlx::query!(
r#"SELECT regime, confidence, detected_at FROM get_latest_regime($1)"#,
req.symbol
).fetch_one(&self.db_pool).await?;
Ok(Response::new(GetRegimeStateResponse {
current_regime: regime_state.regime.unwrap_or("Normal".to_string()),
confidence: regime_state.confidence.unwrap_or(0.0),
// ...
}))
}
Paper Trading Executor: No equivalent logic.
4. Feature Configuration Architecture
Analysis: SharedMLStrategy uses MLFeatureExtractor which has a legacy field for feature count:
File: common/src/ml_strategy.rs (lines 66-84)
pub struct MLFeatureExtractor {
pub lookback_periods: usize,
/// Expected feature count (26=Wave A, 30=Wave A+4 extra, 36=Wave B, 65=Wave C)
expected_feature_count: usize, // ❌ Outdated comment - no Wave D (225)
price_history: Vec<f64>,
volume_history: Vec<f64>,
// ...
}
Problem: MLFeatureExtractor does NOT use FeatureConfig from ml/src/features/config.rs which supports Wave D:
File: ml/src/features/config.rs (lines 345-355)
pub fn wave_d() -> Self {
Self {
enable_wave_a: true,
enable_wave_b: true,
enable_wave_c: true,
enable_wave_d_regime: true, // ✅ Enables 24 regime features (201→225)
// ...
}
}
Root Cause: Architecture mismatch between common::ml_strategy (legacy extractor) and ml::features::config (Wave D-aware).
Integration Gaps
Gap 1: No Wave D Feature Config
Current: SharedMLStrategy::new(20, 0.6) - hardcoded defaults
Required: Pass FeatureConfig::wave_d() to enable 225-feature extraction
Blocker: SharedMLStrategy constructor does NOT accept FeatureConfig
Solution:
// Option A: Add new constructor
impl SharedMLStrategy {
pub fn new_with_feature_config(
lookback: usize,
confidence: f64,
feature_config: FeatureConfig,
) -> Self {
// ...
}
}
// Option B: Modify existing constructor
pub fn new(
lookback: usize,
confidence: f64,
feature_config: Option<FeatureConfig>,
) -> Self {
let config = feature_config.unwrap_or(FeatureConfig::wave_a());
// ...
}
Gap 2: No Regime State Queries
Current: No database queries for regime_states or regime_transitions
Required: Query latest regime before position sizing decisions
Blocker: Database access exists (self.db_pool) but not used
Solution:
async fn get_regime_for_symbol(&self, symbol: &str) -> Result<RegimeState> {
let regime = sqlx::query!(
r#"
SELECT regime, confidence, detected_at
FROM get_latest_regime($1)
"#,
symbol
)
.fetch_one(&self.db_pool)
.await
.context("Failed to fetch regime state")?;
Ok(RegimeState {
regime: regime.regime.unwrap_or("Normal".to_string()),
confidence: regime.confidence.unwrap_or(0.0),
detected_at: regime.detected_at,
})
}
Gap 3: No Adaptive Position Sizing
Current: Fixed 1.0 contract size (line 570) Required: Regime-adaptive sizing (0.2x-1.5x) + confidence-based Kelly multiplier Blocker: Regime state not queried, Kelly logic not implemented
Solution:
async fn calculate_adaptive_position_size(
&self,
prediction: &PendingPrediction,
) -> Result<f64> {
// Step 1: Get regime state
let regime = self.get_regime_for_symbol(&prediction.symbol).await?;
// Step 2: Apply regime-adaptive multiplier (Wave D design)
let regime_multiplier = match regime.regime.as_str() {
"Trending" => 1.5,
"Ranging" => 0.8,
"Volatile" => 0.5,
"Transition" => 0.2,
_ => 1.0,
};
// Step 3: Apply confidence-based Kelly multiplier
// Kelly formula: f* = (p*b - q) / b
// For trading: simplified to linear confidence scaling
let confidence_factor = prediction.ensemble_confidence.clamp(0.6, 1.0);
let kelly_multiplier = (confidence_factor - 0.6) / 0.4; // 0.6→0.0, 1.0→1.0
// Step 4: Calculate final position size
let base_size = 1.0; // Base contract size
let adaptive_size = base_size * regime_multiplier * (1.0 + kelly_multiplier);
// Step 5: Apply safety limits
Ok(adaptive_size.clamp(0.2, 5.0))
}
Testing Implications
Current Paper Trading Behavior
- Feature Set: Uses Wave C baseline (201 features) - NO regime detection
- Position Sizing: Fixed 1.0 contracts - NO adaptive sizing
- Regime Awareness: None - trades blindly across all market conditions
Expected Wave D Behavior
- Feature Set: 225 features (201 + 24 regime detection)
- Position Sizing: 0.2x-1.5x adaptive multipliers based on regime
- Regime Awareness: Queries
regime_states, avoids transitions
Risk Assessment
⚠️ HIGH RISK: Paper trading will NOT validate Wave D features before production deployment.
Scenario: If paper trading passes with Wave C config, we have NO evidence that:
- 225-feature extraction works in production
- Regime detection improves performance
- Adaptive sizing reduces drawdowns
Recommendation: Block production deployment until paper trading uses Wave D config.
Action Items
Priority 1: Enable Wave D Features (2 hours)
- Modify
SharedMLStrategy::new()to acceptFeatureConfigparameter - Update
paper_trading_executor.rsto useFeatureConfig::wave_d() - Verify 225-feature extraction in paper trading logs
Priority 2: Implement Regime Queries (1 hour)
- Add
get_regime_for_symbol()method toPaperTradingExecutor - Query
regime_statestable before each trade - Log regime transitions for debugging
Priority 3: Adaptive Position Sizing (2 hours)
- Replace
calculate_position_size()withcalculate_adaptive_position_size() - Implement regime multipliers (0.2x-1.5x)
- Add confidence-based Kelly multiplier
- Validate position size range (0.2-5.0 contracts)
Priority 4: Testing & Validation (1 hour)
- Run paper trading with ES.FUT, NQ.FUT for 24 hours
- Monitor regime transitions vs. position sizing
- Compare performance: Wave C baseline vs. Wave D adaptive
- Document results in
PAPER_TRADING_WAVE_D_VALIDATION.md
Total Effort: 6 hours
Technical Debt
Issue 1: Architecture Mismatch
Problem: common::ml_strategy::MLFeatureExtractor does NOT use ml::features::config::FeatureConfig.
Current State:
MLFeatureExtractorhas hardcoded feature count expectations (comment: "26=Wave A, 36=Wave B, 65=Wave C")- No mention of Wave D (225 features)
- No integration with
FeatureConfig::wave_d()
Solution:
// common/src/ml_strategy.rs
pub struct MLFeatureExtractor {
pub lookback_periods: usize,
feature_config: ml::features::config::FeatureConfig, // ✅ Use canonical config
price_history: Vec<f64>,
// ...
}
impl MLFeatureExtractor {
pub fn new(lookback: usize, feature_config: FeatureConfig) -> Self {
Self {
lookback_periods: lookback,
feature_config,
// ...
}
}
}
Blocker: Cross-crate dependency (common depends on ml).
Issue 2: Kelly Criterion Stub
Problem: Line 569 comment says "could use Kelly Criterion" but NOT implemented.
Current Code:
// In production, this could use Kelly Criterion or volatility-adjusted sizing
let position_size = 1.0; // 1 contract
Required Implementation:
use risk::kelly_sizing::{KellyResult, KellySizer};
async fn calculate_kelly_position(&self, prediction: &PendingPrediction) -> Result<f64> {
// Query historical performance for win rate
let win_rate = self.get_strategy_win_rate(&prediction.symbol).await?;
// Use ensemble confidence as win probability
let win_prob = prediction.ensemble_confidence;
let loss_prob = 1.0 - win_prob;
// Expected profit/loss ratio (from historical data)
let profit_loss_ratio = 1.5; // 1.5:1 risk/reward
// Kelly formula: f* = (p*b - q) / b
let kelly_fraction = (win_prob * profit_loss_ratio - loss_prob) / profit_loss_ratio;
// Use fractional Kelly (25%) for safety
let fractional_kelly = kelly_fraction * 0.25;
Ok(fractional_kelly.clamp(0.0, 1.0))
}
Existing Code: services/trading_service/src/core/risk_manager.rs has KellySizer but NOT used in paper trading.
References
Codebase Files
services/trading_service/src/paper_trading_executor.rs(897 lines)common/src/ml_strategy.rs(MLFeatureExtractor definition)ml/src/features/config.rs(FeatureConfig::wave_d() implementation)services/trading_service/src/services/trading.rs(GetRegimeState gRPC method)services/trading_service/src/core/risk_manager.rs(KellySizer implementation)
Database Schema
migrations/045_regime_detection.sql(regime_states, regime_transitions tables)- Stored function:
get_latest_regime(symbol TEXT)
Wave D Documentation
CLAUDE.md(Wave D Phase 6 status, production targets)WAVE_D_DEPLOYMENT_GUIDE.md(regime detection integration guide)WAVE_D_QUICK_REFERENCE.md(adaptive sizing formulas)
Conclusion
Status: ⚠️ PARTIAL INTEGRATION - CRITICAL GAPS
The paper trading executor is architecturally sound (uses SharedMLStrategy, ONE SINGLE SYSTEM) but NOT configured for Wave D testing:
- ❌ No 225-feature extraction (stuck on Wave C baseline)
- ❌ No regime state queries (blind to market conditions)
- ❌ No adaptive position sizing (fixed 1.0 contracts)
Recommendation: BLOCK production deployment until paper trading validates Wave D features. Implement action items (6 hours) and run 24-hour validation before proceeding.
Next Agent: WIRE-15 should implement calculate_adaptive_position_size() with regime multipliers and Kelly logic.
Agent WIRE-14 signing off. Mission: PARTIAL - Integration gaps identified, action plan provided. Handoff: WIRE-15 (Adaptive Position Sizing Implementation)