独立 Git 仓库:
github.com/W-M-R/quantcore(见 ADR-0007)。本目录在主仓库已 gitignore,通过quantcore @ file://./quantcore安装。 纯量化计算库,独立可发布。零 IO,零网络,零数据库 — 输入 DataFrame/dict,输出 dataclass。
把项目里所有"纯算法"代码(评分模型 + 技术指标 + 风险/相关性统计)抽离到这里,让它们:
- 不依赖 stocklens / api / bot / tickbridge / querybus / pulsefan
- 仅依赖 numpy + pandas
- 可独立测试、独立版本、独立发布到 PyPI
quantcore/
├── pyproject.toml 独立包定义(pip install -e quantcore/)
├── __init__.py 暴露 ScoringEngine + ScoringOverview + BacktestEngine + EvaluationConfig
├── scoring/ 量化评分(18 模型)
│ ├── __init__.py
│ ├── types.py 所有 dataclass 结果类型 + classify_industry / _sf / _unwrap_block + FundamentalContext (M5, 2026-05)
│ ├── fundamental.py Piotroski F-Score / Altman Z / Ohlson O / Composite Distress
│ ├── valuation.py Rule of 40 / PEG / FCF Yield / Graham / Beneish M / DuPont / Magic Formula / Dividend Safety
│ ├── sentiment.py Insider / Options(CBOE 数据,纯计算) / Momentum / Earnings Surprise / Short Interest
│ ├── technical.py SCTR / Risk(Sharpe/Sortino/Beta) / Macro / Market Regime / Peer Rank
│ └── engine.py ScoringEngine — 编排 18 模型 + composite_score(0-100) + format_overview_table
├── indicators/ 纯技术指标
│ ├── __init__.py
│ ├── trend.py StockTrendAnalyzer / TrendSnapshot — MA/MACD/RSI/BB Squeeze/RS vs SPY
│ ├── bollinger.py BollingerResult / MultiBollingerSnapshot + compute_bollinger + update_position_signal
│ ├── resample.py OHLCV 通用 resample 原语:resample_ohlcv + 5 个具名 helper
│ │ (weekly / monthly / quarterly / yearly / N-hour) — 双列名约定 ('date' / 'datetime')
│ ├── labels.py 中文标签函数:describe_volume_ratio / compute_ma_status
│ ├── tech.py FibonacciLevels / SwingPoint / KlinePattern / TechIndicatorSnapshot
│ │ + detect_swing_points / select_fibonacci_swing / compute_tech_indicators
│ └── changepoint.py Changepoint / ChangepointResult + detect_changepoints
│ (二分段 + BIC 惩罚的变点检测,O(N²) 但 N 通常 < 500 故无性能问题)
├── stats/ 统计/风险原语
│ ├── __init__.py
│ ├── risk.py compute_sharpe / compute_sortino / compute_max_drawdown / compute_volatility
│ │ + compute_calmar / compute_omega / compute_tail_ratio (2026-05)
│ ├── correlation.py compute_correlation_pair(成对 stock/benchmark DataFrame → CorrelationResult)
│ ├── hurst.py compute_hurst — Hurst exponent (R/S analysis), 检测均值回归/趋势型
│ └── garch.py fit_garch — GARCH(1,1) 波动率预测,纯 numpy MLE + Nelder-Mead 兜底
└── backtest/ 回测评估引擎(DB-agnostic 协议接口)
├── __init__.py
└── engine.py BacktestEngine(中英双语关键词 + 否定识别)/ EvaluationConfig /
DailyBarLike, BacktestResultLike Protocol
# 评分
from quantcore.scoring import (
ScoringEngine, ScoringOverview, FundamentalContext,
calc_piotroski, calc_distress,
calc_valuation, calc_beneish, calc_dupont,
calc_options_sentiment, calc_momentum,
calc_sctr, calc_risk, calc_macro, calc_market_regime,
classify_industry,
)
# 指标
from quantcore.indicators import (
StockTrendAnalyzer, TrendSnapshot,
BollingerResult, MultiBollingerSnapshot, compute_bollinger,
TechIndicatorSnapshot, FibonacciLevels, compute_tech_indicators,
resample_ohlcv, resample_to_weekly, resample_to_monthly,
resample_to_quarterly, resample_to_yearly, resample_hourly,
describe_volume_ratio, compute_ma_status,
)
# 统计
from quantcore.stats import (
compute_sharpe, compute_sortino, compute_max_drawdown, compute_volatility,
compute_calmar, compute_omega, compute_tail_ratio,
compute_correlation_pair,
compute_hurst, HurstResult, # 均值回归 vs 趋势型检测
fit_garch, GarchResult, # GARCH(1,1) 波动率预测
)
# 指标 — 变点检测
from quantcore.indicators import detect_changepoints, Changepoint, ChangepointResult
# 回测
from quantcore.backtest import (
BacktestEngine, EvaluationConfig,
DailyBarLike, BacktestResultLike, OVERALL_SENTINEL_CODE,
)- 零 IO 边界:quantcore 内部不可有
requests/akshare/sqlite/ 文件读写。所有需要外部数据的模型(如 CBOE 期权情绪)通过 callable 注入 或 直接传 dict 的方式接收已抓取的数据。 - CBOE 期权情绪的边界:
calc_options_sentiment(symbol, current_price, cboe_data)是纯计算;fetch_cboe_options(symbol)这个网络调用留在stocklens.services.scoring._cboe_fetcher,由 stocklens 侧的ScoringService在构造时通过cboe_fetcher参数注入。 - 基准相关性的边界:
compute_correlation_pair(stock_df, benchmark_df, ...)是纯计算;通过 akshare 拉 SPY/QQQ 的 4h 缓存逻辑留在stocklens.services.tech_indicators_service.compute_correlation。 - 多周期布林带的边界:
compute_bollinger / resample_to_weekly / resample_hourly等是纯计算;从 akshare 拉日线 + 雪球拉 60m + 二级缓存的fetch_bollinger_multi_timeframe留在stocklens.services.bollinger_service。 - scoring 命名兼容:
stocklens.services.scoring.ScoringService仍可用(它现在是quantcore.scoring.ScoringEngine的子类,注入了 CBOE fetcher)。
quantcore 内多个热点函数从 Python 循环改为 numpy/pandas 向量化:
| 函数 | 文件 | 优化 | 预期提速 |
|---|---|---|---|
compute_tech_indicators 中的 OBV |
indicators/tech.py |
np.cumsum(np.sign(diff) * volume) 替换 for i in range(...) 配 .iloc[i] |
30-100× |
detect_swing_points |
indicators/tech.py |
Series.rolling(window, center=True).max()/min() 替换 O(n × window) 双循环 |
显著(对长 df) |
StockTrendAnalyzer._calc_volume |
indicators/trend.py |
rolling(5).mean().shift(1) 一次预计算 5 日均量基线 |
lookback 倍数级别 |
calc_options_sentiment 中的 Max Pain |
scoring/sentiment.py |
numpy 广播 (strikes[:, None] - strikes[None, :]) 替换 O(M²) Python 双循环 |
100× (SPY/QQQ 等 200+ 行权价名尤其显著) |
compute_correlation_pair Beta/Alpha (F7) |
stats/correlation.py |
np.corrcoef / np.cov 替换 tail.cov().iloc[0,1] + 重复 tail[bm].var();从原始 numpy array 直接计算,省 2x2 协方差矩阵的 pandas 对象构造 |
50-100× |
compute_correlation_pair 数值正确性由 tests/unit/test_correlation.py::test_numpy_matches_pandas_reference 锁定(金标准等价性测试,6 位小数精度)。
另外,scoring/types.py:classify_industry 加 lru_cache(maxsize=512) —— 一次 pipeline 运行
industry/sector pair 基数极小(≤30 唯一值),memoize 完美命中。
| stocklens 文件 | 保留职责(quantcore 不做) | 委托给 quantcore 的部分 |
|---|---|---|
stocklens/services/scoring/__init__.py |
ScoringService 子类 + 注入 CBOE fetcher + 兼容性 re-export |
ScoringEngine / 全部 calc_* / 18 个 dataclass |
stocklens/services/scoring/{types,fundamental,valuation,sentiment,technical,engine}.py |
纯 re-export shim(保留旧导入路径) | 全部内容 |
stocklens/services/scoring/_cboe_fetcher.py |
fetch_cboe_options 网络调用 |
— |
stocklens/analyzer/trend_analyzer.py |
纯 re-export shim | StockTrendAnalyzer / TrendSnapshot |
stocklens/services/bollinger_service.py |
fetch_bollinger_multi_timeframe(akshare/雪球抓取 + 二级缓存) |
compute_bollinger / 全部 resample / dataclass |
stocklens/services/tech_indicators_service.py |
compute_correlation(akshare 抓 SPY/QQQ + 4h 缓存) |
compute_tech_indicators / 全部纯算法 helper |
stocklens/backtest/engine.py |
纯 re-export shim | 全部 555 行回测算法(关键词识别 / 止损止盈命中 / 胜率聚合) |
stocklens/pipeline/data_collector.py |
DataCollector 类(IO + 业务编排) | _resample_daily / _resample_daily_to_weekly / describe_volume_ratio / compute_ma_status 退化为 quantcore 调用 |
quantcore 没有自己的 tests/(暂时复用 stocklens 现有测试)。新增独立测试套件的工作量较小,建议拆出后再补。
现有 stocklens 测试中以下文件直接覆盖 quantcore 内核:
tests/unit/test_scoring_types.py—_sf/classify_industry/ dataclass label 推断tests/unit/test_composite_score.py—ScoringEngine.calc_composite_score14 个固定用例
pytest tests/ -q → 341 用例全部通过(拆包前后无差异)。
quantcore ──┐
├──→(无任何下游依赖)
└── 仅 numpy / pandas
stocklens ──→ quantcore (单向,stocklens 包装 quantcore 加 IO/缓存)
api / bot ──→ stocklens
quantcore 与 tickbridge / querybus / pulsefan 同级,互不依赖。
-
2026-05 M5 —
FundamentalContext共享解析视图:8+ 个评分函数过去都重复 5 行的嵌套 dict 解包:earn_raw = fundamental.get("earnings", {}) if isinstance(fundamental, dict) else {} earn = _unwrap_block(earn_raw) fr = earn.get("financial_report", {}) or {} bs = earn.get("balance_sheet", {}) or {} bs_prev = earn.get("balance_sheet_prev", {}) or {}
quantcore.scoring.types.FundamentalContext(from_dict(fundamental)classmethod)一次性解析为earnings / financial_report / balance_sheet / balance_sheet_prev / financial_indicators / financial_indicators_prev / cash_flow / income_history / growth / valuation / shares_outstanding / dividend字段,模型可以按属性访问。便利访问器:net_income()/total_assets()/total_liabilities()/total_equity()/revenue()/operating_cash_flow()/prev_net_income()/ebit()。FundamentalContext.ebit()是 EBIT 兜底链的单一来源(先取income_history[0].operating_income,再取financial_report.operating_profit,最后net_profit_parent + |interest_expense| + |income_tax|)—— 之前calc_altman_z/calc_distress/calc_magic_formula各自重复这套兜底,细节不完全一致。 -
2026-05 F1 / F2 — 全部 13 个评分函数迁移到 FundamentalContext:M5 的工具落地。
fundamental.py中的calc_piotroski/calc_mohanram/calc_altman_z/calc_ohlson_o/calc_distress,以及valuation.py中的calc_valuation/calc_beneish/calc_dupont/calc_earnings_quality/calc_magic_formula全部改为ctx = FundamentalContext.from_dict(fundamental)然后用ctx.financial_report/ctx.net_income()/ctx.ebit()访问。_unwrap_block仍然导出(外部用户可能用),但 quantcore 内部已经不再调用。新增 30 个回归测试 (tests/unit/test_fundamental_context.py) 覆盖:dataclass 构造(含None/ 非 dict / 部分缺失的 5 个边界)、所有便利访问器、3 级 EBIT 兜底链(含负值 abs 处理)、与旧_unwrap_block路径的等价性、以及 8 个迁移后的评分函数端到端冒烟。 -
2026-05 高级量化原语接入(开源算法替代品):
stats/hurst.py— Hurst 指数 (R/S analysis),区分均值回归 (H<0.45) / 随机游走 (0.45≤H≤0.55) / 趋势型 (H>0.55)。Mandelbrot & Wallis (1969) 标准 R/S 算法,纯 numpy 实现,无需引入hurst第三方库。直接影响策略选择(趋势策略 vs 均值回归策略)。stats/garch.py— GARCH(1,1) 波动率预测,纯 numpy MLE + Nelder-Mead 单纯形优化器作为 scipy 不可用时的兜底(替代arch第三方库)。输出 ω/α/β/persistence + 长期波动率 + H 步预测。比静态历史标准差准 30-50%,对风险评估和期权定价价值大。indicators/changepoint.py— 变点检测 (Binary Segmentation + BIC penalty),纯 numpy 实现(替代ruptures第三方库)。识别价格/收益序列中的均值漂移点,比 MA 交叉更早识别趋势转折,自动附 ISO 日期串方便报告。复杂度 O(N²) 在 N≤500 时无性能问题。- 新增
tests/unit/test_advanced_quant.py— 14 个测试用例覆盖 Hurst(5)/ GARCH(4)/ Changepoint(5),合成数据验证已知性质(H≈0.5 of 随机游走、α+β<1 of 平稳 GARCH、变点位置接近真实分割点)。 - 测试套件总数 511 → 525,全部通过。
-
2026-05 新增模型与风险指标:
scoring/fundamental.py— 新增 Mohanram G-Score (0-8):成长股质量评分(Mohanram 2005),8 个信号覆盖盈利能力/稳定性/成长投入。与 Piotroski F-Score 互补(F-Score 适合价值股,G-Score 适合成长股)。engine 中两者共存,composite_score 在两者都有时分配 F-Score 10pts + G-Score 2pts,仅有 F-Score 时保持原 12pts(向后兼容)。scoring/fundamental.py— 新增 Altman Z'' Emerging Market 变体(Altman 2005):calc_altman_z新增market参数,当market="A"或"HK"时使用Z''_EM = 3.25 + 6.56X1 + 3.26X2 + 6.72X3 + 1.05X4,阈值 5.85/4.15(比 US modified 版更适合新兴市场资产结构)。calc_distress同步透传market参数。stats/risk.py— 新增 3 个风险指标(纯 numpy/pandas 实现,无外部依赖):- Calmar ratio(Young 1991):年化收益 / |最大回撤|,衡量每单位回撤风险的回报
- Omega ratio(Keating & Shadwick 2002):概率加权收益 / 概率加权损失,比 Sharpe 更全面(不假设正态分布)
- Tail ratio:|95th percentile| / |5th percentile|,衡量收益分布尾部不对称性
stats/risk.py— Sortino ratio 修正:从excess[excess < 0].std()(仅负收益的 std)改为连续下行偏差sqrt(mean(min(R-MAR, 0)²)),与 Sortino & van der Meer (1991) 原始定义一致(所有观测值参与计算,正收益贡献 0)。scoring/types.py—RiskResult新增calmar_60d/omega_60d/tail_ratio_60d字段;新增MohanramResultdataclass;ScoringOverview新增mohanram字段;AltmanResult.version新增"emerging"取值。
-
2026-05 量化模型正确性修复:
scoring/technical.py— Sortino ratio 不再用Sharpe * 1.2伪近似(无学术依据)。改为从上游tech_indicators对象直接读取sortino_20d/sortino_60d(由quantcore.stats.risk.compute_sortino从原始收益序列计算下行标准差得出)。无数据时保持None。scoring/fundamental.py— Altman Z-Score 和 Composite Distress 的 EBIT 估算从NI * 1.25(无依据的固定倍数)改为NI + |Interest Expense| + |Income Tax|(标准会计恒等式 EBIT = NI + IE + Tax)。scoring/fundamental.py— Ohlson O-Score 的 GNP deflator 从硬编码650.0改为可配置参数gnp_index(默认 700.0,更接近 2025 BEA 实际值)。函数签名新增gnp_index: float = DEFAULT_GNP_INDEX。scoring/valuation.py— Beneish M-Score 修复 DSRI bug:原代码(recv/revenue)/(recv/rev_prev)数学退化为rev_prev/revenue(分子分母用同一个 recv)。修正为正确公式(recv_t/revenue_t) / (recv_prev/rev_prev),需要上期应收账款。同时补全 AQI(Asset Quality Index)、DEPI(Depreciation Index)、SGAI(SGA Expense Index)三个原先硬编码为 1.0 的变量——当数据可用时计算真实值,不可用时标注为 defaulted。结果 details 字段标注N/8-var和 defaulted 变量列表。scoring/valuation.py— Graham Number 的 EPS 优先级修正:优先使用 trailing EPS(符合 Benjamin Graham 原始公式),其次从 NI/shares 推导,最后才 fallback 到 forward EPS(标注为 less accurate)。scoring/valuation.py— Magic Formula 从概念错误的1/PE(E/P on equity)改为正确的EBIT/EV(Greenblatt 原始定义),ROIC 从 ROE fallback 改为优先计算EBIT / Invested Capital(IC = NWC + Net Fixed Assets)。当数据不足时 fallback 到旧方法并在 details 中标注(fallback)。scoring/sentiment.py— Earnings Surprise 诚实标注:实际计算的是 EPS QoQ Growth(环比增长率),不是真正的 SUE(需要分析师一致预期数据)。zone 标签从"超预期/不及预期"改为"正增长/下滑",details 标注(QoQ growth, not analyst surprise)。scoring/sentiment.py— Momentum 改进:优先使用真实 12-1 month momentum(P_1m_ago / P_12m_ago - 1,Jegadeesh & Titman 1993),当trenddict 提供price_12m_ago和price_1m_ago时启用。无历史价格时 fallback 到 price vs MA200 并标注(proxy, not true 12-1M)。scoring/sentiment.py— Options Max Pain 计算修复变量遮蔽:numpy 数组从calls/puts/strikes重命名为call_oi_arr/put_oi_arr/strikes_arr,避免覆盖外层同名 list 变量。
-
2026-05 清理死变量:
quantcore/scoring/fundamental.py— Ohlson O-Score 计算只需total_assets/total_liab/net_profit_parent/operating_cash_flow/current_ratio,原代码多提取了total_equity/total_cash但从未使用;composite distress 函数也多余提取了cash_flow/total_assets。已删除,函数行为不变。quantcore/indicators/tech.py— 晨星模式(Morning Star Doji)的判定逻辑里body2 = abs(c2["c"] - c2["o"])和range2 = c2["h"] - c2["l"]计算了但从未参与判定(公式只需c2["c"] < c2["o"]和body1/range1 < 0.2),属研究层面遗留。已删除。