WebSocket 流式传输
机器翻译译自英文(docs.alpaca.markets)本页 30 段已全部译完
Alpaca 的 API 提供用于交易、账户和订单更新的 WebSocket 流式传输,遵循 RFC6455 WebSocket 协议。
要连接到 WebSocket,请遵循 RFC 规范定义的标准打开握手流程,连接至 wss://paper-api.alpaca.markets/stream 或 wss://api.alpaca.markets/stream。Alpaca 的流式传输服务同时支持 JSON 和 MessagePack 编解码器。
连接授权后,客户端可以监听 trade_updates 流以获取交易、账户和订单变更的更新。
📘 注意:
来自
wss://paper-api.alpaca.markets/stream的trade_updates流使用二进制帧,这与来自wss://data.alpaca.markets/stream流的文本帧不同。
为了监听流,客户端向服务器发送 listen 消息,如下所示:
{
"action": "listen",
"data": {
"streams": ["trade_updates"]
}
}服务器通过在监听流中回复一条消息来进行确认。
{
"stream": "listening",
"data": {
"streams": ["trade_updates"]
}
}如果请求的任何流不可用,它们将不会出现在确认消息的 streams 列表中。请注意,监听消息中的 streams 字段用于告知要监听的流集合,因此如果你想停止从该流接收更新,必须发送一个空的 streams 值列表作为监听消息。同样,如果你想在已接收更新的基础上添加更多流,必须发送所有流名称,而不仅仅是新增的流。
订阅实时交易更新可确保用户始终掌握其账户活动的最新情况。
📘 注意
要使用 MessagePack 发起请求,请添加标头:Content-Type:
application/msgpack。
身份验证
WebSocket 客户端可以使用发起 HTTP 请求时所用的同一 API 密钥进行身份验证。连接到 WebSocket 时,客户端必须通过 WebSocket 连接发送一条身份验证消息,其负载包含 API 密钥和密钥。
{
"action": "auth",
"key": "{YOUR_API_KEY_ID}",
"secret": "{YOUR_API_SECRET_KEY}"
}然后服务器将授权连接,并以已授权(成功)的响应回复
{
"stream": "authorization",
"data": {
"status": "authorized",
"action": "authenticate"
}
}或未授权(不成功)的响应:
{
"stream": "authorization",
"data": {
"status": "unauthorized",
"action": "authenticate"
}
}如果套接字连接尚未授权,则会针对监听请求在授权流下发出新消息作为响应。
{
"stream": "authorization",
"data": {
"status": "unauthorized",
"action": "listen"
}
}交易更新
对于与已授权 API 密钥关联的账户,在 Alpaca 下达的订单的更新会通过 WebSocket 连接在 trade_updates 事件下派发。这些消息包含与在 Alpaca 执行的订单相关的任何数据。这包括订单成交、部分成交、取消和拒绝。客户端可以通过发送监听消息来监听此流:
{
"action": "listen",
"data": {
"streams": ["trade_updates"]
}
}服务器收到的任何监听消息都会通过监听流上的消息进行确认。消息的数据负载将包含客户端当前正在监听的流列表:
{
"stream": "listening",
"data": {
"streams": ["trade_updates"]
}
}通过 trade_updates 流发送的消息中包含哪些字段取决于它们所传达的事件类型。所有消息都包含 event 类型和 order 字段,其中 order 字段与从 REST API 返回的订单对象相同。可能的事件类型及其消息中将包含的额外字段如下所列。
常见事件
这些事件是你通过发送 API 请求所采取的操作的预期结果。
new:当订单已被路由至交易所执行时发送。fill:当订单已完全成交时发送。timestamp:订单成交的时间。price:成交事件的每股价格。如果存在部分成交,这可能与订单的平均成交价不同。qty:成交事件的股份数量。如果存在部分成交,这将与订单的已成交数量不同。position_qty:此事件后你持仓的总规模(以股份计)。多头持仓为正,空头持仓为负。
partial_fill:当订单中少于剩余总数量的一部分股份已成交时发送。timestamp:订单部分成交的时间。price:部分成交事件的每股价格。qty:部分成交事件的股份数量。position_qty:此事件后你持仓的总规模(以股份计)。多头持仓为正,空头持仓为负。
canceled:当你请求的订单取消被处理时发送。timestamp:订单被取消的时间。
expired:当订单达到其有效期末尾(由订单的订单有效期值确定)时发送。timestamp:订单过期的时间。
done_for_day:当订单当日执行完毕,并且在下一个交易日之前不会再收到进一步更新时发送。replaced:当你请求的订单替换被处理时发送。timestamp:订单被替换的时间。
不常见事件
这些事件由于交易所发生的不常见情况而可能很少发送。你不太可能需要围绕它们设计代码,但你可能仍希望考虑到它们可能发生的情况。
accepted:当 Alpaca 已收到你的订单,但尚未将其路由至执行场所时发送。rejected:当你的订单被拒绝时发送。timestamp:订单被拒绝的时间。
pending_new:当 Alpaca 已收到订单并将其路由至交易所,但尚未被接受执行时发送。stopped:当你的订单已被停止,并且订单的交易得到保证(通常以指定价格或更优价格)但尚未发生时发送。pending_cancel:当订单等待取消时发送。大多数取消不会让订单进入此状态。pending_replace:当订单等待替换时发送。calculated:当订单当日已完成时发送——它要么是“filled”(已成交),要么是“done_for_day”(当日完成)——但剩余的结算计算仍在进行中。suspended:当订单被暂停且不符合交易资格时发送。order_replace_rejected:当订单替换被拒绝时发送。order_cancel_rejected:当订单取消被拒绝时发送。
示例
通过 trade_updates 流发送的消息示例如下:
{
"stream": "trade_updates",
"data": {
"event": "fill",
"execution_id": "2f63ea93-423d-4169-b3f6-3fdafc10c418",
"order": {
"asset_class": "crypto",
"asset_id": "1cf35270-99ee-44e2-a77f-6fab902c7f80",
"cancel_requested_at": null,
"canceled_at": null,
"client_order_id": "4642fd68-d59a-47d7-a9ac-e22f536828d1",
"created_at": "2022-04-19T13:45:04.981350886-04:00",
"expired_at": null,
"extended_hours": false,
"failed_at": null,
"filled_at": "2022-04-19T17:45:05.024916716Z",
"filled_avg_price": "105.8988475",
"filled_qty": "1790.86",
"hwm": null,
"id": "a5be8f5e-fdfa-41f5-a644-7a74fe947a8f",
"legs": null,
"limit_price": null,
"notional": null,
"order_class": "",
"order_type": "market",
"qty": "1790.86",
"replaced_at": null,
"replaced_by": null,
"replaces": null,
"side": "sell",
"status": "filled",
"stop_price": null,
"submitted_at": "2022-04-19T13:45:04.980944666-04:00",
"symbol": "SOLUSD",
"time_in_force": "gtc",
"trail_percent": null,
"trail_price": null,
"type": "market",
"updated_at": "2022-04-19T13:45:05.027690731-04:00"
},
"position_qty": "0",
"price": "105.8988475",
"qty": "1790.86",
"timestamp": "2022-04-19T17:45:05.024916716Z"
}
}
MultilegOptionsOrder 成交事件的消息示例:
{
"stream": "trade_updates",
"data": {
"at": "2025-01-21T07:32:40.70095Z",
"event_id": "01JJ3WE73W5PG672TC4XACXH5R",
"event": "fill",
"timestamp": "2025-01-21T07:32:40.695569506Z",
"order": {
"id": "31cd620f-3bd5-41b7-8bb2-6834524679d0",
"client_order_id": "fe999618-6435-497b-9fdd-a63d3da3615f",
"created_at": "2025-01-21T07:32:40.678963102Z",
"updated_at": "2025-01-21T07:32:40.699359002Z",
"submitted_at": "2025-01-21T07:32:40.691562346Z",
"filled_at": "2025-01-21T07:32:40.695569506Z",
"expired_at": null,
"cancel_requested_at": null,
"canceled_at": null,
"failed_at": null,
"replaced_at": null,
"replaced_by": null,
"replaces": null,
"asset_id": "00000000-0000-0000-0000-000000000000",
"symbol": "",
"asset_class": "",
"notional": null,
"qty": "1",
"filled_qty": "1",
"filled_avg_price": "1.62",
"order_class": "mleg",
"order_type": "limit",
"type": "limit",
"side": "buy",
"time_in_force": "day",
"limit_price": "2",
"stop_price": null,
"status": "filled",
"extended_hours": false,
"legs": [
{
"id": "3cbe69ef-241c-43ba-9d8c-09361930a1af",
"client_order_id": "e868fb88-ce92-442b-91be-4b16defbc883",
"created_at": "2025-01-21T07:32:40.678963102Z",
"updated_at": "2025-01-21T07:32:40.697474882Z",
"submitted_at": "2025-01-21T07:32:40.687356797Z",
"filled_at": "2025-01-21T07:32:40.695564076Z",
"expired_at": null,
"cancel_requested_at": null,
"canceled_at": null,
"failed_at": null,
"replaced_at": null,
"replaced_by": null,
"replaces": null,
"asset_id": "925af3ed-5c00-4ef1-b89b-e4bd05f04486",
"symbol": "AAPL250321P00200000",
"asset_class": "us_option",
"notional": null,
"qty": "1",
"filled_qty": "1",
"filled_avg_price": "1.6",
"order_class": "mleg",
"order_type": "",
"type": "",
"side": "buy",
"time_in_force": "day",
"limit_price": null,
"stop_price": null,
"status": "filled",
"extended_hours": false,
"legs": null,
"trail_percent": null,
"trail_price": null,
"hwm": null,
"ratio_qty": "1"
},
{
"id": "ec694de5-5028-4347-8f89-d8ea00c9341f",
"client_order_id": "0a1bf1e1-6992-4c23-85a6-9469bbe05f1a",
"created_at": "2025-01-21T07:32:40.678963102Z",
"updated_at": "2025-01-21T07:32:40.699294952Z",
"submitted_at": "2025-01-21T07:32:40.691562346Z",
"filled_at": "2025-01-21T07:32:40.695569506Z",
"expired_at": null,
"cancel_requested_at": null,
"canceled_at": null,
"failed_at": null,
"replaced_at": null,
"replaced_by": null,
"replaces": null,
"asset_id": "9f8c3d65-f5f7-42cd-acbc-9636cc32d3b5",
"symbol": "AAPL250321C00380000",
"asset_class": "us_option",
"notional": null,
"qty": "1",
"filled_qty": "1",
"filled_avg_price": "0.02",
"order_class": "mleg",
"order_type": "",
"type": "",
"side": "buy",
"time_in_force": "day",
"limit_price": null,
"stop_price": null,
"status": "filled",
"extended_hours": false,
"legs": null,
"trail_percent": null,
"trail_price": null,
"hwm": null,
"ratio_qty": "1"
}
],
"trail_percent": null,
"trail_price": null,
"hwm": null
},
"price": "1.62",
"qty": "1",
"position_qtys": {
"AAPL250321P00200000": "1",
"AAPL250321C00380000": "1"
},
"legs": [
{
"execution_id": "69a70e98-f370-427d-bcd3-834dc4800aed",
"qty": "1",
"price": "1.6",
"order_id": "3cbe69ef-241c-43ba-9d8c-09361930a1af",
"symbol": "AAPL250321P00200000",
"timestamp": "2025-01-21T07:32:40.695564076Z"
},
{
"execution_id": "fb878d87-569e-49f3-b42e-a09ad06e3d3a",
"qty": "1",
"price": "0.02",
"order_id": "ec694de5-5028-4347-8f89-d8ea00c9341f",
"symbol": "AAPL250321C00380000",
"timestamp": "2025-01-21T07:32:40.695569506Z"
}
]
}
}错误消息
对于流内错误,服务器会在关闭连接之前发送一个 error 操作。
{
"action": "error",
"data": {
"error_message": "internal server error"
}
}