feat(data): B1-2 指数成分同步(Provider + CLI sync index_weight)

- MarketDataProvider.get_index_weight(协议);Tushare 实现 normalize_index_weight +
  get_index_weight(ts_code=... 全历史成分权重);Sina 抛 DataSourceNotSupported;
  FailoverProvider 代理并审计每次尝试
- CLI:sync index_weight --code 000300.SH(拉取→幂等落库 index_weight→打印最新快照;
  失败走 sync_log 审计并返回非零)
- tests:Tushare 映射与调用(FakePro)、Failover 主源单源语义(新浪不支持被审计);
  全量 pytest 通过
This commit is contained in:
Simon
2026-09-09 07:29:26 +08:00
parent 9cc4bfccac
commit 93e32f4e63
7 changed files with 140 additions and 0 deletions
+29
View File
@@ -41,6 +41,9 @@ from app.infrastructure.data_sources.errors import DataSourceError
from app.infrastructure.data_sources.sina import SinaProvider
from app.infrastructure.data_sources.tushare import TushareProvider
from app.infrastructure.persistence.sqlalchemy.models.market import StockModel
from app.infrastructure.persistence.sqlalchemy.repositories.index_impl import (
SqlAlchemyIndexConstituentRepository,
)
from app.infrastructure.persistence.sqlalchemy.repositories.market_impl import (
SqlAlchemyAdjustFactorRepository,
SqlAlchemyDailyBarRepository,
@@ -277,6 +280,28 @@ def cmd_financial(args) -> int:
return 0
def cmd_index_weight(args) -> int:
"""同步指数历史成分(Tushare index_weight;新浪不支持 → failover 审计留痕)。"""
code = args.code
with _session_ctx() as session:
provider = _failover_provider(session)
try:
rows = provider.get_index_weight(code)
except DataSourceError as exc:
print(f"[index_weight] {code} 失败:{exc}")
return 1
repo = SqlAlchemyIndexConstituentRepository(session)
touched = repo.upsert_many(rows)
latest = repo.latest_date(code)
session.commit()
print(
f"[index_weight] {code} 拉取 {len(rows)} 期成分行,落库 {touched} 条"
f",最新快照 {latest}(as_of 查询见 Universe.index_code)"
)
return 0
def cmd_verify(args) -> int:
"""新浪交叉验证:取新浪最新前复权收盘,与本地最新交易日对照。
@@ -399,6 +424,10 @@ def build_parser() -> argparse.ArgumentParser:
)
p_fin.set_defaults(func=cmd_financial)
p_idx = sub.add_parser("index_weight", help="同步指数历史成分(如沪深300 000300.SH)")
p_idx.add_argument("--code", required=True, help="指数代码,如 000300.SH / 000905.SH")
p_idx.set_defaults(func=cmd_index_weight)
p_verify = sub.add_parser("verify", help="新浪交叉验证最新行情")
p_verify.add_argument("--symbol", required=True)
p_verify.set_defaults(func=cmd_verify)