Commit Graph
100 Commits
Author SHA1 Message Date
GitHub 7c9e19de93 release: v1.20.8 — 信号雷达:一键扫描全部已保存策略买卖信号 2026-08-21 16:57:16 +08:00
GitHub 9336273f17 feat(web): 信号雷达——一键扫描全部已保存策略的最近买卖信号
新增导航页 /signals:把策略库 single/portfolio/multi 策略统一展开成
"策略×标的"子任务,按标的去重取最近 800 根 K 线,用与回测引擎同口径的
逐 bar 信号流程(含仓位跟踪)判断最近 N 根(窗口 1/3/5/10 可选,默认 5)
的买/卖信号,汇总卡片 + 筛选 tab + 明细表展示;上次结果缓存 localStorage。

- 后端 signal_scan.py(展开/去重取数/信号评估/汇总)+ POST /backtest/signal-scan/run/async
- 只扫信号不重跑回测,不改写策略库业绩快照;单行失败(未知策略/停牌/参数非法)不中断整批
- normalize_symbol 按代码段纠正历史错标市场前缀(与前端 detectMarket 同规则)
- 新增 20 个单测(含与回测引擎成交序列一致性对照),全套 1030 个单测通过
2026-08-21 16:57:12 +08:00
GitHub 67a5e1d08a release: v1.20.7 — /bars MIN_1 时间修复(#49)+ 寻优参数语义约束(#39)+ 依赖安全升级 2026-08-19 19:06:59 +08:00
GitHub 1d3d45828d style: ruff format 调整新增测试换行 2026-08-19 19:00:42 +08:00
GitHub 3180ab3002 fix(backtest): 策略参数加跨语义约束,杜绝寻优选出快慢倒挂组合(issue #39)
寻优器网格探索不区分语义:ma_cross 的 fast∈[5..60] × slow∈[10..250]
笛卡尔积包含 {"fast":30,"slow":20} 这类倒挂组合,倒挂的双均线交叉
本质是反向策略,回测成绩可能反而突出,从而被选为"最优参数"展示
(即 issue #39 截图中 {"fast":30,"slow":20} 的来源)。presets.py 的
注释"快线<慢线才有意义;去重无效组合"早已写下意图但从未实现。

根因是参数校验只有单参数 min/max,缺跨参数语义约束:

- ParametrizedStrategy 新增 param_constraints 类属性 [(a,b), ...]
  表示要求 a<b,在 __init__ 解析后统一校验,报错带中文标签;
  语义约束不受 skip_bounds 影响(寻优跳过的只是数值边界)
- 7 个策略声明约束:ma_cross/ema_cross(fast<slow)、macd
  (short<long)、triple_ma(short<mid<long)、rsi_reversal/cci/
  wr_reversal(oversold<overbought)
- 寻优器 build 阶段的 ValueError 降为 info 级跳过(无堆栈噪音),
  回测异常仍走 warning;预设网格 36 组合 → 有效 25 个
- 新增 10 个回归测试(旧代码全失败、新代码全通过)
2026-08-19 18:55:48 +08:00
GitHub fc63873717 style: 拆行修复 ruff E501(test_web_api.py 超长行) 2026-08-19 18:22:49 +08:00
GitHub bcaee1404d fix(web): /bars MIN_1 被误判为日线,datetime 归一化为 date 00:00:00(issue #49)
KlineCategory 枚举值不按周期长短排序(MIN_1=7、MIN_3=8 均大于 DAY=4),
/bars 的 MAC 路径用 int(cat) >= int(KlineCategory.DAY) 判定"日线及以上",
把 1 分钟线误判为日线,_normalize_mac_df 因此将 datetime 截断为 00:00:00
并把列名改为 date。回退 TdxClient 路径与 MAC symbol_bar 均为显式判定,
仅此一处用整数比较,故只有 MAC 路径复现。

改为 _is_daily_plus() 查表判定(复用 _df._CATEGORY_MINUTES,与回退路径
同一判定源),保证两条路径 date/datetime 语义一致。新增表驱动单测 +
端点级回归测试(假 MAC 客户端,在未修复代码上失败、修复后通过)。
2026-08-19 18:19:07 +08:00
GitHub 01a9823ed4 fix(web): 升级 postcss/nanoid 修复 Dependabot 安全告警(alerts #2 #3 #5)
- postcss 8.5.16 -> 8.5.26:修复路径遍历读取任意 .map 文件(GHSA 高危)及后续不完整修复
- nanoid 3.3.15 -> 3.3.18:修复非安全生成器负数 size 死循环(高危)

均为 vite / @vue/compiler-sfc 的 semver 兼容间接依赖,仅更新 lockfile;
npm run build 验证通过。
2026-08-14 17:30:13 +08:00
GitHub 5a3ad15477 feat(web): /bars 迁移到 MacClient + 支持复权(issue #43)
Web 获取 K 线此前用 AsyncTdxClient.get_security_bars(标准协议不支持复权),
导致 REST API 无法取前复权/后复权数据。将 /bars(个股 K 线)迁移到
AsyncMacClient.get_stock_kline(MAC 协议,支持 NONE/QFQ/HFQ + QFQ 负价兜底),
保持旧输出契约不变(日线 date 列、分钟线 datetime 列、OHLC 顺序、无 float_shares),
新增 adjust 参数(默认 QFQ),MAC 主机不可用时自动回退标准 TdxClient。

⚠️ 半破坏性变更:/bars 默认复权从"不复权"改为 QFQ(前复权)。老调用方若需
不复权请显式传 ?adjust=NONE。输出 DataFrame 列名/顺序/字段与旧版完全一致
(_normalize_mac_df 规整),仅价格数值因复权变化。

改动:
- bars.py:/bars 改走 mac_client.get_stock_kline(adjust=...),MAC 不可用回退
  get_security_bars(无复权 + warning);新增 _normalize_mac_df 规整输出契约;
  新增 adjust 查询参数(默认 QFQ)。
- convert.py:period_times_from_category(KlineCategory→Period 映射,显式处理
  YEAR 9→YEARLY 11、SEASON→QUARTERLY)+ adjust_from_str。
- deps.py:get_mac_client_optional(未连接返回 None,供回退判断)。
- schemas.py:AdjustEnum(OpenAPI 文档用)。

测试:新增 7 个(period_times 映射全表 + 不可映射值、adjust 转换、_normalize_mac_df
日线/分钟线/空 df)。全套 996 passed;ruff format/check + mypy 改动文件零错误。

不在本次范围:/bars/index(指数 K 线,MAC 另一套接口)、/minute、/transaction*
(MacClient tick_chart 语义不同,暂不迁移)。
2026-08-05 16:37:10 +08:00
GitHub 60bd0586f9 style(tests): ruff format 修复 patch.object 参数换行(CI ruff format --check 失败) 2026-08-05 15:58:00 +08:00
GitHub 0490f67a16 fix(client): get_history_fund_flow 加空数据故障转移(issue #41)
用户反馈 get_history_fund_flow(SH, "600519") 返回空 DataFrame,日志显示
"K线响应为空(声称 800 条但首条即解析失败...)"。排查定位:当前 host 对
常见标的也返回 ret_count 撒谎的空 body,但资金流兼容回退路径(直连空 →
拉 K 线 + 历史逐笔重算)未接入 v1.20.4 的空数据故障转移,"服务器回包正常
但内容是假的空" 既非 TdxConnectionError 也不触发换台,用户卡在坏服务器上。

修复:get_history_fund_flow(sync+async)当前 host 直连与 K 线回退均空时,
按延迟顺序逐台实测找首台返回有效数据的服务器(与 get_security_bars/
get_index_bars 同源逻辑)。因资金流获取涉及多命令,无法用单 cmd 复用泛化版
_find_host_returning_data,故内联 _fund_flow_failover:每台候选上跑完整
_fetch_fund_flow_records(原直连+K线回退逻辑抽出成独立方法),返回首台非空
结果。全空返回空 DataFrame(不 raise,区分"真无历史数据"与"服务器缺数据")。

测试:新增 6 个(4 sync + 2 async)。全套 989 passed;ruff/mypy 改动文件零错误。
2026-08-05 15:53:49 +08:00
GitHub a8c035010e style(tests): ruff format 修复尾随空行(CI ruff format --check 失败) 2026-07-10 15:17:00 +08:00
GitHub d84a08b7f2 fix(backtest): v1.20.3 修复回测绩效统计两个 bug(issues #30 #31)
#31: RebalanceEngine 缺失价格导致净值假崩塌
  已持仓标的当日缺 K 线(停牌/日历错位)时 prices.get(code,0)=0,
  持仓市值记 0 → 净值单日暴跌(159915 在 20210208 缺一天,持仓 ~93%,
  净值 1.1M→91,845,全期最大回撤 -92%)。
  修复:last_known_price forward-fill,缺失日沿用最近已知收盘价。
  附带:_compute_performance 最大回撤改正值口径(与 BacktestEngine 一致)。
  验证:真实 ETF 数据 max_drawdown 24.01%(backtrader 基准 27%),
  total_return 220.56% 不变。

#30: PortfolioTracker 交易静默漏单
  apply_trades 用 trade.datetime 作 dict key、df["datetime"].to_numpy()[i]
  查找;两端类型不一致(int vs datetime64)时永不命中,交易被静默丢弃,
  净值恒定(total_return=0 但 trades 表有 PnL)。
  修复:改为按"位置索引"匹配(归一化 datetime 后查位置),类型无关。
  验证:int-trade+datetime64-df 修复前净值=100000(恒定),修复后=100289。

测试:新增 4 回归测试(未修复代码上均失败,修复后通过);
全套 936 passed;mypy 改动文件零错误;ruff 全绿。
2026-07-10 15:12:47 +08:00
GitHub 06be298c92 ci(publish): 暂时关闭 attestations 规避 OIDC 503 故障
GitHub OIDC → sigstore 服务连续 503 overflow(v1.20.2 两次 publish 失败),
非配置问题(v1.20.1 能发成功证明 trusted publishing 配置正确)。
attestations 是可选签名,关闭后上传正常进行;待服务稳定后改回 true。
2026-07-09 22:12:20 +08:00
GitHub bc0ea064ba chore: retrigger CI (Actions queue stuck 20min) 2026-07-09 20:55:16 +08:00
GitHub a67e5588d0 fix(types): v1.20.2 修复 v1.20.1 引入的 CI mypy 失败
v1.20.1 把 BacktestResult.performance 扩大为 dict[str, float | str]
(为塞 diagnostic_warning 字符串),破坏 6 处下游消费方类型契约,
CI mypy job 转红。重构为更干净的设计:

- 诊断信息走独立的 BacktestResult.diagnostic 字段(performance.py
  PerformanceAnalyzer.diagnostic 属性 → engine 透出 → to_dict 含该字段
  → CLI 显示),performance 字典回归 dict[str, float](保留别名键)。
- optimizer.py 补 npt.NDArray 标注,消除 3 个既有 ndarray type-arg 错误。

测试:932 passed;mypy backtest/+portfolio/ 零错误;ruff 全绿。
2026-07-09 20:34:23 +08:00
GitHub 00b8c6374a fix(backtest): v1.20.1 修复回测引擎 3 个 bug(issues #22 #23 #25)
排查发现用户反馈的"回测统计数据缺失/异常"并非服务器连接问题,
而是回测引擎与组合优化器自身的代码缺陷:

#23: 首根 bar 访问 close[-1] 崩溃
  _SeriesAccessor 负向越界改返回 NaN(不抛 IndexError);
  BacktestEngine 新增 warmup_bars 参数跳过指标预热期。

#25-A: FactorWeightedOptimizer 权重坍缩
  n_stocks=2 且得分接近时,减最小值把低分标的权重压到 ~6e-8,
  等于单股满仓、n_stocks 被无视,进而出现持仓1只/-99.98%回撤。
  新增 _apply_weight_floor 权重下限保证入选标的都有实质权重。

#25-B: RebalanceEngine total_trades 统计错误
  total_trades = len(equity_curve)(天数)改为 len(trades_df)(真实笔数)。

#22: 绩效别名键 + 数据异常诊断
  performance dict 新增 sharpe_ratio/start_cash/end_value 别名键;
  资金曲线异常时返回 diagnostic_warning 而非静默全 0,CLI 显示提示。

文档:README 加入回测手册导航;backtest_usage.md 补充 warmup 说明。
测试:新增 6 个回归测试,更新 3 个;932 passed。
2026-07-09 20:16:12 +08:00
GitHub 052119e6ae feat(backtest): v4.2 新增 FSL 分水岭指标策略(单标的/组合/寻优)
- MyTT.py: 新增 FSL(CLOSE, VOL, CAPITAL) 分水岭指标
  - SWL = (EMA(C,5)*7 + EMA(C,10)*3) / 10
  - SWS = DMA(EMA(C,12), MAX(1, 100*SUM(VOL,5)/(3*CAPITAL)))
    MIN(A,1.0) 模拟通达信 DMA(X,A) 内部钳制 A<=1 的语义
- MyTT.pyi: 补 FSL 类型 stub(CI mypy 用 .pyi 校验)
- strategies/builtin.py: 注册 FslStrategy(SWL/SWS 金叉死叉)
  capital 作为 Param 暴露流通股本输入
- strategies/presets.py: fsl 寻优网格(4 档 capital)
- tests: 注册表断言加 fsl,阈值 18→19
2026-07-09 18:42:00 +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
GitHub e3e8dd492e fix: K线响应截断容错 + 一键寻优并发默认8进程
- security_bars: parse_response 遇末尾残缺记录时丢弃并返回前 N-1 条,
  避免 TDX 服务端截断响应导致整页 500(如 000408 count=800 日线)
- OptimizeView: 一键寻优并发默认 8 进程,用户选择持久化到 localStorage

bump version to 1.18.3
2026-07-06 13:23:37 +08:00
GitHub 9245bb2ce9 chore(tests): 修复 ruff UP038 (isinstance 元组 -> int | float)
test_web_backtest.py:556 的 isinstance(x, (int, float)) 触发 ruff UP038。
requires-python>=3.10 支持 PEP 604 的 int | float 运行时语法, 转换安全。
该报错会导致 GitHub Actions CI 失败。
2026-07-03 15:42:24 +08:00
GitHub cc9c1e264d test(tick_charts): 补 partial-day 回归测试覆盖 PR #13 修复
PR #13 修复了 start_date=None 且最新交易日数据不完整时
tail_offset 越界/读错位的 bug。原 3 个测试构造的都是完整数据
(total = days*page_size),走 fallback 分支,未覆盖真正的 partial 分支。

新增 test_multi_tick_charts_partial_day: 构造 days=3, page_size=4,
total=6 的 body,验证 tick_counts 分配为 [2,4,0]、尾部元数据在
actual_total 反推的偏移处正确解析。已反向验证(回退旧 tail_offset
公式时该测试立即失败复现 '偏移 239 越界'),非空壳测试。
2026-07-03 15:42:06 +08:00
GitHub 2067b80958 fix(ci): scipy 1.17 要求 Python>=3.11,CI 跑 3.10 装不上
requirements-dev.txt 锁定的 scipy==1.17.0 与 pyproject 声明的
requires-python=>=3.10 冲突(scipy 1.16+ 起要求 Python>=3.11),
导致 CI 矩阵里 3.10 的 job(ubuntu + windows)pip install 失败。

修复:
- requirements-dev.txt: scipy 1.17.0 → 1.15.3(支持 >=3.10 的最新 scipy)
- pyproject.toml [dev]/[science]: scipy>=1.10 → >=1.10,<1.16
  (CI 第一步 pip install -e .[dev] 在 3.10 上也会拉到 1.17,加同上界)

附注:仅影响开发/CI 环境,运行时用户(pip install easy-tdx)不受影响。
本地 761 单测 + ruff + coverage(62%) 全过。requirements-dev.txt
头部加注释说明 3.10 兼容约束,防日后再次踩坑。
2026-07-02 03:53:25 +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 bc83ffa4ac fix(tick_charts): 多日分时图 minutes>=1440 报 ValueError (Issue #10) 2026-07-01 16:22:57 +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
GitHub db83e7505d fix(security_quotes): 修复 ETF/指数实时行情价格被放大10倍 (Issue #8) 2026-06-29 22:15:28 +08:00
GitHubandClaude c54071e85e release: v1.14.1 — 高级回测 ExecutionModel 路径 3 个真实数据兼容 Bug 修复
- datetime 类型分歧(致命):Trade.datetime 转 int 与 PortfolioTracker 的 Timestamp key 失配,TWAP/VWAP/Limit 路径交易全部静默丢失、权益曲线恒定、收益归零
- volume 列名分歧:回测认 volume 而真实行情为 vol,滑点 volume 恒 0 退化百分比模式,VWAP 退化为等权
- date/datetime 列名分歧:日线返回 date 列引擎要 datetime,run() 入口由 date 派生下游无感兼容
新增 3 个回归测试(均红灯验证)。650 单测通过,backtest 模块 ruff + mypy strict 清洁。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-15 20:50:49 +08:00
GitHubandClaude a6ed0eac16 docs: add quantitative guide, update README + CHANGELOG, bump v1.11.1
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 22:12:19 +08:00
GitHubandClaude bfefadf70b feat(backtest): v1.15.0 — attribution analysis
- AttributionReport dataclass with Brinson/factor/cost fields
- AttributionAnalyzer with 3 attribution modes:
  - Cost attribution (commission/slippage/stamp tax breakdown)
  - Brinson attribution (allocation + selection + interaction)
  - Factor attribution (factor contribution + specific return)
- Priority: factor > Brinson > cost in full_report()
- 556 tests passing (12 new)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 21:11:33 +08:00
GitHubandClaude 2eeb7f9806 chore: bump version to v1.15.0
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 21:11:23 +08:00
GitHubandClaude 06f2e1f1a2 feat(backtest): add AttributionAnalyzer with Brinson, factor, cost attribution
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 21:10:50 +08:00
GitHubandClaude 8c2c204002 feat(backtest): v1.14.0 — pluggable slippage models + execution simulation
- SlippageModel ABC with 4 built-in models (Fixed, Percent, SquareRoot, Volume)
- ExecutionModel ABC with 4 built-in models (Immediate, TWAP, VWAP, Limit)
- OrderSimulator integration with SlippageModel
- BacktestEngine integration with SlippageModel + ExecutionModel
- Full backward compatibility (all existing code unchanged)
- 544 tests passing (46 new)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 21:06:15 +08:00
GitHubandClaude 8c4c4a6629 chore: bump version to v1.14.0
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 21:05:46 +08:00
GitHub 0945e47990 feat(backtest): integrate SlippageModel + ExecutionModel into BacktestEngine 2026-06-12 21:04:24 +08:00
GitHub d18af98855 feat(backtest): add LimitExecution 2026-06-12 20:59:59 +08:00
GitHub fe68d9da95 feat(backtest): add TWAPExecution + VWAPExecution 2026-06-12 20:56:57 +08:00
GitHub 0772666be3 feat(backtest): add ExecutionModel ABC + ImmediateExecution 2026-06-12 20:53:07 +08:00
GitHub 6414c2cc11 feat(backtest): integrate SlippageModel into OrderSimulator 2026-06-12 20:50:42 +08:00
GitHub d081eeb265 feat(backtest): add SquareRootSlippage + VolumeSlippage 2026-06-12 20:47:03 +08:00
GitHub 4098af02bf feat(backtest): add SlippageModel ABC + FixedSlippage + PercentSlippage 2026-06-12 20:44:28 +08:00
GitHub b7b72b10d1 feat(portfolio): add optimizer, risk model, rebalance engine, CLI pfactor command, bump v1.13.0 2026-06-12 20:25:50 +08:00
GitHubandClaude e6a69d51e4 feat(portfolio): add optimizer, risk model, and rebalance engine
- WeightOptimizer base class with registry (equal, factor_weighted, risk_parity, mean_variance)
- RiskModel with shrinkage covariance estimation and portfolio risk metrics
- RebalanceEngine for multi-period backtesting with commission/slippage
- 20 unit tests covering all components

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 20:22:31 +08:00
GitHub 6b6b7c66a0 docs: add v1.13.0 portfolio management implementation plan 2026-06-12 20:17:43 +08:00
GitHub 303964ea67 feat(factor): add analysis/transform exports, CLI analyze command, bump v1.12.0 2026-06-12 20:11:28 +08:00
GitHub 9d7bf84d5d feat(factor): add FactorAnalyzer with IC/quantile/turnover/decay analysis 2026-06-12 20:09:08 +08:00
GitHub c6f2580b73 feat(factor): add factor preprocessing pipeline (winsorize/zscore/rank/fill/orthogonalize) 2026-06-12 20:08:10 +08:00
GitHub 799a4da428 docs: add v1.12.0 factor analysis implementation plan 2026-06-12 20:05:24 +08:00
GitHubandClaude d5fa572a43 style: ruff format factor module
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 19:58:34 +08:00
GitHubandClaude d35b08ff85 chore: bump version to v1.11.0
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 19:58:28 +08:00
GitHubandClaude 54e06009d4 test(factor): add integration tests for FactorEngine with builtins
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 19:57:18 +08:00
GitHub f47a6df776 feat(cli): add 'easy-tdx factor list' command 2026-06-12 19:55:40 +08:00
GitHub d9bb37f750 feat(factor): wire up builtin factor auto-registration and export 2026-06-12 19:53:18 +08:00
GitHubandClaude c9be1f85d9 feat(factor): add 19 builtin factors (momentum/volatility/quality/volume/technical/chanlun/value)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 19:50:05 +08:00
GitHubandClaude e766cace73 feat(factor): add FactorEngine with single/cross-section/forward-return compute
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 19:47:08 +08:00
GitHub 67d9963f20 feat(factor): add Factor base class and registry 2026-06-12 19:43:54 +08:00
GitHub 7d6607b0cf docs: add v1.11.0 factor engine implementation plan (13 tasks, TDD) 2026-06-12 19:35:16 +08:00
GitHub 64f8a5e8b6 docs: add quantitative factor engine + portfolio management design spec 2026-06-12 19:27:02 +08:00
GitHub e6ed6efcd4 chore: bump version to v1.10.5 + update changelog 2026-06-12 17:19:47 +08:00
GitHubandClaude de2b37e1e3 fix(web): use redoc@2.2.0 standalone bundle (v3 is ESM-only)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 17:06:54 +08:00
GitHubandClaude 79c81cc3b6 fix(web): override redoc endpoint with pinned JS v3.0.0-rc.0
FastAPI does not accept redoc_js_url as a constructor param — the old
approach silently ignored it, leaving the default redoc@next CDN URL
(which returns 404). Manually register /redoc with get_redoc_html()
using the fixed v3.0.0-rc.0 bundle URL.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 17:05:25 +08:00
GitHubandClaude 9848d754a8 fix(web): use redoc@3.0.0-rc.0 bundle
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 16:55:21 +08:00
GitHubandClaude 0d673f1972 fix(web): pin ReDoc JS to v2.1.3 (cdn redoc@next returns 404)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 16:54:03 +08:00
GitHubandClaude 46c5d3cc05 fix(web): guard MAC client None + filter _raw bytes from Ex responses
- get_mac_client() now raises TdxConnectionError (503) when MAC client
  is None, matching get_ex_client() behavior. Previously returned None
  causing AttributeError (500) on all 12 MAC endpoints.
- _records_to_df_resp() filters out internal _raw: bytes fields from
  Ex dataclass models. Previously asdict() included binary protocol
  data that is not JSON-serializable and would cause 500 errors.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 16:51:47 +08:00
GitHubandClaude d17895e92b feat(web): full Web API parity with CLI — 18 new endpoints (v1.10.2)
- Board analysis: list/members/belong/summary/ranking/change-ranking (6)
- Capital flow, symbol info, server info (3)
- Quote list, auction, unusual (3)
- Extended market: bars/quote/minute/transaction (4)
- Technical indicators: list + compute (2)
- Multi-client DI: AsyncMacClient + AsyncExTdxClient lifecycle
- 6 MAC enum converters, DictResponse, ComputeIndicatorsRequest schemas
- Web API endpoints: 22 → 40

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 16:46:48 +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 b4f63c85a6 feat: add OBV trend strategy (v1.9.5)
- New obv_trend.py strategy: OBV energy flow trend following
- Entry: OBV > MAOBV*1.02 buffer + MAOBV 20-bar uptrend confirmed
- Exit: OBV drops below MAOBV
- Tunable params: maobv_period(30), maobv_lookback(20), obv_buffer(0.02)
- Update README changelog and strategy table
- Bump version to 1.9.5

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 18:53:06 +08:00
GitHubandClaude Opus 4.8 79c6fcee0e fix: remove unused type: ignore comments in analyser.py
Use 'row_any: Any = row' pattern to avoid arg-type mismatch between
local (pandas-stubs) and CI (bare pandas) environments.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 15:12:38 +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.8 7f1bc645c2 release: v1.8.2 - 5 new strategies, --show chart, 15 total
- New strategies: dmi_trend, cci_breakout, mfi_volume, trix_cross, mtm_momentum
- run_all_strategies.py --show: dual-axis equity curve vs stock price chart
- zhuoyao_momentum strategy (from earlier commit)
- README: updated strategy table (9→15), changelog, demo screenshots
- Bump version to 1.8.2

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 23:17:04 +08:00
GitHubandClaude Opus 4.8 8fcedeb47a feat(strategies): add zhuoyao_momentum strategy + Maotai demo screenshot
- New ZHUOYAO multi-timeframe momentum strategy (strategies/zhuoyao_momentum.py)
- Entry: SHORT>0 + TREND>0 + SHORT>MID (triple resonance)
- Exit: SHORT<0 or TREND<0 (conservative, any triggers sell)
- Add SH600519 Maotai demo screenshot (strategies/demo/4.png)
- Update README with 4th demo screenshot

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 22:59:19 +08:00
GitHub b57d8f4669 feat(backtest): add --show flag for best strategy equity curve chart
- Add --show/--show-chart flag to run_all_strategies.py
- Display dual-axis chart: normalized stock price vs strategy equity curve
- Mark buy/sell points with green/orange triangles
- Auto-detect Chinese fonts (SimHei/YaHei on Windows, PingFang on macOS)
- Fetch stock name via get_stock_quotes for chart title
- Add 3 demo screenshots to README with disclaimer
- Update README with --show usage and visual examples
2026-06-09 22:41:14 +08:00
GitHubandClaude Opus 4.8 b44636207b release: v1.8.1 - single-source version, batch backtest detail output
- Consolidate version to pyproject.toml as single source of truth
- __init__.py, cli/__init__.py, docs/conf.py all read dynamically
- run_all_strategies.py now shows best strategy full trade details
- Update README changelog for 1.8.1

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 22:12:27 +08:00
GitHubandClaude Opus 4.8 b5b5d0dc5b release: v1.8.0 - backtest engine with batch strategy comparison
- Add backtest section to README with CLI usage and run_all_strategies.py demo
- Update all version numbers to 1.8.0 (pyproject.toml, __init__.py, cli/__init__.py, docs/conf.py)
- Fix turtle_breakout strategy: TAQ returns 3 values (UP, MID, DOWN)
- Add run_all_strategies.py batch comparison script
- Update README intro to highlight backtest feature
- Add backtest to CLI command table and architecture tree

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 20:35:38 +08:00
GitHubandClaude Opus 4.8 70c69c8a66 fix(backtest): cli _print_table used wrong key 'sharpe_ratio' instead of 'sharpe'
Performance dict outputs 'sharpe' but _print_table looked up 'sharpe_ratio',
so perf.get('sharpe_ratio', 0) always returned the default 0 regardless of
actual Sharpe value.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 20:02:20 +08:00
GitHubandClaude Opus 4.8 46298e68d7 fix(backtest): max drawdown now correctly measures peak-to-trough percentage
Previous formula was: max(absolute_drawdown) / initial_capital, which
exceeds 100% when the portfolio grows then drops (e.g. from 600k to 300k
on a 100k initial = 300% drawdown, which is nonsensical).

Fixed to use drawdown_pct (drawdown / peak) which is always in [0, 1].
This correctly measures the maximum percentage drop from the highest
equity peak, matching the standard financial definition.

Also added regression test: test_max_drawdown_never_exceeds_100_pct.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 19:00:11 +08:00
GitHubandClaude Opus 4.8 5550702620 fix(strategies): unpack BIAS triple return value in bias_reversal
MyTT.BIAS returns (BIAS6, BIAS12, BIAS24) but the strategy was assigning
all three to a single variable, causing 'array with more than one element'
ValueError when comparing to a scalar threshold.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:56:07 +08:00
GitHubandClaude Opus 4.8 6a6d75f5d5 fix(backtest): strategy position not tracked during signal generation
Root cause: _generate_signals() iterated all bars calling strategy.next()
but never updated _position_size or _cash on the strategy. Strategies
that check self.position['size'] before buy/sell always saw 0, producing
only BUY signals with no SELL — exhausting cash and producing drawdowns
exceeding 100%.

Fix: add _update_strategy_position() that estimates position changes
after each bar's signals using close price. This gives the strategy an
accurate view of its holdings so it can correctly alternate buy/sell.

Regression tests added:
- test_position_aware_buy_sell_alternation: verifies BUY/SELL alternation
- test_position_aware_no_duplicate_buys: no suspicious tiny duplicate buys

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:50:13 +08:00
GitHubandClaude Opus 4.8 f7e1abd873 feat: add 9 demo strategy files for backtest engine
Strategies included:
- ma_cross: MA5/MA20 dual moving average crossover
- expma_cross: EMA12/EMA50 crossover (more responsive)
- macd_cross: MACD golden/death cross
- bollinger_breakout: Bollinger band breakout
- rsi_reversal: RSI overbought/oversold reversal
- kdj_golden: KDJ low golden cross / high death cross
- turtle_breakout: Turtle trading (Donchian channel)
- bias_reversal: BIAS mean reversion
- volume_price: Volume-price confirmation

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:45:01 +08:00
GitHubandClaude Opus 4.8 00b7d75caa docs: add backtest engine usage manual
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:37:58 +08:00
GitHubandClaude Opus 4.8 04c2be1d7f fix(backtest): resolve mypy and ruff lint issues
- dsl.py: use NDArray type annotations, fix None narrowing
- cli.py: add type annotations, fix import sorting
- strategy.py: fix UP038 isinstance, add noqa for I() method name
- tests: fix E712 bool comparison assertions

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:21:25 +08:00
GitHubandClaude Opus 4.8 fc0777533e feat(backtest): add CLI command with auto data fetch and table output
- Created src/easy_tdx/backtest/cli.py with backtest command
- Supports --strategy-file to load Python strategy classes
- Supports --indicators to precompute technical indicators
- Supports --cash, --commission, --execution, --period, --adjust, --count options
- Supports json/table/csv output formats
- Auto-loads K-line data via get_mac_client()
- Registered backtest command in src/easy_tdx/cli/__init__.py
- Added tests/unit/test_backtest_cli.py with basic CLI tests

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:15:37 +08:00
GitHubandClaude Opus 4.8 706f22ba5e feat(backtest): add DSL strategy skeleton and update __init__.py exports
- Add dsl_strategy decorator in dsl.py (P1 skeleton implementation)
- Update __init__.py to export BacktestEngine, Strategy, and related types
- All 106 backtest unit tests pass

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:12:38 +08:00
GitHubandClaude Opus 4.8 371915a5f9 feat(backtest): add BacktestEngine with vectorized execution pipeline
- Implement BacktestEngine orchestrator with 4-step pipeline:
  1. Signal generation (Strategy)
  2. Order simulation (OrderSimulator)
  3. Portfolio tracking (PortfolioTracker)
  4. Performance analysis (PerformanceAnalyzer)
- Support both strategy class and instance initialization
- Add PnL calculation for sell trades
- Add JSON serialization with numpy/timestamp support
- Include comprehensive test coverage (12 tests, all passing)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:11:20 +08:00
GitHubandClaude Opus 4.8 94fabccef8 feat(backtest): add PerformanceAnalyzer with 19 metrics
- Implement PerformanceAnalyzer class with compute() method
- Calculate 19 performance metrics: total_return, annual_return, max_drawdown,
  max_dd_duration, sharpe, sortino, calmar, trade statistics, and volatility
- Handle edge cases: empty data, no negative returns (sortino=999), no drawdown (calmar=999)
- Add 20 comprehensive unit tests covering all metrics
- Type annotations use NDArray pattern for mypy strict compliance
- All tests pass, mypy and ruff checks clean

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:05:33 +08:00
GitHubandClaude Opus 4.8 a2aa319803 feat(backtest): add PortfolioTracker with equity curve and drawdown
- Pre-allocate numpy arrays for performance (cash, position, avg_price)
- apply_trades() processes buys/sells with commission and slippage
- equity_curve returns DataFrame with drawdown calculation
- positions returns DataFrame with market value and unrealized PnL
- 12 unit tests covering all scenarios

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 17:55:24 +08:00
GitHubandClaude Opus 4.8 16dc2e7da9 feat(backtest): add OrderSimulator with 5 execution modes and reject policy
- Implement OrderSimulator class for order matching simulation
- Support 5 execution modes: next_open, next_close, this_close, worst, best
- Support 3 position modes: full, fixed, percent
- Support 2 reject policies: reduce (partial fill), skip (reject)
- Implement fee model: commission (min 5 CNY), stamp tax (0.1% sell only), slippage
- Add future_leak_warning flag for this_close mode
- Handle both int and datetime column types in DataFrame
- Add comprehensive test suite with 24 test cases covering all modes

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 17:52:31 +08:00
GitHubandClaude Opus 4.8 687851fc67 feat(backtest): add Strategy base class with DataProxy and crossover
- Add _SeriesAccessor for relative indexed data access ([0] current, [-1] previous)
- Add StrategyDataProxy for efficient DataFrame column access via numpy arrays
- Add crossover() function for golden cross detection (fast line crosses above slow line)
- Add Strategy abstract base class with:
  - init() for indicator registration via self.I()
  - next() for signal generation via buy()/sell()
  - Internal engine hooks (_bind_data, _call_init, _set_bar_index, etc.)
- All code is mypy strict compliant with full type annotations
- 25 unit tests covering all components

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 16:53:57 +08:00
GitHubandClaude Opus 4.8 f37b75ea42 feat(backtest): add core data types (Signal/Trade/Position/BacktestResult)
- Add Signal dataclass for trading signals with optional price/stop_loss/take_profit
- Add Trade dataclass for executed trades with commission/slippage/pnl/rejected
- Add Position dataclass for position snapshots (long/short/flat)
- Add BacktestResult dataclass with to_dict()/to_json()/summary() methods
- Add comprehensive unit tests (13 test cases, 100% pass)
- All code passes mypy strict, ruff lint+format checks

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 16:43:44 +08:00
GitHubandClaude Opus 4.8 5f14c44791 docs: add backtest engine implementation plan
10 tasks, TDD approach, covering:
- Core data types (Signal/Trade/Position/BacktestResult)
- Strategy base class with DataProxy and crossover
- OrderSimulator (5 execution modes + reject policy)
- PortfolioTracker (equity curve + drawdown)
- PerformanceAnalyzer (18 metrics)
- BacktestEngine (vectorized execution pipeline)
- DSL skeleton (P1)
- CLI integration with auto data fetch

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 16:25:11 +08:00
GitHubandClaude Opus 4.8 28925063d4 docs: finalize backtest spec with minor clarifications (rev 2.1)
- DSL identifier rules: letters/digits/underscores
- reduce mode: min(requested, max_affordable) formula
- Chanlun time alignment: nearest K-line <= timestamp
- GridResult/run_many return types documented

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 16:17:02 +08:00
GitHubandClaude Opus 4.8 480e635dcb docs: revise backtest spec per feasibility review (rev 2)
- DSL requires explicit column references (close/open/high/low)
- Add order_reject_policy: reduce | skip
- Add future_leak_warning for this_close execution
- Add benchmark datetime alignment rules
- Support pre-computed indicator columns via StrategyDataProxy
- Add chanlun_result injection (P0 interface, v2 auto-integration)
- Adjust priorities: DSL→P1, run_many/run_grid→P1, chanlun→P1

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 16:14:05 +08:00
GitHubandClaude Opus 4.8 8d68e9c094 docs: add backtest engine design spec
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 16:05:17 +08:00
GitHubandClaude Opus 4.7 2eabbb219a chore: bump version to 1.4.3
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 22:31:31 +08:00
GitHubandClaude Opus 4.7 4c5817f7b0 feat: add BIAS_SIGNAL indicator (30-day bias with signal lines)
Add BIAS_SIGNAL indicator derived from TongDaXin's 30-day bias formula.
Outputs BS_X (raw bias), BS_SMA (short signal line), BS_LMA (long signal
line) for trend direction and reversal detection via asymmetric bull/bear
logic.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 22:31:17 +08:00
GitHubandClaude Opus 4.7 7572b16614 chore: bump version to 1.4.2
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 18:07:48 +08:00
GitHubandClaude Opus 4.7 3410b922ad fix: include ZHUOYAO function in MyTT.py (missing from 1.4.1 release)
The 1.4.1 commit added the indicator registry entry in indicator.py but
forgot to include the actual ZHUOYAO() function definition in MyTT.py.
Also includes lint cleanups (trailing semicolons, import formatting).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 18:07:31 +08:00
GitHubandClaude Opus 4.7 6b06f9eb40 feat: add ZHUOYAO indicator (multi-period momentum resonance), bump to 1.4.1
Add 捉妖大师 (ZHUOYAO) indicator to the indicator registry. Outputs
ZY_LONG/ZY_MID/ZY_SHORT/ZY_TREND four lines based on 20/60/120-day
ROC with EMA smoothing for trend resonance detection.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 17:49:30 +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