run_replay.py 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. from __future__ import annotations
  2. from pathlib import Path
  3. import argparse
  4. import json
  5. import sys
  6. ROOT = Path(__file__).resolve().parents[1]
  7. SRC = ROOT / "src"
  8. SIM_SRC = ROOT / "simulation" / "src"
  9. for path in (str(SRC), str(SIM_SRC)):
  10. if path not in sys.path:
  11. sys.path.insert(0, path)
  12. from hermes_sim.candles import load_candles_csv
  13. from hermes_sim.harness import ReplayConfig, rows_to_jsonl, run_replay
  14. def main() -> int:
  15. parser = argparse.ArgumentParser(description="Replay Hermes decisions from historic candles.")
  16. parser.add_argument("--candles", required=True, help="Path to a CSV with timestamp,open,high,low,close,volume columns")
  17. parser.add_argument("--symbol", default="XRPUSD")
  18. parser.add_argument("--base", default="XRP")
  19. parser.add_argument("--quote", default="USD")
  20. parser.add_argument("--account-id", default="sim-account")
  21. parser.add_argument("--fee-rate", type=float, default=0.004)
  22. parser.add_argument("--horizon-bars", type=int, default=30)
  23. parser.add_argument("--lookback-bars", type=int, default=2000, help="How many most-recent 1m candles to use for feature/regime computation")
  24. parser.add_argument("--progress-every", type=int, default=2000, help="Print progress every N replay rows")
  25. parser.add_argument("--base-balance", type=float, default=500.0)
  26. parser.add_argument("--quote-balance", type=float, default=500.0)
  27. parser.add_argument("--inventory-state", default="balanced")
  28. parser.add_argument("--rebalance-needed", action="store_true")
  29. parser.add_argument("--out", help="Optional JSONL output file")
  30. args = parser.parse_args()
  31. candles = load_candles_csv(args.candles)
  32. config = ReplayConfig(
  33. market_symbol=args.symbol,
  34. base_currency=args.base,
  35. quote_currency=args.quote,
  36. account_id=args.account_id,
  37. fee_rate=args.fee_rate,
  38. horizon_bars=args.horizon_bars,
  39. base_balance=args.base_balance,
  40. quote_balance=args.quote_balance,
  41. inventory_state=args.inventory_state,
  42. rebalance_needed=args.rebalance_needed,
  43. )
  44. rows = run_replay(candles=candles, config=config, lookback_bars=args.lookback_bars, progress_every=args.progress_every)
  45. output = rows_to_jsonl(rows)
  46. if args.out:
  47. Path(args.out).write_text(output + ("\n" if output else ""), encoding="utf-8")
  48. else:
  49. print(output)
  50. summary = {
  51. "candles": len(candles),
  52. "rows": len(rows),
  53. "avg_score": round(sum(r.score for r in rows) / len(rows), 4) if rows else 0.0,
  54. }
  55. print(json.dumps(summary, indent=2), file=sys.stderr)
  56. return 0
  57. if __name__ == "__main__":
  58. raise SystemExit(main())