--- title: 情绪与强弱类技术指标因子(cn_stock_factors_ta_sentiment) source: bigfactorwarehouse / cn_stock / cn_stock_factors_ta_sentiment format: markdown --- # 情绪与强弱类技术指标因子(cn_stock_factors_ta_sentiment) > 从多空双方“意愿”和“力量”的对比刻画市场情绪:CR/ARBR 用高低价相对中枢的距离衡量买卖意愿,ADTM/SRDM 用开盘/高低价的动量差衡量买卖气与动向速度,DPTB/JDQS/JDRS 统计收阳收阴天数占比,ZDZB 用长周期涨跌比判别筑底,YLTR/YMTR 给出 34 日高低区间内的平滑位置。 > > - **因子数量**:10 个因子 / 14 个数据列 > - **主键**:`date` + `instrument`(按 `cn_stock_instruments` 对齐全市场标的) > - **数据起始**:2010-01-01,日频增量更新 > - **复权口径**:后复权(`cn_stock_bar1d` 全表统一) --- ## 1. 上游依赖(基础数据表) | 上游表 | 用途 | 本表用到的字段 | |---|---|---| | `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": [...]})` 下推完成。 --- ## 2. 因子清单(14 列) | # | 因子中文名 | 字段名 | 参数 | 因子逻辑 | 所属因子族 | |---|---|---|---|---|---| | 1 | CR 能量指标 | `cr26` | 26 | 多方力量 / 空方力量 | CR 能量指标 | | 2 | 人气指标 AR | `ar26` | 26 | 多空人气(高开差 / 开低差) | ARBR 人气意愿指标 | | 3 | 意愿指标 BR | `br26` | 26 | 买卖意愿(高前收差 / 前收低差) | ARBR 人气意愿指标 | | 4 | 大盘同步指标 | `dptb7` | 7 | 7 日内收阳天数占比(以个股自身收阳近似) | DPTB / JDQS / JDRS 收阳收阴统计 | | 5 | 阶段强势指标 | `jdqs20` | 20 | 20 日收阳/收阴天数比 | DPTB / JDQS / JDRS 收阳收阴统计 | | 6 | 阶段弱势指标 | `jdrs20` | 20 | 20 日收阴/收阳天数比 | DPTB / JDQS / JDRS 收阳收阴统计 | | 7 | 顶底指标(长周期) | `yltr` | 34/19 | 34 日高低区间的 19 日平滑位置 | 顶底指标(长 / 中周期) | | 8 | 顶底指标(中周期) | `ymtr` | 34/4 | 34 日高低区间位置的 EMA 平滑 | 顶底指标(长 / 中周期) | | 9 | 动态买卖气指标 | `adtm` | 23/8 | DTM/DBM 的动量差 | ADTM 动态买卖气指标 | | 10 | 动态买卖气均线 | `maadtm` | 23/8 | ADTM 的 8 日移动平均 | ADTM 动态买卖气指标 | | 11 | 动向速度比率 | `srdm` | 30 | 正负动向速度的相对强弱 | SRDM 动向速度比率 | | 12 | 筑底指标 A | `zdzb_a` | 125 | 125 日上涨天数 / 下跌天数 | ZDZB 筑底指标 | | 13 | 筑底指标 B | `zdzb_b` | 125/5 | A 的 5 日移动平均 | ZDZB 筑底指标 | | 14 | 筑底指标 D | `zdzb_d` | 125/5/20 | B 的 20 日移动平均 | ZDZB 筑底指标 | --- ## 3. 因子族公式与 DAI SQL ### 3.1 CR 能量指标 **公式**:YM = (前H + 前L + 前C)/3;CR = SUM(MAX(0, H−YM), 26) / SUM(MAX(0, YM−L), 26) × 100 **输出列(1)**:`cr26` ```sql WITH cr_base AS ( SELECT date, instrument, high, low, (m_lag(high, 1) + m_lag(low, 1) + m_lag(close, 1)) / 3 AS ym FROM cn_stock_bar1d WHERE close IS NOT NULL ) SELECT date, instrument, m_sum(greatest(high - ym, 0), 26) / NULLIF(m_sum(greatest(ym - low, 0), 26), 0) * 100 AS cr26 FROM cr_base ORDER BY date, instrument ``` ### 3.2 ARBR 人气意愿指标 **公式**:AR = SUM(H − O, 26) / SUM(O − L, 26);BR = SUM(MAX(0, H−前C), 26) / SUM(MAX(0, 前C−L), 26) × 100 **输出列(2)**:`ar26`、`br26` ```sql SELECT date, instrument, m_sum(high - open, 26) / NULLIF(m_sum(open - low, 26), 0) AS ar26, 100.0 * m_sum(greatest(high - m_lag(close, 1), 0), 26) / NULLIF(m_sum(greatest(m_lag(close, 1) - low, 0), 26), 0) AS br26 FROM cn_stock_bar1d WHERE close IS NOT NULL ORDER BY date, instrument ``` ### 3.3 DPTB / JDQS / JDRS 收阳收阴统计 **公式**:DPTB = MA7(IF(C>O,1,0));JDQS = SUM20(收阳) / SUM20(收阴);JDRS = SUM20(收阴) / SUM20(收阳) **输出列(3)**:`dptb7`、`jdqs20`、`jdrs20` ```sql SELECT date, instrument, m_avg(if(close > open, 1, 0), 7) AS dptb7, m_sum(if(close > open, 1, 0), 20) / NULLIF(m_sum(if(close < open, 1, 0), 20), 0) AS jdqs20, m_sum(if(close < open, 1, 0), 20) / NULLIF(m_sum(if(close > open, 1, 0), 20), 0) AS jdrs20 FROM cn_stock_bar1d WHERE close IS NOT NULL ORDER BY date, instrument ``` ### 3.4 顶底指标(长 / 中周期) **公式**:YLTR = MA19(−100 × (MAX34(H) − C) / (MAX34(H) − MIN34(L))) + 100;YMTR = EMA4(同上核) + 100 **输出列(2)**:`yltr`、`ymtr` ```sql SELECT date, instrument, m_avg(-100.0 * (m_max(high, 34) - close) / NULLIF(m_max(high, 34) - m_min(low, 34), 0), 19) + 100.0 AS yltr, m_ta_ema(-100.0 * (m_max(high, 34) - close) / NULLIF(m_max(high, 34) - m_min(low, 34), 0), 4) + 100.0 AS ymtr FROM cn_stock_bar1d WHERE close IS NOT NULL ORDER BY date, instrument ``` ### 3.5 ADTM 动态买卖气指标 **公式**:DTM = IF(O ≤ 前O, 0, MAX(H−O, O−前O));DBM = IF(O ≥ 前O, 0, MAX(O−L, 前O−O));STM = SUM(DTM, 23);SBM = SUM(DBM, 23);ADTM = IF(STM>SBM, (STM−SBM)/STM, IF(STM<SBM, (STM−SBM)/SBM, 0));MAADTM = MA8(ADTM) **输出列(2)**:`adtm`、`maadtm` ```sql WITH adtm_base AS ( SELECT date, instrument, if(open <= m_lag(open, 1), 0, greatest(high - open, open - m_lag(open, 1))) AS dtm, if(open >= m_lag(open, 1), 0, greatest(open - low, m_lag(open, 1) - open)) AS dbm FROM cn_stock_bar1d WHERE close IS NOT NULL ), adtm_sum AS ( SELECT date, instrument, m_sum(dtm, 23) AS stm, m_sum(dbm, 23) AS sbm FROM adtm_base ), adtm_calc AS ( SELECT date, instrument, CASE WHEN stm > sbm THEN (stm - sbm) / NULLIF(stm, 0) WHEN stm < sbm THEN (stm - sbm) / NULLIF(sbm, 0) ELSE 0 END AS adtm FROM adtm_sum ) SELECT date, instrument, adtm, m_avg(adtm, 8) AS maadtm FROM adtm_calc ORDER BY date, instrument ``` ### 3.6 SRDM 动向速度比率 **公式**:DMZ = IF(H+L ≤ 前H+前L, 0, MAX(|H−前H|, |L−前L|));DMF 对称;ADMZ = MA30(DMZ);ADMF = MA30(DMF);SRDM = IF(ADMZ>ADMF, (ADMZ−ADMF)/ADMZ, IF(ADMZ=ADMF, 0, (ADMZ−ADMF)/ADMF)) **输出列(1)**:`srdm` ```sql WITH srdm_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 ), srdm_dm AS ( SELECT date, instrument, CASE WHEN high + low <= pre_h + pre_l THEN 0 ELSE greatest(abs(high - pre_h), abs(low - pre_l)) END AS dmz, CASE WHEN high + low >= pre_h + pre_l THEN 0 ELSE greatest(abs(high - pre_h), abs(low - pre_l)) END AS dmf FROM srdm_base ), srdm_ma AS ( SELECT date, instrument, m_avg(dmz, 30) AS admz, m_avg(dmf, 30) AS admf FROM srdm_dm ) SELECT date, instrument, CASE WHEN admz > admf THEN (admz - admf) / NULLIF(admz, 0) WHEN admz = admf THEN 0 ELSE (admz - admf) / NULLIF(admf, 0) END AS srdm FROM srdm_ma ORDER BY date, instrument ``` ### 3.7 ZDZB 筑底指标 **公式**:A = SUM125(上涨) / SUM125(下跌)(上涨 = C ≥ 前C);B = MA5(A);D = MA20(B) **输出列(3)**:`zdzb_a`、`zdzb_b`、`zdzb_d` ```sql WITH zdzb_mark AS ( SELECT date, instrument, if(close >= m_lag(close, 1), 1, 0) AS is_up, if(close < m_lag(close, 1), 1, 0) AS is_down FROM cn_stock_bar1d WHERE close IS NOT NULL ), zdzb_a AS ( SELECT date, instrument, m_sum(is_up, 125) / NULLIF(m_sum(is_down, 125), 0) AS a FROM zdzb_mark ), zdzb_b AS ( SELECT date, instrument, a, m_avg(a, 5) AS b FROM zdzb_a ) SELECT date, instrument, a AS zdzb_a, b AS zdzb_b, m_avg(b, 20) AS zdzb_d FROM zdzb_b ORDER BY date, instrument ``` --- ## 4. 数据加工说明 ### 4.1 加工链路 ``` cn_stock_bar1d(后复权,WHERE close IS NOT NULL) → 7 组因子族 SQL 并行执行(joblib loky, n_jobs=8) → 按 cn_stock_instruments 左连接对齐全市场标的 → schema 归一化(列序 / 类型 / 缺失值) → dai_write 按 date 的年份分区落库 ``` - 历史构建:`create()`,自 **2010-01-01** 起按 **2 年**一段滚动执行,每段结束后 `gc.collect()` 释放内存。 - 增量构建:`build()`,默认覆盖最近 5 个自然日;落库前跑 `tester.py`,落库后更新前端文档。 ### 4.2 回溯冗余(避免窗口未预热导致的缺失值) 窗口算子只在查询下推后的行集上计算,所以每次计算都会**向前多取一段行情**: | 参数 | 取值 | 说明 | |---|---|---| | `lookback_days` | **500 个自然日**(≈ 334 个交易日) | 本表最长窗口 / 预热需求约 150 个交易日 | 多读一段历史不改变任何输出值(窗口算子只向前看),只是把区间首日的"本可避免的缺失"消掉。 EMA / RSI / ATR / MACD / TRIX 属于 IIR 递推算子,理论上预热期无限长,因此这些表的冗余按 **约 5 倍最长周期**取值,而非刚好等于窗口长度。 ### 4.3 停牌空值行的处理 `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%** | ### 4.4 累计型因子的锚点 本表不含累计型因子,全部因子都是固定长度的滚动窗口计算,因此只受 `lookback_days` 影响。 ### 4.5 标的对齐与覆盖度 落库前以 `cn_stock_instruments` 为基准左连接,因此**每个交易日都是全市场标的的完整行**, 停牌股与上市不足窗口长度的新股在对应因子列上为 NULL。入库校验要求单因子整体覆盖度 ≥ 85% (`tester.py` 关键测试点),单日覆盖度 ≥ 80%(非关键,仅告警)。 ### 4.6 本表实现要点 - 本类 10 个因子共 14 个数据列:`arbr26`(ar26/br26)、`adtm`(adtm/maadtm)、`zdzb`(zdzb_a/b/d)为一因子多列输出。 - `dptb7` 按上游口径用**个股自身收阳天数占比**近似“大盘同步”,并非真正的个股-大盘同步率。若需严格口径,需另取大盘指数(如 000001.SH)的收阳序列 join 后计算。此处保留近似口径以保证个股级有值。 - `cr26` 的 YM 按标准定义取 (前H+前L+前C)/3;部分上游写法误写为“前高前低前收的 3 日均值”,本表已修正。 - `zdzb` 的最长依赖为 125 + 5 + 20 ≈ 150 个交易日,回溯冗余取 500 个自然日(约 330 个交易日)。 --- ## 5. 覆盖度实测 实测区间 **2026-09-07 ~ 2026-09-17**(9 个交易日、50052 行,已按 `cn_stock_instruments` 对齐全市场标的): | 指标 | 数值 | |---|---| | 因子列数 | 14 | | 最低覆盖度 | **97.94%**(zdzb_d) | | 中位覆盖度 | 99.39% | | 最高覆盖度 | 99.79% | | 覆盖度 < 85% 的列数 | 0 | | `tester.py` 关键测试点 | ✅ 通过 | 覆盖度最低的三列:`zdzb_d`(97.9%)、`zdzb_b`(98.1%)、`zdzb_a`(98.2%)。缺失主要来自**上市不足窗口长度的新股**与**当日停牌**,逐列明细见 `testdata/coverage_report.md`,数据示例见 `testdata/sample_data.csv`。 --- ## 6. 示例数据 {{sample_data}} --- ## 7. 使用建议 1. **横截面标准化**:本表含绝对量纲列(价位、波幅、成交量等),跨股票比较前建议用 `c_zscore(因子, group=date)` 或 `c_rank(因子, group=date)` 处理,或改用同族的比值型因子。 2. **去极值**:比值类因子分母虽已做 `NULLIF` 保护,但小分母仍会放大尾部,建议按日做分位数截断。 3. **冗余筛选**:同一指标的多参数档位之间相关性很高,建模前建议按 IC / 相关性 / 特征重要性做筛选, 而不是把全部列直接喂给模型。 4. **无未来函数**:全部因子只用当期与历史滚动数据;回测时注意前向收益口径(建议用次日开盘价), 收盘价口径会系统性高估短周期反转类因子的收益。
情绪与强弱因子 (cn_stock_factors_ta_sentiment)
数据描述: 情绪与强弱类技术指标因子
文档
用例
表结构
| 字段 | 字段类型 | 字段描述 |
| srdm | double | 动向速度比率(参数 30)。正负动向速度的相对强弱。计算式见 ta_sentiment_formula.py 中 srdm 族 SQL |
| yltr | double | 顶底指标(长周期)(参数 34/19)。34 日高低区间的 19 日平滑位置。计算式:m_avg(-100.0 * (m_max(high, 34) - close) / NULLIF(m_max(high, 34) - m_min(low, 34), 0), 19) + 100.0 |
| ymtr | double | 顶底指标(中周期)(参数 34/4)。34 日高低区间位置的 EMA 平滑。计算式:m_ta_ema(-100.0 * (m_max(high, 34) - close) / NULLIF(m_max(high, 34) - m_min(low, 34), 0), 4) + 100.0 |
| dptb7 | double | 大盘同步指标(参数 7)。7 日内收阳天数占比(以个股自身收阳近似)。计算式:m_avg(if(close > open, 1, 0), 7) |
| jdqs20 | double | 阶段强势指标(参数 20)。20 日收阳/收阴天数比。计算式:m_sum(if(close > open, 1, 0), 20) / NULLIF(m_sum(if(close < open, 1, 0), 20), 0) |
| date | timestamp[ns] | 日期 |
| maadtm | double | 动态买卖气均线(参数 23/8)。ADTM 的 8 日移动平均。计算式见 ta_sentiment_formula.py 中 adtm 族 SQL |
| zdzb_a | double | 筑底指标 A(参数 125)。125 日上涨天数 / 下跌天数。计算式见 ta_sentiment_formula.py 中 zdzb 族 SQL |
| zdzb_b | double | 筑底指标 B(参数 125/5)。A 的 5 日移动平均。计算式见 ta_sentiment_formula.py 中 zdzb 族 SQL |
| zdzb_d | double | 筑底指标 D(参数 125/5/20)。B 的 20 日移动平均。计算式见 ta_sentiment_formula.py 中 zdzb 族 SQL |
| instrument | string | 证券代码 |
| __PARTITION__ | int64 | - |
| jdrs20 | double | 阶段弱势指标(参数 20)。20 日收阴/收阳天数比。计算式:m_sum(if(close < open, 1, 0), 20) / NULLIF(m_sum(if(close > open, 1, 0), 20), 0) |
| adtm | double | 动态买卖气指标(参数 23/8)。DTM/DBM 的动量差。计算式见 ta_sentiment_formula.py 中 adtm 族 SQL |
| ar26 | double | 人气指标 AR(参数 26)。多空人气(高开差 / 开低差)。计算式:m_sum(high - open, 26) / NULLIF(m_sum(open - low, 26), 0) |
| br26 | double | 意愿指标 BR(参数 26)。买卖意愿(高前收差 / 前收低差)。计算式:100.0 * m_sum(greatest(high - m_lag(close, 1), 0), 26) / NULLIF(m_sum(greatest(m_lag(close, 1) - low, 0), 26), 0) |
| cr26 | double | CR 能量指标(参数 26)。多方力量 / 空方力量。计算式见 ta_sentiment_formula.py 中 cr 族 SQL |
表名:cn_stock_factors_ta_sentiment
起始时间:
最近更新时间: