算子库 ops 说明
因子挖掘的乐高积木 · 每个算子含 公式 + 实现 + 真实算例 · 算例数字来自 ops.py 在小样本上的实跑结果
设计原则 · 闭合性:所有算子都是
例:
T×C → T×C(行=10s时间桶,列=股票)。
输入输出同形状,所以能像积木一样无限嵌套,符号回归才能自由搜索表达式树。例:
cs_rank( ts_decay_linear( sub(大单主买占比, 大单主卖占比), 6 ) )
—— 相减得净主买 → 6根线性衰减平滑 → 全市场排名,每层输出都还是 T×C。
全局约定:① 窗口
下方算例统一用一只股票 000001.sz 的 10 个 10s 桶(截面算子用 2 只股票演示)。
k 以 10s 为单位(k=6→1分钟,k=180→30分钟);
② NaN感知:空值不参与计算、有效值不足输出空值·,绝不当0;
③ 不跨日:时序算子按(股票,交易日)滚动,cumsum每日开盘重置;
④ 数值安全:除法分母0→空值,对数用带符号 ln(1+|x|)。下方算例统一用一只股票 000001.sz 的 10 个 10s 桶(截面算子用 2 只股票演示)。
① 基本算子(逐元素 element-wise)
无轴,对每个格子单独运算。是闭合性的基石。
add(x,y)加公式add = xᵢⱼ + yᵢⱼ
实现两张 T×C 表逐格相加。
逐格相加。A=
0.40 0.55 …,B=0.60 0.45 … → 1.00 1.00 …sub(x,y)减公式sub = xᵢⱼ − yᵢⱼ
实现逐格相减。常用于「净主买 = 主买占比 − 主卖占比」。
A(主买):
B(主卖):
sub(A,B)=净主买:
第1根 0.40−0.60=−0.20(净卖出);第4根 0.62−0.38=+0.24(净买入)。
0.4 0.55 0.12 0.62 0.14 0.17 0.54 0.31 0.48 0.5B(主卖):
0.6 0.45 0.88 0.38 0.86 0.83 0.46 0.69 0.52 0.5sub(A,B)=净主买:
-0.2 0.1 -0.76 0.24 -0.72 -0.66 0.08 -0.38 -0.04 0第1根 0.40−0.60=−0.20(净卖出);第4根 0.62−0.38=+0.24(净买入)。
mul(x,y)乘公式mul = xᵢⱼ · yᵢⱼ
实现逐格相乘。
逐格相乘,如把信号与权重相乘。
div(x,y)安全除公式div = xᵢⱼ / yᵢⱼ (yᵢⱼ=0 → 空值)
实现逐格相除;分母为 0 输出空值,绝不产生 inf。
分母 0 → 空值。如 0.4/0=
·(不是 inf)。pow(x,p)幂公式pow = xᵢⱼ ^ p
实现逐格取 p 次幂。
p=2 时即平方。
abs(x)绝对值公式abs = |xᵢⱼ|
实现逐格取绝对值。
sub(A,B)=
-0.2 0.1 -0.76 0.24 -0.72 -0.66 0.08 -0.38 -0.04 0 → abs → 0.2 0.1 0.76 …sign(x)符号公式sign = +1 / 0 / −1
实现取正负号;常用于把强度转成方向。
sub(A,B) → sign →
-1 1 -1 1 -1 -1 1 -1 -1 0(净买卖方向)sqrt(x)带符号开方公式sqrt = sign(x)·√|x|
实现保号开方,压缩大值且不丢负号。
−0.64 → −0.8;0.49 → 0.7
square(x)平方公式square = xᵢⱼ²
实现逐格平方,放大大值。
signlog(x)带符号对数公式signlog = sign(x)·ln(1+|x|)
实现压缩长尾、保号、x=0 时为 0;金额类右偏数据常用。
输入 A(000001.sz, 10根10s):
输出:
0.40→ln(1.40)=0.3365;单调压缩,负数同样保号处理。
0.4 0.55 0.12 0.62 0.14 0.17 0.54 0.31 0.48 0.5输出:
0.3365 0.4383 0.1133 0.4824 0.131 0.157 0.4318 0.27 0.392 0.40550.40→ln(1.40)=0.3365;单调压缩,负数同样保号处理。
exp(x)截断指数公式exp = e^{clip(x,−50,50)}
实现先截断再取指数,防数值溢出。
clip(x,lo,hi)截断公式clip = min(max(x,lo),hi)
实现把值限制在 [lo,hi]。
clip(x,0,1):0.62→0.62,1.3→1.0,−0.2→0.0
max(x,y) / min(x,y)逐格极值公式max = max(xᵢⱼ,yᵢⱼ)
实现两张表对应格取较大/较小。
② 时序算子(沿时间轴 T,单股内按交易日滚动)
窗口 k 根 10s。不跨日泄漏。
ts_delay(x,k)滞后公式ts_delay(x,k)ₜ = xₜ₋ₖ
实现把序列整体后移 k 根(拿 k 根前的值)。按交易日分组,开盘前 k 根为空。
k=1:今根放上一根的值。第1根无前值→
·ts_delta(x,k)差分公式ts_delta(x,k)ₜ = xₜ − xₜ₋ₖ
实现当前比 k 根前变化了多少 → 字典「变化」系列。
输入 A(000001.sz, 10根10s):
输出:
k=1:第2根 0.55−0.40=+0.15;第3根 0.12−0.55=−0.43。首根无前值→·。
0.4 0.55 0.12 0.62 0.14 0.17 0.54 0.31 0.48 0.5输出:
· 0.15 -0.43 0.5 -0.48 0.03 0.37 -0.23 0.17 0.02k=1:第2根 0.55−0.40=+0.15;第3根 0.12−0.55=−0.43。首根无前值→·。
ts_pct_change(x,k)变化率公式(xₜ − xₜ₋ₖ)/xₜ₋ₖ
实现相对变化;分母 0 → 空值。
ts_mean(x,k)滚动均值公式ts_mean(x,k)ₜ = (1/k)Σxₜ₋ₖ₊₁..ₜ
实现过去 k 根均值,平滑噪声。NaN 不计入。
输入 A(000001.sz, 10根10s):
输出:
k=3:第3根=(0.40+0.55+0.12)/3=0.3567;窗口不足按已有值算。
0.4 0.55 0.12 0.62 0.14 0.17 0.54 0.31 0.48 0.5输出:
0.4 0.475 0.3567 0.43 0.2933 0.31 0.2833 0.34 0.4433 0.43k=3:第3根=(0.40+0.55+0.12)/3=0.3567;窗口不足按已有值算。
ts_std(x,k)滚动标准差公式ts_std = √(Var(xₜ₋ₖ₊₁..ₜ))
实现过去 k 根波动率,至少 2 个有效值。
输入 A(000001.sz, 10根10s):
输出:
k=3:第3根 std(0.40,0.55,0.12)=0.2183。首根不足2个→·。
0.4 0.55 0.12 0.62 0.14 0.17 0.54 0.31 0.48 0.5输出:
· 0.1061 0.2183 0.2707 0.2831 0.2689 0.2228 0.1868 0.1193 0.1044k=3:第3根 std(0.40,0.55,0.12)=0.2183。首根不足2个→·。
ts_min / ts_max(x,k)滚动极值公式ts_max = max(xₜ₋ₖ₊₁..ₜ)
实现过去 k 根最大/最小。
ts_median(x,k)滚动中位数公式过去 k 根中位数
实现抗离群的中心。
ts_zscore(x,k)滚动标准化公式(xₜ − ts_mean)/ts_std
实现当前值偏离自身近期均值几个标准差。
ts_rank(x,k)滚动分位公式#{xₛ ≤ xₜ, s∈窗口}/k
实现当前值在过去 k 根中的分位 [0,1] → 字典「统计S」口径。
输入 A(000001.sz, 10根10s):
输出:
k=3:第3根 0.12 是窗口(0.40,0.55,0.12)最小→分位1/3=0.3333;第4根0.62最大→1.0。
0.4 0.55 0.12 0.62 0.14 0.17 0.54 0.31 0.48 0.5输出:
1 1 0.3333 1 0.6667 0.6667 1 0.6667 0.6667 1k=3:第3根 0.12 是窗口(0.40,0.55,0.12)最小→分位1/3=0.3333;第4根0.62最大→1.0。
ts_cumsum(x)当日累计公式Σ(开盘..当前),按日重置
实现当日开盘至今累加 → 字典「累计」系列。每天开盘清零,不跨日。
输入 A(000001.sz, 10根10s):
输出:
逐根累加:0.40→0.95→1.07→1.69…;次日开盘会重新从0累计。
0.4 0.55 0.12 0.62 0.14 0.17 0.54 0.31 0.48 0.5输出:
0.4 0.95 1.07 1.69 1.83 2 2.54 2.85 3.33 3.83逐根累加:0.40→0.95→1.07→1.69…;次日开盘会重新从0累计。
ts_decay_linear(x,k)线性衰减加权公式Σ wᵢ·xₜ₋ᵢ , wᵢ=(k−i)/Σw
实现近的权重大、远的权重小的加权平滑。逐笔噪声大时优于等权均值。
输入 A(000001.sz, 10根10s):
输出:
k=3权重(1,2,3)/6:第3根=(0.40·1+0.55·2+0.12·3)/6=0.31。前2根窗口不足→·。
0.4 0.55 0.12 0.62 0.14 0.17 0.54 0.31 0.48 0.5输出:
· · 0.31 0.4417 0.2967 0.235 0.35 0.3633 0.4333 0.4617k=3权重(1,2,3)/6:第3根=(0.40·1+0.55·2+0.12·3)/6=0.31。前2根窗口不足→·。
ts_ewm(x,halflife)指数加权公式EWMA,半衰期 halflife
实现越近权重指数级越大,平滑且反应快。
ts_slope(x,k)趋势斜率公式对时间 0..k−1 最小二乘斜率 = cov(t,x)/var(t)
实现过去 k 根的上升/下降趋势 → 字典「趋势」系列。
k根线性回归的斜率。正=上行趋势,负=下行。
ts_corr(x,y,k)滚动相关公式corr(xₜ₋ₖ₊₁..ₜ, yₜ₋ₖ₊₁..ₜ)
实现两序列过去 k 根的相关系数 → 字典「价量相关」系列。
A=
B=
ts_corr(A,B,3)=
本样本 A、B 几乎完全反向,故滚动相关恒为 −1(价量背离的极端示例)。
0.4 0.55 0.12 0.62 0.14 0.17 0.54 0.31 0.48 0.5B=
0.6 0.45 0.88 0.38 0.86 0.83 0.46 0.69 0.52 0.5ts_corr(A,B,3)=
· -1 -1 -1 -1 -1 -1 -1 -1 -1本样本 A、B 几乎完全反向,故滚动相关恒为 −1(价量背离的极端示例)。
ts_cov(x,y,k)滚动协方差公式cov(过去k根)
实现相关的未标准化版本。
③ 截面算子(沿股票轴 C,每个时刻全市场横向)
同一时刻把所有股票放一起比较。
cs_rank(x)截面排名公式rankₜ(across stocks)/(N−1) ∈[0,1]
实现每个时刻把全市场股票横向排名 → 字典「相对R」口径。
某时刻全市场 {000001.sz:0.40, 000002.sz:0.30} → cs_rank →
0.40 最大→排名1.0;0.30 最小→0.0。(仅2只股票演示)
{000001.sz:1, 000002.sz:0}0.40 最大→排名1.0;0.30 最小→0.0。(仅2只股票演示)
cs_demean(x)截面去均值公式xₜ − meanₜ(across stocks)
实现减掉当时刻全市场均值,得到相对强弱。
{0.40, 0.30} 均值0.35 → cs_demean →
{+0.05, -0.05}cs_zscore(x)截面标准化公式(xₜ − meanₜ)/stdₜ
实现截面去均值再除以截面标准差。
{0.40, 0.30} → cs_zscore →
{+0.7071, -0.7071}cs_scale(x)截面归一化公式xₜ / Σ|xₜ|
实现转成组合权重(绝对值和为1)。
cs_winsorize(x,n)截面去极值公式clip(x, med ± n·MAD)
实现按中位数绝对偏差截断离群值,防个别异常股污染。
④ 统计算子(规约核)
均值/标准差/偏度/相关/残差是「统计量」,须套上「轴」才落地:
| 统计量 | 沿时间轴 → 时序形式 | 沿股票轴 → 截面形式 |
| 均值 mean | ts_mean(x,k) | cs_demean 用到截面均值 |
| 标准差 std | ts_std(x,k) | cs_zscore 用到截面std |
| 偏度 skew | ts_skew(x,k) | cs_skew(x) |
| 相关 corr | ts_corr(x,y,k) 滚动相关 | cs_corr(x,y) 截面相关 |
| 残差 residual | ts_slope/regbeta 趋势 | cs_neutralize 中性化残差 |
算例由 infra/mine/ops.py 实跑产出 · T×C 闭合 · polars 实现 · NaN感知 · 按日滚动