Commit Graph
18 Commits
Author SHA1 Message Date
Justin Gu 7456f81c80 fix: 板块成分股/排行报价分页合并顺序颠倒 — 多页前插改按页序追加
BoardMembersQuotesCmd 分页合并曾用 batch + all_quotes 前插,而协议 start=0
返回排序后最前一页:成分股超过单页 80 只的板块(半导体 SH881319、
光学光电 SH881329、通信设备 SH881338 等)弹窗涨跌幅榜从第 81~100 名开头,
前 80 名被压到后面,肉眼即乱序;≤80 只的板块单页不受影响。

同步/异步 get_board_members 与 get_stock_quotes_list 共 4 处统一改为
按页序追加(all_quotes = all_quotes + batch),回归测试钉死多页合并顺序、
start 偏移推进与末页不足一页的终止行为。

注:test_ex_reconnect::test_all_retries_relogin_each_time 存量失败
(干净工作树同样失败),与本修复无关,另案处理。
2026-09-05 03:30:52 +08:00
GitHub 1fc1d00c90 release: v1.24.0 — QFQ 对拍验证体系 + 回测任务持久化 + 品种感知费率
升级计划 P0(docs/upgrade-plan-2026H2.md)。源自 backtest-system / indicator-lab 两个下游项目的逆向调研。

- QFQ 对拍验证:公式法(NONE+XDXR)与跳空检测法(板块感知涨跌停阈值)双证据链互检,
  检出负价/残留跳空/方向反演/XDXR 缺记录四类问题,接入 MAC 同步/异步客户端(mac/qfq_check.py);
  含茅台式多重分红、浦发式送转方向合成案例回归(13 用例)
- 回测任务 SQLite 持久化:~/.easy_tdx/tasks.db 双写内存 LRU + 磁盘(保留 500 条),serve 重启不丢;
  重启恢复中断任务标记;GET /backtest/tasks/{id}/export?format=json|csv 导出端点
- 品种感知费率:ETF/可转债免印花税等法定差异(backtest/fees.py),CLI --auto-fees、
  REST auto_fees 字段、组合引擎逐标的解析(34 用例)
- 修正 avg_holding_days 过时注释(实现早已是 FIFO 真实口径)
- tests/conftest.py 默认 EASY_TDX_NO_TASK_DB=1 防止单测污染用户任务库
- 注:engine/cli/routers/schemas 为跨版本累积态,后续版本提交继续演进
2026-09-01 22:16:44 +08:00
GitHub fd53ec4c90 fix(mac): 板块列表涨速恒 0——值槽实为排序键列值,暴露 sort_column(issue #53)
抓包+对值锚定确认:0x1231 响应中 price 与 pre_close 之间的 float 是
"当前排序列的值"(板块与领涨股各一份),并非固定涨速;此前硬编码
sort_column=0(涨跌幅,仅排序键、值槽恒 0),故该列永远全 0。

排序列映射(实测):0=涨跌幅(值槽恒0) 1=涨速 2=3日 3=20日 4=60日
5=年初至今 6=5日 7=10日。

- 新增 BoardSortColumn 枚举并公开导出;get_board_list(sync/async)
  新增 sort_column 参数,取涨速传 SPEED,默认涨跌幅排序行为不变
- BoardInfo 字段更名 rise_speed→sort_value、symbol_rise_speed→
  symbol_sort_value(旧名语义错误且恒 0,属破坏性更名)
- Web /board-mac/list 新增 sort_column 参数;CLI board-list 新增 --sort
- 新增 9 个测试;README 示例更新
2026-08-26 15:21:35 +08:00
Justin Gu 1f040afabf feat(reconnect): 引入服务器健康分引擎 + K线空数据故障转移
彻底解决通达信服务器"跳来跳去"问题:

1. 新增 _health.py 健康分引擎:失败乘性降权(×0.5)、连续失败3次进
   120s 冷却、成功加性恢复(+0.2)。rank_by_health 按 latency/score
   (有效延迟)重排,冷却中的剔除。全健康时恒等映射,对既有测试零影响。

2. get_index_bars/get_security_bars 空数据时自动逐台换台(此前直接
   返回空 DataFrame,是日志"指数K线响应在第1/800条处被截断"后用户拿
   不到数据的根因)。复用泛化后的 _find_host_returning_data。

3. select_best_host_*/find_working_host_* 应用 rank_by_health 重排;
   空数据验证失败/异常时调 record_failure,命中调 record_success。

4. 8 个 _execute(A股/MAC/EX/MAC-EX × sync/async)统一注入健康分记录:
   成功 record_success、连接失败 record_failure。

5. security_bars 截断日志区分"首条即空(服务器无数据)"与"末尾截断"。

测试:26 个新增(15 health + 7 failover + 4 ex-client 健康分追踪),
全量 reconnect/failover/decode 回归通过,ruff/mypy 通过。
2026-07-13 15:59:28 +08:00
GitHub d0d65d64b8 feat: v1.20.0 服务器失败自动 ping 切换(无需手动 easy-tdx ping)
服务器连不上或返回空数据时,自动测速切到延迟最低的可用服务器再试,
Python API / CLI / Web API 三入口全部自动生效。

核心改动:
- _reconnect.py 新增 select_best_host_sync/async(连接失败 failover)
  和 find_working_host_sync/async(空数据逐台实测)
- 8 个 client 的 _execute 注入跨主机故障转移(复用 auto_reconnect 开关)
- get_market_stat 空数据时按延迟顺序逐台实测找返回数据的服务器
- 新增 _reconnect/_areconnect helper 收敛重建连接副本
- MacClient failover 用 save_best_mac_host(延续 v1.19.4 不污染 best_host)
- 顺手修复 test_commands_offline 未使用 import(main CI failure 根因)

测试:925 passed(新增 18 个 failover 测试),ruff/mypy 零新增错误。
2026-07-08 18:07:37 +08:00
Justin Gu 3bc15e620c fix(config): v1.19.4 MAC客户端不再污染标准best_host(取不到数据根因)
根因:mac/client.py 的 MacClient.from_best_host 和 AsyncMacClient.from_best_host
调用 save_best_host(best),把选中的 MAC 协议服务器(如 121.36.248.138)
写进了全局 best_host 字段——但这个字段是标准 TDX 协议用的。之后标准
AsyncTdxClient 用 get_best_host 读到这个 MAC host,用标准协议请求 MAC
服务器,返回空 body(偏移 2 剩余 0)。web app lifespan 启动 MAC 客户端
时触发污染。

修复:
- config.py 新增独立的 best_mac_host 字段 + get_best_mac_host / save_best_mac_host
- mac/client.py 4 处改用新字段(不再碰 save_best_host / get_best_host)
- get_best_host 加交叉污染校验:缓存 host 不在标准列表里自动重置
  (自动修复已被污染的 config.json,用户无需手动操作)

测试:新增 5 个回归测试(污染检测 + MAC host 隔离),907 全过。
2026-07-07 20:36:44 +08:00
Justin Gu 648c9ccfaf style: ruff format 修复预存格式债(CI ruff format --check 转绿)
v1.17.2 引入的 QFQ 重算代码(adjust.py/client.py/test_mac_qfq_integration.py)
含 magic trailing comma 导致 ruff format 期望多行参数展开,CI 的
'ruff format --check src/ tests/' 自 v1.17.0 起一直失败。纯格式变更,
零逻辑改动(20 例 QFQ 测试全过)。
2026-07-04 00:17:06 +08:00
Justin Gu c15bd8232f release: v1.17.2 — QFQ 深层历史负价修复
通达信服务端 QFQ 模式对长期重度除权股票(如 601088)深层历史页
返回负价格,导致回测总收益 -3087%、回撤 326.85%、年化 nan、
bollinger 崩溃、10 策略 invalid-value-in-scalar-power、MyTT divide-by-zero。

客户端兜底:检测 QFQ 负价时用 NONE+XDXR 本地重算前复权
(因子以除权日前一交易日含权收盘价为基准,保证除权日前后连续)。
同步+异步双路径一致修复,失败降级返回原值。

- 新增 src/easy_tdx/mac/adjust.py(纯函数 compute_forward_factor/
  apply_forward_adjust/has_bad_prices)
- MacClient/AsyncMacClient 触发本地重算,XDXR 按 (market,code) 缓存
- tests: +20 例(16 纯函数 + 4 集成),844 全绿,ruff/mypy 通过
2026-07-03 22:42:04 +08:00
GitHub 155328df8b release: v1.16.2 — 三轮审计质量加固(B6.9→A7.9)
经三轮代码审计后的综合质量加固版本,覆盖协议核心层、数据正确性、
错误处理、测试真实度与可维护性。761 单测全绿(+58),ruff/mypy 全过。

主要修复:
- 离线 .day 写入原子化(fsync + _repair_tail + 读取校验,CQS 守住)
- 回测止损前视偏差(延迟下一根开盘 + 跳空保护)
- VWAP 权重索引 / bar_time fail-fast / 绩效除零保护
- 闭包绑定 / 路径穿越 / naive datetime 跨时区 / ruff UP038

重构:
- 抽 AsyncHeartbeatMixin 收敛 4 处心跳副本(12→1)
- 统一 _RETRY_DELAYS 退避序列 / scanner 失败可观测性

新增 5 个测试文件 + 公共 API 类型契约,CI 加 Windows 矩阵 +
trusted publishing 签名 + 锁文件。

详见 CHANGELOG.md
2026-07-02 03:37:37 +08:00
GitHub 615994ad72 feat(kline): 分钟级K线时间戳可选bar_time对齐Tushare (Discussion #7)
通达信协议用bar开始时间打时间戳(5min线上午最后一根标11:25、下午第一根标13:00;午休11:30-13:00无bar),而Tushare/同花顺/聚宽用bar结束时间(标11:30/13:05)。新增bar_time参数让用户一键切换,避免自行+5分钟偏移。

- 全部3条K线路径覆盖:A股get_security_bars/get_index_bars、扩展行情get_instrument_bars、MAC get_stock_kline(含同步+异步、get_stock_kline_with_indicators)

- CLI kline新增--bar-time {start,end}选项;Web /bars、/bars/index新增bar_time查询参数

- bar_time=start(默认)保持完全向后兼容;bar_time=end仅对分钟级周期(1/5/15/30/60min)生效,自动按周期时长右移并处理跨小时/跨日边界

- 协议解码层零改动,偏移作为纯展示语义在client层后处理,单一工具函数_apply_bar_time_align_df/_apply_bar_time_align_bars复用于全部路径

- 新增27个单元测试(test_codec_datetime.py偏移逻辑 + test_kline_bar_time.py三路径覆盖),全量700单测通过

- bump 版本号至 1.16.0
2026-06-30 15:02:27 +08:00
Justin Gu 88638e82ad release: v1.11.5 — scipy 依赖声明 + 文档同步 + 工程化清理
- pyproject: 新增 science 可选依赖组(scipy),dev 纳入 scipy;版本号 1.11.5
- factor/analysis: spearman 分支加 scipy 软依赖保护,缺失时友好报错
- mac/client: 板块排行吞异常处补 logger.debug
- CLAUDE.md: 架构章节补全 mac/ex/unified/portfolio/factor/offline/screen 子包
- .gitignore: 补全 .coverage、signals.json
- README: 补 1.11.5 changelog
2026-06-13 21:10:35 +08:00
GitHubandClaude Opus 4.8 fd03e2a334 fix: ruff format compliance for CI
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 22:56:23 +08:00
GitHubandClaude Opus 4.8 e290ea3f21 feat: add board N-day change ranking (v1.9.10)
- Add get_board_change_ranking() to MacClient and AsyncMacClient
- Add 'board-change-ranking' CLI command (--type/--date/--days/--top/--asc)
- Calculate N-day price change from board index K-lines directly
- Default to listing all boards; --top N to truncate
- 12 unit tests covering calculation, edges, sorting

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 17:40:51 +08:00
GitHubandClaude Opus 4.8 4dfd18050e fix: resolve all CI mypy (265→0) and ruff (26→0) errors
- pyproject.toml: add mypy overrides for pandas/tabulate/matplotlib stubs,
  disable strict checking for vendored MyTT library
- config.py: use cast() for dict[str, Any] .get() returns
- beichi.py: widen _calc_bi_force param to BI | XD, import XD
- backtest/cli.py: split combo/single strategy into separate typed variables
- backtest/combo.py: add bool_array() helper for numpy return types
- chanlun/analyser.py: type ignore for pandas row access, fix dict type arg
- unified.py: change fields param from object to Any
- ex/mac_client.py: add type args to list literals
- cli/cmd_offline.py: wrap int market as Market enum before API call
- cli/cmd_chanlun.py: fix dict type arg
- offline/write_*.py: explicit int() cast for struct.unpack returns
- MyTT.py: fix line-too-long comments, UP038 isinstance syntax
- tests: fix E712 (==False → ~mask), E741 (noqa), F841, import sorting
- ruff format applied across codebase

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 15:03:41 +08:00
GitHubandClaude Opus 4.7 bcddf5a052 feat: add technical indicator calculation (30 indicators via MyTT), bump to 1.4.0
Integrate MyTT library to provide 30 technical indicators (MACD, KDJ, RSI,
BOLL, DMI, ATR, etc.) accessible via API and CLI with automatic EMA warm-up.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 16:05:40 +08:00
GitHubandClaude Opus 4.7 72652b9f8b feat: add get_board_ranking() for board change-pct ranking
New MacClient/AsyncMacClient method that ranks all boards of a given
type (industry/concept) by change_pct, amount, main_net_amount, or vol.
Aggregates member quotes via get_board_summary() for each board.

Also bumps version to 1.3.0 and updates README + CLI version.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 22:46:52 +08:00
GitHubandClaude Opus 4.7 ba032da9ed feat: add get_board_summary() for board capital flow aggregation
New MacClient/AsyncMacClient method that aggregates board member quotes
into total amount, main force net inflow (1d/3d/5d), and up/down counts.
Includes example demo.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 17:35:00 +08:00
GitHubandClaude Opus 4.7 4820b4a049 feat: v1.1.0 - MAC protocol, CLI tool, extended markets, unified client
- Add MacClient/AsyncMacClient with full MAC protocol support (quotes, kline
  with adjustment, tick charts, transactions, boards, capital flow, auction,
  unusual, symbol info, server info)
- Add MacExClient/AsyncMacExClient for extended markets (HK, US, futures)
- Add UnifiedTdxClient auto-routing between A-share and extended markets
- Add `easy-tdx` CLI tool with JSON default output, Agent-friendly
- Add field bitmap protocol for custom quote field selection
- Fix quote-list missing fields (default to BASIC+VOLUME preset)
- Add config.py with centralized host management and auto-discovery
- Add 50+ examples covering all APIs (01-20)
- Rewrite README with CLI-first, Agent-friendly documentation
- Bump version to 1.1.0

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 22:44:45 +08:00