🔧 Wave 33: Partial TimeDelta Migration - ML Crate Complete

## Progress Update
-  ml/src/features.rs: Complete TimeDelta migration (6 fixes)
-  ml/src/training_pipeline.rs: Complete TimeDelta migration (3 fixes)
- ⚠️  backtesting crate: Needs TimeDelta migration
- ⚠️  trading_service: Needs TimeDelta migration
- ⚠️  ml_training_service: Needs TimeDelta migration

## Fixes Applied
- Added TimeDelta to imports across ml crate
- Converted Duration::hours/days/minutes → TimeDelta::hours/days/minutes
- Added TimeDelta::from_std() conversions for std::time::Duration
- Fixed method calls: as_secs_f64() → num_milliseconds() / 1000.0

## Next Steps
Deploy parallel agents to complete migration workspace-wide

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2025-10-01 20:36:58 +02:00
parent 3cc57a068b
commit bb1042b848
2 changed files with 17 additions and 14 deletions

View File

@@ -16,7 +16,7 @@ use common::types::{Price, Quantity, Volume, Symbol};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use chrono::{DateTime, Utc}; use chrono::{DateTime, TimeDelta, Utc};
use rand::prelude::*; use rand::prelude::*;
use rust_decimal::prelude::ToPrimitive; use rust_decimal::prelude::ToPrimitive;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -985,15 +985,15 @@ impl UnifiedFeatureExtractor {
let news_sentiment_1h = alt_data let news_sentiment_1h = alt_data
.news_data .news_data
.as_ref() .as_ref()
.and_then(|news| self.calculate_news_sentiment_score(news, Duration::hours(1))); .and_then(|news| self.calculate_news_sentiment_score(news, TimeDelta::hours(1)));
let news_sentiment_1d = alt_data let news_sentiment_1d = alt_data
.news_data .news_data
.as_ref() .as_ref()
.and_then(|news| self.calculate_news_sentiment_score(news, Duration::days(1))); .and_then(|news| self.calculate_news_sentiment_score(news, TimeDelta::days(1)));
let news_volume_1h = alt_data let news_volume_1h = alt_data
.news_data .news_data
.as_ref() .as_ref()
.map(|news| self.calculate_news_volume(news, Duration::hours(1))); .map(|news| self.calculate_news_volume(news, TimeDelta::hours(1)));
// Social media sentiment // Social media sentiment
let social_sentiment = alt_data let social_sentiment = alt_data
@@ -1332,13 +1332,13 @@ impl UnifiedFeatureExtractor {
news_data: Some(NewsData { news_data: Some(NewsData {
articles: vec![ articles: vec![
NewsArticle { NewsArticle {
timestamp: Utc::now() - Duration::minutes(30), timestamp: Utc::now() - TimeDelta::minutes(30),
sentiment_score: 0.65, sentiment_score: 0.65,
relevance_score: 0.8, relevance_score: 0.8,
title: "Sample positive news".to_string(), title: "Sample positive news".to_string(),
}, },
NewsArticle { NewsArticle {
timestamp: Utc::now() - Duration::hours(2), timestamp: Utc::now() - TimeDelta::hours(2),
sentiment_score: -0.3, sentiment_score: -0.3,
relevance_score: 0.6, relevance_score: 0.6,
title: "Sample negative news".to_string(), title: "Sample negative news".to_string(),
@@ -1358,7 +1358,7 @@ impl UnifiedFeatureExtractor {
}), }),
earnings_data: Some(EarningsData { earnings_data: Some(EarningsData {
latest_surprise: Some(0.12), // 12% earnings surprise latest_surprise: Some(0.12), // 12% earnings surprise
next_earnings_date: Utc::now() + Duration::days(45), next_earnings_date: Utc::now() + TimeDelta::days(45),
}), }),
options_data: Some(OptionsData { options_data: Some(OptionsData {
put_call_ratio: 0.85, put_call_ratio: 0.85,

View File

@@ -8,7 +8,7 @@
use common::types::Price; use common::types::Price;
use std; use std;
use chrono::{DateTime, Utc}; use chrono::{DateTime, TimeDelta, Utc};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use std::time::Instant; use std::time::Instant;
@@ -201,7 +201,7 @@ pub struct ProductionTrainingMetrics {
pub nan_detections: usize, pub nan_detections: usize,
/// Training performance /// Training performance
pub epoch_duration: Duration, pub epoch_duration: TimeDelta,
pub memory_usage_bytes: usize, pub memory_usage_bytes: usize,
pub gpu_utilization: Option<f64>, pub gpu_utilization: Option<f64>,
@@ -339,8 +339,10 @@ impl ProductionMLTrainingSystem {
}; };
// Collect comprehensive metrics // Collect comprehensive metrics
let elapsed = epoch_start.elapsed();
let epoch_duration = TimeDelta::from_std(elapsed).unwrap_or(TimeDelta::zero());
let epoch_metrics = self let epoch_metrics = self
.collect_epoch_metrics(epoch, train_loss, val_loss, epoch_start.elapsed()) .collect_epoch_metrics(epoch, train_loss, val_loss, epoch_duration)
.await?; .await?;
training_metrics.push(epoch_metrics.clone()); training_metrics.push(epoch_metrics.clone());
@@ -353,7 +355,7 @@ impl ProductionMLTrainingSystem {
train_loss, train_loss,
val_loss, val_loss,
epoch_metrics.learning_rate, epoch_metrics.learning_rate,
epoch_metrics.epoch_duration.as_secs_f64() epoch_metrics.epoch_duration.num_milliseconds() as f64 / 1000.0
); );
// Early stopping logic // Early stopping logic
@@ -401,6 +403,7 @@ impl ProductionMLTrainingSystem {
history.extend(training_metrics.clone()); history.extend(training_metrics.clone());
let training_duration = training_start.elapsed(); let training_duration = training_start.elapsed();
let training_duration_td = TimeDelta::from_std(training_duration).unwrap_or(TimeDelta::zero());
info!( info!(
"Training completed in {:.2}s. Best validation loss: {:.6}", "Training completed in {:.2}s. Best validation loss: {:.6}",
training_duration.as_secs_f64(), training_duration.as_secs_f64(),
@@ -414,7 +417,7 @@ impl ProductionMLTrainingSystem {
.map(|m| m.train_loss) .map(|m| m.train_loss)
.unwrap_or(f64::NAN), .unwrap_or(f64::NAN),
final_val_loss: best_val_loss, final_val_loss: best_val_loss,
training_duration, training_duration: training_duration_td,
epochs_trained: training_metrics.len(), epochs_trained: training_metrics.len(),
metrics_history: training_metrics, metrics_history: training_metrics,
convergence_achieved: best_val_loss < f64::INFINITY, convergence_achieved: best_val_loss < f64::INFINITY,
@@ -692,7 +695,7 @@ impl ProductionMLTrainingSystem {
epoch: usize, epoch: usize,
train_loss: f64, train_loss: f64,
val_loss: f64, val_loss: f64,
duration: Duration, duration: TimeDelta,
) -> SafetyResult<ProductionTrainingMetrics> { ) -> SafetyResult<ProductionTrainingMetrics> {
let grad_manager = self.gradient_manager.lock().await; let grad_manager = self.gradient_manager.lock().await;
let gradient_stats = grad_manager.get_statistics().await; let gradient_stats = grad_manager.get_statistics().await;
@@ -737,7 +740,7 @@ pub struct TrainingResult {
pub model_id: Uuid, pub model_id: Uuid,
pub final_train_loss: f64, pub final_train_loss: f64,
pub final_val_loss: f64, pub final_val_loss: f64,
pub training_duration: Duration, pub training_duration: TimeDelta,
pub epochs_trained: usize, pub epochs_trained: usize,
pub metrics_history: Vec<ProductionTrainingMetrics>, pub metrics_history: Vec<ProductionTrainingMetrics>,
pub convergence_achieved: bool, pub convergence_achieved: bool,