fix: TushareSource.get_price 修复 ts_code 重命名并校验必要列#30
Open
DrIsDr wants to merge 15 commits into
Open
Conversation
SmallCapStrategy 和 SmallCapStrategyV2 中使用了 logger.info, 但模块未导入 logging 也未定义 logger,导致实例化时抛出 NameError。
Tushare daily 接口返回的 DataFrame 使用 ts_code 列表示股票代码, 但 get_price 只重命名了 trade_date/vol,未将 ts_code 重命名为 symbol。 后续按 ['symbol', 'date', ...] 选取列时触发 KeyError,被外层捕获后返回 None, 使得 HybridDataManager 在 QMT 无数据时 fallback 到 Tushare 也失败, 最终导致回测获取不到价格、无法产生交易。
There was a problem hiding this comment.
Pull request overview
该 PR 修复 TushareSource.get_price 在对 Tushare daily 接口返回结果做列选择时,由于缺少 symbol 列导致 KeyError 进而返回 None 的问题,从而让 HybridDataManager 在 QMT 获取失败时能够正确 fallback 到 Tushare 并拿到价格数据。
Changes:
- 将 Tushare
daily返回的ts_code重命名为symbol,避免后续按symbol取列时报错。 - 调整列选择逻辑:仅保留实际存在的列,以提升对上游字段差异的兼容性。
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
回测引擎记录的交易方向为 'long'/'short',但展示代码按 'buy'/'sell' 过滤,导致买入/卖出次数始终为 0。
stock_daily 表定义包含 adjust_type、factor 两列(共14列), 但实际插入的 DataFrame 只有12列,导致 DuckDB 在执行 INSERT OR REPLACE ... SELECT * 时因 excluded 伪表列数不匹配而报错。 修复: - 删除 stock_daily 表中无用的 adjust_type、factor 列 - 主键从 (stock_code, date, period, adjust_type) 改为 (stock_code, date, period) - INSERT 语句显式指定12个目标列,兼容已存在的旧14列表
- 验证 is_available() 仅依据 is_connected 返回状态 - 验证 is_available() 不再调用 xtdata API 做真实探测 - 验证 close() 正确重置连接状态、清空缓存、重置 _last_used - 配置 pytest 入口:pyproject.toml [tool.pytest.ini_options] - gitignore 保留 unit_tests/ 目录,忽略 .worktrees/
修复 Code Review 发现的两个问题: 1. INSERT 列顺序与 DataFrame 顺序强耦合:将保存逻辑提取为 TushareDownloadThread._save_daily_dataframe(),INSERT 列名从 DataFrame 列动态推导,避免硬编码列名导致的数据错位风险。 2. created_at 在冲突替换时被覆盖:INSERT 不再包含 created_at, 新建行使用 DEFAULT CURRENT_TIMESTAMP,冲突行保留原 created_at。 新增测试: - unit_tests/gui_app/widgets/test_tushare_data_widget.py - 覆盖正确写入、无废弃列、列顺序无关、created_at 保留、忽略多余列 同时更新 .gitignore 与 pyproject.toml,使用 unit_tests/ 作为测试目录。
# Conflicts: # .gitignore
e04bc9a to
d01c3bc
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
修复
TushareSource.get_price因列名缺失导致返回None的问题。问题现象
运行
学习实例/04_策略回测.py时,HybridDataManager尝试从 QMT 获取股价失败后 fallback 到 Tushare,但 Tushare 也返回空,导致:✅ 回测完成!根因
Tushare
daily接口返回的 DataFrame 列名为ts_code/trade_date/vol,而get_price只做了部分重命名:未将
ts_code重命名为symbol。后续按['symbol', 'date', ...]选取列时触发:异常被外层
except捕获后返回None,于是上层认为 Tushare 也没有数据。修复
'ts_code': 'symbol'验证
修复后,
TushareSource.get_price('002808.SZ', '20241231', '20241231')已能正常返回:同时
HybridDataManager.get_price对策略选出的小市值股票组合也能从 Tushare 成功取到价格数据。