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>
111 lines
3.7 KiB
Rust
111 lines
3.7 KiB
Rust
//! Position Sizing Neural Networks for HFT Risk Management
|
|
//!
|
|
//! Implements advanced neural networks for position sizing that enhance
|
|
//! Kelly criterion optimization with market microstructure insights.
|
|
|
|
use ndarray::Array1;
|
|
|
|
use crate::MLResult as Result;
|
|
|
|
// Using placeholder type for PositionSizingRecommendation
|
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
|
pub struct PositionSizingRecommendation {
|
|
pub recommended_size: f64,
|
|
pub max_size: f64,
|
|
pub confidence: f64,
|
|
}
|
|
|
|
// CIRCULAR DEPENDENCY FIX: Use MarketRegime from core types
|
|
use common::trading::MarketRegime;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct PositionSizingConfig {
|
|
pub max_position_size: f64,
|
|
pub min_position_size: f64,
|
|
pub regime_scaling: bool,
|
|
}
|
|
|
|
impl Default for PositionSizingConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
max_position_size: 1.0,
|
|
min_position_size: 0.01,
|
|
regime_scaling: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct PositionSizingNetwork {
|
|
config: PositionSizingConfig,
|
|
}
|
|
|
|
impl PositionSizingNetwork {
|
|
pub fn new(config: PositionSizingConfig) -> Result<Self> {
|
|
Ok(Self { config })
|
|
}
|
|
|
|
pub fn calculate_regime_scaling(&self, regime: MarketRegime) -> Result<f64> {
|
|
match regime {
|
|
MarketRegime::Normal => Ok(1.0),
|
|
MarketRegime::Crisis => Ok(0.5),
|
|
MarketRegime::Trending => Ok(1.2),
|
|
MarketRegime::Sideways => Ok(0.8),
|
|
MarketRegime::Bull => Ok(1.3),
|
|
MarketRegime::Bear => Ok(0.6),
|
|
}
|
|
}
|
|
|
|
pub fn softmax_activation(&self, input: &Array1<f64>) -> Result<Array1<f64>> {
|
|
let max_val = input.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b));
|
|
let exp_values: Vec<f64> = input.iter().map(|&x| (x - max_val).exp()).collect();
|
|
let sum: f64 = exp_values.iter().sum();
|
|
let result: Vec<f64> = exp_values.iter().map(|&x| x / sum).collect();
|
|
Ok(Array1::from_vec(result))
|
|
}
|
|
}
|
|
|
|
// DISABLED: Tests
|
|
// // #[cfg(test)]
|
|
// mod tests {
|
|
// use super::*;
|
|
// // use crate::safe_operations; // DISABLED - module not found
|
|
//
|
|
// #[test]
|
|
// fn test_regime_scaling() {
|
|
// let config = PositionSizingConfig::default();
|
|
// let network = PositionSizingNetwork::new(config)?;
|
|
//
|
|
// let crisis_scaling = network.calculate_regime_scaling(MarketRegime::Crisis)?;
|
|
// let bull_scaling = network.calculate_regime_scaling(MarketRegime::Bull)?;
|
|
// let normal_scaling = network.calculate_regime_scaling(MarketRegime::Normal)?;
|
|
//
|
|
// assert!(crisis_scaling < normal_scaling); // Crisis should reduce positions
|
|
// assert!(bull_scaling > normal_scaling); // Bull should increase positions
|
|
// assert_eq!(normal_scaling, 1.0); // Normal should be baseline
|
|
// assert_eq!(crisis_scaling, 0.5); // Crisis should be 50% of normal
|
|
// }
|
|
//
|
|
// #[test]
|
|
// fn test_softmax_activation() {
|
|
// let config = PositionSizingConfig::default();
|
|
// let network = PositionSizingNetwork::new(config)?;
|
|
//
|
|
// let input = Array1::from_vec(vec![1.0, 2.0, 0.5]);
|
|
// let output = network.softmax_activation(&input)?;
|
|
//
|
|
// // Check that outputs sum to approximately 1
|
|
// let sum: f64 = output.iter().sum();
|
|
// assert!((sum - 1.0).abs() < 0.01); // Within 1% tolerance
|
|
//
|
|
// // Check that all outputs are positive
|
|
// for &val in &output {
|
|
// assert!(val > 0.0);
|
|
// }
|
|
//
|
|
// // Check that the softmax ordering is preserved (higher input -> higher output)
|
|
// assert!(output[1] > output[0]); // input[1]=2.0 > input[0]=1.0
|
|
// assert!(output[0] > output[2]); // input[0]=1.0 > input[2]=0.5
|
|
// }
|
|
// }
|