feat: QMT Bridge 设为主数据源,新增指数日K支持及数据源文档
- QmtBridgeSource: provides 增加 index_daily,新增 fetch_index_daily 方法 - task_kline_index: 优先级改为 qmt_bridge → mairui → sina 三级降级 - task_kline_5min: 优先用 qmt_bridge,不可用时降级 mairui - task_kline_daily: 优先级加入 qmt_bridge(首位) - config: 新增 qmt_bridge_url 配置项 - registry: qmt_bridge 注册信息同步更新 - docs: 新增 DATASETS_AND_SOURCES.md,完整说明数据集与数据源依赖关系 - AGENTS.md: 同步更新指数数据源描述
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"""同步任务:六大指数日 K 线。
|
||||
|
||||
数据流:新浪指数日K接口 → 写 kline_index + indices 表。"""
|
||||
数据流:QMT Bridge(主)→ 麦蕊 → 新浪 逐级 fallback → 写 kline_index + indices 表。"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
@@ -24,32 +24,46 @@ MAJOR_INDICES = {
|
||||
"000852": {"name": "中证1000", "market": "CN", "category": "broad_market"},
|
||||
}
|
||||
|
||||
# 数据源优先级:qmt_bridge(免限速免凭证)→ mairui → sina
|
||||
SOURCE_PRIORITY = [
|
||||
("datasource_qmt_bridge", True, "qmt_bridge_index_daily"),
|
||||
("datasource_mairui", True, "mairui_index_daily"),
|
||||
("datasource_xinlang", False, "sina_index_daily"),
|
||||
]
|
||||
|
||||
|
||||
class SyncKlineIndex(SyncTask):
|
||||
dataset_id = "kline_index"
|
||||
|
||||
def _run(self, *, trigger_source: str = "manual", **kwargs) -> dict[str, Any]:
|
||||
# 优先 mairui(指数无单日空窗问题),sina 作为 fallback
|
||||
primary = ds_registry.get("datasource_mairui")
|
||||
use_mairui = primary is not None and is_source_ready(primary.key)[0]
|
||||
if not use_mairui:
|
||||
primary = ds_registry.get("datasource_xinlang")
|
||||
# 按优先级选择第一个就绪的数据源
|
||||
primary = None
|
||||
use_suffix = True
|
||||
source_label = ""
|
||||
for key, suffix, label in SOURCE_PRIORITY:
|
||||
src = ds_registry.get(key)
|
||||
if src is not None and is_source_ready(src.key)[0]:
|
||||
primary = src
|
||||
use_suffix = suffix
|
||||
source_label = label
|
||||
break
|
||||
|
||||
if primary is None:
|
||||
return {"status": "error", "message": "指数数据源均不可用(mairui + 新浪)"}
|
||||
return {"status": "error", "message": "指数数据源均不可用(qmt_bridge + mairui + 新浪)"}
|
||||
ok, reason = is_source_ready(primary.key)
|
||||
if not ok:
|
||||
mark_sync_blocked(self.dataset_id, message=f"{primary.key} 未就绪: {reason}")
|
||||
return {"status": "blocked", "message": f"{primary.key} 未就绪: {reason}"}
|
||||
|
||||
self._progress(message=f"开始同步 {len(MAJOR_INDICES)} 个指数...")
|
||||
self._progress(message=f"开始同步 {len(MAJOR_INDICES)} 个指数,数据源: {source_label}...")
|
||||
total = len(MAJOR_INDICES)
|
||||
ok_cnt = fail_cnt = 0
|
||||
results = {}
|
||||
|
||||
for i, (code, info) in enumerate(MAJOR_INDICES.items(), 1):
|
||||
try:
|
||||
# mairui 需带交易所后缀(如 000300.SH),sina 用纯6位
|
||||
if use_mairui:
|
||||
# qmt_bridge / mairui 需带交易所后缀(如 000300.SH),sina 用纯6位
|
||||
if use_suffix:
|
||||
# 000xxx 上证 → .SH;399xxx 深证 → .SZ
|
||||
if code.startswith("399"):
|
||||
suffix = ".SZ"
|
||||
@@ -82,7 +96,7 @@ class SyncKlineIndex(SyncTask):
|
||||
db_ops.upsert_index(
|
||||
index_code=code, index_name=info["name"],
|
||||
market=info["market"], category=info["category"],
|
||||
source="mairui_index_daily" if use_mairui else "sina_index_daily", enabled=True,
|
||||
source=source_label, enabled=True,
|
||||
)
|
||||
ok_cnt += 1
|
||||
results[code] = {
|
||||
@@ -100,7 +114,7 @@ class SyncKlineIndex(SyncTask):
|
||||
current=i, total=total, current_step=code,
|
||||
)
|
||||
|
||||
msg = f"六大指数 {ok_cnt}成 {fail_cnt}败"
|
||||
msg = f"六大指数 {ok_cnt}成 {fail_cnt}败({source_label})"
|
||||
return {
|
||||
"status": "ok" if fail_cnt == 0 else "warning",
|
||||
"message": msg,
|
||||
|
||||
Reference in New Issue
Block a user