feat(proto): add epoch financial metrics + GetEpochHistory to monitoring.proto
Add 11 financial fields (sharpe, sortino, win_rate, max_drawdown, profit_factor, total_return, avg_return, total_trades, action distribution) to TrainingSession (fields 36-46), a new GetEpochHistory RPC with request/response messages, and wire the Prometheus metric mapping in the monitoring service with a stub RPC handler for task 7. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,10 @@ service MonitoringService {
|
||||
// Server-streaming: pushes updates every N seconds
|
||||
rpc StreamTrainingMetrics(StreamTrainingMetricsRequest)
|
||||
returns (stream GetLiveTrainingMetricsResponse);
|
||||
|
||||
// Epoch history for a specific session (ring buffer, max 50 epochs)
|
||||
rpc GetEpochHistory(GetEpochHistoryRequest)
|
||||
returns (GetEpochHistoryResponse);
|
||||
}
|
||||
|
||||
message GetLiveTrainingMetricsRequest {
|
||||
@@ -81,6 +85,20 @@ message TrainingSession {
|
||||
uint32 hyperopt_trial_epoch = 33;
|
||||
float hyperopt_trial_best_loss = 34;
|
||||
float hyperopt_elapsed_seconds = 35;
|
||||
|
||||
// Epoch-level financial metrics
|
||||
float epoch_sharpe = 36;
|
||||
float epoch_sortino = 37;
|
||||
float epoch_win_rate = 38;
|
||||
float epoch_max_drawdown = 39;
|
||||
float epoch_profit_factor = 40;
|
||||
float epoch_total_return = 41;
|
||||
float epoch_avg_return = 42;
|
||||
uint32 epoch_total_trades = 43;
|
||||
// Action distribution
|
||||
float action_buy_pct = 44;
|
||||
float action_sell_pct = 45;
|
||||
float action_hold_pct = 46;
|
||||
}
|
||||
|
||||
message GpuSnapshot {
|
||||
@@ -90,3 +108,33 @@ message GpuSnapshot {
|
||||
float temperature_celsius = 4;
|
||||
float power_watts = 5;
|
||||
}
|
||||
|
||||
message GetEpochHistoryRequest {
|
||||
string model = 1;
|
||||
string fold = 2;
|
||||
uint32 max_epochs = 3; // 0 = all (up to 50)
|
||||
}
|
||||
|
||||
message EpochFinancialSnapshot {
|
||||
uint32 epoch = 1;
|
||||
float sharpe = 2;
|
||||
float sortino = 3;
|
||||
float win_rate = 4;
|
||||
float max_drawdown = 5;
|
||||
float profit_factor = 6;
|
||||
float total_return = 7;
|
||||
float avg_return = 8;
|
||||
uint32 total_trades = 9;
|
||||
float loss = 10;
|
||||
float val_loss = 11;
|
||||
float learning_rate = 12;
|
||||
float action_buy_pct = 13;
|
||||
float action_sell_pct = 14;
|
||||
float action_hold_pct = 15;
|
||||
}
|
||||
|
||||
message GetEpochHistoryResponse {
|
||||
string model = 1;
|
||||
string fold = 2;
|
||||
repeated EpochFinancialSnapshot epochs = 3;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,10 @@ service MonitoringService {
|
||||
// Server-streaming: pushes updates every N seconds
|
||||
rpc StreamTrainingMetrics(StreamTrainingMetricsRequest)
|
||||
returns (stream GetLiveTrainingMetricsResponse);
|
||||
|
||||
// Epoch history for a specific session (ring buffer, max 50 epochs)
|
||||
rpc GetEpochHistory(GetEpochHistoryRequest)
|
||||
returns (GetEpochHistoryResponse);
|
||||
}
|
||||
|
||||
message GetLiveTrainingMetricsRequest {
|
||||
@@ -81,6 +85,20 @@ message TrainingSession {
|
||||
uint32 hyperopt_trial_epoch = 33;
|
||||
float hyperopt_trial_best_loss = 34;
|
||||
float hyperopt_elapsed_seconds = 35;
|
||||
|
||||
// Epoch-level financial metrics
|
||||
float epoch_sharpe = 36;
|
||||
float epoch_sortino = 37;
|
||||
float epoch_win_rate = 38;
|
||||
float epoch_max_drawdown = 39;
|
||||
float epoch_profit_factor = 40;
|
||||
float epoch_total_return = 41;
|
||||
float epoch_avg_return = 42;
|
||||
uint32 epoch_total_trades = 43;
|
||||
// Action distribution
|
||||
float action_buy_pct = 44;
|
||||
float action_sell_pct = 45;
|
||||
float action_hold_pct = 46;
|
||||
}
|
||||
|
||||
message GpuSnapshot {
|
||||
@@ -90,3 +108,33 @@ message GpuSnapshot {
|
||||
float temperature_celsius = 4;
|
||||
float power_watts = 5;
|
||||
}
|
||||
|
||||
message GetEpochHistoryRequest {
|
||||
string model = 1;
|
||||
string fold = 2;
|
||||
uint32 max_epochs = 3; // 0 = all (up to 50)
|
||||
}
|
||||
|
||||
message EpochFinancialSnapshot {
|
||||
uint32 epoch = 1;
|
||||
float sharpe = 2;
|
||||
float sortino = 3;
|
||||
float win_rate = 4;
|
||||
float max_drawdown = 5;
|
||||
float profit_factor = 6;
|
||||
float total_return = 7;
|
||||
float avg_return = 8;
|
||||
uint32 total_trades = 9;
|
||||
float loss = 10;
|
||||
float val_loss = 11;
|
||||
float learning_rate = 12;
|
||||
float action_buy_pct = 13;
|
||||
float action_sell_pct = 14;
|
||||
float action_hold_pct = 15;
|
||||
}
|
||||
|
||||
message GetEpochHistoryResponse {
|
||||
string model = 1;
|
||||
string fold = 2;
|
||||
repeated EpochFinancialSnapshot epochs = 3;
|
||||
}
|
||||
|
||||
@@ -8,8 +8,9 @@ use tonic::{Request, Response, Status};
|
||||
use tracing::error;
|
||||
|
||||
use crate::monitoring::{
|
||||
monitoring_service_server::MonitoringService, GetLiveTrainingMetricsRequest,
|
||||
GetLiveTrainingMetricsResponse, GpuSnapshot, StreamTrainingMetricsRequest, TrainingSession,
|
||||
monitoring_service_server::MonitoringService, GetEpochHistoryRequest,
|
||||
GetEpochHistoryResponse, GetLiveTrainingMetricsRequest, GetLiveTrainingMetricsResponse,
|
||||
GpuSnapshot, StreamTrainingMetricsRequest, TrainingSession,
|
||||
};
|
||||
use crate::prometheus_client::{MetricSample, PrometheusClient};
|
||||
|
||||
@@ -92,6 +93,16 @@ impl MonitoringService for MonitoringServiceImpl {
|
||||
|
||||
Ok(Response::new(Box::pin(stream)))
|
||||
}
|
||||
|
||||
async fn get_epoch_history(
|
||||
&self,
|
||||
_request: Request<GetEpochHistoryRequest>,
|
||||
) -> Result<Response<GetEpochHistoryResponse>, Status> {
|
||||
// TODO(task-7): wire to epoch ring buffer storage
|
||||
Err(Status::unimplemented(
|
||||
"GetEpochHistory not yet wired — see task 7",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Group flat metric samples into TrainingSession structs keyed by (model, fold)
|
||||
@@ -178,6 +189,29 @@ fn group_into_sessions(samples: &[MetricSample], model_filter: &str) -> Vec<Trai
|
||||
"foxhunt_hyperopt_elapsed_seconds" => {
|
||||
session.hyperopt_elapsed_seconds = s.value as f32;
|
||||
}
|
||||
// Epoch-level financial metrics
|
||||
"foxhunt_training_epoch_sharpe" => session.epoch_sharpe = s.value as f32,
|
||||
"foxhunt_training_epoch_sortino" => session.epoch_sortino = s.value as f32,
|
||||
"foxhunt_training_epoch_win_rate" => session.epoch_win_rate = s.value as f32,
|
||||
"foxhunt_training_epoch_max_drawdown" => {
|
||||
session.epoch_max_drawdown = s.value as f32;
|
||||
}
|
||||
"foxhunt_training_epoch_profit_factor" => {
|
||||
session.epoch_profit_factor = s.value as f32;
|
||||
}
|
||||
"foxhunt_training_epoch_total_return" => {
|
||||
session.epoch_total_return = s.value as f32;
|
||||
}
|
||||
"foxhunt_training_epoch_avg_return" => {
|
||||
session.epoch_avg_return = s.value as f32;
|
||||
}
|
||||
"foxhunt_training_epoch_total_trades" => {
|
||||
session.epoch_total_trades = s.value as u32;
|
||||
}
|
||||
// Action distribution
|
||||
"foxhunt_training_action_buy_pct" => session.action_buy_pct = s.value as f32,
|
||||
"foxhunt_training_action_sell_pct" => session.action_sell_pct = s.value as f32,
|
||||
"foxhunt_training_action_hold_pct" => session.action_hold_pct = s.value as f32,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user