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)
|
# Download data (close + open)
|
||||||
close_data, open_data, _ = load_strategy_prices(
|
close_data, open_data, _ = load_strategy_prices(
|
||||||
market, strategy_name, tickers, benchmark, with_open=True,
|
market, strategy_name, tickers, benchmark, with_open=True,
|
||||||
|
refresh=getattr(args, "refresh", True),
|
||||||
)
|
)
|
||||||
tickers = filter_tradable_tickers(close_data, tickers)
|
tickers = filter_tradable_tickers(close_data, tickers)
|
||||||
|
|
||||||
@@ -1601,8 +1602,14 @@ def cmd_monitor(args):
|
|||||||
|
|
||||||
market_fee = MARKET_FEES.get(market, args.fixed_fee)
|
market_fee = MARKET_FEES.get(market, args.fixed_fee)
|
||||||
eligible = [s for s in strategies if strategy_supports_market(s, market)]
|
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:
|
for strat_name in eligible:
|
||||||
sub_args = copy.copy(args)
|
sub_args = copy.copy(args)
|
||||||
|
sub_args.refresh = False
|
||||||
sub_args.strategy = strat_name
|
sub_args.strategy = strat_name
|
||||||
sub_args.market = market
|
sub_args.market = market
|
||||||
sub_args.fixed_fee = market_fee
|
sub_args.fixed_fee = market_fee
|
||||||
@@ -1695,6 +1702,18 @@ def cmd_monitor(args):
|
|||||||
print()
|
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,
|
def _process_sessions(args, state: dict | None, start: pd.Timestamp | None = None,
|
||||||
label: str = "auto", refresh: bool = True) -> dict | None:
|
label: str = "auto", refresh: bool = True) -> dict | None:
|
||||||
"""Run every completed session not yet recorded in ``state`` (catch-up safe).
|
"""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
|
0 16 * * 1-5 cd /path/to/quant && uv run python trader.py auto --market cn
|
||||||
"""
|
"""
|
||||||
state = load_state(args.market, args.strategy)
|
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:
|
if state is not None:
|
||||||
save_state(state, args.market, args.strategy)
|
save_state(state, args.market, args.strategy)
|
||||||
pnl = state["daily_equity"][state["last_evening"]] - state["initial_capital"]
|
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)]
|
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.
|
# Refresh each price panel once for the union of tickers, then replay offline.
|
||||||
requests: dict[str, set[str]] = {}
|
refresh_panels(args.market, live_names, label="replay")
|
||||||
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)
|
|
||||||
|
|
||||||
for name in names:
|
for name in names:
|
||||||
if name.startswith("sim_"):
|
if name.startswith("sim_"):
|
||||||
|
|||||||
Reference in New Issue
Block a user