FIX 协议开发(1):协议介绍及开发方案

本系列导航

FIX 协议开发(1):协议介绍及开发方案(本文)
FIX 协议开发(2):QuickFIX/J 入门
FIX 协议开发(3):QuickFIX/J 实战经验小结

本文背景

公司因业务需要,准备接入 FIX 协议。在调研过程中,我发现中文的 FIX 协议相关资料不太多,准备边学边记录,预计会写 3 篇左右。

FIX 协议简介

FIX(Financial Information eXchange Protocol,金融信息交换协议)是由国际FIX协会组织提供的一个开放式协议,目的是推动国际贸易电子化进程,在各类参与者之间,包括投资经理、经纪人、买方、卖方建立起实时的电子化通讯协议。

FIX协议的目标是把各类证券金融业务需求流程格式化,成为一个可用计算机语言描述的功能流程,并在每个业务功能接口上统一交换格式,方便各个功能模块的连接。

消息格式

FIX 协议消息均由多个 “key=value” 组成。其中 key 可以是协议规定的字段,或自定义字段。协议规定的key可查询 FIX 协议字典,【不同版本的 FIX 协议均有其字典,用于开发的库一般也有自带;也可参考第三方,如 wireshark】例如 8 代表 begin string,34 代表消息的序列号,52 代表时间戳等。自定义字段不与规定的 key 重复,供金融机构定制,开发时需要向对应金融机构获取其专有字段的字典。只要有了对应的字典,就可以读懂 FIX 数据包的内容。

一般来说,一个 消息由“头部 + 消息体 + 尾部”构成。头部包含一些必要的字段,例如 BeginString (8)、BodyLength (9)、MsgType (35)、MsgSeqNum (34)、SenderCompID (49) 等,尾部包含的必要字段是 CheckSum (10)。

FIX 登陆消息示例(假设”^”是分隔符):

8=FIX.4.3^9=65^35=A^34=1^49=TESTACC^52=20130703-15:55:08.609^56=EXEC^98=0^108=30^10=225^

对照字典可知,BeginString (8) 是 FIX.4.3;BodyLength (9) 是 65 字节;MsgType (35) 是 A,A 对应 logon 操作;MsgSeqNum (34) 是 1,即这是我方发送的第 1 个消息。

有关更详细的协议介绍,可参考 https://blog.51cto.com/9291927/2536105

开发方案

不使用库

由上面的示例可以发现,FIX 协议十分简单。可以不需要依赖第三方库,手动查字典构造消息
8=FIX.4.3^9=65^35=A^34=1<省略>
再通过标准的 socket 通信,即可完成交互。

这个方案自由度最高,不依赖底层开发语言,但开发流程与查字典较为繁琐,后续维护也不太方便。

Python 库 simplefix

simplefix 是一个 FIX 协议的简易实现。它使用户可以方便地任意构造 FIX 消息,非常适合学习、测试协议。但这个库不包含任何网络收发、FIX 异常处理等功能模块。因此,开发 FIX 客户端时,我使用该库构造数据包,然后通过标准 socket 发送,再分析其网络底层交互。

示例:发送 logon 消息的代码

import socket
import time

import simplefix
from simplefix.constants import (ENCRYPTMETHOD_NONE, MSGTYPE_LOGON,
                                 TAG_BEGINSTRING, TAG_CLIENTID,
                                 TAG_ENCRYPTMETHOD, TAG_HEARTBTINT,
                                 TAG_MSGSEQNUM, TAG_MSGTYPE, TAG_SENDER_COMPID,
                                 TAG_SENDING_TIME, TAG_TARGET_COMPID)

HOST = '1.2.3.45'
PORT = 9000
CLIENT_ID = 12345678
PASSWORD = 'mypassword'

seq_num = 1  # 需维护msg sequence number,每次发送后加1


if __name__ == "__main__":
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)  # 长连接
    sock.connect((HOST, PORT))

    # logon
    msg_logon = simplefix.FixMessage()
    msg_logon.append_pair(TAG_BEGINSTRING, 'FIX.4.2')
    msg_logon.append_pair(TAG_MSGSEQNUM, seq_num)  # 需维护msg sequence number,每次发送后加1
    msg_logon.append_pair(TAG_SENDER_COMPID, 'FIXTEST001')
    msg_logon.append_utc_timestamp(TAG_SENDING_TIME)
    msg_logon.append_pair(TAG_TARGET_COMPID, 'TESTENV')

    msg_logon.append_pair(TAG_MSGTYPE, MSGTYPE_LOGON)  # 类型

    msg_logon.append_pair(TAG_ENCRYPTMETHOD, ENCRYPTMETHOD_NONE)
    msg_logon.append_pair(TAG_HEARTBTINT, 30)
    msg_logon_buffer = msg_logon.encode()

    sock.send(msg_logon_buffer)
    print('seq', seq_num, 'sent')
    seq_num += 1


    time.sleep(1)
    sock.close()

多平台 QuickFix 引擎

QuickFix 是全功能的 FIX 开源引擎,目前很多 Fix 解决方案都是根据或参考 QuickFix 实现的。目前(2020年10月)它有 C++、Python、Java、.NET、Go 和 Ruby 共 6 种语言的实现/接口。

根据我司的情况,选择其中的 Java 实现 QuickFIX/J 进行下一步开发。其使用方法,将在下一篇文章继续。


发表评论

解决 : *
83 + 96 =