feat(live): CTA实盘vt_symbol裸6位码自动补交易所后缀(6→SSE,0/3→SZSE);表单提示+单策略原因说明(实盘需A股适配,陆续扩展) [nas]
This commit is contained in:
@@ -195,15 +195,15 @@ async function onSubmit(): Promise<void> {
|
||||
:value="opt.value"
|
||||
/>
|
||||
</el-select>
|
||||
<span class="muted form-hint">MVP 仅支持 AShareDoubleMaStrategy</span>
|
||||
<span class="muted form-hint">实盘需 A 股适配(定寸/禁空/分钟合成),目前仅 DoubleMa 完成适配,其余策略陆续扩展</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="策略实例名" required>
|
||||
<el-input v-model="form.strategy_name" placeholder="AShareDoubleMa_600000" style="width: 320px" />
|
||||
<span class="muted form-hint">engine 内唯一</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="标的(vt_symbol)">
|
||||
<el-input v-model="form.vt_symbol" placeholder="600000.SSE" style="width: 320px" />
|
||||
<span class="muted form-hint">交易所代码 .SSE / .SZSE</span>
|
||||
<el-input v-model="form.vt_symbol" placeholder="600000 或 600000.SSE" style="width: 320px" />
|
||||
<span class="muted form-hint">可只写 6 位代码,自动补交易所后缀(.SSE / .SZSE)</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="K 线周期">
|
||||
<el-input v-model="form.interval" placeholder="15m" style="width: 160px" />
|
||||
|
||||
@@ -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"] = (
|
||||
|
||||
@@ -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("") == ""
|
||||
|
||||
Reference in New Issue
Block a user