Zero-config monitor and compare

- `trader.py monitor` — runs ALL 9 strategies by default, $10k capital,
  $2 fee, integer shares. Just start and forget.
- `trader.py compare` — auto-discovers all state files in data/, no
  --strategy needed. Ranks by return with equity curves.
- Monitor defaults: --capital 10000, --fixed-fee 2.0, --integer-shares

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-07 00:10:00 +08:00
parent 7f618b9c31
commit 4aa17c7e98

View File

@@ -595,8 +595,31 @@ def cmd_status(args):
def cmd_compare(args):
"""Compare multiple strategies side-by-side."""
import glob as _glob
market = args.market
strategy_names = args.strategy
strategy_names = getattr(args, "strategy", None)
# Auto-discover: find all trader_{market}_*.json state files
if not strategy_names:
pattern = os.path.join("data", f"trader_{market}_*.json")
files = sorted(_glob.glob(pattern))
strategy_names = []
for f in files:
# Extract strategy name: trader_{market}_{name}.json
base = os.path.basename(f) # trader_us_foo.json
prefix = f"trader_{market}_"
name = base[len(prefix):-len(".json")]
# Skip sim_ prefixed (historical simulations) unless no live ones
strategy_names.append(name)
if not strategy_names:
print(f"No state files found for market '{market}' in data/.")
print(f"Run 'monitor' or 'auto' first to generate state.")
return
print(f" Auto-discovered {len(strategy_names)} strategies: "
f"{', '.join(strategy_names)}")
# Load all states
states = {}
@@ -1277,19 +1300,19 @@ def main():
# Monitor (long-running daemon for tmux) — supports multiple strategies
p_monitor = sub.add_parser("monitor",
help="Long-running daemon: auto-runs daily after market close (for tmux)")
help="Long-running daemon: runs ALL strategies daily (for tmux)")
p_monitor.add_argument("--market", choices=UNIVERSES.keys(), default="us")
p_monitor.add_argument("--strategy", nargs="+",
choices=list(STRATEGY_REGISTRY.keys()),
default=["recovery_mom_top10"],
help="One or more strategies to run in parallel")
p_monitor.add_argument("--capital", type=float, default=100_000)
default=list(STRATEGY_REGISTRY.keys()),
help="Strategies to run (default: ALL)")
p_monitor.add_argument("--capital", type=float, default=10_000)
p_monitor.add_argument("--tx-cost", type=float, default=0.001,
help="Proportional transaction cost (default: 0.001 = 10bps)")
p_monitor.add_argument("--fixed-fee", type=float, default=0.0,
help="Fixed dollar fee per trade")
p_monitor.add_argument("--integer-shares", action="store_true", default=False,
help="Only trade whole shares (no fractional)")
p_monitor.add_argument("--fixed-fee", type=float, default=2.0,
help="Fixed dollar fee per trade (default: $2)")
p_monitor.add_argument("--integer-shares", action="store_true", default=True,
help="Only trade whole shares (default: True)")
# Status (strategy is a free-form string to allow sim_ prefixed names)
p_status = sub.add_parser("status", help="Show current portfolio")
@@ -1316,10 +1339,11 @@ def main():
p_log.add_argument("--end", default=None, help="End date filter (YYYY-MM-DD)")
# Compare strategies
p_cmp = sub.add_parser("compare", help="Compare multiple strategies side-by-side")
p_cmp = sub.add_parser("compare",
help="Compare strategies side-by-side (auto-discovers all if no --strategy)")
p_cmp.add_argument("--market", choices=UNIVERSES.keys(), default="us")
p_cmp.add_argument("--strategy", nargs="+", required=True,
help="Strategy state names to compare (e.g. recovery_mom_top10 momentum)")
p_cmp.add_argument("--strategy", nargs="+", default=None,
help="Strategy names to compare (default: auto-discover all)")
args = parser.parse_args()