feat(ml): wire Prometheus eval metrics into evaluate_baseline

Emit set_eval_metrics (win_rate, sharpe, profit_factor, return) per fold
for DQN/PPO evaluation. Start metrics server on :9094. Feeds training
cockpit Grafana dashboard eval panels.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-03-01 22:56:21 +01:00
parent 2cc68af7d6
commit 6c829d59a8

View File

@@ -29,6 +29,7 @@ use serde::Serialize;
use serde_json::Value;
use tracing::{error, info, warn};
use common::metrics::{server as metrics_server, training_metrics as tm};
use ml::dqn::{DQNConfig, DQN};
#[allow(unreachable_pub)]
@@ -645,6 +646,10 @@ fn main() -> Result<()> {
eprintln!("Observability init failed (non-fatal): {e}");
}
tm::init();
metrics_server::start_metrics_server(9094);
tm::set_active_workers(1.0);
let args = Args::parse();
let eval_dqn = args.model == "dqn" || args.model == "both";
@@ -667,7 +672,15 @@ fn main() -> Result<()> {
// 1. Load all OHLCV bars from DBN files
info!("Step 1/5: Loading OHLCV bars from DBN files...");
let data_load_start = std::time::Instant::now();
let bars = load_all_bars(&args.data_dir, &args.symbol)?;
let data_load_secs = data_load_start.elapsed().as_secs_f64();
if eval_dqn {
tm::record_data_load("dqn", data_load_secs);
}
if eval_ppo {
tm::record_data_load("ppo", data_load_secs);
}
if bars.is_empty() {
anyhow::bail!("No bars loaded from {}", args.data_dir.display());
}
@@ -781,16 +794,26 @@ fn main() -> Result<()> {
&hp,
) {
Ok((returns, action_counts)) => {
let metrics = compute_metrics(&returns);
let fold_metrics = compute_metrics(&returns);
let fold_str = window.fold.to_string();
tm::set_epoch("dqn", &fold_str, window.fold as f64);
tm::set_eval_metrics(
"dqn",
&fold_str,
fold_metrics.win_rate_pct / 100.0,
fold_metrics.sharpe_ratio,
fold_metrics.profit_factor,
fold_metrics.total_return_pct / 100.0,
);
info!(
" [DQN] Fold {} - Sharpe={:.4} MaxDD={:.2}% WinRate={:.1}% PF={:.2} Return={:.4}% Trades={}",
window.fold,
metrics.sharpe_ratio,
metrics.max_drawdown_pct,
metrics.win_rate_pct,
metrics.profit_factor,
metrics.total_return_pct,
metrics.num_trades,
fold_metrics.sharpe_ratio,
fold_metrics.max_drawdown_pct,
fold_metrics.win_rate_pct,
fold_metrics.profit_factor,
fold_metrics.total_return_pct,
fold_metrics.num_trades,
);
info!(
" [DQN] Actions - BUY={} SELL={} HOLD={}",
@@ -801,12 +824,12 @@ fn main() -> Result<()> {
all_fold_metrics.push(FoldMetrics {
fold: window.fold,
model: "dqn".to_owned(),
sharpe_ratio: metrics.sharpe_ratio,
max_drawdown_pct: metrics.max_drawdown_pct,
win_rate_pct: metrics.win_rate_pct,
profit_factor: metrics.profit_factor,
total_return_pct: metrics.total_return_pct,
num_trades: metrics.num_trades,
sharpe_ratio: fold_metrics.sharpe_ratio,
max_drawdown_pct: fold_metrics.max_drawdown_pct,
win_rate_pct: fold_metrics.win_rate_pct,
profit_factor: fold_metrics.profit_factor,
total_return_pct: fold_metrics.total_return_pct,
num_trades: fold_metrics.num_trades,
test_start: test_start.clone(),
test_end: test_end.clone(),
});
@@ -830,16 +853,26 @@ fn main() -> Result<()> {
&hp,
) {
Ok((returns, action_counts)) => {
let metrics = compute_metrics(&returns);
let fold_metrics = compute_metrics(&returns);
let fold_str = window.fold.to_string();
tm::set_epoch("ppo", &fold_str, window.fold as f64);
tm::set_eval_metrics(
"ppo",
&fold_str,
fold_metrics.win_rate_pct / 100.0,
fold_metrics.sharpe_ratio,
fold_metrics.profit_factor,
fold_metrics.total_return_pct / 100.0,
);
info!(
" [PPO] Fold {} - Sharpe={:.4} MaxDD={:.2}% WinRate={:.1}% PF={:.2} Return={:.4}% Trades={}",
window.fold,
metrics.sharpe_ratio,
metrics.max_drawdown_pct,
metrics.win_rate_pct,
metrics.profit_factor,
metrics.total_return_pct,
metrics.num_trades,
fold_metrics.sharpe_ratio,
fold_metrics.max_drawdown_pct,
fold_metrics.win_rate_pct,
fold_metrics.profit_factor,
fold_metrics.total_return_pct,
fold_metrics.num_trades,
);
info!(
" [PPO] Actions - BUY={} SELL={} HOLD={}",
@@ -850,12 +883,12 @@ fn main() -> Result<()> {
all_fold_metrics.push(FoldMetrics {
fold: window.fold,
model: "ppo".to_owned(),
sharpe_ratio: metrics.sharpe_ratio,
max_drawdown_pct: metrics.max_drawdown_pct,
win_rate_pct: metrics.win_rate_pct,
profit_factor: metrics.profit_factor,
total_return_pct: metrics.total_return_pct,
num_trades: metrics.num_trades,
sharpe_ratio: fold_metrics.sharpe_ratio,
max_drawdown_pct: fold_metrics.max_drawdown_pct,
win_rate_pct: fold_metrics.win_rate_pct,
profit_factor: fold_metrics.profit_factor,
total_return_pct: fold_metrics.total_return_pct,
num_trades: fold_metrics.num_trades,
test_start: test_start.clone(),
test_end: test_end.clone(),
});
@@ -917,5 +950,7 @@ fn main() -> Result<()> {
info!(" Report saved to: {}", args.output.display());
info!(" Total fold evaluations: {}", report.folds.len());
tm::set_active_workers(0.0);
Ok(())
}