feat(data): Tushare 限速退避 + 新浪兜底(财务 getFinanceReport2022 / 日K 前复权),source+adjust 口径标记
- TushareProvider:频率超限按指数退避重试(不再一次 200/min 即中断),最长等待 30s
- SinaProvider 重构(参考 cc-cursor 公开接口实现):
· 新增财务通道 CompanyFinanceService.getFinanceReport2022(source=gjzb) → FinancialIndicator
(report_date / announce_date=publish_date),与 Tushare fina_indicator schema 一致
· 日 K 保留 jsonp(前复权),统一 UA + 重试
· 不支持方法仍抛 DataSourceNotSupported(复权因子/交易日历/基础信息)
- FailoverProvider 现在可对 daily 与 financial 兜底(CLI _failover_provider 接 SinaProvider)
- DailyBar + stock_daily 表新增 source/adjust 列:新浪兜底行标记 sina/qfq,
Tushare 恢复后 --resume 按同键覆盖回不复权 → 两源格式一致且可追溯
- 迁移 91c4e27a03fb 已生成;执行需在全市场同步结束后:uv run alembic upgrade head
- 测试 34+ 项(新浪财务解析/格式一致/限速退避等)通过
This commit is contained in:
@@ -148,3 +148,24 @@ class TestCall:
|
||||
def test_missing_token_rejected(self) -> None:
|
||||
with pytest.raises(DataSourceAuthenticationError, match="TUSHARE_TOKEN"):
|
||||
TushareProvider(token="")
|
||||
|
||||
|
||||
class TestRateLimitBackoff:
|
||||
def test_rate_limit_retries_with_sleep(self) -> None:
|
||||
"""频率超限:按退避等待后重试,最终抛错带原始信息(不当作鉴权错误)。"""
|
||||
import app.infrastructure.data_sources.tushare as ts_mod
|
||||
|
||||
orig_sleep = ts_mod.time.sleep
|
||||
sleeps: list[float] = []
|
||||
ts_mod.time.sleep = lambda w: sleeps.append(w) # noqa: SLF001 —— 测试桩
|
||||
try:
|
||||
provider = _pro(
|
||||
error=RuntimeError("抱歉,您访问接口(adj_factor)频率超限(200次/分钟)"), retries=3
|
||||
)
|
||||
provider._rate_limit_wait = 0.1 # noqa: SLF001
|
||||
with pytest.raises(DataSourceError, match="频率超限"):
|
||||
provider.get_stock_basic()
|
||||
finally:
|
||||
ts_mod.time.sleep = orig_sleep
|
||||
assert len(provider._pro.calls) == 3 # noqa: SLF001 —— 完整重试 3 次
|
||||
assert len(sleeps) >= 2
|
||||
|
||||
Reference in New Issue
Block a user