第二章:日志数据采集——从交易所到本地,一个都不能少

做量化交易,数据就是你的血液。没有数据,策略再好也是纸上谈兵。

我个人习惯把日志数据采集分成三个层次:交易所API、本地文件、实时流。这三个层次,说白了就是「过去、现在、未来」的数据都要抓在手里。你想想看,如果只盯着实时数据,回测怎么做?如果只读本地文件,错过行情怎么办?

2.1 从交易所API获取交易数据

这是最基础的一步。交易所API就像一扇门,你得知道钥匙怎么配。

我在项目中遇到过最坑的事:某次行情波动剧烈,API调用频率没控制好,直接被交易所封了IP。嗯,这里要注意——每个交易所的限频规则都不一样。

核心要点:API鉴权、请求频率控制、数据格式解析

以币安为例,获取K线数据的代码大概长这样:

import requests
import json

# 我个人习惯把API密钥放在环境变量里
api_key = "你的API_KEY"
secret_key = "你的SECRET_KEY"

# 获取BTC/USDT的1小时K线
url = "https://api.binance.com/api/v3/klines"
params = {
    "symbol": "BTCUSDT",
    "interval": "1h",
    "limit": 100
}

response = requests.get(url, params=params)
data = response.json()

# 解析数据:时间戳、开盘价、最高价、最低价、收盘价、成交量
for kline in data:
    print(f"时间: {kline[0]}, 开盘: {kline[1]}, 收盘: {kline[4]}")

避坑指南:我曾经因为没处理API返回的异常状态码,导致策略在交易所维护时还在疯狂下单。一定要加try-except!

2.2 本地日志文件读取

本地日志文件,说白了就是你的「交易日记」。每次下单、撤单、成交,都应该留下痕迹。

我建议日志文件采用CSV或JSON格式,按日期分文件存储。为什么?因为单文件太大时,读取速度会慢到你怀疑人生。

日志字段 说明 示例
timestamp 时间戳(毫秒级) 1712345678000
symbol 交易对 BTCUSDT
side 买卖方向 BUY / SELL
price 成交价格 65000.12
quantity 成交数量 0.01

读取本地日志,我一般用Pandas,又快又方便:

import pandas as pd

# 读取昨天的交易日志
df = pd.read_csv("logs/trade_2024-04-01.csv")
print(f"共 {len(df)} 条交易记录")
print(df.head())

小技巧:如果日志文件超过100MB,建议用chunksize分块读取,不然内存会爆。我曾经在8GB的机器上硬读2GB的日志文件,结果你懂的...

2.3 实时日志流处理(WebSocket)

实时数据流,是量化交易的「眼睛」。WebSocket比轮询API高效得多——它就像一根水管,数据自己流过来,不用你一次次去拧水龙头。

为什么会这样?因为WebSocket建立一次连接后,服务器会主动推送数据,延迟低、带宽省。

一个典型的WebSocket连接代码:

import websocket
import json

def on_message(ws, message):
    data = json.loads(message)
    # 实时处理行情数据
    print(f"最新价格: {data['p']}")

def on_error(ws, error):
    print(f"连接出错: {error}")

def on_close(ws, close_status_code, close_msg):
    print("连接关闭")

def on_open(ws):
    print("连接成功")
    # 订阅BTC/USDT的实时交易数据
    subscribe_msg = {
        "method": "SUBSCRIBE",
        "params": ["btcusdt@trade"],
        "id": 1
    }
    ws.send(json.dumps(subscribe_msg))

# 启动WebSocket连接
ws = websocket.WebSocketApp(
    "wss://stream.binance.com:9443/ws",
    on_open=on_open,
    on_message=on_message,
    on_error=on_error,
    on_close=on_close
)
ws.run_forever()

注意:WebSocket连接可能会断。我建议加一个自动重连机制,比如每5秒检查一次连接状态,断了就重新连。我曾经因为没做重连,半夜策略断线了都不知道,第二天一看亏了5%...

2.4 三种采集方式的对比

这三种方式各有各的用处,我整理了一张表:

采集方式 适用场景 延迟 数据完整性
交易所API 回测、历史数据分析 高(秒级) 完整
本地日志文件 复盘、绩效评估 无(离线) 取决于记录频率
WebSocket实时流 实盘交易、监控 低(毫秒级) 实时但不保证历史

2.5 知识体系结构图

下面这张图,是我对日志数据采集的整体理解:

日志数据采集体系 交易所API 本地日志文件 WebSocket实时流 RESTful请求 / 限频控制 CSV/JSON / 分文件存储 长连接 / 自动重连 统一数据仓库

你看,三种采集方式最终汇聚到统一的数据仓库。我个人习惯把API数据存一份、本地日志存一份、实时流也存一份——三份数据互相校验,出问题能快速定位。

总结一下:日志数据采集不是简单的「拿到数据就行」。你要考虑数据完整性、实时性、存储效率。我见过太多人只盯着实时流,结果回测时发现历史数据不全,策略评估直接废了。

专注资料整理