第4章:基础篇:pandas在量化中的应用

做量化交易,说白了就是跟数据打交道。而pandas,就是咱们手里最顺手的工具。我刚开始做期货策略那会儿,还傻乎乎地用Excel手工处理数据,后来发现根本跑不动——几千根K线,手动算个均线都得半天。直到用了pandas,才真正体会到什么叫「效率」。这一章,我就把pandas在量化里最常用的三板斧教给你。

4.1 DataFrame操作:你的数据工作台

DataFrame是什么?你可以把它想象成一张Excel表格,但比Excel灵活得多。每一列是一个字段,每一行是一根K线。我习惯把DataFrame叫做「数据工作台」——你所有的清洗、计算、筛选,都在这个台面上完成。

4.1.1 创建与查看数据

先从最基础的开始。假设我们有一份螺纹钢的日线数据:

import pandas as pd
import numpy as np

# 模拟数据
dates = pd.date_range('2024-01-01', periods=10, freq='D')
data = {
    'open': [3800, 3810, 3795, 3820, 3835, 3825, 3810, 3805, 3840, 3850],
    'high': [3820, 3830, 3810, 3840, 3850, 3840, 3825, 3820, 3855, 3865],
    'low':  [3790, 3800, 3785, 3810, 3825, 3815, 3800, 3795, 3830, 3840],
    'close':[3815, 3820, 3805, 3835, 3845, 3830, 3815, 3810, 3845, 3855],
    'volume':[12000, 13500, 11000, 15000, 16000, 14000, 12500, 11800, 15500, 17000]
}
df = pd.DataFrame(data, index=dates)
print(df.head())  # 看前5行

嗯,这里要注意:index参数我习惯用时间序列,这样后面做时间切片会非常方便。你想想看,如果索引是数字,你要取某一天的数据还得先查行号,多麻烦。

4.1.2 列操作:加减乘除随心所欲

量化里最常用的,就是根据已有列计算新列。比如计算涨跌幅:

# 计算涨跌幅
df['return'] = df['close'].pct_change()
# 计算振幅
df['range'] = (df['high'] - df['low']) / df['open']
# 计算典型价格
df['typical'] = (df['high'] + df['low'] + df['close']) / 3

我在项目中遇到过一个问题:新手喜欢用for循环逐行计算,数据量一上来就卡死。记住,pandas的向量化操作比循环快几十倍。能用一行代码解决的,绝不用循环。

4.1.3 筛选与切片:快速定位

做策略回测时,经常需要筛选特定条件的数据。比如找出涨幅超过2%的交易日:

# 条件筛选
big_up = df[df['return'] > 0.02]
print(big_up)

# 多条件筛选
condition = (df['volume'] > 15000) & (df['return'] > 0.01)
selected = df[condition]

这里有个坑:条件筛选要用&而不是and,用|而不是or。我曾经因为这个bug排查了半小时,最后发现是逻辑运算符用错了。嗯,这种低级错误,犯过一次就记住了。

4.2 时间序列处理:量化交易的时间轴

期货数据天然就是时间序列。开盘、收盘、交割、换月……每一个动作都跟时间绑定。pandas的时间序列处理能力,说实话,是我见过最顺手的。

4.2.1 时间索引的威力

把时间设为索引后,切片变得极其优雅:

# 取某一天
print(df.loc['2024-01-05'])

# 取某段时间
print(df.loc['2024-01-03':'2024-01-07'])

# 取某个月
print(df.loc['2024-01'])

你想想看,如果用数字索引,你要取1月3日到1月7日的数据,还得先知道这两天的行号。但用时间索引,直接写日期就行,是不是很爽?

4.2.2 重采样:切换时间周期

做量化经常需要把日线转成周线、月线。pandas的resample就是干这个的:

# 日线转周线
weekly = df.resample('W').agg({
    'open': 'first',
    'high': 'max',
    'low': 'min',
    'close': 'last',
    'volume': 'sum'
})
print(weekly)

我个人习惯用W表示周,M表示月,Q表示季度。注意:resample默认以结束日期为标签,如果你想要开始日期,可以加参数label='left'

4.2.3 移位操作:获取历史数据

策略里经常要用到前一天的收盘价。用shift就能搞定:

# 获取前一天收盘价
df['prev_close'] = df['close'].shift(1)

# 获取前5日最高价
df['high_5'] = df['high'].shift(5)

# 计算当日涨跌
df['change'] = df['close'] - df['prev_close']

这里要注意:shift(1)会把第一行变成NaN。我建议在计算前先dropna(),不然NaN会像病毒一样传染到后面的计算中。

4.3 滚动计算:移动平均线的秘密

滚动计算,说白了就是「滑动窗口」。均线、布林带、RSI……这些技术指标的核心都是滚动计算。pandas的rolling函数,就是专门干这个的。

4.3.1 简单移动平均线

最经典的例子:计算5日均线:

# 5日均线
df['ma5'] = df['close'].rolling(window=5).mean()

# 20日均线
df['ma20'] = df['close'].rolling(window=20).mean()

# 查看结果
print(df[['close', 'ma5', 'ma20']].head(10))

你可能会问:为什么前4行的ma5是NaN?因为窗口需要5个数据才能计算。嗯,这是滚动计算的特性,记得处理一下。

4.3.2 滚动标准差:布林带的基础

布林带需要均线和标准差。用rolling一步到位:

# 计算滚动标准差
df['std20'] = df['close'].rolling(window=20).std()

# 布林带上下轨
df['upper'] = df['ma20'] + 2 * df['std20']
df['lower'] = df['ma20'] - 2 * df['std20']

我在项目中遇到过一个问题:直接用rolling计算标准差,默认是样本标准差(分母n-1)。但有些策略需要总体标准差(分母n)。这时候可以加参数ddof=0

# 总体标准差
df['std20_pop'] = df['close'].rolling(window=20).std(ddof=0)

4.3.3 自定义滚动函数

有时候内置函数不够用,比如你想计算滚动窗口内的最大值出现位置。这时候可以用apply

# 自定义:滚动窗口内最高价的位置
def argmax_in_window(series):
    return series.argmax()

df['high_pos'] = df['high'].rolling(window=10).apply(argmax_in_window)

不过要提醒你:apply比内置函数慢很多。数据量大的时候,尽量用meanstd这些原生方法。我一般只在万不得已时才用apply

4.4 实战:一个完整的均线策略数据准备

光说不练假把式。咱们把上面学的串起来,做一个完整的均线策略数据准备流程:

# 1. 读取数据(假设已有CSV)
df = pd.read_csv('rb2401.csv', index_col=0, parse_dates=True)

# 2. 计算技术指标
df['ma5'] = df['close'].rolling(5).mean()
df['ma20'] = df['close'].rolling(20).mean()
df['std20'] = df['close'].rolling(20).std()

# 3. 生成交易信号
df['signal'] = 0
df.loc[df['ma5'] > df['ma20'], 'signal'] = 1  # 金叉做多
df.loc[df['ma5'] < df['ma20'], 'signal'] = -1 # 死叉做空

# 4. 计算每日收益
df['daily_return'] = df['close'].pct_change()
df['strategy_return'] = df['signal'].shift(1) * df['daily_return']

# 5. 清理NaN
df = df.dropna()

print(df.tail())

这个流程,说白了就是量化策略的标准模板。你以后写任何策略,基本都逃不出这个框架:数据加载 → 指标计算 → 信号生成 → 收益计算。

核心要点:

  • DataFrame是数据工作台,所有操作都在上面完成
  • 时间索引让切片变得优雅,一定要养成习惯
  • 滚动计算是技术指标的基础,掌握rolling就掌握了半壁江山
  • 向量化操作比循环快几十倍,能用一行别用十行

我的小技巧:

写pandas代码时,我习惯每写一步就print(df.head())看一眼。数据量大的时候,用.shape检查行数列数。这样能及时发现数据异常,避免后面全盘出错。

避坑指南:

我曾经在回测时发现策略收益异常高,排查了半天,原来是shift用错了方向——把未来的数据当成了历史数据。记住:shift(1)是取前一天的数据,不是后一天。这个方向搞反了,你的策略就是「未来函数」,实盘必亏。

4.5 本章知识体系

下面这张图,帮你理清本章的核心脉络:

pandas在量化中的应用 DataFrame操作 时间序列处理 滚动计算 创建与查看数据 列操作(加减乘除) 筛选与切片 时间索引切片 重采样(日转周/月) 移位操作(shift) 移动平均线 滚动标准差 自定义滚动函数 实战:均线策略数据准备 三大模块相互配合,构成量化策略的数据处理基础

这张图展示了本章的三大核心模块。它们不是孤立的,而是层层递进的关系:先用DataFrame操作整理数据,再用时间序列处理对齐时间轴,最后用滚动计算生成技术指标。三者结合,你就能搭建出策略的数据处理流水线。


公众号:蓝海资料掘金营,微信deep3321