GitHub
1ad88371da
docs: 升级计划 P4 收尾进度更新——三项遗留(E2E/WebSocket/引擎向量化)全部落地
2026-09-01 23:47:52 +08:00
GitHub
36ea8497ae
perf(engine): 信号管线提速 ×12.6 — 向量化快速路径 + 日期查找表 + 去 strftime
...
基准先行(scripts/bench_engine.py):ma_cross 800 根全流程基线 93.6ms。
profile 打破预期:85% 墙钟在 OrderSimulator._find_bar_index(每信号全列
strftime),而非计划认为的逐 bar 信号循环。三处优化(行为逐位一致):
- Strategy 新增 entry_exit_masks() 显式钩子,19 个内置策略全实现;引擎按
掩码 + 候选事件 bar 状态机一次产出信号,持仓估算逐行复刻
_update_strategy_position(含买不足 1 手退化路径);约束检测
_vectorize_eligibility 显式可测,signal_path=auto/vector/loop 可指定;
不满足约束(无钩子/缠论注入/掩码形状错)自动回退逐 bar
- OrderSimulator._build_dt_lookup:O(信号×bar) 全列扫描 → 每 simulate 一次
O(bar) 查找表(重复日期取首个、未命中 None、object 恒不匹配语义对齐)
- _datetime_to_int 去 strftime:year*10000+month*100+day 整数算术
(NaT→NaN 行为一致),_bind_data 与查找表共用
实测:ma_cross 全流程 93.6→7.4ms(×12.6),信号层 ×1.39~1.72(四策略);
32 点网格寻优 ~3.0s→231ms。对拍 39 例:19 策略×参数变体×warmup/低资金/
费率/缓存,performance/trades/equity/positions 逐位一致。
顺带记录:wr_reversal 默认阈值与 MyTT WR 刻度不匹配(策略恒不交易,既有问题未改)
2026-09-01 23:47:06 +08:00
GitHub
1aacce9b7d
release: v1.27.1 — 回测页附加分析布局修复 + WebSocket 实时推送收录
2026-09-01 23:30:02 +08:00
GitHub
b693af5ca2
fix(web-ui): 附加分析开关复选框被全局 input{width:100%} 撑满整行导致文字折行
...
根因:全局样式 input,select,textarea{width:100%}(style.css:75)把勾选框也撑满
整行(实测 156px),文字被挤到下一行、窗口数控件块状堆叠。修复:
- 复选框显式 width:auto 恢复原生 13px(.check-label input[type=checkbox])
- 布局重写为单行 flex:勾选框+文字+窗口数同行,white-space:nowrap 不折行,
显式覆盖全局 label{display:block} 与 margin
- 实机验证(Chrome CDP):复选框 13px 靠左、两行均单行(行高 18-21px)、
窗口数输入框 44px 同行跟排、区域零横向溢出
2026-09-01 23:26:39 +08:00
GitHub
e58de789ab
feat(ws): /ws/realtime 接通 RealtimeDataFeed — 按需轮询 hub + fan-out + 冒烟脚本
...
- web/realtime_hub.py:RealtimeStreamHub——订阅集合变化按需启停 RealtimeDataFeed,
无人订阅完全停止轮询(对齐 QuoteStreamer 节能);EventBus → 每连接队列
fan-out(丢最旧保最新);去重标的上限 80;lifespan 挂载/关闭
- routers/realtime.py 重写:连接即订阅、断开退订、subscribe/unsubscribe 控制帧、
30s ping 心跳;单一写者泵模型(全部出站帧经队列串行,防并发 send 交错)
- 修复 RealtimeDataFeed stop-before-start 竞态(_stop_requested 标志),
补 2 个回归用例;hub 单测 10 例(并发订阅/退订竞态、跨标的串扰、背压、
TestClient 端到端)
- 前端接入选文档方案(api_reference.md 协议+重连/心跳骨架;README 撤「未联动」):
SSE 已覆盖看板/自选实时刷新,WS 定位按需单标的 tick,双通道冗余无必要
- scripts/ws_smoke.py:手动冒烟(mock 模式实测 tick 帧与动态订阅确认可见)
2026-09-01 23:21:42 +08:00
GitHub
bec231e8be
test: 修复时段门控用例的时间相关 flaky(当地 23 点档必炸)
...
test_outside_session_no_fetch 此前用固定 23:00-23:59 模拟盘外时段,
但当测试跑在当地 23:00-23:59 时当前时刻恰好落在该时段内,断言必炸(本地
23 点后全量回归复现)。改为动态构造「当前时刻 +5~+6 分钟」的 1 分钟未来
时段,任何时刻运行都保证盘外。1263 全量通过。
2026-09-01 23:05:14 +08:00
GitHub
697fad71e1
docs: README 介绍补充 v1.24~v1.27 能力,CHANGELOG 补录 1.27.0 修复与文档
...
- README:介绍部分新增「防过拟合验证链」「通达信公式 + 轮动组合」「本地 K 线数据仓库」
三段;回测可视化段补充附加分析开关;CLI 参考新增 --wf/--evaluate 示例与
formula / warehouse 两个命令组小节
- CHANGELOG:1.27.0 条目补录「修复」(CI UP038 版本漂移、任务状态跃迁锁内
落盘竞态)与「文档」两节
2026-09-01 23:01:42 +08:00
GitHub
211052f0e3
feat(e2e): Playwright E2E 前端测试基建 — 后端合成数据 mock 模式 + 5 用例 + CI
...
- web/e2e_mock.py:EASY_TDX_E2E_MOCK=1 时 lifespan 替换 TDX/MAC 客户端为
确定性合成数据(CRC32 播种随机游走,分页语义对齐真实 /bars);回测/WF/
评估/自选/策略库仍走真实后端,SSE 由 QuoteStreamer 真轮询(mock 下 2s 一拍)
- web-ui:@playwright/test + playwright.config.ts(webServer 自动起 serve,
EASY_TDX_CONFIG_DIR 指向每轮临时目录);e2e/ 5 用例覆盖看板五指数/SSE、
自选增删、回测全流程、附加分析(WF 柱状图+一条龙评估卡)、策略库保存
- package.json 加 test:e2e;CI frontend job 追加 E2E;verify_ci.sh 补前端段
- tests/unit/test_e2e_mock.py(11 例)守护 mock 契约;本地 npx playwright test 全绿
2026-09-01 22:56:38 +08:00
GitHub
6b67885588
fix(web): 任务状态跃迁在锁内先落盘再对内存可见,消除 done/running 竞态窗口
...
CI(ubuntu 3.12 + coverage 插桩)复现:_run 在锁内置内存状态为 done 后才在锁外
persist SQLite,测试轮询到内存 done 立即读库仍见 running。慢速环境下窗口被
放大。修法与 submit 的 pending 写法对齐:running/done/failed 三次跃迁均在
同一把锁内先 _persist_locked 再改内存字段,状态对外可见前必已落盘(本地
15 次压测 + 1252 全量回归通过)。
2026-09-01 22:46:01 +08:00
GitHub
561e2d3e61
fix(lint): isinstance 元组写法改 PEP 604 联合类型,修复 CI 的 UP038
...
CI 经 requirements-dev.txt 锁定 ruff==0.11.11(UP038 仍生效),本地 0.16.4 已移除该
规则导致漏检。10 处 isinstance(x, (A, B)) 统一改为 isinstance(x, A | B)(项目
requires-python>=3.10,联合类型 isinstance 合法;strategy.py 已有同风格先例)。
已用 CI 同版本工具链本地复验:ruff 0.11.11 check/format、mypy 2.1.0 strict、
1252 单测全过。
2026-09-01 22:36:37 +08:00
GitHub
917295edaf
release: v1.27.0 — 通达信公式解析器三通道 + 轮动组合引擎 + 回测页WF/评估开关 + Docker 部署
...
升级计划 P3 + P4(部分)。全量 1252 单测、ruff/mypy strict、前端 vue-tsc+vite build 全绿。
- 通达信公式解析器(formula.py):自建 tokenizer + 递归下降 AST + 30+ 函数白名单求值
(不走 Python eval);命名布尔输出=信号列、数值输出=排名列;除零→NaN、预热期不出信号
- 公式三通道:CLI easy-tdx formula compute|screen|backtest;REST /formula/validate|compute|
backtest|screen(run/async);Python API run_formula_backtest(买/卖列自动挑选)
- 轮动组合引擎(rotation.py):排名定期换仓(打分只用截至当日数据)、槽位等额、
跌出排名自动补位、日/周/月刷新、槽内止盈止损;momentum_score/formula_score 打分;
REST /backtest/rotation/run/async
- 回测页附加分析开关(Web UI):勾选后随回测并行跑 WF(逐窗红涨绿跌柱状图+汇总卡,
窗口数 2~12)与一条龙评估(评分分项条/高适配徽标/买入持有对比/8 项适配检查);
新增 WalkForwardPanel/EvaluatePanel 组件与 store runWalkforward/runEvaluate;
WF 端点 ?n_windows= 透传;修复报告 numpy 标量 REST 400(源头清洗)
- Docker 部署(Dockerfile + docker-compose.yml,/data 卷 + 健康检查)与
scripts/verify_ci.sh 一键门禁
- 升级计划文档 docs/upgrade-plan-2026H2.md(四阶段全部完成 + 诚实实测数据)
- 未做(独立排期):Playwright E2E、WebSocket 实时联动、引擎逐 bar 向量化
2026-09-01 22:17:57 +08:00
GitHub
9569b2653c
release: v1.26.0 — DuckDB K线仓库 + provisional 状态机 + 增量同步 + 健康自检
...
升级计划 P2(P2-2 评级后端化已随 1.25.0 提前交付):把碎片化缓存升级为统一数据底座,
对齐 indicator-lab 自建 DuckDB 层的定位。
- warehouse/ 包:DuckDB 单文件(~/.easy_tdx/warehouse.duckdb,随 EASY_TDX_CONFIG_DIR),
列存 + 主键 upsert 去重;duckdb 为可选依赖(pip install easy-tdx[warehouse])惰性导入
- provisional/completed 状态机:15:05 前当日 bar 逐行标记临时,查询/回测默认忽略,
promote_provisional 过期转正,include_provisional 显式可见
- 增量同步器:首同步全量(默认 8000 根)此后只补尾部 15 根,批次进度回调、单标失败不中断
- 健康自检:疑似缺口/异常跳变(复用 QFQ 对拍跳空检测)/最新度/provisional 统计
- CLI easy-tdx warehouse sync|query|stats|check(sync 支持 @文件标的列表)
2026-09-01 22:17:28 +08:00
GitHub
b2509a8d0e
release: v1.25.0 — Walk-Forward/适配性/一条龙评估防过拟合链 + 评分评级后端化 + 寻优加速
...
升级计划 P1:补上两个下游项目都在自研的样本外验证空白。
- Walk-Forward 引擎(walkforward.py):7 窗样本外、每窗独立开仓(backtest-system v1.2.1 踩坑语义)、
上下文预热不污染;CLI --wf、REST /backtest/wf/run/async
- 适配性评估(fitness.py):train/valid/test 三段 + 8 项可解释检查 + 高适配标记;
evaluate_prefix 滚动过滤原语(无未来泄漏)
- 一条龙评估(benchmark.py evaluate_strategy):回测+WF+适配性+评分+评级+买入持有基准对比;
CLI --evaluate、REST /backtest/evaluate/run/async
- 综合评分(scoring.py,收益50/夏普15/回撤10/Sortino5/WF20)+ 评级后端化(grading.py,
前端 TS 忠实移植,REST 响应新增 grade/score 字段)
- 多 seed 验证 + 四项晋级门槛(validation.py);REST /backtest/multiseed/run/async
- 寻优两段式加速:IndicatorCache(36 点网格命中率 41.7%)+ workers 进程并行(实测约 2x);
诚实注:指标缓存墙钟 ~1.01x,瓶颈在逐 bar 循环,后续向量化
- strategy.I() 指标缓存钩子 + 数据代理零拷贝(astype copy=False);
types.to_json_native 统一 numpy 清洗
2026-09-01 22:17:08 +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
6412880dbe
release: v1.23.3 — serve --no-ui 纯 API 模式 + 概念冷榜修复 + 文档截图
2026-09-01 18:37:00 +08:00
GitHub
ac4ac6b2aa
feat(cli): serve 新增 --no-ui 纯 API 模式
...
- --no-ui:不托管 Web UI 前端(根路径 404),仅 /api/v1/* REST 接口,
且不自动打开浏览器——给 AI Agent / 程序化调用省去前端资源
- create_app/_create_app 新增 enable_ui 参数(默认 True 行为不变)
- 测试锁定:no-ui 模式无 web-ui Mount 且 API 路由完整;四道门禁全绿
(ruff / ruff format / mypy / 1079 tests),实测根路径 404 + API 正常
2026-09-01 18:33:49 +08:00
GitHub
9d206c121b
docs: README 三通道介绍下方新增 CLI 输出示例截图(cli-page-1)
2026-09-01 18:28:08 +08:00
GitHub
62ae92e7f0
docs: README 数据评级系统段落下方新增评级徽章截图(web-ui-page-5)
2026-09-01 18:25:04 +08:00
GitHub
8b20bbe17e
docs: README 简介区行情终端段落下方新增看板截图(web-ui-page-4)
2026-09-01 18:22:04 +08:00
GitHub
b65870fa79
fix(webui): 概念板块冷榜拉全量——120 截断致冷榜全为正值板块
...
概念板块约 269 个,降序拉 120 时第 113-120 名仍在 +0.7% 附近(正值),
slice(-8) 展示的是'涨幅第 120 名附近'而非跌幅榜。行业板块仅 86 个,
120 已全量故表现正常。概念改为拉 500(MAC 分页 150/批共 2 页请求,
实测尾部 -2.35%~-3.83% 恢复真冷榜)。
2026-09-01 18:10:42 +08:00
GitHub
6bfe5a2cee
release: v1.23.2 — 1.23.1 质量门禁补丁(mypy strict + ruff 全绿)
2026-09-01 18:02:40 +08:00
GitHub
dffcd9f792
style: ruff format 三文件重排(quote_streamer/watchlist_store/test_ex_tick_chart_date)
...
本地预演 CI 全部四道门禁通过:ruff check / ruff format --check /
mypy (226 files) / 1078 tests
2026-09-01 17:58:12 +08:00
GitHub
6fe3f0f8c4
fix: 补齐 CI 质量门禁——mypy strict 类型标注 + ruff 行宽/导入排序
...
- watchlist_store/routers/watchlist: 裸 dict 补泛型参数 dict[str, object]
- routers/stream: event_gen 返回 AsyncGenerator[str, None] 注解
- app: _watch_symbols 返回类型;teardown 变量改名消除类型冲突
- ruff: 5 处超长行拆行、3 处导入排序自动修复
ruff / mypy (226 files) / 1078 tests 全绿
2026-09-01 17:52:36 +08:00
GitHub
a79861af76
release: v1.23.1 — 行情终端 WebUI 重大升级
2026-09-01 17:45:12 +08:00
GitHub
33d44ba5d6
feat(webui)!: 行情终端重大升级——市场看板/自选/个股与板块弹窗 + SSE 实时推送
...
展示层对标专业看盘终端(tick-stock-panel 模式),数据全部来自通达信协议直连:
- 市场看板:五大指数实时条(迷你分时)、涨跌统计、四维情绪雷达、
全市场涨跌分布直方图(约 5500 只 22 桶、鼠标跟随浮窗)、涨停雷达、
行业/概念热冷榜(可下钻)、涨幅/跌幅/成交额/换手四联排行榜、异动雷达
- 自选行情:6 位代码即加(symbol-info 自动取名)、SSE 实时全表刷新、
行内迷你分时;SQLite 持久化(watchlist.db,幂等加删)
- 个股弹窗:五档盘口 + 1/3/5 日分时 + 日K(MA/BOLL/EMA + MACD/KDJ/RSI
前端本地计算)+ 一键加自选 + 一键全策略寻优
- 板块弹窗:板块分时/日K + 成分股涨跌榜直达个股
- SSE 架构:QuoteStreamer 单循环轮询 fan-out(独立队列 + 背压丢旧、
无订阅休眠、盘中 8s/盘外 60s 降频);前端 pinia 单连接指数退避重连
- fix(codec): SH 000 系大盘指数与 881/885 板块指数报价按 2 位小数解析
(曾缩小 10 倍:科创50 1647.53→164.753);880 统计指数保持 3 位
- fix: 前端批量五档路径 /security/quotes→/quotes、SSE 五档白名单
bid1_vol→bid_vol1、MAC 排行 close 列归一化、日K v-if 撑满、
寻优查看跳转 /→/backtest、FastAPI 0.141 _IncludedRouter 测试适配
新增 27 个单测(streamer/自选/小数位语义),全套 1078 passed
2026-09-01 17:45:07 +08:00
GitHub
6c30b72e29
release: v1.20.13 — sync-daily 成交量单位修复(#60):股→手换算,修复大盘股 uint32 溢出
2026-08-31 20:28:32 +08:00
GitHub
a7b14d3388
release: v1.20.12 — ex tick --date 修复(#56):接受 YYYYMMDD 整数,对齐 A 股日期语义
2026-08-28 22:41:24 +08:00
GitHub
05db452cc0
release: v1.20.11 — 资金流口径标注(#55):聚合逐笔成交额分档,实质为主动买卖总失衡
2026-08-28 20:14:41 +08:00
GitHub
1b7d8a5fff
docs(client): 资金流口径标注——0x0fb5 逐笔为聚合记录、按成交额分档,与东财主力净额不可比(issue #55)
2026-08-28 20:14:41 +08:00
GitHub
31599a6e13
release: v1.20.10 — 板块列表涨速恒 0 修复(#53):暴露 sort_column 排序键
2026-08-26 15:21:53 +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
GitHub
8c35a864e8
release: v1.20.9 — 历史资金流修复(#52):当日主力净额盘中可取 + main_net_inflow 列
2026-08-26 15:01:50 +08:00
GitHub
574ffdd2a4
fix(client): 历史资金流当日行全零 + 主力净额列缺失(issue #52)
...
三个根因(全部实测核实):
1. Category 22 直连接口为虚构协议——52 台已知服务器中 46 台可达的
全部仅回 2 字节空包,从未成功过;移除死代码与臆造解析格式。
2. 历史逐笔接口当日数据要收盘清算后才有,日 K 盘中已含当日 bar,
故 start=0 的最新一行恒为全 0——当日 bar 改走当日实时逐笔接口。
3. main_net_inflow 此前仅为 dataclass property,asdict 静默丢弃,
返回 DataFrame 无主力净额列——新增 _fund_flow_df_with_net 物化
(history 紧随 date 列、当日快照放首列)。
sync + async 双客户端同步修改;更新示例与三份文档;重写/新增回归
测试(当日实时逐笔路径、主力净额列断言)。
2026-08-26 15:00:53 +08:00
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
GitHub and Claude
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
GitHub and Claude
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
GitHub and Claude
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
GitHub and Claude
2eeb7f9806
chore: bump version to v1.15.0
...
Co-Authored-By: Claude <noreply@anthropic.com >
2026-06-12 21:11:23 +08:00
GitHub and Claude
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
GitHub and Claude
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
GitHub and Claude
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
GitHub and Claude
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
GitHub and Claude
d5fa572a43
style: ruff format factor module
...
Co-Authored-By: Claude <noreply@anthropic.com >
2026-06-12 19:58:34 +08:00
GitHub and Claude
d35b08ff85
chore: bump version to v1.11.0
...
Co-Authored-By: Claude <noreply@anthropic.com >
2026-06-12 19:58:28 +08:00
GitHub and Claude
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
GitHub and Claude
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
GitHub and Claude
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
GitHub and Claude
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
GitHub and Claude
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
GitHub and Claude
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
GitHub and Claude
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
GitHub and Claude
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
GitHub and Claude
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
GitHub and Claude 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
GitHub and Claude 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