3. 金融数据特征工程:时间特征提取与滚动统计

各位同学,咱们今天聊点实在的。金融数据里,时间就是金钱——这句话真不是开玩笑。我做了这么多年量化,见过太多人把原始时间戳直接扔进模型,结果跑出来一堆垃圾。说白了,时间特征工程就是把「几月几号几点几分」这种原始信息,翻译成模型能理解的数学语言。

我个人习惯,拿到金融数据第一件事,先看时间列。不看时间,后面所有分析都是空中楼阁。好,咱们直接进入正题。

3.1 时间特征提取:从日历里挖金子

时间特征提取,说白了就是把一个时间戳拆成多个维度。为什么要拆?因为金融市场的规律往往藏在特定的时间节点里。

核心维度包括:

  • 年、月、日:捕捉年度周期、月度效应、月末效应
  • 星期几:周一效应、周五效应,这些在A股市场特别明显
  • 节假日:节前节后的异常波动,我吃过不少亏
  • 交易日序号:月内第几个交易日,这个很多人忽略

避坑指南:我曾经在做一个股指期货策略时,直接用日期作为特征,结果模型学到的全是「每月15号附近涨」这种伪规律。后来拆成星期和月内日,效果才正常。记住:模型不懂日历,它只认数字。

import pandas as pd
import numpy as np
from datetime import datetime

# 假设df已经加载,'date'列是时间戳
df['date'] = pd.to_datetime(df['date'])

# 基础时间特征
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month
df['day'] = df['date'].dt.day
df['weekday'] = df['date'].dt.weekday  # 0=周一, 6=周日
df['is_weekend'] = df['weekday'].isin([5, 6]).astype(int)

# 节假日特征(以中国A股为例)
# 这里需要外部节假日数据,我一般用tushare或自己维护的日历
holiday_list = ['2024-01-01', '2024-02-10', '2024-02-11', ...]  # 实际需要完整列表
df['is_holiday'] = df['date'].isin(holiday_list).astype(int)

# 交易日序号(月内第几个交易日)
df['trading_day_in_month'] = df.groupby(['year', 'month'])['date'].rank(method='first').astype(int)

我的小技巧:对于节假日特征,别只做0/1二值化。我习惯把「节前第N天」「节后第N天」也做出来,因为市场情绪是渐变的,不是突变的。比如春节前5天和春节前1天,市场行为完全不同。

3.2 滞后特征(Lag Features):让数据「记住」过去

金融数据最核心的假设是什么?历史会重演。滞后特征就是把这个假设变成数学公式。

滞后特征,说白了就是把过去N天的数据「搬」到今天来用。比如今天的收盘价,和昨天的收盘价、前天的收盘价,它们之间是有依赖关系的。

# 滞后特征示例
# 假设df已经按时间排序
df = df.sort_values('date')

# 创建滞后1天、2天、5天的收盘价
df['close_lag1'] = df['close'].shift(1)
df['close_lag2'] = df['close'].shift(2)
df['close_lag5'] = df['close'].shift(5)

# 滞后收益率(更常用)
df['return_lag1'] = df['return'].shift(1)
df['return_lag5'] = df['return'].shift(5)

# 注意:shift后会产生NaN,需要处理
df = df.dropna(subset=['close_lag1'])

⚠️ 重要警告:做滞后特征时,千万注意数据泄露!我见过有人用未来数据预测过去,结果回测曲线漂亮得像假的一样——因为它本来就是假的。记住:shift()的方向要正确,永远用过去预测未来。

我个人习惯,滞后阶数不是随便选的。对于日频数据,我一般试1、2、5、10、20、60这几个阶数。为什么?1天是超短期,5天是一周,20天是一个月,60天是一个季度。这些时间窗口在金融里都有实际意义。

3.3 滚动窗口统计:捕捉趋势与波动

滚动窗口统计,说白了就是「过去N天的平均值/标准差」。它能帮我们平滑噪声,抓住趋势。

常用滚动统计量:

  • 滚动均值(Rolling Mean):趋势指标,比如20日均线
  • 滚动标准差(Rolling Std):波动率指标,衡量风险
  • 滚动最大值/最小值:支撑位/压力位
  • 滚动偏度/峰度:分布形态,用于异常检测
# 滚动窗口统计示例
# 20日滚动均值和标准差
df['ma20'] = df['close'].rolling(window=20).mean()
df['std20'] = df['close'].rolling(window=20).std()

# 滚动波动率(年化)
df['volatility_20d'] = df['return'].rolling(window=20).std() * np.sqrt(252)

# 滚动最大值/最小值(过去20天)
df['high_20d'] = df['high'].rolling(window=20).max()
df['low_20d'] = df['low'].rolling(window=20).min()

# 滚动偏度(用于检测尾部风险)
df['skew_20d'] = df['return'].rolling(window=20).skew()

经验之谈:滚动窗口大小的选择,取决于你的交易频率。做日频策略,20天和60天是标配;做高频,可能用5分钟或30分钟窗口。我刚开始做量化时,总想用复杂的窗口,后来发现简单窗口往往更稳健。

3.4 知识体系总览

下面这张图,是我自己总结的时间特征工程知识体系。你看一眼,就能明白今天讲的内容是怎么串起来的。

金融数据时间特征工程知识体系 时间特征提取 滞后特征 滚动窗口统计 年/月/日 星期/周末 节假日特征 价格滞后 收益率滞后 成交量滞后 滚动均值 滚动标准差 滚动极值 核心原则:用过去的信息,预测未来的走势 避免数据泄露 | 窗口选择有实际意义 | 特征要可解释 数据流方向:原始时间戳 → 特征提取 → 模型输入 注:实际应用中,三大模块通常组合使用,形成高维特征空间

3.5 实战组合:把三个模块串起来

光讲理论没意思,咱们来个实战案例。假设我们要预测某只股票明天的涨跌,特征工程怎么做?

# 完整特征工程流水线
def create_features(df):
    """
    输入:原始DataFrame,包含date, open, high, low, close, volume
    输出:带有全部特征的DataFrame
    """
    df = df.copy()
    df['date'] = pd.to_datetime(df['date'])
    df = df.sort_values('date')
    
    # 1. 时间特征
    df['month'] = df['date'].dt.month
    df['weekday'] = df['date'].dt.weekday
    df['is_month_end'] = df['date'].dt.is_month_end.astype(int)
    
    # 2. 滞后特征(过去1天、5天、20天的收益率)
    df['ret'] = df['close'].pct_change()
    df['ret_lag1'] = df['ret'].shift(1)
    df['ret_lag5'] = df['ret'].shift(5)
    df['ret_lag20'] = df['ret'].shift(20)
    
    # 3. 滚动统计(20日均线、20日波动率)
    df['ma20'] = df['close'].rolling(20).mean()
    df['vol20'] = df['ret'].rolling(20).std()
    
    # 4. 衍生特征(价格与均线的偏离度)
    df['price_to_ma20'] = df['close'] / df['ma20'] - 1
    
    # 清理NaN
    df = df.dropna()
    
    return df

# 使用示例
featured_df = create_features(raw_data)
print(featured_df[['date', 'ret_lag1', 'ma20', 'vol20', 'price_to_ma20']].head())

核心要点:特征工程不是越多越好。我见过有人一口气造了200个特征,结果模型过拟合得一塌糊涂。记住奥卡姆剃刀——简单有效的特征,远胜于花哨无用的特征。我个人习惯,先造20-30个核心特征,跑一轮模型,再根据特征重要性筛选。

嗯,今天的内容就到这儿。时间特征、滞后特征、滚动统计,这三板斧用好了,你的金融模型就已经赢在起跑线上了。下次咱们聊更高级的特征交互,到时候你会发现,原来特征还能这么玩。


专注资料整理