)
Tushare's daily() only serves A-share stocks. ETF/LOF symbols need
fund_daily(), indices need index_daily(), and HK equities need
hk_daily(). Previously all codes went through daily(), returning
empty for non-stock types and silently falling back to tencent.
- Add _is_etf_listed/_is_index/_is_hk_equity detection helpers
- Route _fetch_daily_frame to correct endpoint per symbol type
- Warn and skip US/crypto (not in tushare)
- Add runner partial-fetch warning for mixed batches
- Unit + mock + E2E tests
Closes HKUDS#310
Co-Authored-By: OpenCode <noreply@opencode.ai>
AI-Model: qwen3.7-max
Co-Authored-By: opencode <noreply@ai-tool.com>
Co-Authored-By: Claude Code <noreply@anthropic.com>
AI-Contributed/Feature: 70/70
AI-Contributed/UT: 237/237
Summary
_fetch_daily_frame()to route ETF/LOF →fund_daily(), index →index_daily(), HK equity →hk_daily()instead of always callingdaily()which returns empty for non-stock symbolsWhy
Tushare's
daily()endpoint only serves A-share stocks. ETF/LOF symbols (510050.SH,159915.SZ), indices (000001.SH,399001.SZ), and HK equities (00700.HK) return empty throughdaily(), causing silent fallback totencent.Worse, in mixed batches (e.g.
["600519.SH", "510050.SH"]), the runner's runtime fallback only triggers when ALL symbols are empty — so the ETF is silently dropped from the backtest with no warning at all.Closes #310
Changes
agent/backtest/loaders/tushare.py: Add_ETF_PREFIXESfrozenset +_is_etf_listed(),_is_index(),_is_hk_equity(),_is_us_equity(),_is_crypto()detection helpers. Modify_fetch_daily_frame()to route each symbol type to the correct tushare endpoint. Warn and skip US/crypto (not in tushare). Add per-symbol empty-result warning.agent/backtest/runner.py: Add partial-fetch warning whensource != "auto"and some requested codes are missing fromdata_map(catches mixed-batch silent data loss).agent/tests/test_tushare_loader.py(new): 42 unit/mock tests for all detection helpers + routing verification viaunittest.mock. 4 E2E tests gated behindTUSHARE_TOKENenv var (auto-skip when absent).Test Plan
Automated tests
pytest tests/test_baostock_loader.py tests/test_akshare_loader.py tests/test_loader_retry_helpers.py tests/test_local_loader.py -q→ 54 passed in 1.11s)pytest tests/test_tushare_loader.py -v→ 42 passed, 4 skipped in 0.47s)TUSHARE_TOKEN=... pytest tests/test_tushare_loader.py::TestTushareE2E -v→ 4 passed in 0.98s)E2E / manual test cases (real tushare API)
All tests use
TUSHARE_TOKENenv var, date range2025-01-02to2025-01-10.daily()000001.SZapi.daily()fund_daily()510050.SHapi.fund_daily()index_daily()000001.SHapi.index_daily()600519.SH,510050.SH,000001.SHPre-fix behavior (verified against upstream
main):api.daily()rows000001.SZ(stock)600519.SH(stock)510050.SH(ETF)fund_daily)510300.SH(ETF)fund_daily)159915.SZ(ETF)fund_daily)588000.SH(STAR ETF)fund_daily)161725.SZ(LOF)fund_daily)000001.SH(index)index_daily)399001.SZ(index)index_daily)00700.HK(HK equity)hk_daily)Unit test breakdown (42 tests, no network required)
TestIsEtfListedTestIsIndexTestIsHkEquityTestIsUsEquityTestIsCryptoTestFetchDailyFrameRoutingdaily, ETF→fund_daily, index→index_daily, HK→hk_daily, US→None+warn, crypto→None+warn, empty→warnChecklist
src/agent/,src/session/,src/providers/) without prior discussion