4、交易信号处理核心:行情数据解析(Level1/Level2)、订单簿数据结构设计
行情数据,说白了就是市场的「心跳」。
做量化交易,尤其是高频方向,你每天打交道最多的就是它。我刚开始接触这个领域时,总觉得行情解析不就是把网络包拆开读字段吗?后来被现实狠狠教育了一顿——解析速度慢一拍,你的策略就比别人晚进场,盈亏可能就是天壤之别。
这一章,我们聊聊行情数据的两种主流规格,以及如何在FPGA里给订单簿设计一个「快、准、狠」的数据结构。
4.1 Level1 与 Level2:你看到的是同一个市场吗?
先搞清楚一个概念。Level1和Level2,不是谁比谁高级,而是信息颗粒度不同。
- Level1(快照行情):只告诉你当前最优的买一卖一,以及最新成交价、成交量。信息量小,适合做趋势跟踪或者低频策略。
- Level2(逐笔行情):把整个订单簿的挂单情况都给你,甚至每一笔委托的到达、撤单、成交都告诉你。信息量大,适合做高频做市、套利。
我在项目中遇到过一个问题:用Level1的数据做订单簿重建,结果发现重建出来的深度跟真实市场对不上。为什么?因为Level1只给你「结果」,不给你「过程」。中间那些撤单、改价,你根本不知道。
4.2 行情数据解析:从字节流到结构化数据
不管Level1还是Level2,数据到了FPGA里,都是一串字节流。你的任务就是:用最快的速度,把它拆成有意义的字段。
举个例子,深交所的Level2行情快照,结构大致如下:
// 简化版行情快照结构(C语言风格)
typedef struct {
uint32_t channel_id; // 频道ID
uint64_t timestamp_ns; // 时间戳(纳秒)
uint32_t security_id; // 证券代码
uint64_t pre_close_px; // 昨收价
uint64_t open_px; // 开盘价
uint64_t high_px; // 最高价
uint64_t low_px; // 最低价
uint64_t last_px; // 最新价
uint64_t volume; // 成交量
uint64_t turnover; // 成交额
// ... 还有买卖十档的价格和数量
} market_snapshot_t;
在FPGA里解析,我建议用流水线架构。一个时钟周期解析一个字段,而不是等全部收完再解析。你想想看,如果等整个包收完再处理,延迟至少增加几十个时钟周期。在高频场景下,这几十个周期可能就是一笔交易的胜负手。
4.3 订单簿数据结构设计:FPGA里的「账本」
订单簿,就是记录所有未成交委托的「账本」。在软件里,你可以用红黑树、跳表这些高级数据结构。但在FPGA里,简单粗暴才是王道。
我个人习惯用价格桶(Price Bucket)结构。什么意思?就是把每个价格档位,映射到一个固定的存储位置。比如价格从1.00到100.00,每个价格对应一个桶,桶里存着这个价格上的总委托量。
为什么用桶?因为FPGA的BRAM(块内存)访问延迟固定,而且可以并行读写。你想想看,如果用一个链表,查找一个价格要遍历,延迟完全不可控。用桶,一个时钟周期就能拿到数据。
下面是一个简化版的订单簿结构设计:
// 价格桶结构(Verilog风格)
module order_book #(
parameter PRICE_BUCKET_NUM = 10000, // 价格桶数量
parameter DEPTH_BITS = 64 // 每个桶的深度位宽
)(
input wire clk,
input wire rst_n,
// 写端口:更新某个价格上的委托量
input wire [13:0] wr_addr, // 价格索引
input wire [63:0] wr_data, // 新的委托量
input wire wr_en,
// 读端口:查询某个价格上的委托量
input wire [13:0] rd_addr,
output reg [63:0] rd_data
);
// 使用BRAM实现价格桶
reg [63:0] bucket [0:PRICE_BUCKET_NUM-1];
always @(posedge clk) begin
if (wr_en) begin
bucket[wr_addr] <= wr_data;
end
rd_data <= bucket[rd_addr];
end
endmodule
4.4 实战中的避坑指南
嗯,这里要重点说说我踩过的坑。
- 时间戳对齐:不同交易所的时间戳格式不一样。有的是纳秒,有的是微秒。我曾经因为没做对齐,导致策略在回测和实盘时表现完全不一样。后来我统一在解析阶段就把所有时间戳转成纳秒。
- 价格精度:行情数据里的价格,很多是定点数。比如深交所的价格是乘以10000后的整数。千万别当成浮点数处理,否则FPGA里会多出一堆DSP资源。
- 乱序处理:网络传输中,行情包可能乱序到达。我建议在解析模块后面加一个重排序缓冲区,保证订单簿更新的顺序正确。否则,先到的撤单包可能把后到的挂单包给覆盖了。
4.5 本章知识体系总览
为了让你更直观地理解整个流程,我画了一张图。这张图展示了从行情数据到达FPGA,到最终生成订单簿快照的完整链路。
这张图里,最核心的就是「双缓冲订单簿」那块。你想想看,如果没有双缓冲,解析模块在写的时候,策略模块就不能读,整个系统的吞吐量就卡住了。用了双缓冲,两边各干各的,互不干扰。
好了,这一章的内容就到这里。行情解析和订单簿设计,是FPGA加速交易信号处理的基础。把这些搞扎实了,后面的策略实现才能跑得稳、跑得快。