支持短合约代码自动补全交易所后缀
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -53,7 +53,9 @@ def health():
|
|||||||
def run_pipeline(req: RunRequest):
|
def run_pipeline(req: RunRequest):
|
||||||
ref_date = datetime.strptime(req.trade_date, "%Y%m%d").date() if req.trade_date else None
|
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)
|
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}")
|
print(f"[AUTO] {req.symbol} 当月主力 -> {ts_code}")
|
||||||
|
|
||||||
df = fetcher.fetch_contract(ts_code)
|
df = fetcher.fetch_contract(ts_code)
|
||||||
@@ -138,7 +140,8 @@ def run_range(req: RunRangeRequest):
|
|||||||
@app.post("/api/v1/run/full")
|
@app.post("/api/v1/run/full")
|
||||||
def run_full(req: RunFullRequest):
|
def run_full(req: RunFullRequest):
|
||||||
"""拉取指定合约全部历史数据,保存 candles,对所有可打分日期逐日打分并保存。"""
|
"""拉取指定合约全部历史数据,保存 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)
|
storage.save_candles(df)
|
||||||
|
|
||||||
results, warnings, total_days, scored_count = scorer.score_all(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
|
skipped_count = total_days - scored_count
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"ts_code": req.ts_code,
|
"ts_code": ts_code,
|
||||||
"total_days": total_days,
|
"total_days": total_days,
|
||||||
"scored_count": scored_count,
|
"scored_count": scored_count,
|
||||||
"skipped_count": skipped_count,
|
"skipped_count": skipped_count,
|
||||||
|
|||||||
@@ -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:
|
def active_contract(symbol: str, today: Optional[date] = None) -> str:
|
||||||
"""按主力轮换规则,返回当日 ts_code(含交易所后缀)。"""
|
"""按主力轮换规则,返回当日 ts_code(含交易所后缀)。"""
|
||||||
if symbol not in ROLLOVER_RULES:
|
if symbol not in ROLLOVER_RULES:
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ onMounted(async () => {
|
|||||||
<div style="display: flex; gap: 8px;">
|
<div style="display: flex; gap: 8px;">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="filter.ts_code"
|
v-model="filter.ts_code"
|
||||||
placeholder="输入合约代码如 FG2509.ZCE"
|
placeholder="输入合约代码如 FG2509"
|
||||||
clearable
|
clearable
|
||||||
:style="{ width: isMobile ? '100%' : '200px' }"
|
:style="{ width: isMobile ? '100%' : '200px' }"
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user