Commit Graph
84 Commits
Author SHA1 Message Date
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
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 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
GitHubandClaude d5fa572a43 style: ruff format factor module
Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-12 19:58:34 +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
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
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 9d7a9161f7 fix(web): remove TYPE_CHECKING guard for AsyncTdxClient in deps.py
The typing.cast(AsyncTdxClient, ...) evaluated AsyncTdxClient at
runtime, but the import was gated behind TYPE_CHECKING, causing
NameError in production.  Direct import is safe here — web module
already depends on easy_tdx core.
2026-06-12 03:21:39 +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
Justin Gu 7f44ba1d06 feat(web): scaffold web API module with [web] optional dependency 2026-06-12 03:00:49 +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
Justin Gu 786c7e3619 fix: remove unused type: ignore comments for mypy strict 2026-06-11 04:30:39 +08:00
Justin Gu c25570eb86 fix: mypy strict — type annotate co_filename in _get_strategy_file 2026-06-11 04:27:54 +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 15cc7680c4 release: v1.9.7 — CLI全量集成(workers/cache/chanlun-level/portfolio/multi-level)+ bugfix 2026-06-11 03:57:48 +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 fa5bd2d44d feat: add MyTT.pyi type stubs, enable strict mypy
- Create type stub file for 50+ MyTT indicator functions
- Covers all 31 functions used in the project + common utilities
- Remove mypy disallow_untyped_defs/calls override for MyTT
- MyTT now covered by strict mypy via .pyi stubs
2026-06-11 02:29:47 +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 6d74c2e5eb feat: enhance multi-level chanlun analysis with trend/overlap/divergence
- Add trend_direction detection (up/down/None) via consecutive bi analysis
- Add bi_overlap detection for consolidation identification
- Add divergence_possible check (2+ ZS + diminishing amplitude)
- Return type changed from dict[str, int] to dict[str, Any]
- Backward compatible: all original fields preserved
- Extract 3 helper functions for clean separation of concerns
2026-06-11 02:22:31 +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
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
Justin Gu 531d0c05bc fix: remove hardcoded version in 'version' command, read from importlib.metadata 2026-06-10 03:39:09 +08:00
Justin Gu 862f713483 feat: add 'run-all' CLI command for batch strategy backtesting (v1.9.3) 2026-06-10 03:24:31 +08:00