Extract 9 new sub-crates from the ml monolith to enable parallel compilation across the workspace: New crates (this commit): - ml-features (282 tests): feature engineering, 21 modules - ml-labeling (45 tests): triple barrier, meta-labeling, fractional diff - ml-ensemble (116 tests): ensemble coordination, voting, confidence - ml-hyperopt (47 tests): core PSO/TPE optimizer, parameter space - ml-checkpoint (41 tests): checkpoint persistence, compression, signing - ml-regime (68 tests): CUSUM, Bayesian changepoint, regime classification - ml-data-validation (67 tests): FDR correction, CPCV, data quality - ml-risk (33 tests): neural VaR, Kelly criterion, circuit breakers - ml-validation (43 tests): statistical validation, walk-forward, DSR Extended existing crates: - ml-dqn: added evaluation/ (backtesting engine, metrics, reports) and checkpoint implementation - ml-supervised: added checkpoint implementations - ml-core: added shared types needed by new sub-crates Pattern: each module in ml/ becomes a thin facade (pub use subcrate::*) with bridge modules staying in ml for cross-model adapter code. Dead code deleted (~7K lines): - 13 undeclared files in microstructure/ (never compiled) - 7 undeclared files + tests/ in risk/ (never compiled) - parquet_io, cache_service, cache_storage, minio_integration (unused) - extraction_wave_d_impl.rs (bare fn outside impl block) All 2,746 sub-crate tests + 951 ml tests pass. Full workspace builds clean. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
107 lines
2.6 KiB
Rust
107 lines
2.6 KiB
Rust
//! High-performance signal aggregation with SIMD optimization
|
|
//!
|
|
//! Ensemble aggregation for ML model predictions.
|
|
|
|
use std::collections::HashMap;
|
|
use std::sync::Arc;
|
|
|
|
use parking_lot::RwLock;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::confidence::ConfidenceCalculator;
|
|
use crate::weights::ModelWeights;
|
|
use crate::MLError;
|
|
|
|
/// Model signal structure
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct ModelSignal {
|
|
pub model_id: String,
|
|
pub signal: f32,
|
|
pub confidence: f32,
|
|
pub timestamp: u64,
|
|
pub metadata: SignalMetadata,
|
|
}
|
|
|
|
/// Signal metadata
|
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
|
pub struct SignalMetadata {
|
|
pub model_version: String,
|
|
pub features_used: Vec<String>,
|
|
pub prediction_horizon: u32,
|
|
}
|
|
|
|
/// Signal statistics
|
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
|
pub struct SignalStatistics {
|
|
pub total_signals: u64,
|
|
pub avg_confidence: f32,
|
|
pub accuracy_rate: f32,
|
|
pub last_updated: u64,
|
|
}
|
|
|
|
/// Signal aggregator configuration
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct AggregatorConfig {
|
|
pub max_signals: usize,
|
|
pub confidence_threshold: f32,
|
|
pub enable_simd: bool,
|
|
}
|
|
|
|
impl Default for AggregatorConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
max_signals: 100,
|
|
confidence_threshold: 0.5,
|
|
enable_simd: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Main signal aggregator
|
|
#[derive(Debug)]
|
|
pub struct SignalAggregator {
|
|
config: AggregatorConfig,
|
|
weights: ModelWeights,
|
|
confidence_calc: ConfidenceCalculator,
|
|
stats: Arc<RwLock<HashMap<String, SignalStatistics>>>,
|
|
}
|
|
|
|
impl SignalAggregator {
|
|
pub fn new(
|
|
config: AggregatorConfig,
|
|
weights: ModelWeights,
|
|
confidence_calc: ConfidenceCalculator,
|
|
) -> Self {
|
|
Self {
|
|
config,
|
|
weights,
|
|
confidence_calc,
|
|
stats: Arc::new(RwLock::new(HashMap::new())),
|
|
}
|
|
}
|
|
|
|
pub fn aggregate_signals(&self, signals: Vec<ModelSignal>) -> Result<f32, MLError> {
|
|
if signals.is_empty() {
|
|
return Ok(0.0);
|
|
}
|
|
|
|
// Simple weighted average for now
|
|
let mut weighted_sum = 0.0;
|
|
let mut total_weight = 0.0;
|
|
|
|
for signal in &signals {
|
|
if signal.confidence >= self.config.confidence_threshold {
|
|
let weight = 1.0; // Simplified - should use actual weights
|
|
weighted_sum += signal.signal * weight;
|
|
total_weight += weight;
|
|
}
|
|
}
|
|
|
|
if total_weight > 0.0 {
|
|
Ok(weighted_sum / total_weight)
|
|
} else {
|
|
Ok(0.0)
|
|
}
|
|
}
|
|
}
|