Skip to main content

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"
  }
}