- Add scripts/scoring/ module with normalizer, sensitivity analysis, and config - Enhance stock_viewer.html with standardized scoring display - Add integration tests and normalization verification scripts - Add documentation for standardization implementation and usage guides - Add data distribution analysis reports for strength scoring dimensions - Update discussion documents with algorithm optimization plans
24 KiB
强度分系统优化方案 - 深度分析
分析日期: 2026-01-29
基于: 18,004个收敛三角形样本的分布分析结果
视角: 量化研究 + 基金经理实战
一、当前系统问题诊断
1.1 分布分析揭示的核心问题
基于18,004个样本的统计分析,发现以下关键问题:
| 维度 | 均值 | 中位数 | 超额峰度 | 核心问题 |
|---|---|---|---|---|
| 突破幅度分(up) | 0.056 | 0.000 | 13.38 | ❌ 中位数=0,50%数据无信息量 |
| 突破幅度分(down) | 0.019 | 0.000 | 45.72 | ❌ 更极端的零膨胀 |
| 成交量分 | 0.151 | 0.000 | 2.77 | ❌ 中位数=0,区分度极低 |
| 形态规则度 | 0.052 | 0.005 | 4.56 | ⚠️ 普遍极低,区分度差 |
| 倾斜度分 | 0.497 | 0.500 | 46.33 | ⚠️ 75%数据=0.5,无区分度 |
| 收敛度分 | 0.798 | 0.803 | -1.05 | ✅ 相对稳定 |
| 价格活跃度 | 0.069 | 0.071 | -0.25 | ✅ 近正态,最稳定 |
1.2 问题本质:维度间不可比性
当前等权相加会产生什么后果?
假设等权(各16.67%)后的计算:
强度分 = 1/6 × (0.00 + 0.80 + 0.00 + 0.05 + 0.07 + 0.50)
= 1/6 × 1.42
= 0.237
其中:
突破幅度分(up) = 0.00 (中位数情况)
收敛度分 = 0.80 (中位数情况)
成交量分 = 0.00 (中位数情况)
形态规则度 = 0.05 (中位数情况)
价格活跃度 = 0.07 (中位数情况)
倾斜度分 = 0.50 (中位数情况)
问题:收敛度分和倾斜度分"吃掉"了大部分强度分,即使没有任何突破!
1.3 问题根源
- 零膨胀分布 (Zero-Inflated):突破幅度分、成交量分的中位数=0
- 点质量分布 (Point Mass):倾斜度分75%恰好=0.5
- 尺度不一致:各维度的有效取值范围差异巨大
- 语义不同步:未突破时,突破幅度分=0是合理的,但收敛度分=0.8也是合理的
二、SOTA方法论调研
2.1 多因子量化领域的标准化方法
(1) 截面分位数标准化 (Cross-Sectional Quantile Normalization)
原理: 将每个因子在截面上(同一时点的所有股票)转换为分位数排名
def quantile_normalize(scores):
"""将原始分数转换为百分位排名"""
ranks = scores.rank(pct=True) # 百分位排名 [0, 1]
return ranks
优点:
- ✅ 消除尺度差异
- ✅ 消除偏度和厚尾的影响
- ✅ 各因子变为均匀分布,可直接等权相加
缺点:
- ❌ 丢失绝对信息(强突破10%和1%可能排名相同)
- ❌ 对零膨胀分布效果差(50%的0会被平分排名)
(2) 截面Z-Score标准化
原理: 减去截面均值,除以截面标准差
def zscore_normalize(scores):
"""截面Z-Score标准化"""
return (scores - scores.mean()) / scores.std()
优点:
- ✅ 保留相对强度信息
- ✅ 简单直观
缺点:
- ❌ 对非正态分布效果差
- ❌ 对极端值敏感
- ❌ 零膨胀分布会导致大量负值
(3) Power Sorting (2023年新方法)
原理: 利用因子-收益关系的非线性特征,通过幂变换捕获不对称性
def power_transform(scores, power=2):
"""非线性幂变换,捕获尾部效应"""
return np.sign(scores) * np.abs(scores) ** power
优点:
- ✅ 专门处理厚尾分布
- ✅ 保留极端值信息
- ✅ 在多因子策略中表现优于传统方法
参考: Hübner et al. (2023) "Power Sorting", SSRN 4552208
(4) 自适应分组标准化 (Class-Specific Normalization)
原理: 根据数据特性选择不同的标准化策略
def adaptive_normalize(scores, data_type):
if data_type == 'zero_inflated':
# 零膨胀: 对非零部分单独标准化
non_zero = scores[scores > 0]
return conditional_rank(scores, non_zero)
elif data_type == 'point_mass':
# 点质量: 转换为离散分类
return categorize(scores)
else:
# 正常: 标准分位数
return quantile_normalize(scores)
2.2 控制论视角:PID自适应权重
参考: Mehra & Patel (2011) "PID Control for Portfolio Optimization"
将强度分系统视为反馈控制系统:
目标: 最大化风险调整收益
输入: 6个维度的原始得分
控制器: 自适应权重调整
输出: 综合强度分
反馈: 实际交易结果
PID权重调整公式:
def pid_weight_update(w, error, error_integral, error_derivative):
"""
w: 当前权重
error: 当前收益偏差
error_integral: 累积偏差
error_derivative: 偏差变化率
"""
Kp, Ki, Kd = 0.1, 0.01, 0.05 # 需要调优
w_new = w + Kp * error + Ki * error_integral + Kd * error_derivative
return normalize(w_new) # 确保权重和为1
优点:
- ✅ 自动适应市场变化
- ✅ 基于实际反馈优化
- ✅ 可解释性强
缺点:
- ❌ 需要足够的历史交易数据
- ❌ 参数调优复杂
2.3 机器学习视角:端到端优化
参考: Chen et al. (2025) "ML Enhanced Multi-Factor Quantitative Trading", arXiv 2507.07107
将"因子得分 → 组合权重 → 交易决策"作为端到端优化问题:
class FactorScoreOptimizer(nn.Module):
def __init__(self, n_factors=6):
self.factor_transform = nn.Sequential(
nn.Linear(n_factors, 32),
nn.ReLU(),
nn.Linear(32, n_factors),
nn.Sigmoid() # 输出[0,1]
)
self.weight_layer = nn.Linear(n_factors, n_factors)
self.softmax = nn.Softmax(dim=-1)
def forward(self, raw_scores):
transformed = self.factor_transform(raw_scores)
weights = self.softmax(self.weight_layer(transformed))
return (transformed * weights).sum(dim=-1)
优点:
- ✅ 自动学习最优变换和权重
- ✅ 可处理复杂非线性关系
缺点:
- ❌ 黑箱,可解释性差
- ❌ 需要大量标注数据
- ❌ 容易过拟合
三、平滑性优化方案
3.1 推荐方案:分层标准化
针对不同类型的分布,采用不同的标准化策略:
第一层:零膨胀分布处理
适用维度: 突破幅度分、成交量分
def normalize_zero_inflated(scores, name):
"""
零膨胀分布标准化:
1. 分离零值和非零值
2. 非零值进行分位数标准化
3. 零值赋予基准分0.5(中性)
"""
is_zero = scores == 0
is_nonzero = scores > 0
result = pd.Series(index=scores.index, dtype=float)
# 零值 -> 0.5 (中性基准)
result[is_zero] = 0.5
# 非零值 -> 在0.5~1.0之间排名
if is_nonzero.sum() > 0:
nonzero_rank = scores[is_nonzero].rank(pct=True) # [0, 1]
result[is_nonzero] = 0.5 + 0.5 * nonzero_rank # [0.5, 1.0]
return result
效果:
- 未突破(score=0) → 标准化后=0.5 (中性)
- 弱突破(score=0.05) → 标准化后≈0.6
- 强突破(score=0.30) → 标准化后≈0.95
第二层:点质量分布处理
适用维度: 倾斜度分
def normalize_point_mass(scores, center=0.5):
"""
点质量分布标准化:
1. 中心值(0.5)保持不变
2. 偏离中心的值进行拉伸
"""
deviation = scores - center
# 正偏离和负偏离分别处理
pos_dev = deviation[deviation > 0]
neg_dev = deviation[deviation < 0]
result = pd.Series(center, index=scores.index)
if len(pos_dev) > 0:
# 正偏离 -> 在0.5~1.0之间排名
result[deviation > 0] = center + 0.5 * pos_dev.rank(pct=True)
if len(neg_dev) > 0:
# 负偏离 -> 在0.0~0.5之间排名
result[deviation < 0] = center * neg_dev.rank(pct=True, ascending=False)
return result
第三层:正常分布处理
适用维度: 收敛度分、价格活跃度
def normalize_standard(scores):
"""
标准分位数标准化:
直接转换为百分位排名
"""
return scores.rank(pct=True)
第四层:低区分度分布处理
适用维度: 形态规则度
def normalize_low_variance(scores, expansion_factor=3):
"""
低区分度分布处理:
1. 对数变换扩大区分度
2. 分位数标准化
"""
# 对数变换扩大小值区间的区分度
log_scores = np.log1p(scores * expansion_factor)
return log_scores.rank(pct=True)
3.2 综合标准化流程
def normalize_all_dimensions(df):
"""
综合标准化流程
"""
normalized = pd.DataFrame(index=df.index)
# 突破幅度分 - 零膨胀处理
normalized['price_score_up'] = normalize_zero_inflated(
df['price_score_up'], 'price_up'
)
normalized['price_score_down'] = normalize_zero_inflated(
df['price_score_down'], 'price_down'
)
# 成交量分 - 零膨胀处理
normalized['volume_score'] = normalize_zero_inflated(
df['volume_score'], 'volume'
)
# 倾斜度分 - 点质量处理
normalized['tilt_score'] = normalize_point_mass(
df['tilt_score'], center=0.5
)
# 收敛度分 - 标准处理
normalized['convergence_score'] = normalize_standard(
df['convergence_score']
)
# 价格活跃度 - 标准处理
normalized['activity_score'] = normalize_standard(
df['activity_score']
)
# 形态规则度 - 低区分度处理
normalized['geometry_score'] = normalize_low_variance(
df['geometry_score']
)
return normalized
3.3 标准化后的等权计算
def calculate_strength_equal_weight(normalized_df, direction='up'):
"""
等权强度分计算 (标准化后)
参数:
direction: 'up' 或 'down',决定使用哪个突破幅度分
"""
if direction == 'up':
price_score = normalized_df['price_score_up']
else:
price_score = normalized_df['price_score_down']
# 等权: 各1/6
strength = (
price_score / 6 +
normalized_df['convergence_score'] / 6 +
normalized_df['volume_score'] / 6 +
normalized_df['geometry_score'] / 6 +
normalized_df['activity_score'] / 6 +
normalized_df['tilt_score'] / 6
)
return strength
四、参数可调性设计
4.1 应用层接口设计
为基金经理提供可解释、可调节的参数接口:
class StrengthScoreConfig:
"""强度分配置 - 应用层接口"""
def __init__(self):
# 权重参数 (默认等权)
self.weight_price = 1/6
self.weight_convergence = 1/6
self.weight_volume = 1/6
self.weight_geometry = 1/6
self.weight_activity = 1/6
self.weight_tilt = 1/6
# 阈值参数
self.price_threshold = 0.6 # 突破幅度分阈值(标准化后)
self.convergence_threshold = 0.7 # 收敛度分阈值
self.volume_threshold = 0.5 # 成交量分阈值(设为中性)
# 筛选模式
self.filter_mode = 'and' # 'and' 或 'or'
# 方向偏好
self.direction_preference = 'both' # 'up', 'down', 'both'
def set_aggressive(self):
"""激进模式: 重视突破"""
self.weight_price = 0.35
self.weight_volume = 0.25
self.weight_convergence = 0.15
self.weight_geometry = 0.10
self.weight_activity = 0.10
self.weight_tilt = 0.05
def set_conservative(self):
"""保守模式: 重视形态质量"""
self.weight_price = 0.15
self.weight_convergence = 0.30
self.weight_volume = 0.10
self.weight_geometry = 0.20
self.weight_activity = 0.20
self.weight_tilt = 0.05
def set_volume_focus(self):
"""放量模式: 重视成交量确认"""
self.weight_price = 0.25
self.weight_volume = 0.35
self.weight_convergence = 0.15
self.weight_geometry = 0.10
self.weight_activity = 0.10
self.weight_tilt = 0.05
4.2 多维度筛选器
class MultiDimensionFilter:
"""多维度筛选器"""
def __init__(self, config: StrengthScoreConfig):
self.config = config
def filter(self, df):
"""
根据配置筛选信号
返回:
满足条件的行索引
"""
conditions = []
# 突破幅度条件
if self.config.direction_preference in ['up', 'both']:
conditions.append(
df['price_score_up_normalized'] >= self.config.price_threshold
)
if self.config.direction_preference in ['down', 'both']:
conditions.append(
df['price_score_down_normalized'] >= self.config.price_threshold
)
# 收敛度条件
conditions.append(
df['convergence_score_normalized'] >= self.config.convergence_threshold
)
# 成交量条件 (可选)
if self.config.volume_threshold > 0.5: # 只有设置高于中性时才过滤
conditions.append(
df['volume_score_normalized'] >= self.config.volume_threshold
)
# 组合条件
if self.config.filter_mode == 'and':
final_condition = conditions[0]
for cond in conditions[1:]:
final_condition = final_condition & cond
else: # 'or'
final_condition = conditions[0]
for cond in conditions[1:]:
final_condition = final_condition | cond
return df[final_condition].index
4.3 敏感性分析工具
def sensitivity_analysis(df, config, param_name, param_range):
"""
参数敏感性分析
示例: 分析 price_threshold 从 0.5 到 0.9 的影响
"""
results = []
for value in param_range:
# 设置参数
setattr(config, param_name, value)
# 筛选
filter = MultiDimensionFilter(config)
selected = filter.filter(df)
# 统计
results.append({
'param_value': value,
'n_signals': len(selected),
'pct_selected': len(selected) / len(df) * 100,
# 可添加更多指标: 平均收益、胜率等
})
return pd.DataFrame(results)
五、基金经理视角:各维度量化意义
5.1 突破幅度分 - 信号强度
量化意义:
- 衡量价格动能的核心指标
- 反映市场对突破的认可程度
- 是最直接的交易信号
实战应用:
- >P90: 强信号,可考虑立即入场
- P75-P90: 中等信号,需配合其他确认
- <P75: 弱信号,观望为主
当前问题:
- 中位数=0导致大量信号被"埋没"
- 建议:标准化后使用,而非原始值
基金经理关注点:
"突破幅度多大才值得交易?我需要一个可量化的入场标准。"
建议阈值:
- 激进策略: 标准化后 > 0.60
- 稳健策略: 标准化后 > 0.75
- 保守策略: 标准化后 > 0.85
5.2 收敛度分 - 蓄势程度
量化意义:
- 衡量多空博弈的激烈程度
- 收敛越紧,突破后动能越大
- 反映市场分歧逐渐收窄的过程
实战应用:
- 高收敛(>0.85): 能量积蓄充分,突破概率高
- 中收敛(0.70-0.85): 标准形态
- 低收敛(<0.70): 形态不成熟,信号可靠性低
当前评价:
- ✅ 分布稳定,是最可靠的维度
- ✅ 区分度好,有实际筛选价值
- 建议:可适当提高权重
基金经理关注点:
"收敛程度是否与后续涨幅相关?越收敛越好吗?"
实证建议: 收敛度与突破成功率正相关,但与突破幅度的关系需进一步回测验证
5.3 成交量分 - 资金确认
量化意义:
- 衡量资金介入的强度
- 放量突破更具可持续性
- 是区分真突破和假突破的关键
实战应用:
- 高放量(>P80): 资金确认,信号可信度高
- 中等放量(P50-P80): 一般确认
- 无放量(<P50): 存疑,可能是假突破
当前问题:
- ❌ 中位数=0,50%三角形无放量信息
- ❌ 作为必要条件会过滤太多信号
- 建议:降权或作为"加分项"而非"扣分项"
基金经理关注点:
"没有放量的突破能信吗?放量标准应该是多少倍?"
建议策略:
- 不作为必要条件(会丢失50%潜在机会)
- 作为信号评级的加分项
- 放量突破 → 加仓或延长持有期
5.4 形态规则度 - 形态质量
量化意义:
- 衡量形态的几何标准性
- 高规则度意味着市场对关键价位有共识
- 反映形态是否"教科书级别"
实战应用:
- 高规则度(>P80): 教科书形态,交易员容易识别
- 中规则度(P50-P80): 标准形态
- 低规则度(<P50): 非典型,不易被市场认可
当前问题:
- ⚠️ 普遍极低(中位数0.005),区分度差
- ⚠️ 可能是算法对"规则度"的定义过于严格
- 建议:对数变换扩大区分度,或重新定义计算方式
基金经理关注点:
"形态越标准越好吗?非标准形态是否也有交易价值?"
思考: 过于"完美"的形态可能是市场共识过高,反而需要警惕。建议:
- 规则度作为辅助参考,权重不宜过高
- 非标准形态不应直接排除
5.5 价格活跃度 - 真实博弈
量化意义:
- 衡量价格振荡充分性
- 区分真实博弈 vs 僵尸形态
- 反映市场参与度
实战应用:
- 高活跃度(>P75): 市场参与充分,形态有效
- 中活跃度(P25-P75): 正常情况
- 低活跃度(<P25): 僵尸形态,可能是流动性问题
当前评价:
- ✅ 近正态分布,最稳定的维度
- ✅ 有实际区分价值
- 建议:可适当提高权重
基金经理关注点:
"如何区分'健康的收敛'和'无人问津的死股'?"
价格活跃度正是解决这个问题的关键指标
5.6 倾斜度分 - 趋势一致性
量化意义:
- 衡量突破方向与形态趋势的一致性
- 顺势突破更可靠,逆势突破需谨慎
- 区分上升/下降/对称三角形
实战应用:
- 高倾斜度(>0.6): 强趋势一致,高置信度
- 中性(≈0.5): 对称三角形,方向不明确
- 低倾斜度(<0.4): 逆势突破,需额外确认
当前问题:
- ❌ 75%的值=0.5,几乎无区分度
- ❌ 算法强烈偏好对称三角形
- 建议:重新标准化或调整算法参数
基金经理关注点:
"上升三角形向上突破 vs 下降三角形向上突破,胜率有差异吗?"
实证建议: 需要回测验证,但直觉上顺势突破应该更可靠
六、整体刻画准确性评估
6.1 当前系统的优点
-
覆盖维度全面:
- ✅ 价格维度: 突破幅度、收敛度
- ✅ 量能维度: 成交量
- ✅ 形态维度: 几何规则度、倾斜度
- ✅ 行为维度: 价格活跃度
-
归一化方式合理:
- ✅ 所有维度输出在[0, 1]区间
- ✅ 使用tanh、exp等非线性变换
-
权重可配置:
- ✅ 代码支持权重参数调整
- ✅ 突破幅度作为主要权重是合理的
6.2 当前系统的不足
-
维度间不可比:
- ❌ 原始得分直接加权,未考虑分布差异
- ❌ 中位数差异巨大(0 vs 0.8)
-
零膨胀问题未处理:
- ❌ 突破幅度分、成交量分50%为0
- ❌ 这些0值参与加权计算会稀释信号
-
点质量问题未处理:
- ❌ 倾斜度分75%为0.5
- ❌ 无法区分真正的对称三角形和算法偏好
-
缺乏截面标准化:
- ❌ 未考虑同一时点不同股票的相对排名
- ❌ 强度分的绝对值缺乏参照系
6.3 刻画准确性评分
| 评估维度 | 当前评分 | 优化后预期 |
|---|---|---|
| 维度完整性 | ⭐⭐⭐⭐⭐ (5/5) | 5/5 |
| 归一化合理性 | ⭐⭐⭐☆☆ (3/5) | 4/5 |
| 维度可比性 | ⭐⭐☆☆☆ (2/5) | 4/5 |
| 分布平滑性 | ⭐⭐☆☆☆ (2/5) | 4/5 |
| 参数可调性 | ⭐⭐⭐☆☆ (3/5) | 5/5 |
| 实战可用性 | ⭐⭐⭐☆☆ (3/5) | 4/5 |
| 综合评分 | 2.8/5 | 4.3/5 |
七、优化建议总结
7.1 短期优化(立即可做)
-
实施分层标准化
- 对突破幅度分、成交量分使用零膨胀处理
- 对倾斜度分使用点质量处理
- 对其他维度使用分位数标准化
-
调整权重分配
当前 → 建议(等权基础): 突破幅度分: 45% → 16.67% (标准化后等权) 收敛度分: 15% → 16.67% 成交量分: 10% → 16.67% 形态规则度: 10% → 16.67% 价格活跃度: 15% → 16.67% 倾斜度分: 5% → 16.67% -
提供预设配置
- 激进模式、保守模式、放量模式等
- 让用户可以快速切换
7.2 中期优化(需要开发)
-
截面标准化
- 在每个时间点对所有股票排名
- 提供"相对强度"而非"绝对强度"
-
敏感性分析工具
- 参数变化对信号数量的影响
- 参数变化对回测收益的影响
-
动态权重调整
- 基于市场状态自动调整权重
- 牛市/熊市/震荡市不同配置
7.3 长期优化(研究方向)
-
机器学习优化
- 端到端学习最优变换和权重
- 需要构建完整的回测框架
-
控制论框架
- PID自适应权重调整
- 基于实际交易反馈优化
-
因子有效性验证
- 各维度与未来收益的IC分析
- 剔除无效因子,保留有效因子
八、代码实现建议
8.1 目录结构
technical-patterns-lab/
├── src/
│ ├── scoring/
│ │ ├── normalizer.py # 标准化模块
│ │ ├── strength_score.py # 强度分计算
│ │ ├── config.py # 配置管理
│ │ └── filter.py # 多维度筛选
│ └── analysis/
│ ├── sensitivity.py # 敏感性分析
│ └── backtest.py # 回测框架
└── configs/
├── aggressive.yaml # 激进配置
├── conservative.yaml # 保守配置
└── volume_focus.yaml # 放量配置
8.2 核心类设计
# scoring/normalizer.py
class FactorNormalizer:
"""因子标准化器"""
def normalize_zero_inflated(self, series): ...
def normalize_point_mass(self, series): ...
def normalize_standard(self, series): ...
def normalize_low_variance(self, series): ...
def normalize_all(self, df) -> pd.DataFrame: ...
# scoring/strength_score.py
class StrengthScoreCalculator:
"""强度分计算器"""
def __init__(self, config: Config):
self.config = config
self.normalizer = FactorNormalizer()
def calculate(self, raw_df) -> pd.Series: ...
def calculate_with_details(self, raw_df) -> pd.DataFrame: ...
# scoring/filter.py
class MultiDimensionFilter:
"""多维度筛选器"""
def filter(self, df, config) -> pd.Index: ...
def filter_top_n(self, df, n, config) -> pd.Index: ...
九、下一步行动计划
立即行动
- ✅ 实现分层标准化函数
- ✅ 创建等权强度分计算
- ✅ 提供3种预设配置
短期计划
- 📝 实现敏感性分析工具
- 📝 对标准化后的数据重新进行分布分析
- 📝 验证标准化效果
中期计划
- 🔬 实现截面标准化
- 🔬 构建简单回测框架
- 🔬 验证各维度的预测能力
长期研究
- 🔮 探索机器学习优化
- 🔮 探索控制论框架
- 🔮 发表研究报告
参考文献
- Hübner et al. (2023). "Power Sorting". SSRN 4552208.
- Chen et al. (2025). "Machine Learning Enhanced Multi-Factor Quantitative Trading". arXiv 2507.07107.
- Mehra & Patel (2011). "PID Control for Portfolio Optimization". InTech.
- Lo et al. (2000). "Foundations of Technical Analysis". SSRN 228099.
报告创建时间: 2026-01-29
作者: AI量化研究助手
版本: v1.0