2. 时间序列数据基础:时间戳处理、重采样、滑窗概念,Pandas时间序列操作

做量化交易,说白了就是跟时间赛跑。你想想看,每一笔报价、每一次成交,背后都带着一个精确的时间戳。没有时间这根轴,价格数据就是一盘散沙。今天这章,我就带你把这些基础打牢。

2.1 时间戳:交易的「身份证」

时间戳是什么?就是数据点上的一个标签,告诉你在哪个时刻发生了什么事。在量化里,我们通常用两种格式:

  • 字符串格式:比如 '2024-01-15 09:30:00',人类友好,但机器处理慢
  • 数值格式:比如 1705293000(Unix时间戳),机器友好,但人类看着头疼

我个人习惯,在数据清洗阶段先用字符串,方便肉眼检查。等进入计算环节,一律转成 Pandas 的 DatetimeIndex,性能好得多。

核心原则:永远不要用字符串做时间运算。加减一秒、比较先后,这些操作在字符串上跑起来慢得你想哭。

2.2 重采样:把数据「揉」成你想要的形状

重采样,说白了就是改变数据的时间频率。高频数据转低频叫「降采样」,低频转高频叫「升采样」。在量化里,降采样用得最多。

举个例子,你拿到的是 tick 级数据(每笔成交),但策略只需要分钟级 K 线。这时候就要做降采样:

import pandas as pd
import numpy as np

# 模拟 tick 数据
tick_data = pd.DataFrame({
    'price': np.random.rand(100) * 10 + 100,
    'volume': np.random.randint(1, 100, 100)
}, index=pd.date_range('2024-01-15 09:30:00', periods=100, freq='1s'))

# 降采样到 1 分钟 K 线
minute_bar = tick_data.resample('1min').agg({
    'price': 'ohlc',   # Open, High, Low, Close
    'volume': 'sum'
})

print(minute_bar.head())

我在项目中遇到过一个问题:重采样时数据量突然少了。后来发现是时间索引没对齐,有些时间戳落在了采样窗口的边界上。嗯,这里要注意,resample 默认用左闭右开区间,你可以通过 labelclosed 参数调整。

小技巧:降采样时,如果数据有缺失,可以用 fillna()interpolate() 补上。但别盲目补,先搞清楚缺失的原因——是停牌?还是数据源本身就有问题?

2.3 滑窗:滚动计算的核心

滑窗,就是在一个固定大小的窗口里,不断往前滑动做计算。移动平均线、布林带、RSI……这些技术指标,底层全是滑窗。

Pandas 里用 rolling() 实现:

# 计算 5 分钟移动平均
close_prices = minute_bar['price']['close']
ma_5 = close_prices.rolling(window=5).mean()

# 计算 20 分钟标准差(布林带用)
std_20 = close_prices.rolling(window=20).std()

为什么会这样?因为滑窗本质上是一个「延迟计算」的过程。窗口内的数据全部到位后,才会输出结果。所以刚开盘那几分钟,窗口没填满,输出是 NaN。

避坑指南:我曾经在实盘策略里直接用 rolling().mean(),结果发现信号延迟了整整一个窗口长度。后来才意识到,rolling() 默认用窗口的最后一个时间点作为输出位置。如果你想要「当前时刻」的均值,得用 rolling(window).mean().shift(1) 把结果往前挪一位。

2.4 Pandas 时间序列操作速查

下面这张表,是我平时用得最多的几个操作,你直接拿去用:

操作 代码 说明
创建时间序列 pd.date_range(start, end, freq='1min') 生成等间隔时间索引
转换时间戳 pd.to_datetime(df['time_col']) 字符串转时间类型
设置索引 df.set_index('time_col', inplace=True) 把时间列设为行索引
重采样 df.resample('5min').mean() 降采样到 5 分钟
滑窗计算 df['col'].rolling(10).mean() 10 期移动平均
时间偏移 df.shift(1) 数据整体往后挪一行
时间差计算 df.index.to_series().diff() 计算相邻时间戳间隔

2.5 知识体系总览

我把这章的核心逻辑画了张图,你看一眼就能串起来:

时间序列数据基础 · 知识体系 时间戳处理 字符串 ↔ DatetimeIndex 重采样 降采样 · 升采样 · 聚合 滑窗 滚动计算 · 延迟处理 pd.to_datetime() set_index() resample().agg() label / closed 参数 rolling().mean() shift() 消除延迟 三者结合 → 实时特征工程 时间戳对齐 → 重采样统一频率 → 滑窗提取特征 核心思想:时间对齐 → 频率统一 → 特征提取

这张图把三个核心模块串起来了。你从左边开始,先搞定时间戳格式,然后通过重采样统一数据频率,最后用滑窗提取特征。每一步都踩稳了,后面的实时特征工程才能跑得顺。

我的经验:刚开始做量化时,我总想一步到位搞复杂模型。后来发现,80% 的问题出在时间处理上——时间戳没对齐、重采样参数设错了、滑窗延迟没考虑。把基础打牢,比什么都重要。


专注资料整理