From 234b44e1417adda0cfc34e2fb441250ebfc59496 Mon Sep 17 00:00:00 2001 From: claude_dev Date: Fri, 14 Aug 2026 08:30:56 +0800 Subject: [PATCH] =?UTF-8?q?feat(live):=20CTA=E5=AE=9E=E7=9B=98vt=5Fsymbol?= =?UTF-8?q?=E8=A3=B86=E4=BD=8D=E7=A0=81=E8=87=AA=E5=8A=A8=E8=A1=A5?= =?UTF-8?q?=E4=BA=A4=E6=98=93=E6=89=80=E5=90=8E=E7=BC=80(6=E2=86=92SSE,0/3?= =?UTF-8?q?=E2=86=92SZSE);=E8=A1=A8=E5=8D=95=E6=8F=90=E7=A4=BA+=E5=8D=95?= =?UTF-8?q?=E7=AD=96=E7=95=A5=E5=8E=9F=E5=9B=A0=E8=AF=B4=E6=98=8E(?= =?UTF-8?q?=E5=AE=9E=E7=9B=98=E9=9C=80A=E8=82=A1=E9=80=82=E9=85=8D,?= =?UTF-8?q?=E9=99=86=E7=BB=AD=E6=89=A9=E5=B1=95)=20[nas]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/views/live/New.vue | 6 +++--- sanguo_api/routes_live.py | 15 +++++++++++++++ tests/api/test_portfolio_live.py | 13 +++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/frontend/src/views/live/New.vue b/frontend/src/views/live/New.vue index aa01aa6..7840a46 100644 --- a/frontend/src/views/live/New.vue +++ b/frontend/src/views/live/New.vue @@ -195,15 +195,15 @@ async function onSubmit(): Promise { :value="opt.value" /> - MVP 仅支持 AShareDoubleMaStrategy + 实盘需 A 股适配(定寸/禁空/分钟合成),目前仅 DoubleMa 完成适配,其余策略陆续扩展 engine 内唯一 - - 交易所代码 .SSE / .SZSE + + 可只写 6 位代码,自动补交易所后缀(.SSE / .SZSE) diff --git a/sanguo_api/routes_live.py b/sanguo_api/routes_live.py index 087c458..01775f5 100644 --- a/sanguo_api/routes_live.py +++ b/sanguo_api/routes_live.py @@ -55,6 +55,18 @@ class LiveCreateRequest(BaseModel): benchmark: str = "" +def _normalize_vt_symbol(code: str) -> str: + """裸 6 位码自动补交易所后缀(与 jq_to_dbbardata 同规则): + 6 开头→SSE,0/3 开头→SZSE。已带后缀或非 6 位码原样返回。""" + code = (code or "").strip() + if len(code) == 6 and code.isdigit(): + if code.startswith("6"): + return f"{code}.SSE" + if code.startswith(("0", "3")): + return f"{code}.SZSE" + return code + + @router.post("/live/create", dependencies=[Depends(verify_token)]) def create_live(req: LiveCreateRequest): """创建实盘实例(写 live_accounts,status=stopped)。需调 start 才会启动。""" @@ -72,6 +84,9 @@ def create_live(req: LiveCreateRequest): payload.setdefault("benchmark", "000300.XSHG") payload["vt_symbol"] = payload["pool"] payload["interval"] = "d" + else: + # CTA 实盘:标的允许只写 6 位码,后端自动补交易所后缀 + payload["vt_symbol"] = _normalize_vt_symbol(payload.get("vt_symbol", "")) # mini_path 兜底:req → env SANGUO_QMT_PATH → 内置默认(空值会导致 connect=-1) if not payload.get("mini_path"): payload["mini_path"] = ( diff --git a/tests/api/test_portfolio_live.py b/tests/api/test_portfolio_live.py index 55a386e..ce2836a 100644 --- a/tests/api/test_portfolio_live.py +++ b/tests/api/test_portfolio_live.py @@ -141,3 +141,16 @@ def test_live_strategy_adapter_builds_all_strategies(monkeypatch): monkeypatch.setenv("SANGUO_LIVE_STRATEGY", "nope") with pytest.raises(ValueError): live_strategy._build_live_strategy(_FakeProvider()) + + +def test_normalize_vt_symbol_bare_code_gets_exchange_suffix(): + """CTA 实盘标的:裸 6 位码自动补交易所后缀(6→SSE,0/3→SZSE)。""" + from sanguo_api.routes_live import _normalize_vt_symbol + + assert _normalize_vt_symbol("600000") == "600000.SSE" + assert _normalize_vt_symbol("000001") == "000001.SZSE" + assert _normalize_vt_symbol("300750") == "300750.SZSE" + # 已带后缀/非 6 位(池名等)原样 + assert _normalize_vt_symbol("600000.SSE") == "600000.SSE" + assert _normalize_vt_symbol("hs300_subset") == "hs300_subset" + assert _normalize_vt_symbol("") == ""