From 01309dd8ffb8a600343e018fd4d691a867116e79 Mon Sep 17 00:00:00 2001 From: fish Date: Thu, 7 May 2026 22:31:45 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=9F=AD=E5=90=88=E7=BA=A6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=87=AA=E5=8A=A8=E8=A1=A5=E5=85=A8=E4=BA=A4?= =?UTF-8?q?=E6=98=93=E6=89=80=E5=90=8E=E7=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 --- tushare/src/api.py | 9 ++++++--- tushare/src/contracts.py | 12 ++++++++++++ web/frontend/src/views/ChartView.vue | 2 +- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/tushare/src/api.py b/tushare/src/api.py index 0e11f0e..8158b8c 100644 --- a/tushare/src/api.py +++ b/tushare/src/api.py @@ -53,7 +53,9 @@ def health(): def run_pipeline(req: RunRequest): ref_date = datetime.strptime(req.trade_date, "%Y%m%d").date() if req.trade_date else None ts_code = req.ts_code or contracts.active_contract(req.symbol, ref_date) - if not req.ts_code: + if req.ts_code: + ts_code = contracts.normalize_ts_code(ts_code) + else: print(f"[AUTO] {req.symbol} 当月主力 -> {ts_code}") df = fetcher.fetch_contract(ts_code) @@ -138,7 +140,8 @@ def run_range(req: RunRangeRequest): @app.post("/api/v1/run/full") def run_full(req: RunFullRequest): """拉取指定合约全部历史数据,保存 candles,对所有可打分日期逐日打分并保存。""" - df = fetcher.fetch_contract(req.ts_code) + ts_code = contracts.normalize_ts_code(req.ts_code) + df = fetcher.fetch_contract(ts_code) storage.save_candles(df) results, warnings, total_days, scored_count = scorer.score_all(df) @@ -149,7 +152,7 @@ def run_full(req: RunFullRequest): skipped_count = total_days - scored_count return { - "ts_code": req.ts_code, + "ts_code": ts_code, "total_days": total_days, "scored_count": scored_count, "skipped_count": skipped_count, diff --git a/tushare/src/contracts.py b/tushare/src/contracts.py index 733a1ec..0d881ab 100644 --- a/tushare/src/contracts.py +++ b/tushare/src/contracts.py @@ -66,6 +66,18 @@ ROLLOVER_RULES: dict[str, dict] = { } +def normalize_ts_code(ts_code: str) -> str: + """把用户输入的短代码(如 FG2509)补全为带交易所后缀的完整代码(如 FG2509.ZCE)。""" + if "." in ts_code: + return ts_code + # 提取品种代码: 前两个字母 + symbol = ts_code[:2] + if symbol not in ROLLOVER_RULES: + raise ValueError(f"未配置 {symbol} 的品种规则,无法自动补全交易所后缀") + exchange = ROLLOVER_RULES[symbol]["exchange"] + return f"{ts_code}.{exchange}" + + def active_contract(symbol: str, today: Optional[date] = None) -> str: """按主力轮换规则,返回当日 ts_code(含交易所后缀)。""" if symbol not in ROLLOVER_RULES: diff --git a/web/frontend/src/views/ChartView.vue b/web/frontend/src/views/ChartView.vue index 0310873..29dfdc8 100644 --- a/web/frontend/src/views/ChartView.vue +++ b/web/frontend/src/views/ChartView.vue @@ -89,7 +89,7 @@ onMounted(async () => {