Research-Stack/5-Applications/tools-scripts/infrastructure/run_paper_trading_cycle.py

126 lines
No EOL
5.3 KiB
Python

#!/usr/bin/env python3
# ==============================================================================
# COPYRIGHT NO ONE EVERYWHERE LLC (WYOMING HOLDING COMPANY)
# PROJECT: SOVEREIGN STACK
# This artifact is entirely proprietary and cryptographically proven.
# Open-Source usage requires explicit permission from Brandon Scott Schneider.
# ==============================================================================
"""Run paper-trading artifacts against a cycle directory with canonical paths."""
import argparse
from datetime import datetime, timezone
from pathlib import Path
try:
from scripts.paper_trading_simulator import (
finalize_one_page_summary,
run_fast_monte_carlo_sweep,
run_wall_clock_session,
)
except ModuleNotFoundError:
import sys
sys.path.insert(0, str(Path(__file__).resolve().parent))
from paper_trading_simulator import (
finalize_one_page_summary,
run_fast_monte_carlo_sweep,
run_wall_clock_session,
)
def summary_filename() -> str:
"""Return the default one-page summary filename for the current UTC date."""
return f"one_page_summary_filled_{datetime.now(timezone.utc).date().isoformat()}.md"
def cycle_paths(cycle_dir: Path) -> dict[str, Path]:
"""Return canonical artifact locations inside a cycle packet."""
return {
"fast_sweep_output": cycle_dir / "01_strategy_outputs" / "fast_monte_carlo_sweep.json",
"wall_clock_report": cycle_dir / "01_strategy_outputs" / "wall_clock_session_report.json",
"wall_clock_heartbeat": cycle_dir / "01_strategy_outputs" / "wall_clock_heartbeat.log",
"review_heartbeat": cycle_dir / "01_strategy_outputs" / "review_heartbeat.log",
"summary_output": cycle_dir / "08_summary_report" / summary_filename(),
"reconciliation_ledger": cycle_dir / "07_allocation_ledger" / "reconciliation_ledger.csv",
}
def parse_args() -> argparse.Namespace:
"""Parse CLI arguments for cycle-oriented paper trading runs."""
parser = argparse.ArgumentParser(description="Cycle-oriented paper trading runner")
parser.add_argument(
"--mode",
choices=["fast-sweep", "wall-clock", "finalize-summary", "print-paths"],
required=True,
help="Workflow step to run",
)
parser.add_argument("--cycle-dir", required=True, help="Cycle directory root")
parser.add_argument("--initial-usdc", type=float, default=30000.0, help="Initial USDC capital")
parser.add_argument("--duration-hours", type=float, default=4.0, help="Duration in hours")
parser.add_argument("--tick-interval-seconds", type=float, default=60.0, help="Tick interval in seconds")
parser.add_argument("--heartbeat-every-ticks", type=int, default=5, help="Heartbeat write interval")
parser.add_argument("--sweep-count", type=int, default=25, help="Monte Carlo path count")
parser.add_argument("--seed", type=int, help="Optional random seed")
parser.add_argument("--review-log", help="Optional explicit review heartbeat path")
parser.add_argument("--reviewer", default="system-generated", help="Reviewer label for summary output")
parser.add_argument("--objective-target", type=float, default=30000.0, help="Objective target value")
parser.add_argument("--gross-exit-ceiling", type=float, default=37000.0, help="Gross exit ceiling")
return parser.parse_args()
def main() -> None:
"""Entry point for canonical cycle runs."""
args = parse_args()
cycle_dir = Path(args.cycle_dir)
paths = cycle_paths(cycle_dir)
review_log_path = Path(args.review_log) if args.review_log else paths["review_heartbeat"]
if args.mode == "print-paths":
for key, value in paths.items():
print(f"{key}={value}")
return
if args.mode == "fast-sweep":
run_fast_monte_carlo_sweep(
initial_usdc=args.initial_usdc,
duration_hours=args.duration_hours,
tick_interval_seconds=args.tick_interval_seconds,
sweep_count=args.sweep_count,
output_path=paths["fast_sweep_output"],
seed=args.seed,
)
return
if args.mode == "wall-clock":
run_wall_clock_session(
initial_usdc=args.initial_usdc,
duration_hours=args.duration_hours,
tick_interval_seconds=args.tick_interval_seconds,
heartbeat_every_ticks=args.heartbeat_every_ticks,
output_path=paths["wall_clock_report"],
heartbeat_path=paths["wall_clock_heartbeat"],
cycle_dir=cycle_dir,
review_log_path=review_log_path if review_log_path.exists() else None,
summary_output_path=paths["summary_output"],
reviewer=args.reviewer,
objective_target=args.objective_target,
gross_exit_ceiling=args.gross_exit_ceiling,
seed=args.seed,
)
return
summary_path = finalize_one_page_summary(
cycle_dir=cycle_dir,
session_report_path=paths["wall_clock_report"],
heartbeat_log_path=paths["wall_clock_heartbeat"],
review_log_path=review_log_path if review_log_path.exists() else None,
summary_output_path=paths["summary_output"],
reviewer=args.reviewer,
objective_target=args.objective_target,
gross_exit_ceiling=args.gross_exit_ceiling,
)
print(f"summary_output={summary_path}")
if __name__ == "__main__":
main()