perf(monitor): refresh each price panel once per phase
Every strategy used to re-download its whole universe each phase (~75 downloads of 500+ tickers for the US book), which tripped Yahoo's rate limit. The monitor now refreshes each panel once for the union of tickers and runs strategies offline, like replay. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
30
trader.py
30
trader.py
@@ -820,6 +820,7 @@ def cmd_morning(args):
|
||||
# Download data (close + open)
|
||||
close_data, open_data, _ = load_strategy_prices(
|
||||
market, strategy_name, tickers, benchmark, with_open=True,
|
||||
refresh=getattr(args, "refresh", True),
|
||||
)
|
||||
tickers = filter_tradable_tickers(close_data, tickers)
|
||||
|
||||
@@ -1601,8 +1602,14 @@ def cmd_monitor(args):
|
||||
|
||||
market_fee = MARKET_FEES.get(market, args.fixed_fee)
|
||||
eligible = [s for s in strategies if strategy_supports_market(s, market)]
|
||||
# One download per price panel per phase; strategies then read offline.
|
||||
try:
|
||||
refresh_panels(market, eligible, label="monitor")
|
||||
except Exception as e:
|
||||
print(f"[monitor] Panel refresh failed ({e}); using stored prices")
|
||||
for strat_name in eligible:
|
||||
sub_args = copy.copy(args)
|
||||
sub_args.refresh = False
|
||||
sub_args.strategy = strat_name
|
||||
sub_args.market = market
|
||||
sub_args.fixed_fee = market_fee
|
||||
@@ -1695,6 +1702,18 @@ def cmd_monitor(args):
|
||||
print()
|
||||
|
||||
|
||||
def refresh_panels(market: str, strategy_names: list[str], label: str) -> None:
|
||||
"""Refresh every price panel the strategies read, once, for the union of their tickers."""
|
||||
requests: dict[str, set[str]] = {}
|
||||
for name in strategy_names:
|
||||
tickers, benchmark = strategy_universe(market, name)
|
||||
requests.setdefault(strategy_data_market(market, name), set()).update(
|
||||
price_request(market, list(tickers) + [benchmark]))
|
||||
for data_market, request in requests.items():
|
||||
print(f"[{label}] Refreshing {data_market} panel for {len(request)} tickers")
|
||||
data_manager.update(data_market, sorted(request), with_open=True)
|
||||
|
||||
|
||||
def _process_sessions(args, state: dict | None, start: pd.Timestamp | None = None,
|
||||
label: str = "auto", refresh: bool = True) -> dict | None:
|
||||
"""Run every completed session not yet recorded in ``state`` (catch-up safe).
|
||||
@@ -1762,7 +1781,7 @@ def cmd_auto(args):
|
||||
0 16 * * 1-5 cd /path/to/quant && uv run python trader.py auto --market cn
|
||||
"""
|
||||
state = load_state(args.market, args.strategy)
|
||||
state = _process_sessions(args, state)
|
||||
state = _process_sessions(args, state, refresh=getattr(args, "refresh", True))
|
||||
if state is not None:
|
||||
save_state(state, args.market, args.strategy)
|
||||
pnl = state["daily_equity"][state["last_evening"]] - state["initial_capital"]
|
||||
@@ -1786,14 +1805,7 @@ def cmd_replay(args):
|
||||
and n not in LIVE_EXCLUDED_STRATEGIES and strategy_supports_market(n, args.market)]
|
||||
|
||||
# Refresh each price panel once for the union of tickers, then replay offline.
|
||||
requests: dict[str, set[str]] = {}
|
||||
for name in live_names:
|
||||
tickers, benchmark = strategy_universe(args.market, name)
|
||||
requests.setdefault(strategy_data_market(args.market, name), set()).update(
|
||||
price_request(args.market, list(tickers) + [benchmark]))
|
||||
for data_market, request in requests.items():
|
||||
print(f"[replay] Refreshing {data_market} panel for {len(request)} tickers")
|
||||
data_manager.update(data_market, sorted(request), with_open=True)
|
||||
refresh_panels(args.market, live_names, label="replay")
|
||||
|
||||
for name in names:
|
||||
if name.startswith("sim_"):
|
||||
|
||||
Reference in New Issue
Block a user