量化数据基础:金融时间序列数据的特点与读取方法
各位同学,欢迎来到第二章。上一章我们聊了强化学习在量化交易中的整体框架,今天咱们把镜头拉近,聚焦在数据本身。
说实话,我见过太多人一上来就调模型、写策略,结果数据预处理没做好,模型训练出来就是个“垃圾进垃圾出”的悲剧。我自己早期也踩过这个坑——有一次跑了一个月的强化学习训练,回测曲线漂亮得不行,结果上线第一天就亏了。后来排查才发现,数据里有未来函数,我根本没注意到时间戳对齐的问题。
所以这一章,咱们把地基打牢。金融时间序列数据到底有什么“脾气”?怎么拿到靠谱的数据?怎么读进来?这些搞清楚了,后面的模型训练才能站得住脚。
金融时间序列数据的三大“怪脾气”
金融数据跟普通的时间序列数据不一样。它有三个显著特点,我称之为“三大怪脾气”。
1. 非平稳性
什么叫非平稳?说白了,就是数据的统计性质会随时间变化。均值、方差、协方差,这些都不是固定的。
你想想看,2015年股灾时的波动率和2020年疫情时的波动率,能一样吗?肯定不一样。股票价格本身更是典型的非平稳序列——它没有固定的均值,长期来看是向上走的。
我在项目中遇到过一个问题:直接用原始价格序列训练强化学习模型,结果模型学到的全是“价格涨了就买,跌了就卖”这种简单逻辑,根本捕捉不到真正的市场规律。后来改用收益率序列,效果才正常。
2. 自相关性
今天的价格跟昨天的价格有没有关系?当然有。这就是自相关——当前时刻的值与过去时刻的值之间存在相关性。
但要注意,金融数据的自相关通常很弱,尤其是高频数据。我做过一个实验,用5分钟级别的BTC价格数据算自相关系数,滞后1阶的系数大概在0.1左右,再往后基本就接近0了。这说明什么?说明市场在短时间内是相对有效的,你很难用过去的价格简单预测未来。
不过,波动率(比如收益率平方)的自相关却很强。这就是所谓的“波动率聚集”现象——大的波动后面往往跟着大的波动,小的波动后面跟着小的波动。这个特性对强化学习来说很重要,因为它会影响风险控制模块的设计。
3. 异方差性
这个词听起来有点吓人,其实意思很简单:数据的波动率不是恒定的。有时候市场风平浪静,有时候波涛汹涌。
为什么会这样?因为市场受新闻、政策、突发事件的影响。比如美联储加息消息一出,整个市场的波动率瞬间飙升。这种波动率的变化,就是异方差。
在强化学习中,异方差性会直接影响奖励函数的设计。如果你的奖励函数只考虑收益,不考虑波动,那模型可能会在波动大的时候做出极端决策。我个人习惯在奖励函数中加入波动率调整项,让模型学会在波动大的时候更谨慎。
| 特点 | 含义 | 对强化学习的影响 |
|---|---|---|
| 非平稳性 | 统计性质随时间变化 | 需要差分或对数变换,否则模型学不到稳定规律 |
| 自相关性 | 当前值与过去值相关 | 特征工程中需考虑滞后项,但注意不要过拟合 |
| 异方差性 | 波动率不恒定 | 奖励函数需考虑风险调整,避免极端决策 |
常见数据源与读取方法
数据源这块,我按使用频率排个序。新手建议从Yahoo Finance开始,做加密货币的用Binance,做回测的用本地CSV文件。
1. Yahoo Finance
Yahoo Finance 是入门首选。免费、覆盖广、历史数据长。我用它来获取美股和A股的数据。
读取方法很简单,用 yfinance 库,几行代码搞定。
import yfinance as yf
# 下载苹果股票数据
aapl = yf.download('AAPL', start='2020-01-01', end='2023-12-31')
print(aapl.head())
嗯,这里要注意一点:yfinance 返回的是 pandas DataFrame,索引是日期,列包括 Open、High、Low、Close、Volume、Adj Close。我个人习惯用 Adjusted Close(复权收盘价),因为它考虑了分红和拆股,更真实反映价格变化。
2. Binance
做加密货币的,Binance 是首选。它的 API 很完善,支持现货、合约、期权等多种数据。
读取方法可以用 python-binance 库,或者直接通过 REST API 获取。
from binance.client import Client
import pandas as pd
client = Client()
# 获取BTC/USDT的1小时K线数据
klines = client.get_klines(symbol='BTCUSDT', interval=Client.KLINE_INTERVAL_1HOUR, limit=1000)
# 解析数据
data = []
for k in klines:
data.append({
'timestamp': k[0],
'open': float(k[1]),
'high': float(k[2]),
'low': float(k[3]),
'close': float(k[4]),
'volume': float(k[5])
})
df = pd.DataFrame(data)
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
df.set_index('timestamp', inplace=True)
print(df.head())
Binance 的数据频率很灵活,从1分钟到1个月都有。我个人做高频策略时常用1分钟和5分钟数据,做趋势策略时用4小时和日线数据。
3. CSV文件
本地CSV文件是最灵活的方式。很多量化平台(比如聚宽、米筐)都支持导出CSV格式的数据。我自己做回测时,也习惯把数据存成CSV,方便反复使用。
读取方法用 pandas.read_csv(),注意设置日期列为索引。
import pandas as pd
# 读取本地CSV文件
df = pd.read_csv('btc_usdt_1h.csv', parse_dates=['timestamp'], index_col='timestamp')
print(df.info())
这里有个坑:CSV文件里的日期格式可能不统一。有的用 '2023-01-01',有的用 '2023/01/01',还有的用时间戳。我建议在读取时统一用 parse_dates 参数,或者读取后用 pd.to_datetime() 转换。
- 检查缺失值:
df.isnull().sum() - 处理异常值:比如价格出现负数或极端值
- 对齐时间戳:确保数据按时间顺序排列
- 计算衍生特征:收益率、波动率、成交量变化等
本章知识体系
下面这张图总结了本章的核心内容,方便你快速回顾。
这张图把本章的知识点串起来了。左边是数据的三大特点,右边是数据源。你学习的时候可以对照着看,理解每个特点如何影响数据源的选择和处理方式。
好了,这一章的内容就到这里。数据预处理是强化学习量化交易中最枯燥但最重要的一环。别嫌麻烦,把这一步做扎实了,后面的模型训练会顺畅很多。
公众号:蓝海数据掘金营,微信deep3321