feat(fxt): render epoch financial metrics in watch TUI list + detail views
Add Sharpe/Win% columns to training list table, financial summary lines (Sharpe, Sortino, Win Rate, Max DD, PF, Return, Avg, Trades) to the detail overview, action distribution (BUY/SELL/HOLD %) to current metrics, and four new sparklines (Sharpe, Win Rate, Max DD, Total Return) to the Metrics sub-tab. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -149,6 +149,8 @@ fn render_training_list(frame: &mut Frame, area: Rect, tab: &TrainingTabState) {
|
||||
Cell::from("LR"),
|
||||
Cell::from("Batch/s"),
|
||||
Cell::from("Grad"),
|
||||
Cell::from("Sharpe"),
|
||||
Cell::from("Win%"),
|
||||
])
|
||||
.style(
|
||||
Style::default()
|
||||
@@ -171,6 +173,8 @@ fn render_training_list(frame: &mut Frame, area: Rect, tab: &TrainingTabState) {
|
||||
Cell::from(format!("{:.2e}", s.learning_rate)),
|
||||
Cell::from(format!("{:.1}", s.batches_per_second)),
|
||||
Cell::from(format!("{:.3}", s.gradient_norm)),
|
||||
Cell::from(if s.epoch_sharpe != 0.0 { format!("{:.2}", s.epoch_sharpe) } else { "-".to_owned() }),
|
||||
Cell::from(if s.epoch_win_rate > 0.0 { format!("{:.0}%", s.epoch_win_rate * 100.0) } else { "-".to_owned() }),
|
||||
])
|
||||
})
|
||||
.collect();
|
||||
@@ -188,6 +192,8 @@ fn render_training_list(frame: &mut Frame, area: Rect, tab: &TrainingTabState) {
|
||||
Constraint::Length(10),
|
||||
Constraint::Length(8),
|
||||
Constraint::Length(8),
|
||||
Constraint::Length(8),
|
||||
Constraint::Length(8),
|
||||
],
|
||||
)
|
||||
.header(header)
|
||||
@@ -351,8 +357,8 @@ fn render_detail_overview(
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
Constraint::Length(8), // key stats
|
||||
Constraint::Min(0), // loss sparkline
|
||||
Constraint::Length(12), // key stats (incl. financial metrics)
|
||||
Constraint::Min(0), // loss sparkline
|
||||
])
|
||||
.split(area);
|
||||
|
||||
@@ -377,6 +383,17 @@ fn render_detail_overview(
|
||||
" NaN: {} Grad Explosions: {} Feature Errors: {}",
|
||||
session.nan_detected, session.gradient_explosions, session.feature_errors,
|
||||
)),
|
||||
Line::from(""),
|
||||
Line::from(format!(
|
||||
" Sharpe: {:.2} Sortino: {:.2} Win Rate: {:.1}% Max DD: {:.1}%",
|
||||
session.epoch_sharpe, session.epoch_sortino,
|
||||
session.epoch_win_rate * 100.0, session.epoch_max_drawdown * 100.0,
|
||||
)),
|
||||
Line::from(format!(
|
||||
" PF: {:.2} Return: {:+.2}% Avg: {:+.4} Trades: {}",
|
||||
session.epoch_profit_factor, session.epoch_total_return * 100.0,
|
||||
session.epoch_avg_return, session.epoch_total_trades,
|
||||
)),
|
||||
])
|
||||
.block(
|
||||
Block::default()
|
||||
@@ -454,7 +471,7 @@ fn render_detail_metrics(
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
Constraint::Length(5), // current values
|
||||
Constraint::Length(7), // current values (incl. action distribution)
|
||||
Constraint::Min(0), // sparklines
|
||||
])
|
||||
.split(area);
|
||||
@@ -468,6 +485,12 @@ fn render_detail_metrics(
|
||||
" Precision: {:.4} Recall: {:.4}",
|
||||
session.eval_precision, session.eval_recall,
|
||||
)),
|
||||
Line::from(format!(
|
||||
" Action: BUY {:.0}% SELL {:.0}% HOLD {:.0}%",
|
||||
session.action_buy_pct * 100.0,
|
||||
session.action_sell_pct * 100.0,
|
||||
session.action_hold_pct * 100.0,
|
||||
)),
|
||||
])
|
||||
.block(
|
||||
Block::default()
|
||||
@@ -479,10 +502,14 @@ fn render_detail_metrics(
|
||||
let spark_area = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
Constraint::Percentage(25),
|
||||
Constraint::Percentage(25),
|
||||
Constraint::Percentage(25),
|
||||
Constraint::Percentage(25),
|
||||
Constraint::Ratio(1, 8),
|
||||
Constraint::Ratio(1, 8),
|
||||
Constraint::Ratio(1, 8),
|
||||
Constraint::Ratio(1, 8),
|
||||
Constraint::Ratio(1, 8),
|
||||
Constraint::Ratio(1, 8),
|
||||
Constraint::Ratio(1, 8),
|
||||
Constraint::Ratio(1, 8),
|
||||
])
|
||||
.split(chunks[1]);
|
||||
|
||||
@@ -490,6 +517,10 @@ fn render_detail_metrics(
|
||||
render_sparkline_row(frame, spark_area[1], "Precision", &history.precision, 1.0, Color::Cyan);
|
||||
render_sparkline_row(frame, spark_area[2], "Recall", &history.recall, 1.0, Color::Magenta);
|
||||
render_sparkline_row(frame, spark_area[3], "F1", &history.f1, 1.0, Color::Yellow);
|
||||
render_sparkline_row(frame, spark_area[4], "Sharpe", &history.sharpe, 20.0, Color::Cyan);
|
||||
render_sparkline_row(frame, spark_area[5], "Win Rate", &history.win_rate, 1.0, Color::Green);
|
||||
render_sparkline_row(frame, spark_area[6], "Max DD", &history.max_drawdown, 1.0, Color::Red);
|
||||
render_sparkline_row(frame, spark_area[7], "Total Return", &history.total_return, 1.0, Color::Magenta);
|
||||
}
|
||||
|
||||
fn render_detail_hyperopt(
|
||||
|
||||
Reference in New Issue
Block a user