第二章:数据采集与存储

2.1 数据采集——从API到本地

做市商这行,数据就是命根子。我见过太多团队,策略模型再漂亮,数据源一塌糊涂,最后全白搭。今天咱们就从最基础的API数据获取讲起。

我个人习惯用 ccxt 这个库,它统一了上百家交易所的接口。说白了,你写一套代码,就能对接币安、OKX、火币这些主流平台。省心。

核心要点:API数据获取的关键不是“能连上”,而是“连得稳”。

先看一个最简单的例子,获取BTC/USD的实时报价:

import ccxt
import pandas as pd
from datetime import datetime

# 初始化交易所连接
exchange = ccxt.binance({
    'rateLimit': 1200,  # 币安的限制是1200次/分钟
    'enableRateLimit': True,  # 自动限速,别把自己封了
})

# 获取ticker数据
ticker = exchange.fetch_ticker('BTC/USDT')
print(f"时间: {datetime.now()}, 买一价: {ticker['bid']}, 卖一价: {ticker['ask']}")

嗯,这里要注意。很多新手直接写死API Key,这是大忌。我曾经有个同事,把Key硬编码在代码里,结果不小心提交到了GitHub公开仓库...那叫一个惨。建议用环境变量或者配置文件来管理。

我的小技巧:写个config.yaml文件,把API Key、Secret、交易所名称都放进去。代码里用 yaml.safe_load() 读取,既安全又灵活。

2.2 数据清洗——拿到手先别急着用

数据从API下来,你以为就能直接建模了?太天真了。我做了这么多年,遇到的坑能写本书。

常见问题有哪些?

  • 缺失值:网络波动、交易所维护,数据就断了
  • 异常值:比如价格突然跳了100倍,明显是数据错误
  • 时间戳不一致:不同交易所的时钟不同步,差个几毫秒很正常
  • 重复数据:重连后可能收到重复的tick

我曾经在回测一个高频策略时,发现收益曲线漂亮得不像话。后来一查,原来是数据里有重复的tick,导致策略“预知未来”。嗯,从那以后,我每次清洗数据都会加一步去重检查。

清洗代码示例:

def clean_tick_data(df):
    # 1. 去重:按时间戳去重,保留第一条
    df = df.drop_duplicates(subset='timestamp', keep='first')
    
    # 2. 处理缺失值:用前向填充,别用均值填充
    df = df.fillna(method='ffill')
    
    # 3. 异常值过滤:价格超过3个标准差就剔除
    mean_price = df['price'].mean()
    std_price = df['price'].std()
    df = df[(df['price'] > mean_price - 3*std_price) & 
            (df['price'] < mean_price + 3*std_price)]
    
    return df

避坑指南:我曾经用均值填充缺失值,结果把策略搞崩了。外汇数据有很强的自相关性,用前向填充(ffill)更合理。你想想看,下一秒的价格,跟上一秒的关系,肯定比跟整体均值的关系大得多。

2.3 存储方案——CSV、Parquet还是数据库?

数据清洗完了,存哪?这是个好问题。我根据不同场景,一般有三种选择。

存储方式 优点 缺点 适用场景
CSV 简单、通用、人类可读 慢、占空间、不支持压缩 小数据量、临时分析
Parquet 快、压缩率高、列式存储 二进制、不易直接查看 大数据量、机器学习
数据库 支持查询、并发、事务 需要维护、有学习成本 生产环境、团队协作

我个人习惯:开发阶段用CSV,回测用Parquet,生产用数据库。为什么?

CSV方便调试,你打开Excel就能看。但如果你有上亿条tick数据,CSV能把你硬盘撑爆。Parquet的压缩率能达到10:1,而且读取速度是CSV的几十倍。我回测一个5年的欧元兑美元数据,CSV要读30秒,Parquet只要1秒。

数据库的话,我推荐 TimescaleDB,它是基于PostgreSQL的时序数据库。专门为金融数据优化过。你想想看,做市商每秒可能产生几千条数据,普通数据库根本扛不住。

存储代码示例:

import pandas as pd

# CSV存储
df.to_csv('eur_usd_2024.csv', index=False)

# Parquet存储
df.to_parquet('eur_usd_2024.parquet', compression='snappy')

# 数据库存储(以SQLite为例,生产用TimescaleDB)
import sqlite3
conn = sqlite3.connect('forex_data.db')
df.to_sql('tick_data', conn, if_exists='append', index=False)
conn.close()

我的经验:Parquet的压缩算法选snappy,速度快,压缩率也不错。gzip压缩率更高,但写入慢。做市商数据讲究实时性,snappy是平衡之选。

2.4 知识体系总览

说了这么多,咱们用一张图把整个流程串起来。从数据源到最终存储,每一步都有讲究。

数据采集与存储流程 数据源 交易所API 数据采集 ccxt / WebSocket 数据清洗 去重 / 填充 / 过滤 数据存储 CSV/Parquet/DB 常见数据源 采集方式 清洗步骤 存储方案 • 币安 • OKX • 路透 • Bloomberg • REST API • WebSocket • FIX协议 • 定时任务 • 去重 • 缺失值填充 • 异常值过滤 • 时间对齐 • CSV • Parquet • TimescaleDB • InfluxDB

2.5 实战建议

最后,给你几个实在的建议:

  1. 别把所有鸡蛋放一个篮子里。 我建议同时用CSV和数据库存两份。CSV用于快速调试,数据库用于正式回测。
  2. 数据版本控制。 每次清洗完,加个版本号。我吃过亏,改完清洗逻辑后,旧数据找不回来了。
  3. 监控数据质量。 写个定时脚本,每天检查数据有没有断点、异常值。做市商的数据一天断个几分钟,策略可能就亏几万美金。
  4. 压缩是王道。 尤其是高频数据,一天就能产生几个GB。Parquet + snappy,能帮你省下80%的存储成本。

记住:数据采集和存储是整个做市系统的地基。地基不稳,上面盖多高的楼都没用。我见过太多团队,策略模型花里胡哨,结果数据源一换,全崩了。稳扎稳打,先把数据管好。

专注资料整理