AI 原生量化投研平台AI-native quantitative research platform
正在加载…Loading…
页面仍在加载,可以继续等待,或重新加载。The page is still loading. You can keep waiting or reload.
部分页面资源未能加载,请重新加载。Some page resources could not load. Please reload.
设备当前处于离线状态,恢复连接后可以继续等待或重新加载。Your device is offline. Once connected, you can keep waiting or reload.
动量与摆动类技术指标因子
27 个字段 · 主键 date + instrument
围绕价格变化速度与摆动幅度的因子族:CCI 度量价格相对典型价格的标准化偏离,ROC/MTM/MI 直接度量价格变动,PSY 统计上涨天数占比,DPO 剔除长期趋势后的周期波动,DDI/SI/SRDM 类指标从多空方向的动量差角度刻画摆动强度,DBCD/MICD/RCCD 则是“差分后再平滑”的异同离差族。
- 因子数量:23 个因子 / 25 个数据列
- 主键:
date+instrument(按cn_stock_instruments对齐全市场标的)- 数据起始:2010-01-01,日频增量更新
- 复权口径:后复权(
cn_stock_bar1d全表统一)
| 上游表 | 用途 | 本表用到的字段 |
|---|---|---|
cn_stock_bar1d | 后复权日行情,全部因子的计算输入 | date, instrument, open, high, low, close |
cn_stock_instruments | 全市场标的清单,决定本表每日的 date / instrument 组合 | date, instrument |
cn_stock_bar1d为分区表,SQL 的 date 过滤由dai.query(filters={"date": [...]})下推完成。
| # | 因子中文名 | 字段名 | 参数 | 因子逻辑 | 所属因子族 |
|---|---|---|---|---|---|
| 1 | 顺势指标 | cci14 | 14 | 价格偏离典型价格的标准化度量 | CCI 顺势指标族 |
| 2 | 顺势指标 | cci20 | 20 | 价格偏离典型价格的标准化度量(长窗) | CCI 顺势指标族 |
| 3 | 变动率 | roc6 | 6 | 价格 6 期变动率 | ROC 变动率族 |
| 4 | 变动率 | roc12 | 12 | 价格 12 期变动率 | ROC 变动率族 |
| 5 | 变动率 | roc24 | 24 | 价格 24 期变动率 | ROC 变动率族 |
| 6 | 心理线 | psy12 | 12 | 12 日内上涨天数占比 | PSY 心理线族 |
| 7 | 心理线 | psy24 | 24 | 24 日内上涨天数占比 | PSY 心理线族 |
| 8 | 动力指标 | mtm6 | 6 | 当日收盘减 6 日前收盘 | MTM 动力指标 |
| 9 | 动力指标均值 | mamtm6 | 6 | MTM 的 6 日移动平均 | MTM 动力指标 |
| 10 | 价格振荡指标 | priceosc | 12/26 | 短长均线差占短均线比例 | PRICEOSC 价格振荡指标 |
| 11 | 区间震荡线 | dpo | 11/6 | 剔除长期趋势后的周期波动 | DPO 区间震荡线 |
| 12 | MI 修正指标 | srmi9 | 9 | 涨跌方向不同的变化率基准 | SRMI(MI 修正指标) |
| 13 | 商品通道指数 | cci_5 | 5 | TP 相对 TP 均值的标准化偏离 | CCI 商品通道指数族 |
| 14 | 商品通道指数 | cci_30 | 30 | TP 相对 TP 均值的标准化偏离 | CCI 商品通道指数族 |
| 15 | 商品通道指数 | cci_60 | 60 | TP 相对 TP 均值的标准化偏离 | CCI 商品通道指数族 |
| 16 | 商品通道指数 | cci_120 | 120 | TP 相对 TP 均值的标准化偏离 | CCI 商品通道指数族 |
| 17 | 方向标准差偏离指数 | ddi | 13/30/5 | 多空方向波动差的平滑偏离 | DDI 方向标准差偏离指数 |
| 18 | 异同离差乖离率 | dbcd | 5/16/76 | BIAS5 差分后再平滑 | DBCD 异同离差乖离率 |
| 19 | 摆动指标 | si | 1 | 综合开高低收关系的摆动值 | SI 摆动指标 |
| 20 | 慢速随机指标 | sdj | 9/3/3 | KDJ 的 D 值再平滑(慢速) | SDJ 慢速随机指标 |
| 21 | 动量指标 | mi12 | 12 | 收盘 12 日差值的 12 日平滑 | MI 动量指标 |
| 22 | 异同离差动力指数 | micd | 1/3/10/20 | MI 均线的快慢差再平滑 | MICD 异同离差动力指数 |
| 23 | 百化率指数 | rc50 | 50 | 收盘相对 50 日前比率 | RC 百化率指数 |
| 24 | 百化率指数平滑 | arc50 | 50 | RC 滞后一期后的 50 日均值 | RC 百化率指数 |
| 25 | 异同离差变化率指数 | rccd | 59/20/27 | RC 快慢差再平滑 | RCCD 异同离差变化率指数 |
公式:TP = (H+L+C)/3;CCI = (TP − MA_N(TP)) / (0.015 × MAD_N(TP))
输出列(2):cci14、cci20
SELECT date, instrument, m_ta_cci(high, low, close, 14) AS cci14, m_ta_cci(high, low, close, 20) AS cci20FROM cn_stock_bar1dWHERE close IS NOT NULLORDER BY date, instrument公式:ROC_N = (Close − Close_N日前) / Close_N日前 × 100
输出列(3):roc6、roc12、roc24
SELECT date, instrument, m_ta_roc(close, 6) AS roc6, m_ta_roc(close, 12) AS roc12, m_ta_roc(close, 24) AS roc24FROM cn_stock_bar1dWHERE close IS NOT NULLORDER BY date, instrument公式:PSY_N = COUNT(Close > 前Close, N) / N × 100
输出列(2):psy12、psy24
SELECT date, instrument, m_sum(if(close > m_lag(close, 1), 1, 0), 12) / 12.0 * 100 AS psy12, m_sum(if(close > m_lag(close, 1), 1, 0), 24) / 24.0 * 100 AS psy24FROM cn_stock_bar1dWHERE close IS NOT NULLORDER BY date, instrument公式:MTM = Close − Close_6日前;MAMTM = MA6(MTM)
输出列(2):mtm6、mamtm6
SELECT date, instrument, close - m_lag(close, 6) AS mtm6, m_avg(close - m_lag(close, 6), 6) AS mamtm6FROM cn_stock_bar1dWHERE close IS NOT NULLORDER BY date, instrument公式:PRICEOSC = (MA12 − MA26) / MA12 × 100
输出列(1):priceosc
SELECT date, instrument, (m_avg(close, 12) - m_avg(close, 26)) / NULLIF(m_avg(close, 12), 0) * 100 AS priceoscFROM cn_stock_bar1dWHERE close IS NOT NULLORDER BY date, instrument公式:DPO = MA6(Close − MA11)
输出列(1):dpo
SELECT date, instrument, m_avg(close - m_avg(close, 11), 6) AS dpoFROM cn_stock_bar1dWHERE close IS NOT NULLORDER BY date, instrument公式:SRMI = IF(C > C9, (C−C9)/C, IF(C < C9, (C−C9)/C9, 0))
输出列(1):srmi9
SELECT date, instrument, CASE WHEN close > m_lag(close, 9) THEN (close - m_lag(close, 9)) / NULLIF(close, 0) WHEN close < m_lag(close, 9) THEN (close - m_lag(close, 9)) / NULLIF(m_lag(close, 9), 0) ELSE 0 END AS srmi9FROM cn_stock_bar1dWHERE close IS NOT NULLORDER BY date, instrument公式:CCI = (TP − SMA(TP, n)) / (0.015 × MAD(TP, n))
输出列(4):cci_5、cci_30、cci_60、cci_120
SELECT date, instrument, m_ta_cci(high, low, close, 5) AS cci_5, m_ta_cci(high, low, close, 30) AS cci_30, m_ta_cci(high, low, close, 60) AS cci_60, m_ta_cci(high, low, close, 120) AS cci_120FROM cn_stock_bar1dWHERE close IS NOT NULLORDER BY date, instrument公式:DMP = IF(H+L ≤ 前H+前L, 0, MAX(|H−前H|, |L−前L|));DMM 对称;DIZ = SUM(DMP,13)/(SUM(DMP,13)+SUM(DMM,13));DDI = MA5(MA30(DIZ − DIB))
输出列(1):ddi
WITH ddi_base AS ( SELECT date, instrument, high, low, m_lag(high, 1) AS pre_h, m_lag(low, 1) AS pre_l FROM cn_stock_bar1d WHERE close IS NOT NULL),ddi_calc AS ( SELECT date, instrument, CASE WHEN high + low <= pre_h + pre_l THEN 0公式:BIAS5 = (Close − MA5)/MA5;DBCD = MA76(BIAS5 − LAG(BIAS5, 16))
输出列(1):dbcd
WITH dbcd_base AS ( SELECT date, instrument, (close - m_avg(close, 5)) / NULLIF(m_avg(close, 5), 0) AS bias5 FROM cn_stock_bar1d WHERE close IS NOT NULL)SELECT date, instrument, m_avg(bias5 - m_lag(bias5, 16), 76) AS dbcdFROM dbcd_baseORDER BY date, instrument公式:HC = |H−前C|,LC = |L−前C|,HL = H−L;K = MAX(HC, LC);T = MAX(HL, HC, LC);R 按 Wilder 三分支取值(HC 最大 → HC−LC/2+|前C−前O|/4;LC 最大 → LC−HC/2+|前C−前O|/4;否则 → HL+|前C−前O|/4);SI = 50 × ((C−前C) + 0.5×(C−O) + 0.25×(前C−前O)) / R × (K / T)
输出列(1):si
WITH si_base AS ( SELECT date, instrument, open, high, low, close, m_lag(open, 1) AS pre_open, m_lag(close, 1) AS pre_close FROM cn_stock_bar1d WHERE close IS NOT NULL),si_part AS ( SELECT date, instrument, open, close, pre_open, pre_close, abs(high - pre_close) AS hc,公式:RSV = (C − MIN9(L))/(MAX9(H) − MIN9(L))×100;K = MA3(RSV);SDJ = MA3(K)
输出列(1):sdj
WITH sdj_rsv AS ( SELECT date, instrument, (close - m_min(low, 9)) / NULLIF(m_max(high, 9) - m_min(low, 9), 0) * 100 AS rsv FROM cn_stock_bar1d WHERE close IS NOT NULL),sdj_k AS ( SELECT date, instrument, m_avg(rsv, 3) AS k FROM sdj_rsv)SELECT date, instrument, m_avg(k, 3) AS sdjFROM sdj_kORDER BY date, instrument公式:A = Close − Close_12日前;MI = MA12(A)
输出列(1):mi12
WITH mi_base AS ( SELECT date, instrument, close - m_lag(close, 12) AS a FROM cn_stock_bar1d WHERE close IS NOT NULL)SELECT date, instrument, m_avg(a, 12) AS mi12FROM mi_baseORDER BY date, instrument公式:MI = C − 前C;AMI = MA3(MI);DIF = MA10(LAG(AMI,1)) − MA20(LAG(AMI,1));MICD = MA10(DIF)
输出列(1):micd
WITH micd_mi AS ( SELECT date, instrument, close - m_lag(close, 1) AS mi FROM cn_stock_bar1d WHERE close IS NOT NULL),micd_ami AS ( SELECT date, instrument, m_avg(mi, 3) AS ami FROM micd_mi),micd_lag AS ( SELECT date, instrument, m_lag(ami, 1) AS lami FROM micd_ami),micd_dif AS ( SELECT date, instrument, m_avg(lami, 10) - m_avg(lami, 20) AS dif FROM micd_lag)SELECT date, instrument, m_avg(dif, 10) AS micdFROM micd_difORDER BY date, instrument公式:RC = Close / Close_50日前 × 100;ARC = MA50(LAG(RC, 1))
输出列(2):rc50、arc50
WITH rc_base AS ( SELECT date, instrument, close / NULLIF(m_lag(close, 50), 0) * 100 AS rc FROM cn_stock_bar1d WHERE close IS NOT NULL)SELECT date, instrument, rc AS rc50, m_avg(m_lag(rc, 1), 50) AS arc50FROM rc_baseORDER BY date, instrument公式:RC = Close/Close_59日前×100;ARC = MA59(LAG(RC,1));DIF = MA20(LAG(ARC,1)) − MA27(LAG(ARC,1));RCCD = MA10(DIF)
输出列(1):rccd
WITH rccd_rc AS ( SELECT date, instrument, close / NULLIF(m_lag(close, 59), 0) * 100 AS rc FROM cn_stock_bar1d WHERE close IS NOT NULL),rccd_arc AS ( SELECT date, instrument, m_avg(m_lag(rc, 1), 59) AS arc FROM rccd_rc),cn_stock_bar1d(后复权,WHERE close IS NOT NULL) → 16 组因子族 SQL 并行执行(joblib loky, n_jobs=8) → 按 cn_stock_instruments 左连接对齐全市场标的 → schema 归一化(列序 / 类型 / 缺失值) → dai_write 按 date 的年份分区落库create(),自 2010-01-01 起按 2 年一段滚动执行,每段结束后 gc.collect() 释放内存。build(),默认覆盖最近 5 个自然日;落库前跑 tester.py,落库后更新前端文档。窗口算子只在查询下推后的行集上计算,所以每次计算都会向前多取一段行情:
| 参数 | 取值 | 说明 |
|---|---|---|
lookback_days | 500 个自然日(≈ 334 个交易日) | 本表最长窗口 / 预热需求约 155 个交易日 |
多读一段历史不改变任何输出值(窗口算子只向前看),只是把区间首日的"本可避免的缺失"消掉。 EMA / RSI / ATR / MACD / TRIX 属于 IIR 递推算子,理论上预热期无限长,因此这些表的冗余按 约 5 倍最长周期取值,而非刚好等于窗口长度。
cn_stock_bar1d 在停牌日会保留一行、但 open/high/low/close/amount 全为 NULL、volume 为 0。
m_ta_* 递推类算子只要吃到一个 NULL,之后就永久输出 NULL。因此所有 SQL 统一加
WHERE close IS NOT NULL,把停牌行从计算输入中剔除(此时 m_lag(close, 1) 指向上一个交易日,
符合技术指标的常规口径)。
实测(2024-01 全市场,回溯起点 2021-06):
| 处理方式 | bbands_middle_20 | atr14 | kdj_j_9 | macd_diff_12_26_9 |
|---|---|---|---|---|
| 不加过滤 | 88.3% | 88.3% | 88.4% | 88.1% |
加 WHERE close IS NOT NULL | 99.7% | 99.7% | 99.7% | 99.5% |
本表不含累计型因子,全部因子都是固定长度的滚动窗口计算,因此只受 lookback_days 影响。
落库前以 cn_stock_instruments 为基准左连接,因此每个交易日都是全市场标的的完整行,
停牌股与上市不足窗口长度的新股在对应因子列上为 NULL。入库校验要求单因子整体覆盖度 ≥ 85%
(tester.py 关键测试点),单日覆盖度 ≥ 80%(非关键,仅告警)。
mtm6 附带 mamtm6 均值列,rc50 附带 arc50 平滑列。micd、rc50、rccd 在上游写法中使用 AVG(LAG(col) OVER(...)) OVER(...) 嵌套窗口,DAI 兼容性不确定,本表统一改为 CTE 分步实现,公式语义一致。si 不采用因子文档 2.7.9 的简化版实现:简化版的 R 有一个 ELSE 0 分支,在“前收盘落在当日高低区间之外”(跳空)时 R = 0 会把 SI 置为 NULL,实测覆盖度只有 82.9%(跳空多的交易日低至 50%),达不到 85% 的入库要求。本表改用 Wilder 原始的三分支 R(第三分支为 HL + |前C−前O|/4,恒非负且几乎不为 0),并把分子的符号改为标准式 (C−前C) + 0.5(C−O) + 0.25(前C−前O)——简化版写成 (前C−C),会让上涨日的 SI 取负号,与摆动指标语义相反。修正后覆盖度回到 99% 以上。cci_120,回溯冗余取 500 个自然日。实测区间 2026-09-07 ~ 2026-09-17(9 个交易日、50052 行,已按 cn_stock_instruments 对齐全市场标的):
| 指标 | 数值 |
|---|---|
| 因子列数 | 25 |
| 最低覆盖度 | 97.86%(rccd) |
| 中位覆盖度 | 99.42% |
| 最高覆盖度 | 99.79% |
| 覆盖度 < 85% 的列数 | 0 |
tester.py 关键测试点 | ✅ 通过 |
覆盖度最低的三列:rccd(97.9%)、cci_120(98.2%)、arc50(98.5%)。缺失主要来自上市不足窗口长度的新股与当日停牌,逐列明细见 testdata/coverage_report.md,数据示例见 testdata/sample_data.csv。
{{sample_data}}
c_zscore(因子, group=date) 或 c_rank(因子, group=date) 处理,或改用同族的比值型因子。NULLIF 保护,但小分母仍会放大尾部,建议按日做分位数截断。SELECT date, instrument, cci14, cci20, roc6, roc12, roc24 FROM cn_stock_factors_ta_momentum WHERE date >= '2026-10-06' ORDER BY date LIMIT 100
SELECT date, instrument, cci14, cci20, roc6, roc12, roc24 FROM cn_stock_factors_ta_momentum WHERE date >= '2026-10-06' ORDER BY date LIMIT 100