Justin Gu
1e7766754e
style: ruff format tests/unit/test_a_share_extensions.py
...
修复 GitHub Actions 中 ruff format --check 的格式化失败。
2026-07-03 01:30:40 +08:00
Justin Gu
133c208510
release: v1.16.3 — 修复 market-stat 全市场涨跌统计家数偏小10倍
...
通达信统计指数 880005/880006 的计数类字段返回真实家数的 1/10,
get_market_stat 未做缩放还原,导致 up/down/total/limit_up 等系统性偏小 10 倍。
对 6 个计数字段统一 round(field * 10),成交额/量/市值不动。
重写 test_get_market_stat_mapping 覆盖还原逻辑。761 单测全绿。
2026-07-02 12:46:27 +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
Justin Gu
77104a32e3
fix(ci): mypy python_version 3.10 → 3.12 修复 numpy stub 语法错误
...
根因:CI 的 mypy job 在 Python 3.13 下运行,安装的 numpy 2.x stub
使用 PEP 695 type 语句(3.12+ 语法),但 pyproject.toml 的
python_version="3.10" 让 mypy 按 3.10 语义解析,报
'Type statement is only supported in Python 3.12 and greater'。
修复:
- python_version 提升到 3.12(CI mypy job 实际跑 3.13,开发目标版本对齐)
- mypy/ruff 同步排除 gitignored 的 exchange_margin.py 本地脚本
- 顺带修复 market.py / test_screen.py 的 ruff format 漂移
2026-06-25 03:46:57 +08:00
Justin Gu
f36e2d6a6c
feat(screen): v1.15.0 — 强势股排名 + 修复证券类型识别与名称分批查询
...
新增:强势股排名(screen strength)
- 全市场按 5/20/60 日涨幅加权合成强势分,纯离线扫描
- 三种预设:steady(稳健)/breakout(妖股)/balanced(均衡)
- CLI: easy-tdx screen strength --preset steady --top 50 --table
- Web API: GET /api/v1/market/strength
- 支持自定义权重、成交额过滤、并发扫描
修复:
- _detect_security_type 代码段不全,ETF/基金/科创板/逆回购被误判为 A 股
- screen strength/rank 名称补齐超 80 只时末尾被丢弃(分批查询)
详见 CHANGELOG.md
2026-06-25 03:33:13 +08:00
Justin Gu
85e0f8a65f
feat(chanlun): 分钟级别日期自适应输出时分 YYYY-MM-DD HH:MM
2026-06-17 18:17:32 +08:00
Justin Gu
1945fa1261
feat(chanlun): CLI table 模式 zss/mmds/bcs 显示日期字段
2026-06-16 03:00:08 +08:00
Justin Gu
28aad8a84c
release: v1.14.2 — 缠论 JSON 可视化字段增强(中枢/买卖点/背驰补日期)
2026-06-16 02:51:52 +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
Justin Gu
b49cfd66f8
feat(sina): 新增新浪财报三表 — 三层接入(API/CLI/Web),独立数据源
2026-06-15 00:31:13 +08:00
Justin Gu
574b284dd5
fix(cninfo): URL 404 + type null + 表格截断 + PDF 下载(实测 601088 暴露)
2026-06-14 23:58:24 +08:00
Justin Gu
4b439920fc
feat(cninfo): 新增巨潮公告检索 — 三层接入(API/CLI/Web),独立数据源
2026-06-14 23:29:19 +08:00
Justin Gu
a12c2122fc
feat(indicator): 新增 SAR/VWAP/AROON 三指标 + 注册 FK(30 → 34)
2026-06-14 18:46:02 +08:00
Justin Gu
5fc398255d
fix(types): 修复 CI mypy strict + ruff format 失败
...
mypy (13 errors → 0):
- portfolio/optimizer: register_optimizer 返回类型改为 Callable 装饰器签名
(原标注 type[WeightOptimizer] 导致 4 个子类 Too many arguments)
- factor/engine: _datetime_to_int 用 isinstance 收窄替代 object→int 强转
- factor/analysis: 删多余 type:ignore(改由 mypy override 统一处理 scipy)
- backtest/orders, execution: np.sqrt 表达式用 float() 包裹消除 no-any-return
- MyTT.pyi: MACD 签名删除错误的 LOW/HIGH 参数(与 MyTT.py 实际签名对齐)
- pyproject: 新增 scipy mypy override (ignore_missing_imports)
ruff format: 8 个 test 文件格式化
验证: 564 passed, mypy 192 文件零错误, ruff check/format 全绿
2026-06-13 21:21:33 +08:00
Justin Gu
be41746aa9
fix(backtest): _find_bar_index 用 to_numpy().argmax() 取真实位置
...
idxmax() 返回 index label,后续 iloc[] 按位置取行;当 df.index 非默认
RangeIndex 时 label != position,撮合会取错 K 线。两处分支统一改为位置索引。
新增 2 例非连续 index 回归测试。
2026-06-13 21:10:15 +08:00
Justin Gu
095c88f735
fix(transport): ping 容错 TdxConnectionError,避免单台服务器拖垮测速
...
ping_host 仅 except OSError,但握手期 _recv_exact_sock 抛的 TdxConnectionError
继承自 TdxError(Exception) 而非 OSError,逃出捕获后经 ping_all 的 fut.result()
重新抛出,导致非交易时间服务器 accept 后立即 FIN 时整个 easy-tdx ping 崩溃。
- ping_host: except (OSError, TdxConnectionError),对齐 docstring 返回 None
- ping_all: fut.result() 加 try/except 防御层,单 host 失败只跳过不崩
- 新增 2 例回归测试
2026-06-13 21:09:55 +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
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
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 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
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 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
d9bb37f750
feat(factor): wire up builtin factor auto-registration and export
2026-06-12 19:53:18 +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
Justin Gu
0e74752701
fix(web): validate market/category input — support lowercase, reject invalid with 400
...
Root cause: _market_from_str/_market/_category in routers used bare
MarketEnum[key]/Market[key] without .upper() or try/except, so
lowercase or invalid values (sz, ZZZ) threw uncaught KeyError → 500.
Fix: extract shared convert.py with market_from_str/category_from_str
that do .upper() + ValueError on invalid input. All 4 routers updated.
4 regression tests added for case-insensitive and invalid input.
2026-06-12 03:26:29 +08:00
Justin Gu
eb8a7a5675
feat(web): add FastAPI app factory, all routers, CLI serve command, and tests
...
- App factory with lifespan management and CORS middleware
- Market router: security list, quotes, market stat, fund-flow
- Bars router: kline, index kline, minute, transaction
- Finance router: xdxr, finance, company info, financial records
- Block router: block file parsing
- Chanlun router: POST /chanlun/analyze
- Realtime router: WebSocket /ws/realtime/{symbol}
- CLI: easy-tdx serve command
- 16 unit tests, all passing offline (no network)
2026-06-12 03:08:12 +08:00
Justin Gu
9dc70566a5
feat(web): add Pydantic schemas and error handling
2026-06-12 03:02:04 +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
Justin Gu
c9ed57e66d
fix: parallel scan pickle bug — pass strategy file path instead of class to child processes
2026-06-11 04:24:09 +08:00
Justin Gu
bd373b9c3c
fix: exclude .pyi from ruff + fix unused variable in test
2026-06-11 04:06:52 +08:00
Justin Gu
92edc189bb
feat: realtime event-driven market data push framework
...
- Add EventBus for async publish/subscribe market events
- Add MarketEvent dataclass with tick/bar/signal/error types
- Add RealtimeStrategy base class with on_tick/on_bar callbacks
- Add emit_signal() for strategy-to-engine signal publishing
- Support per-symbol and global subscriptions
- API skeleton: transport-level subscription TBD
- Add 10 tests covering events, bus, and strategy
2026-06-11 02:34:00 +08:00
Justin Gu
9c39ad054d
feat: multi-stock portfolio backtest engine
...
- Add PortfolioBacktestEngine for shared-capital multi-stock backtesting
- Support equal allocation mode (total_cash / N per stock)
- Individual BacktestEngine per stock with allocated capital
- Aggregate performance via capital-weighted returns
- Add StockData, PortfolioResult data classes
- Add 4 tests: basic run, equal allocation, empty stocks, serialization
2026-06-11 02:31:43 +08:00
Justin Gu
f4dc28c5d2
feat: add append_klines for incremental chanlun analysis
...
- Store previous DataFrame in ChanlunAnalyser after process_klines
- Add append_klines(df_new) to concatenate and recompute
- Handles datetime deduplication automatically
- Raises RuntimeError if called before initial process_klines
- Add 2 tests: append + recompute, error without init
2026-06-11 02:25:42 +08:00
Justin Gu
ec8d21b7e2
feat: incremental scanning with mtime-based cache
...
- Add cache_file param to SignalScanner for persistent scan cache
- Cache stores {filepath: {mtime, result}} as JSON
- On rescan, skip files with unchanged mtime (reuse cached results)
- Files with changed mtime are rescanned and cache updated
- Add 3 tests: cache reuse, no-cache full scan, cache invalidation
2026-06-11 02:17:52 +08:00
Justin Gu
b7e0f17842
feat: concurrent scanning with ProcessPoolExecutor
...
- Add workers param to SignalScanner.scan() (default=0 for serial)
- workers=2+ uses ProcessPoolExecutor for parallel .day file processing
- Extract _scan_one_file as top-level function for pickle compatibility
- Results identical between serial and parallel modes
- Add 4 tests with synthetic .day file fixtures
2026-06-11 02:09:10 +08:00
Justin Gu
af005d9fe4
feat: auto-bridge chanlun analysis into backtest strategies
...
- Add chanlun_level param to BacktestEngine constructor
- When set, auto-create ChanlunAnalyser and compute ChanlunResult
- Manual chanlun_result in run() takes priority over auto-compute
- Update Strategy.chanlun type to Any (accepts ChanlunResult or dict)
- Add 2 tests: auto-bridge and manual override priority
2026-06-11 01:56:59 +08:00
Justin Gu
815b3ddf7c
feat: implement stop-loss/take-profit execution in backtest engine
...
- Track SL/TP conditions from BUY signals in _generate_signals loop
- Check active conditions against each bar's high/low price range
- Auto-generate SELL signal at trigger price when condition is met
- Modify OrderSimulator to respect signal.price for direct execution
(previously signal.price was stored but never used in execution)
- SL/TP activates on bar AFTER BUY signal (consistent with next_open)
- Stop-loss checked before take-profit (conservative for holder)
- Add 4 tests: SL trigger, TP trigger, no-trigger, priority over manual sell
2026-06-11 01:53:11 +08:00
Justin Gu
06b2617ebc
fix: CI coverage enforcement, real avg_holding_days, vectorize _datetime_to_int
...
- Add --cov and --cov-fail-under=50 to CI pytest command
- Replace hardcoded avg_holding_days=5.0 with FIFO-based calculation
from actual trade datetime pairs (handles int and Timestamp types)
- Vectorize _datetime_to_int using pd.to_datetime().strftime()
instead of Python for-loop (~100-200x faster on large arrays)
- Add 3 new test cases: weighted holding days, no datetime fallback,
only-buys edge case
2026-06-11 01:44:39 +08:00