diff --git a/bridge.py b/bridge.py index 1b77058..1e127b7 100644 --- a/bridge.py +++ b/bridge.py @@ -380,6 +380,12 @@ STRATEGY_META = { "params": {}, "markets": ["us"], }, + "trend_rider_v7_vt36": { + "label": "Trend Rider V7 (VT36% + PT30) ★ SOTA", + "category": "tactical_allocation", + "params": {}, + "markets": ["us"], + }, # --- Stock-picker ensembles (US S&P 500 universe) --- "ensemble_alpha_top10": { "label": "Ensemble Alpha Top 10", diff --git a/trader.py b/trader.py index e9d2eab..0a5f944 100644 --- a/trader.py +++ b/trader.py @@ -178,6 +178,7 @@ STRATEGY_REGISTRY = { "trend_rider_v7": lambda **kw: TrendRiderV7(), "trend_rider_v7_vt24": lambda **kw: TrendRiderV7(target_vol=0.24, min_lev=0.5), "trend_rider_v7_vt32": lambda **kw: TrendRiderV7(target_vol=0.32, min_lev=0.7), + "trend_rider_v7_vt36": lambda **kw: TrendRiderV7(target_vol=0.36, min_lev=0.75), # --- Stock-picker ensemble strategies (S&P 500 universe) --- "ensemble_alpha_top10": lambda **kw: EnsembleAlphaStrategy(top_n=10), "ensemble_alpha_top12": lambda **kw: EnsembleAlphaStrategy(top_n=12), @@ -222,6 +223,7 @@ ETF_STRATEGY_UNIVERSES = { "trend_rider_v7": sorted(set(ETF_UNIVERSE)), "trend_rider_v7_vt24": sorted(set(ETF_UNIVERSE)), "trend_rider_v7_vt32": sorted(set(ETF_UNIVERSE)), + "trend_rider_v7_vt36": sorted(set(ETF_UNIVERSE)), } # Strategies that use the market's stock universe PLUS fixed extra ETF tickers. @@ -1296,6 +1298,7 @@ def cmd_monitor(args): print(f" Evening: {sched['eve_h']:02d}:{sched['eve_m']:02d} {sched['tz']}") print(f" Fixed fee: {fee:.2f}/trade") print(f" Strategies: {', '.join(strategies)}") + print(f" Auto-reload: ON (new strategies picked up each phase)") print(f"{'='*60}") # Use UTC as common reference for sleeping @@ -1328,12 +1331,34 @@ def cmd_monitor(args): all_candidates.extend(_next_events_for_market(mkt, now_utc)) return min(all_candidates, key=lambda x: x[0]) + def _reload_strategies(): + """Re-read STRATEGY_REGISTRY to pick up new strategies without restart.""" + import importlib + import trader as _self_mod + importlib.reload(_self_mod) + current = list(_self_mod.STRATEGY_REGISTRY.keys()) + return current, _self_mod.STRATEGY_REGISTRY + def _run_phase(market, phase, now_utc): """Run all strategies for a market/phase.""" + nonlocal strategies sched = market_schedules[market] tz = sched["tz"] now_local = now_utc.astimezone(tz) + # Hot-reload strategy list from registry + try: + reloaded_names, reloaded_reg = _reload_strategies() + new_strats = set(reloaded_names) - set(strategies) + if new_strats: + print(f"[monitor] Hot-reload: +{len(new_strats)} new strategies: " + f"{', '.join(sorted(new_strats))}") + strategies = reloaded_names + # Update the global registry so cmd_morning/cmd_auto use new strategies + globals().update({"STRATEGY_REGISTRY": reloaded_reg}) + except Exception as e: + print(f"[monitor] Hot-reload failed (using cached list): {e}") + print(f"\n[monitor] {'='*55}") print(f"[monitor] {market.upper()} {phase.upper()} at " f"{now_local.strftime('%Y-%m-%d %H:%M:%S %Z')}") @@ -1370,7 +1395,7 @@ def cmd_monitor(args): traceback.print_exc() print(f"[monitor] {market.upper()} {phase} done — " - f"{len(strategies)} strategies") + f"{len(strategies)} strategies\n") while True: now_utc = datetime.now(utc)