第二章 金融数据基础:股票、期货、加密货币数据获取,数据清洗与预处理,OHLCV数据结构,时间序列基础

各位同学,欢迎来到第二章。说实话,金融数据是量化交易的「原材料」。没有干净、可靠的数据,再牛的强化学习模型也是白搭。我自己刚入行那会儿,就吃过数据不干净的亏——模型在回测里跑得飞起,一上实盘就崩,后来发现是数据里有未来函数。嗯,这种坑,咱们今天就得避开。

2.1 数据来源:股票、期货、加密货币

做量化交易,第一步就是搞到数据。不同品种的数据源,差别还挺大。我个人的习惯是:先用免费数据做原型验证,跑通了再上付费数据。

2.1.1 股票数据

A股数据,我常用 tushareakshare。这两个库都是Python的,免费版够用,但要注意频率限制。比如 tushare 的免费版,每分钟只能请求500次。

import tushare as ts

# 设置token(去官网注册获取)
ts.set_token('your_token_here')
pro = ts.pro_api()

# 获取平安银行日线数据
df = pro.daily(ts_code='000001.SZ', start_date='20230101', end_date='20231231')
print(df.head())

2.1.2 期货数据

期货数据比股票复杂一些。因为有主力合约切换,还有夜盘。我建议用 ccxt 或者 vnpy 的数据服务。期货的持仓量数据很重要,这个在强化学习里可以作为状态特征。

# 使用ccxt获取期货数据(示例为币安期货)
import ccxt

exchange = ccxt.binanceusdm()
symbol = 'BTC/USDT'
timeframe = '1d'

# 获取K线数据
ohlcv = exchange.fetch_ohlcv(symbol, timeframe, limit=100)
print(ohlcv[:3])

2.1.3 加密货币数据

加密货币数据最大的特点是:7x24小时交易,数据量巨大。我推荐 ccxt 库,它支持上百个交易所。不过要注意,不同交易所的数据格式可能略有差异。

# 获取比特币现货数据
import ccxt

exchange = ccxt.binance()
symbol = 'BTC/USDT'
timeframe = '1h'

# 获取最近100根K线
data = exchange.fetch_ohlcv(symbol, timeframe, limit=100)
# 返回格式:[[timestamp, open, high, low, close, volume], ...]
我的小建议: 刚开始做项目,别追求全品种。先盯住1-2个品种,把数据流程跑通。我曾经一口气接了20个品种的数据,结果清洗时把自己搞崩溃了。

2.2 OHLCV数据结构

OHLCV,说白了就是:Open(开盘价)、High(最高价)、Low(最低价)、Close(收盘价)、Volume(成交量)。这是金融时间序列最基础的数据结构。你想想看,一根K线就包含了这四个价格和一个量,信息量其实挺大的。

字段 含义 在强化学习中的用途
Open 开盘价 计算日内涨跌幅
High 最高价 衡量波动范围
Low 最低价 衡量支撑/阻力
Close 收盘价 最常用的价格特征
Volume 成交量 判断市场活跃度

我个人习惯把OHLCV数据存成DataFrame格式,索引是时间戳。这样后续做时间序列分析特别方便。

import pandas as pd

# 假设从交易所拿到了原始数据
raw_data = [
    [1700000000000, 50000, 51000, 49000, 50500, 1000],
    [1700003600000, 50500, 51500, 50000, 51200, 1200],
]

# 转换成DataFrame
df = pd.DataFrame(raw_data, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
df.set_index('timestamp', inplace=True)

print(df)

2.3 数据清洗与预处理

数据清洗,是量化交易里最脏最累的活,但也是最关键的。我见过太多人,模型写得花里胡哨,结果数据里藏着未来函数,回测曲线漂亮得不像话——一上实盘就原形毕露。

2.3.1 常见的数据问题

  • 缺失值: 比如某天停牌,没有交易数据
  • 异常值: 价格突然跳空,或者成交量异常放大
  • 未来函数: 用了未来才知道的数据(比如用当天的收盘价做当天的交易信号)
  • 时间戳不对齐: 不同交易所的时间戳格式不同

2.3.2 清洗实战

# 处理缺失值:向前填充
df.fillna(method='ffill', inplace=True)

# 检测异常值:用Z-score方法
from scipy import stats
z_scores = stats.zscore(df['close'])
df['is_outlier'] = abs(z_scores) > 3

# 剔除异常值
df_clean = df[~df['is_outlier']]

# 检查是否有未来函数(比如用close计算当日的指标)
# 正确做法:用shift(1)取前一天的close
df['return'] = df['close'].pct_change()  # 这是对的
# 错误做法:df['return'] = df['close'] / df['open'] - 1  # 这个没问题,但要注意时间点
避坑指南: 我曾经在回测里用了 df['close'].rolling(5).mean() 作为交易信号,结果发现这个均线包含了当天的收盘价。这就是典型的未来函数!正确做法是用 shift(1) 把数据往后挪一天。

2.4 时间序列基础

金融数据本质上就是时间序列。强化学习模型要处理的,就是这些随时间变化的价格和成交量。说白了,我们要教会模型「看懂」这些数字背后的规律。

2.4.1 时间序列的三大要素

  • 趋势: 价格长期向上或向下
  • 季节性: 比如A股有「春季躁动」效应
  • 残差: 随机波动,也就是噪声

2.4.2 常用时间序列特征

# 计算收益率
df['return'] = df['close'].pct_change()

# 计算波动率(用滚动标准差)
df['volatility'] = df['return'].rolling(window=20).std()

# 计算移动平均线
df['ma5'] = df['close'].rolling(window=5).mean()
df['ma20'] = df['close'].rolling(window=20).mean()

# 计算相对强弱指标(RSI)
def compute_rsi(data, window=14):
    delta = data.diff()
    gain = (delta.where(delta > 0, 0)).rolling(window=window).mean()
    loss = (-delta.where(delta < 0, 0)).rolling(window=window).mean()
    rs = gain / loss
    rsi = 100 - (100 / (1 + rs))
    return rsi

df['rsi'] = compute_rsi(df['close'])

2.4.3 时间序列的平稳性

做量化交易,尤其是用强化学习,我建议先检查数据是否平稳。平稳的时间序列,模型学起来更容易。常用的检验方法是ADF检验。

from statsmodels.tsa.stattools import adfuller

# ADF检验
result = adfuller(df['close'].dropna())
print(f'ADF Statistic: {result[0]}')
print(f'p-value: {result[1]}')

# 如果p-value > 0.05,说明数据非平稳,需要差分
if result[1] > 0.05:
    df['close_diff'] = df['close'].diff().dropna()
    print('数据非平稳,已做一阶差分')
核心要点: 强化学习的状态空间,通常由多个时间序列特征组成。比如:过去N天的收益率、波动率、成交量变化率等。特征工程做得好,模型就成功了一半。

2.5 本章知识体系

下面这张图,是我自己梳理的本章知识结构。你可以把它当成一张地图,随时回来查阅。

金融数据基础:知识体系 数据获取 数据清洗 特征工程 股票(tushare) 期货(ccxt) 缺失值处理 异常值检测 OHLCV结构 时间序列特征 强化学习状态空间 价格 + 成交量 + 技术指标 + 时间特征 数据质量决定模型上限 清洗 → 特征 → 状态空间 → 强化学习

好了,这一章的内容就到这里。数据这块儿,看起来简单,但真正做好需要大量实践。我建议你动手跑一遍上面的代码,把数据下载下来,看看清洗前后的差别。下一章我们会把这些数据喂给强化学习模型,到时候你就知道数据预处理有多重要了。

专注资料整理