mirror of
https://github.com/xavierchuan/FX-ML-Trading-Engine.git
synced 2026-07-27 18:17:44 +00:00
91 lines
3.5 KiB
Python
91 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Append a metrics row using TCA summary + KPI overrides.
|
|
|
|
Example:
|
|
python scripts/update_metrics_from_tca.py \
|
|
--tca QuantTrader/results/execution/tca_summary.json \
|
|
--run-id 20251112_parallel_demo_live \
|
|
--status pass --latency-avg 28 --latency-p95 45 \
|
|
--total-pnl 27.3 --max-exposure 500000 --max-drawdown 0.02 \
|
|
--rolling-sharpe 1.5 --live-drawdown 0.03 \
|
|
--live-latency-p95 45 --slippage-bps 1.2
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import csv
|
|
import json
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(description="Append metrics row from TCA summary.")
|
|
parser.add_argument("--tca", required=True, help="Path to tca_summary.json")
|
|
parser.add_argument("--metrics", default="results/risk/metrics.csv", help="Metrics CSV path")
|
|
parser.add_argument("--run-id", required=True)
|
|
parser.add_argument("--status", default="pass")
|
|
parser.add_argument("--latency-avg", type=float, required=True)
|
|
parser.add_argument("--latency-p95", type=float, required=True)
|
|
parser.add_argument("--total-pnl", type=float, required=True)
|
|
parser.add_argument("--max-exposure", type=float, required=True)
|
|
parser.add_argument("--max-drawdown", type=float, required=True)
|
|
parser.add_argument("--rolling-sharpe", type=float, required=True)
|
|
parser.add_argument("--live-drawdown", type=float, required=True)
|
|
parser.add_argument("--live-latency-p95", type=float, required=True)
|
|
parser.add_argument("--slippage-bps", type=float, required=True)
|
|
parser.add_argument("--rejects", type=int, default=0)
|
|
parser.add_argument("--kills", type=int, default=0)
|
|
parser.add_argument("--max-gross-notional", type=float, default=0.0)
|
|
return parser.parse_args()
|
|
|
|
|
|
def main() -> None:
|
|
args = parse_args()
|
|
tca_path = Path(args.tca)
|
|
if not tca_path.exists():
|
|
raise SystemExit(f"TCA summary not found: {tca_path}")
|
|
with tca_path.open("r", encoding="utf-8") as f:
|
|
tca = json.load(f)
|
|
|
|
timestamp = datetime.now(timezone.utc).isoformat()
|
|
row = {
|
|
"timestamp": timestamp,
|
|
"run_id": args.run_id,
|
|
"rejects": args.rejects,
|
|
"kills": args.kills,
|
|
"status": args.status,
|
|
"latency_ms_avg": args.latency_avg,
|
|
"latency_ms_p95": args.latency_p95,
|
|
"total_pnl": args.total_pnl,
|
|
"max_gross_notional": args.max_gross_notional or args.max_exposure,
|
|
"max_symbol_exposure": args.max_exposure,
|
|
"max_drawdown_pct": args.max_drawdown,
|
|
"rolling_sharpe_30d": args.rolling_sharpe,
|
|
"live_drawdown_pct": args.live_drawdown,
|
|
"live_latency_ms_p95": args.live_latency_p95,
|
|
"slippage_bps": args.slippage_bps,
|
|
"paper_trade_count": tca.get("paper_trade_count"),
|
|
"paper_total_pnl": tca.get("paper_total_pnl"),
|
|
"live_trade_count": tca.get("live_trade_count"),
|
|
"live_total_pnl": tca.get("live_total_pnl"),
|
|
"pnl_diff_mean": tca.get("pnl_diff_mean"),
|
|
"pnl_diff_std": tca.get("pnl_diff_std"),
|
|
}
|
|
|
|
metrics_path = Path(args.metrics)
|
|
metrics_path.parent.mkdir(parents=True, exist_ok=True)
|
|
write_header = not metrics_path.exists()
|
|
with metrics_path.open("a", newline="", encoding="utf-8") as f:
|
|
writer = csv.DictWriter(f, fieldnames=row.keys())
|
|
if write_header:
|
|
writer.writeheader()
|
|
writer.writerow(row)
|
|
print(f"Appended metrics row for run={args.run_id}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|