特征工程基础:技术指标与基本面因子的实战处理

各位同学,今天我们来聊聊特征工程。说实话,这是整个量化模型中最容易被低估的一环。我见过太多人把精力全花在模型调参上,结果特征没处理好,模型效果惨不忍睹。嗯,咱们今天就把这块硬骨头啃下来。

一、技术指标计算:从K线到信号的转化

技术指标,说白了就是把价格和成交量数据,通过数学公式转化成有交易含义的信号。我个人习惯把技术指标分成两类:趋势类和震荡类。

1. 移动平均线(MA)

MA是最基础的指标。它的核心思想很简单:平滑价格波动,看清趋势方向。

核心公式:

MA(N) = (P₁ + P₂ + ... + Pₙ) / N

其中P为收盘价,N为周期数

import pandas as pd
import numpy as np

def calculate_ma(df, periods=[5, 10, 20, 60]):
    """
    计算多周期移动平均线
    """
    for period in periods:
        df[f'MA_{period}'] = df['close'].rolling(window=period).mean()
    return df

# 实战用法
df = calculate_ma(df, periods=[5, 20, 60])
# 金叉信号:MA5上穿MA20
df['golden_cross'] = (df['MA_5'] > df['MA_20']) & (df['MA_5'].shift(1) <= df['MA_20'].shift(1))

我的经验:别只用收盘价算MA。我在做期货策略时,发现用典型价((高+低+收)/3)算出来的MA,对日内波动的过滤效果更好。你想想看,收盘价容易被大单操纵,典型价反而更稳定。

2. MACD指标

MACD是MA的升级版。它用两条不同周期的EMA,来捕捉趋势的强弱变化。

def calculate_macd(df, fast=12, slow=26, signal=9):
    """
    计算MACD指标
    """
    # 计算快慢EMA
    df['EMA_fast'] = df['close'].ewm(span=fast, adjust=False).mean()
    df['EMA_slow'] = df['close'].ewm(span=slow, adjust=False).mean()
    
    # DIF线 = 快EMA - 慢EMA
    df['DIF'] = df['EMA_fast'] - df['EMA_slow']
    
    # DEA线 = DIF的EMA
    df['DEA'] = df['DIF'].ewm(span=signal, adjust=False).mean()
    
    # MACD柱 = 2 * (DIF - DEA)
    df['MACD_bar'] = 2 * (df['DIF'] - df['DEA'])
    
    return df

避坑指南:我曾经在回测中发现MACD信号频繁失效。后来排查发现,是EMA的初始值设置问题。默认的ewm函数会用第一个值作为初始值,这在数据量少的时候偏差很大。建议至少用100根K线预热后再计算。

3. RSI与KDJ:震荡类指标

RSI衡量的是涨跌力度,KDJ则加入了随机思想。这两个指标在震荡行情中特别好用。

def calculate_rsi(df, period=14):
    """
    计算RSI指标
    """
    delta = df['close'].diff()
    gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
    loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
    
    rs = gain / loss
    df['RSI'] = 100 - (100 / (1 + rs))
    return df

def calculate_kdj(df, n=9, m1=3, m2=3):
    """
    计算KDJ指标
    """
    # 计算RSV
    low_n = df['low'].rolling(window=n).min()
    high_n = df['high'].rolling(window=n).max()
    rsv = (df['close'] - low_n) / (high_n - low_n) * 100
    
    # K、D、J值
    df['K'] = rsv.ewm(com=m1-1, adjust=False).mean()
    df['D'] = df['K'].ewm(com=m2-1, adjust=False).mean()
    df['J'] = 3 * df['K'] - 2 * df['D']
    
    return df

二、基本面因子提取:从财报到量化特征

技术指标看的是价格行为,基本面因子看的是公司质地。我个人觉得,两者结合才是王道。

1. PE(市盈率)

PE = 股价 / 每股收益。它反映的是市场愿意为每1元利润支付多少价格。

实战处理要点:

  • PE为负值时,说明公司亏损,需要特殊处理
  • PE过高(>100)或过低(<0)的股票,建议剔除或做截尾处理
  • 不同行业的PE差异很大,建议做行业中性化

2. PB(市净率)

PB = 股价 / 每股净资产。这个指标对金融、地产等重资产行业特别有效。

def extract_fundamental_factors(df_fund):
    """
    提取并清洗基本面因子
    """
    # 处理极端值:用中位数填充
    for col in ['PE', 'PB', 'ROE']:
        median_val = df_fund[col].median()
        df_fund[col] = df_fund[col].clip(lower=df_fund[col].quantile(0.01),
                                          upper=df_fund[col].quantile(0.99))
        df_fund[col].fillna(median_val, inplace=True)
    
    # 行业中性化处理
    df_fund['PE_neutral'] = df_fund.groupby('industry')['PE'].transform(
        lambda x: (x - x.mean()) / x.std()
    )
    
    return df_fund

3. ROE(净资产收益率)

ROE = 净利润 / 净资产。这是巴菲特最看重的指标之一。ROE持续高于15%的公司,通常有较强的护城河。

我的经验:别只看单期ROE。我习惯用过去3年ROE的均值和标准差,均值代表盈利能力,标准差代表稳定性。你会发现,那些ROE稳定在20%左右的消费股,比ROE忽高忽低的周期股更适合做长期策略。

三、特征标准化与归一化:让数据站在同一起跑线

为什么需要标准化?你想想看,PE可能是几十倍,ROE只有百分之十几,MACD柱可能是小数。如果不做处理,模型会天然偏向数值大的特征。这显然不合理。

1. Z-score标准化

把数据变成均值为0、标准差为1的分布。适合数据本身近似正态分布的情况。

from sklearn.preprocessing import StandardScaler

def zscore_normalize(df, columns):
    """
    Z-score标准化
    """
    scaler = StandardScaler()
    df[columns] = scaler.fit_transform(df[columns])
    return df, scaler

# 使用示例
features = ['MA_5', 'RSI', 'PE', 'ROE']
df, scaler = zscore_normalize(df, features)

2. Min-Max归一化

把数据压缩到[0,1]区间。适合有明确上下界的特征,比如RSI天然在0-100之间。

from sklearn.preprocessing import MinMaxScaler

def minmax_normalize(df, columns):
    """
    Min-Max归一化
    """
    scaler = MinMaxScaler()
    df[columns] = scaler.fit_transform(df[columns])
    return df, scaler

避坑指南:我曾经犯过一个低级错误——在回测时对整个数据集做标准化。这会导致未来数据泄露!正确的做法是:用训练集的统计量去标准化测试集。记住,测试集的数据对模型来说应该是"未来"。

3. 如何选择?

方法 适用场景 注意事项
Z-score 数据近似正态分布,有异常值 对异常值敏感度较低
Min-Max 数据有明确边界,无极端值 对异常值敏感
RobustScaler 数据有较多异常值 基于中位数和四分位数

四、知识体系总览

下面这张图,是我整理的特征工程核心流程。你可以把它当作一个检查清单,每次做特征工程时对照着来。

特征工程核心流程 原始数据 技术指标 MA (趋势) MACD (动量) RSI/KDJ (震荡) 基本面因子 PE (估值) PB (资产) ROE (盈利) 其他特征 成交量因子 波动率因子 行业/市值 特征处理:标准化 / 归一化 最终特征矩阵 → 模型训练

这张图把整个流程串起来了。从原始数据出发,分别计算技术指标和基本面因子,然后统一做标准化处理,最终形成特征矩阵。每一步都有坑,每一步都需要细心处理。

核心要点总结:

  • 技术指标要选对参数,不同周期、不同品种参数差异很大
  • 基本面因子要做行业中性化和极端值处理
  • 标准化时务必注意数据泄露问题
  • 特征之间相关性过高时,考虑做PCA降维

好了,特征工程的基础内容就讲到这里。这些方法我在实盘策略中反复验证过,效果稳定。下一章我们会把这些特征组合起来,构建完整的选股模型。记住,好的特征胜过复杂的模型——这是我在量化圈摸爬滚打多年最深的体会。


专注资料整理