改进_开源证券_VCF_多尺度量价背离检测因子!
改进:开源证券_VCF_多尺度量价背离检测因子!
- 原因子(2025.7.142025.7.142025.7.14)
- 代码实现
- 因子表现
- 问题分析
- 深入分析因子构建逻辑的不足之处
- 1. **背离检测逻辑存在根本性缺陷**
- 2. **特征工程结构性问题**
- 3. **标准化方法导致前瞻性偏差**
- 4. **最终因子合成逻辑冲突**
- 5. **市场机制未充分考量**
- 6. **计算效率与实现风险**
- 7. **理论依据薄弱环节**
- 改进方向建议(暂不实施)
- 具体分析:因子头尾部收益率表现反常
- 1. **背离信号的方向性冲突(核心问题)**
- 2. **标准化过程的特征混淆**
- 3. **尾部权重的自我冲突**
- 4. **资金流信号的未被充分利用**
- 5. **极端值区域的逻辑矛盾**
- 根本原因总结
原因子(2025.7.142025.7.142025.7.14)
代码实现
def factor(df):# 计算主动买入量占比df['buy_ratio'] = df['taker_buy_volume'] / (df['volume'] + 1e-7)# 计算价格波动率price_change = df['close'].pct_change()volatility = price_change.ewm(span=96, min_periods=24).std()# 计算量价比率vp_ratio = df['volume'] / (volatility + 1e-7)# 关键周期定义periods = [96, 288, 672, 1440, 2880]# 计算各周期量价比率vp_matrix = np.column_stack([vp_ratio.ewm(span=p, min_periods=int(p/4)).mean()for p in periods])# === 核心改进3: 多尺度量价背离检测 ===divergence_matrix = np.zeros((len(df), len(periods)))for i, p in enumerate(periods):# 价格动量price_momentum = df['close'].pct_change(p)# 成交量动量volume_momentum = df['volume'].pct_change(p)# 资金流动量flow_momentum = df['buy_ratio'].diff(p)# 量价背离检测price_volume_div = np.sign(price_momentum) * np.sign(volume_momentum) < 0# 价资背离检测price_flow_div = np.sign(price_momentum) * np.sign(flow_momentum) < 0# 综合背离强度div_strength = (price_volume_div.astype(int) + price_flow_div.astype(int)) * np.abs(flow_momentum)# 在尾部区域放大背离信号is_tail = (df['buy_ratio'] < 0.25)div_strength = np.where(is_tail, div_strength * 1.5, div_strength)divergence_matrix[:, i] = div_strength# 组合特征矩阵combined_matrix = np.concatenate((vp_matrix, divergence_matrix), axis=1) # 使用背离矩阵替代协同矩阵# 滚动分位数标准化scaled_std = np.zeros_like(combined_matrix)for i in range(combined_matrix.shape[1]):col = pd.Series(combined_matrix[:, i])rolling_q20 = col.rolling(window=2880, min_periods=720).quantile(0.20)rolling_q80 = col.rolling(window=2880, min_periods=720).quantile(0.80)scaled_std[:, i] = (col - rolling_q20) / (rolling_q80 - rolling_q20 + 1e-7)# 最终因子计算 (尾部敏感加权)# 在尾部区域增加背离信号的权重tail_weight = np.where(df['buy_ratio'] < 0.25, 1.5, 1.0)factor = np.mean(scaled_std, axis=1) * np.log1p(df['volume']) * df['buy_ratio'] * tail_weightreturn factor
因子表现
📊 单币种 (single) 详细评估结果:
--------------------------------------------------
📈 平稳性检验 (ADF):p_value: 0.000000是否平稳: 是
🔗 相关性分析:IC (Pearson): 0.015414Rank_IC (Spearman): 0.016373
📊 信息比率:IR: 0.244797
问题分析
深入分析因子构建逻辑的不足之处
1. 背离检测逻辑存在根本性缺陷
- 问题核心:背离检测基于
np.sign(price_momentum) * np.sign(other_momentum) < 0
,但未考虑动量强度- 仅依赖符号会导致弱动量与强动量被同等对待(例如:价格变动0.01%与成交量变动50%被视为有效背离)
- 未设置动量阈值过滤,大量噪音信号被纳入(如微小价格波动+随机成交量波动)
- 量纲不一致:
price_momentum
使用百分比变化(无量纲)volume_momentum
使用百分比变化(无量纲)flow_momentum
却使用原始差分(有量纲),导致三者不可直接比较
- 尾部放大机制失真:
div_strength = ... * np.abs(flow_momentum)
在buy_ratio<0.25
时放大,但:- 低buy_ratio时段本身flow_momentum绝对值较小(分母效应)
- 放大操作反而可能强化无效信号
2. 特征工程结构性问题
- 量价比率(vp_ratio)构建不合理:
vp_ratio = df['volume'] / (volatility + 1e-7)
- 分子
volume
具有时间累积性,分母volatility
是瞬时波动率,两者时间尺度不匹配 - 未考虑成交量自身的波动特性(应使用成交量波动率而非原始volume)
- 分子
- 多周期处理方式粗糙:
vp_matrix = np.column_stack([vp_ratio.ewm(span=p...]) divergence_matrix = np.zeros((len(df), len(periods)))
- 所有周期采用相同权重,未考虑市场周期特性(如:短周期应更高频更新)
- 未处理周期间的共线性问题(如96与288周期高度相关)
3. 标准化方法导致前瞻性偏差
- 滚动分位数标准化缺陷:
rolling_q20 = col.rolling(window=2880).quantile(0.20) scaled_std = (col - rolling_q20) / (rolling_q80 - rolling_q20)
- 窗口长度2880(≈30天)在加密货币市场过长,无法适应快速波动
- 未进行边界处理:当
rolling_q80 ≈ rolling_q20
时产生数值爆炸(尽管有1e-7但治标不治本) - 滚动窗口在时间序列末端使用未来信息(需改为expanding或固定滞后)
4. 最终因子合成逻辑冲突
- 相互矛盾的权重设计:
factor = mean(scaled_std) * log1p(volume) * buy_ratio * tail_weight
log1p(volume)
强化大成交量时段buy_ratio
强化主动买入时段- 但两者常呈负相关(大成交量往往伴随buy_ratio回归均值)
tail_weight
在低buy_ratio区二次放大,形成逻辑闭环但缺乏实证支持
5. 市场机制未充分考量
- 加密货币特性缺失:
- 未处理“鲸鱼地址”的影响(大单导致的瞬时buy_ratio跳变)
- 忽略交易所API的taker数据可靠性问题(部分交易所包含自成交)
- 未考虑山寨币联动效应(BTC主导行情时的传导关系)
- 波动率计算缺陷:
volatility = price_change.ewm(span=96).std()
- 使用固定span=96(24小时)未适应市场波动率聚类特征
- 应引入GARCH类模型或波动率回归调整
6. 计算效率与实现风险
- 循环矩阵操作低效:
for i, p in enumerate(periods): # 5周期循环divergence_matrix[:, i] = ... # 向量化操作可提速10倍+
- 对每个周期独立计算未利用矩阵并行运算
- 滚动分位数循环
for i in range(combined_matrix.shape[1])
更应避免
- 内存消耗隐患:
- 创建
vp_matrix
(5列),divergence_matrix
(5列),combined_matrix
(10列)等中间矩阵 - 在长时序(如ETH 15m 4年数据≈140,160条)消耗超2GB内存
- 创建
7. 理论依据薄弱环节
- 量价背离假设待验证:
- 传统市场“价涨量缩→反转”规律在加密货币市场有效性存疑
- 未区分牛市/熊市中的背离信号差异(如牛市中的无量上涨可持续)
- 尾部强化机制缺乏实证:
buy_ratio<0.25
作为尾部区域的阈值设定随意- 未验证低buy_ratio区间的信号预测能力是否确实更强
改进方向建议(暂不实施)
-
重构背离检测:
- 改用动态阈值:
|price_momentum| > σ(noise) 且 sign(price) != sign(volume)
- 引入自适应动量强度权重:
div_strength = tanh(|Δprice|) * tanh(|Δvolume|) * sign_conflict
- 改用动态阈值:
-
优化特征工程:
# 建议替代方案 vp_ratio = volume_std / (volatility * typical_price) # 引入典型价格归一化 divergence_score = MACD(price) * MACD(volume) < 0 # 基于指标协同性
-
改进标准化方法:
# 动态滚动窗口 + 稳健标准化 window = min(1440, int(22.5 / volatility)) # 波动率自适应窗口 scaled = (x - median) / IQR # 使用四分位距抗异常值
-
因子合成逻辑调整:
# 分层加权方案 alpha = entropy_weights(vp_matrix) # 信息熵赋权 beta = decay_weights(divergence_matrix) # 时间衰减赋权 factor = dot(alpha, vp_scaled) + dot(beta, div_scaled)
该因子核心问题在于试图用复杂结构弥补基础逻辑缺陷。建议回归市场微观结构本质,重点攻关:订单流不平衡度 + 波动率异常检测 + 多尺度市场情绪合成三个核心维度。当前方案中约60%的代码(尤其是矩阵操作部分)可被更简洁的物理意义明确的方法替代。
尝试对以上问题进行了改进。然而无果、效果都不怎么样。
具体分析:因子头尾部收益率表现反常
1. 背离信号的方向性冲突(核心问题)
-
背离检测逻辑:
price_volume_div = np.sign(price_momentum) * np.sign(volume_momentum) < 0 # 量价背离 price_flow_div = np.sign(price_momentum) * np.sign(flow_momentum) < 0 # 价资背离
- 此逻辑将所有类型的背离都标记为正向信号(背离强度值 > 0)
- 但实际包含两种相反的市场信号:
- 看涨背离(价格↓ + 资金流↑):预示底部反转
- 看跌背离(价格↑ + 资金流↓):预示顶部反转
-
尾部放大机制的副作用:
is_tail = (df['buy_ratio'] < 0.25) div_strength = np.where(is_tail, div_strength * 1.5, div_strength) # 尾部区域放大
- 在尾部区域(
buy_ratio < 0.25
),同时放大了看涨和看跌背离信号 - 导致因子头部同时包含:
- 真实的顶部看跌背离(应做空)
- 被放大的底部看涨背离(应做多)
- 在尾部区域(
2. 标准化过程的特征混淆
- 混合标准化问题:
combined_matrix = np.concatenate((vp_matrix, divergence_matrix), axis=1) scaled_std = ... # 对组合矩阵统一标准化 factor = np.mean(scaled_std, axis=1) # 取均值
- 将量价趋势特征(vp_matrix)和背离特征(divergence_matrix)合并后标准化
- 两类特征的经济含义相反:
vp_matrix
代表动量强度(值越大越看涨)divergence_matrix
代表反转强度(值越大反转风险越高)
- 在头部区域,高动量值和高背离值相互抵消,导致因子无法明确表达市场方向
3. 尾部权重的自我冲突
- 重复放大逻辑:
tail_weight = np.where(df['buy_ratio'] < 0.25, 1.5, 1.0) # 二次放大 factor = ... * tail_weight
- 在背离检测阶段已对尾部区域放大1.5倍(
div_strength * 1.5
) - 最终因子又乘以相同的尾部权重(
tail_weight
) - 导致尾部区域的噪声信号被双重放大,而核心信号(资金流方向)被弱化
- 在背离检测阶段已对尾部区域放大1.5倍(
4. 资金流信号的未被充分利用
- buy_ratio的线性使用:
factor = ... * df['buy_ratio'] # 线性乘以资金流
- 在头部区域(因子值最大处),高因子值可能由以下组成:
- 高buy_ratio(看涨) + 高看跌背离(看跌)
- 在尾部区域(因子值最小处):
- 低buy_ratio(看跌) + 高看涨背离(看涨)
- 线性相乘无法解决这种内在矛盾
- 在头部区域(因子值最大处),高因子值可能由以下组成:
5. 极端值区域的逻辑矛盾
-
因子头部(最大值区域):
成分 期望信号 实际信号 量价趋势(vp_matrix) 看涨 ✅ 看涨 背离信号 - ❌ 同时含多空 buy_ratio 看涨 ✅ 看涨 综合效果 看涨 方向模糊 -
因子尾部(最小值区域):
成分 期望信号 实际信号 量价趋势(vp_matrix) 看跌 ✅ 看跌 背离信号 - ❌ 同时含多空 buy_ratio 看跌 ✅ 看跌 综合效果 看跌 方向模糊
根本原因总结
- 信号方向冲突:背离检测未区分看涨/看跌类型,导致头部混入看跌信号,尾部混入看涨信号
- 特征标准化混淆:动量特征(vp_matrix)与反转特征(divergence_matrix)被合并处理,模糊经济含义
- 尾部过度放大:双重放大机制强化了噪声而非有效信号
- 资金流未主导:在极端区域,buy_ratio未能主导因子方向,被冲突信号抵消
这些设计缺陷导致因子在极端值区域失去方向性预测能力:头部可能包含真实看跌信号,尾部可能包含真实看涨信号,与预期收益方向相反。