diff --git a/frontend/src/views/live/New.vue b/frontend/src/views/live/New.vue index 76fbedf..2d5d27a 100644 --- a/frontend/src/views/live/New.vue +++ b/frontend/src/views/live/New.vue @@ -19,7 +19,7 @@ const isPortfolio = computed(() => strategyType.value === 'portfolio') const portfolioOptions = ref([]) const portfolioStrategy = ref('all_weather') -const poolForm = ref({ pool: 'all', max_pool: 30, benchmark: '000300.XSHG' }) +const poolForm = ref({ pool: 'all', max_pool: 0, benchmark: '000300.XSHG' }) const POOL_OPTIONS = [ { label: 'HS300 子集(小范围验证)', value: 'hs300_subset' }, { label: '全市场', value: 'all' }, diff --git a/frontend/src/views/paper/New.vue b/frontend/src/views/paper/New.vue index bbe5088..64a6ded 100644 --- a/frontend/src/views/paper/New.vue +++ b/frontend/src/views/paper/New.vue @@ -27,7 +27,7 @@ const instancesOfCta = computed(() => { const file = classToFile.value[form.value.strategies[0]?.name] return file ? instanceOptions.value.filter((i) => i.code_file === file) : instanceOptions.value }) -const poolForm = reactive({ pool: 'all', max_pool: 30, benchmark: '000300.XSHG' }) +const poolForm = reactive({ pool: 'all', max_pool: 0, benchmark: '000300.XSHG' }) const POOL_OPTIONS = [ { label: 'HS300 子集(小范围验证)', value: 'hs300_subset' }, { label: '全市场', value: 'all' }, diff --git a/sanguo_api/routes_live.py b/sanguo_api/routes_live.py index b5b760d..3227a47 100644 --- a/sanguo_api/routes_live.py +++ b/sanguo_api/routes_live.py @@ -139,7 +139,7 @@ def create_live(req: LiveCreateRequest): if not payload.get("strategy_class"): raise HTTPException(400, "组合实盘需选择策略(strategy_class)") payload.setdefault("pool", "all") - payload.setdefault("max_pool", 30) + payload.setdefault("max_pool", 0) payload.setdefault("benchmark", "000300.XSHG") payload["vt_symbol"] = payload["pool"] # 周期由前端下拉传(miniQMT 成品K线档位);空=默认日线 diff --git a/sanguo_api/routes_paper.py b/sanguo_api/routes_paper.py index cca218e..c6e2339 100644 --- a/sanguo_api/routes_paper.py +++ b/sanguo_api/routes_paper.py @@ -62,7 +62,7 @@ class PaperCreateRequest(BaseModel): # 撮合引擎(影子柜台 P1):eod_replay=日终回放(NAS 20:30) / shadow=影子柜台(VPS 盘中实时) engine: str = "eod_replay" pool: str = "all" - max_pool: int = 30 + max_pool: int = 0 benchmark: str = "000300.XSHG" # §12.6 实例做实:账户绑档案;空=发起即建档(自动创建实例再发起) instance_id: int | None = None diff --git a/sanguo_live/runner.py b/sanguo_live/runner.py index 596e201..a190664 100644 --- a/sanguo_live/runner.py +++ b/sanguo_live/runner.py @@ -349,7 +349,7 @@ def _portfolio_env_for(account_row: dict[str, Any], db_path: str) -> dict[str, s "SANGUO_QMT_ACCOUNT": account_row.get("account", ""), "SANGUO_QMT_PATH": account_row.get("mini_path", ""), "SANGUO_LIVE_STRATEGY": account_row.get("strategy_class", "all_weather"), - "SANGUO_LIVE_MAX_POOL": str(account_row.get("max_pool", 30) or 30), + "SANGUO_LIVE_MAX_POOL": str(account_row.get("max_pool", 0) or 0), "SANGUO_LIVE_BENCHMARK": account_row.get("benchmark", "000300.XSHG"), "SANGUO_LIVE_CASH": str(account_row.get("initial_capital", 1_000_000)), "SANGUO_LIVE_DB": db_path, diff --git a/sanguo_portfolio/live_strategy.py b/sanguo_portfolio/live_strategy.py index d2a9910..5b21840 100644 --- a/sanguo_portfolio/live_strategy.py +++ b/sanguo_portfolio/live_strategy.py @@ -7,7 +7,7 @@ sanguo_portfolio 的 StrategyTemplate 策略挂到 run_daily/run_monthly 定时 配置从 env 读(supervisor 注入,或手动 set 后直跑 ``python -m sanguo_portfolio.runner_live``): SANGUO_LIVE_STRATEGY all_weather / momentum_timing / value_selection / small_cap - SANGUO_LIVE_MAX_POOL 选股池上限(默认 30) + SANGUO_LIVE_MAX_POOL 选股池上限(默认 0=不限;>0 截断成份池前 N 只) 数据 provider 由 runner_live ``set_data_provider`` 先行注入(miniQMT live 模式)。 @@ -45,7 +45,7 @@ def _build_live_strategy(provider): ) name = os.environ.get("SANGUO_LIVE_STRATEGY", "all_weather") - max_pool = int(os.environ.get("SANGUO_LIVE_MAX_POOL", "30") or 30) + max_pool = int(os.environ.get("SANGUO_LIVE_MAX_POOL", "0") or 0) factories = { "all_weather": lambda: AllWeatherStrategy( provider=provider, config=AllWeatherConfig(max_pool=max_pool)), diff --git a/sanguo_portfolio/runner_live.py b/sanguo_portfolio/runner_live.py index 07e499d..0953c33 100644 --- a/sanguo_portfolio/runner_live.py +++ b/sanguo_portfolio/runner_live.py @@ -49,7 +49,7 @@ def live_env() -> Dict[str, str]: """解析 env 实盘配置(带默认值)。独立出来便于单测。""" return { "strategy": os.environ.get("SANGUO_LIVE_STRATEGY", "all_weather"), - "max_pool": os.environ.get("SANGUO_LIVE_MAX_POOL", "30"), + "max_pool": os.environ.get("SANGUO_LIVE_MAX_POOL", "0"), "benchmark": os.environ.get("SANGUO_LIVE_BENCHMARK", "000300.XSHG"), "cash": os.environ.get("SANGUO_LIVE_CASH", "1000000"), "account": os.environ.get("SANGUO_QMT_ACCOUNT", ""), diff --git a/sanguo_trader/portfolio_paper.py b/sanguo_trader/portfolio_paper.py index 90664d0..811d8c9 100644 --- a/sanguo_trader/portfolio_paper.py +++ b/sanguo_trader/portfolio_paper.py @@ -72,7 +72,7 @@ def run_portfolio_live_step(db_path: str, account_id: int, today: str | None = N raise ValueError("portfolio 账户缺少策略配置") strategy_name = strategies[0].get("name", "all_weather") pool = (json.loads(acc["symbols"] or "[]") or ["hs300_subset"])[0] - max_pool = int(strategies[0].get("params", {}).get("max_pool", 30)) + max_pool = int(strategies[0].get("params", {}).get("max_pool", 0)) benchmark = strategies[0].get("params", {}).get("benchmark", "000300.XSHG") from sanguo_portfolio.runner_backtest import run_backtest_json diff --git a/sanguo_trader/shadow/supervisor.py b/sanguo_trader/shadow/supervisor.py index ab06247..bdefa94 100644 --- a/sanguo_trader/shadow/supervisor.py +++ b/sanguo_trader/shadow/supervisor.py @@ -51,7 +51,7 @@ def account_env(acc: dict[str, Any], db_path: str) -> Dict[str, str]: env = dict(os.environ) env.update({ "SANGUO_LIVE_STRATEGY": name, - "SANGUO_LIVE_MAX_POOL": _num(params.get("max_pool", 30)), + "SANGUO_LIVE_MAX_POOL": _num(params.get("max_pool", 0)), "SANGUO_LIVE_BENCHMARK": str(params.get("benchmark", "000300.XSHG")), "SANGUO_LIVE_CASH": _num(acc.get("initial_capital") or 1_000_000), "SANGUO_SHADOW_DB": db_path, diff --git a/tests/api/test_portfolio_live.py b/tests/api/test_portfolio_live.py index 400cde2..fdae217 100644 --- a/tests/api/test_portfolio_live.py +++ b/tests/api/test_portfolio_live.py @@ -118,6 +118,13 @@ def test_portfolio_env_mapping(): assert env["SANGUO_LIVE_CASH"] == "2000000" assert env["SANGUO_LIVE_DB"] == "live.db" assert env["SANGUO_LIVE_ACCOUNT_ID"] == "7" + # 行缺 max_pool / 存 0 → env "0"(0=不限);显式 30 等存量值不篡改 + no_pool = {k: v for k, v in acc.items() if k != "max_pool"} + assert live_runner._portfolio_env_for(no_pool, "live.db")["SANGUO_LIVE_MAX_POOL"] == "0" + zero_pool = dict(acc, max_pool=0) + assert live_runner._portfolio_env_for(zero_pool, "live.db")["SANGUO_LIVE_MAX_POOL"] == "0" + kept = dict(acc, max_pool=30) + assert live_runner._portfolio_env_for(kept, "live.db")["SANGUO_LIVE_MAX_POOL"] == "30" def test_runner_live_env_defaults(monkeypatch): @@ -129,7 +136,7 @@ def test_runner_live_env_defaults(monkeypatch): monkeypatch.delenv(k, raising=False) cfg = runner_live.live_env() assert cfg["strategy"] == "all_weather" - assert cfg["max_pool"] == "30" + assert cfg["max_pool"] == "0" # 0=不限(2026-08-24 巡检:MVP 默认 30 泄漏生产致选股池失真) assert cfg["benchmark"] == "000300.XSHG" assert cfg["account"] == "" # 空 → run_live 拒绝启动(防误下单)