FIX API
[!NOTE] 此 API 只能用于现货 (
SPOT) 交易所。
一般 API 信息
- FIX 连接需要 TLS 加密。请使用本地 TCP+TLS 连接或设置本地代理如 stunnel 来处理 TLS 加密。
- API 处理请求的超时时间为 10 秒。如果撮合引擎的响应时间超过此时间,API 将返回 “Timeout waiting for response from backend server. Send status unknown; execution status unknown.”。(-1007 超时)
- 这并不总是意味着该请求在撮合引擎中失败。
- 如果请求状态未显示在 用户数据流 中,请执行 API 查询以获取其状态。
- 如果您的请求包含非 ASCII 字符的交易对名称,那么响应中可能包含以 UTF-8 编码的非 ASCII 字符。
- 为确保连接不中断,请确保您的客户端在 TLS 握手过程中发送 SNI(服务器名称指示),并对目标主机名进行证书验证。
- 未发送 SNI 的客户端可能会收到证书错误的消息,导致 TLS 握手或主机名验证失败。
示例实现
NodeJS
如果你正在使用 Node.js,并且通过原始 TLS 套接字(tls.connect())进行连接,你必须显式设置 servername 选项。请参考下面的示例:
const tls = require("tls");
const hostname = "fix-dc.binance.com"; //示例
const options = {
host: hostname,
port: 9002,
servername: hostname // 启用 SNI
};
注意:NodeJS 默认不启用 TLS 的 SNI(详见 https://nodejs.org/api/tls.html#tlsconnectoptions-callback)。
如果您使用 Node.js 中的标准 HTTPS 库(例如 https.request()、axios、fetch),通常在通过主机名/URL 连接时会自动设置 SNI。
其他语言/自定义 TLS 实现
使用自定义 TLS 代理或 TLS API 时,请确保将相应字段(通常名为 server_hostname、hostname 或 ServerName)设置为目标主机名,以便发送 SNI。
FIX 会话仅支持 Ed25519 密钥。
关于如何设置 Ed25519 密钥对,请参考 本教程。
FIX API 订单接入会话
- 端点为:
tcp+tls://fix-oe.binance.com:9000 - 支持下单,取消订单和查询当前限制使用情况。
- 支持接收账户的所有 ExecutionReport
<8>和 List Status<N>。 - 仅允许带有
FIX_API的 API Key 连接。 - 关于 QuickFIX 模式文件, 请点击 这里。
FIX API Drop Copy 会话
- 端点为:
tcp+tls://fix-dc.binance.com:9000 - 支持接收账户的所有 ExecutionReport
<8>和 List Status<N>。 - 仅允许连接带有
FIX_API或FIX_API_READ_ONLY的 API Key。 - 关于 QuickFIX 模式文件, 请点击 这里。
- Drop Copy 会话中的数据存在 1 秒的延迟。
FIX API Market Data 会话
- 端点 为:
tcp+tls://fix-md.binance.com:9000 - 支持市场数据流和活动工具查询。
- 不支持下订单或取消订单。
- 仅允许连接带有
FIX_API或FIX_API_READ_ONLY的 API 密钥。 - 关于 QuickFIX 模式文件,请点击 这里。
FIX 连接生命周期
- 所有 FIX API 会话将尽最大努力,尽可能长时间地保持开放状态。
- 没有最短连接时间保证,服务器可能随时进入维护状态。
- 当服务器进入维护状态时,系统将会向客户端每隔 10 秒发送一条 News
<B>消息,直到断开连接,以提示客户端重新连接。收到此消息后,客户端应建立新会话并关闭旧会话。如果客户端在服务器断开连接前没有关闭旧会话,那么服务器会将其注销并关闭会话。
- 当服务器进入维护状态时,系统将会向客户端每隔 10 秒发送一条 News
- 连接后,客户端必须发送 Logon
<A>请求。有关详情,请参阅 如何签署登录请求。 - 客户端应在断开连接之前发送 Logout
<5>消息来关闭会话。未能发送注销消息将导致在 2xHeartInt (108)定义的时间间隔内无法将会话的SenderCompID (49)用于新会话的建立。 - 系统允许在登录过程中协商
HeartInt (108)值。可接受值的范围为 5 到 60 秒。- 如果服务器在
HeartInt (108)间隔内没有发送任何消息,将发送 HeartBeat<0>。 - 如果服务器在
HeartInt (108)间隔内没有收到任何消息,将发送 TestRequest<1>。如果服务器在HeartInt (108)秒内没有收到来自客户端的包含预期TestReqID (112)的 HeartBeat<0>消息,服务器将发送 Logout<5>消息并关闭连接。 - 如果客户端在
HeartInt (108)间隔内未收到任何消息,那么客户端应负责发送 TestRequest<1>消息以确保连接正常。收到这样的 TestRequest<1>后,服务器会发送包含预期TestReqID (112)的 HeartBeat<0>消息来进行响应。如果客户端在HeartInt (108)间隔内没有收到服务器的响应,那么客户端应关闭现有的会话和连接,并且建立新的会话和连接。
- 如果服务器在
API Key 权限
如果您需要使用 FIX API 的订单接入会话,您的 API key 必须配置 FIX_API 权限。
如果您需要使用 FIX API 的 Drop Copy 会话,您的 API key 必须配置 FIX_API_READ_ONLY 或 FIX_API 权限。
要访问 FIX Market Data 会话,您的 API 密钥必须配置为 FIX_API 或 FIX_API_READ_ONLY 权限
FIX 会话仅支持 Ed25519 密钥。
关于如何设置 Ed25519 密钥对,请参考 本教程。
关于消息处理顺序
初始 Logon<A> 消息中必需的 MessageHandling (25035) 字段控制客户端消息在被撮合引擎处理之前是否可以被重新排序。
| 模式 | 描述 |
|---|---|
UNORDERED(1) | 客户端消息可以按任意顺序发送到撮合引擎。 |
SEQUENTIAL(2) | 客户端消息始终按 MsgSeqNum (34) 顺序发送到撮合引擎。 |
在所有模式下,客户端的 MsgSeqNum (34) 必须单调递增,即每条后续消息的序列号都比前一条消息正好大 1。
[!TIP] 在有多个消息需要从客户端传输到服务器的情况时,
UNORDERED(1)应该会提供更好的性能。
响应模式
默认情况下,所有并发订单录入会话都会接收到账户所有
成功的 ExecutionReport <8> 和 ListStatus <N> 消息,
包括从其他 FIX 会话和通过非 FIX API 下达的订单。
用户可以在初始消息 Logon<A> 中使用 ResponseMode (25036) 字段来改变这种行为。
EVERYTHING(1): 默认模式。ONLY_ACKS(2): 无论操作成功还是失败,都只接收 ACK 消息。禁用ExecutionReport推送。
时间同步安全
- 所有请求都需要一个
SendingTime(52)字段,该字段应为当前时间戳。 - 另有一个可选字段
RecvWindow(25000),用以指定请求的有效期(以毫秒为单位)。RecvWindow(25000)扩展为三位小数(例如 6000.346),以便可以指定微秒。- 如果未指定
RecvWindow(25000),则仅对 Logon<A>请求默认为 5000 毫秒。对于其他请求,如果未设置,则不会执行 RecvWindow 检查。 RecvWindow(25000)的最大有效时间为 60000 毫秒。
- 请求处理逻辑如下:
serverTime = getCurrentTime()
if (SendingTime < (serverTime + 1 second) && (serverTime - SendingTime) <= RecvWindow) {
// 开始 处理请求
serverTime = getCurrentTime()
if (serverTime - SendingTime) <= RecvWindow {
// 将请求转发到撮合引擎
} else {
// 拒绝请求
}
// 结束处理请求
} else {
// 拒绝请求
}
如何签署 Logon<A> 请求
Logon<A> 消息用于验证您与 FIX API 的连接。
这条消息必须是客户端发送的第一条消息。
Username (553)字段必须包含 API key。RawData (96)字段必须包含使用 API key 生成的有效签名。
签名 payload 是一个文本字符串。该字符串通过按以下所列顺序去连接下列字段来构成, 并且以 SOH 字符作为分隔符:
MsgType (35)SenderCompId (49)TargetCompId (56)MsgSeqNum (34)SendingTime (52)
请使用您的密钥签署 payload。请使用 base64 对签名进行编码。
生成的文本字符串是 RawData (96) 字段的值。
以下是实现签名算法的 Python 代码示例:
import base64
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.serialization import load_pem_private_key
def logon_raw_data(private_key: Ed25519PrivateKey,
sender_comp_id: str,
target_comp_id: str,
msg_seq_num: str,
sending_time: str):
"""
Computes the value of RawData (96) field in Logon<A> message.
"""
payload = chr(1).join([
'A',
sender_comp_id,
target_comp_id,
msg_seq_num,
sending_time,
])
signature = private_key.sign(payload.encode('ASCII'))
return base64.b64encode(signature).decode('ASCII')
with open('private_key.pem', 'rb') as f:
private_key = load_pem_private_key(data=f.read(),
password=None)
raw_data = logon_raw_data(private_key,
sender_comp_id='5JQmUOsm',
target_comp_id='SPOT',
msg_seq_num='1',
sending_time='20240612-08:52:21.613')
以下值可用于验证签名计算实现的正确性:
| 字段 | 取值 |
|---|---|
| MsgType (35) | A |
| SenderCompID (49) | EXAMPLE |
| TargetCompID (56) | SPOT |
| MsgSeqNum (34) | 1 |
| SendingTime (52) | 20240627-11:17:25.223 |
示例计算中使用的 Ed25519 密钥如下所示:
[!CAUTION] 以下密钥仅用于示范说明目的。请务必不要在任何实际应用中使用该密钥,因为它不安全,可能会危及您的加密实现。请在实际使用中生成属于您自己的唯一且安全的密钥。
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIIJEYWtGBrhACmb9Dvy+qa8WEf0lQOl1s4CLIAB9m89u
-----END PRIVATE KEY-----
经过计算生成的签名:
4MHXelVVcpkdwuLbl6n73HQUXUf1dse2PCgT1DYqW9w8AVZ1RACFGM+5UdlGPrQHrgtS3CvsRURC1oj73j8gCA==
生成的 Logon <A> 消息:
8=FIX.4.4|9=247|35=A|34=1|49=EXAMPLE|52=20240627-11:17:25.223|56=SPOT|95=88|96=4MHXelVVcpkdwuLbl6n73HQUXUf1dse2PCgT1DYqW9w8AVZ1RACFGM+5UdlGPrQHrgtS3CvsRURC1oj73j8gCA==|98=0|108=30|141=Y|553=sBRXrJx2DsOraMXOaUovEhgVRcjOvCtQwnWj8VxkOh1xqboS02SPGfKi2h8spZJb|25035=2|10=227|
限制
消息限制
- 每个连接都有一个关于 可以发送到交易所的消息数量 的限制。
- 消息限制 不计算从接口发回到客户端的响应消息数量。
- 违反消息限制会立即导致 Logout
<5>并断开连接。 - 要了解当前的限制和使用情况,请发送 LimitQuery
<XLQ>消息。 接口将发送 LimitResponse<XLR>消息作为响应,其中包含了有关订单速率限制和消息限制的信息。 - FIX API 订单输入会话的限制为每 10 秒 10,000 条消息。
- FIX Drop Copy 会话的限制为每 60 秒 60 条消息。
- FIX Market Data 会话的限制为每 60 秒 2000 条消息。