x-anchors:
  sub-send: &sub-send
    description: |
      ## Subscribe
      Multiple subscriptions could be opened within the same websocket.

      The trades of different markets to be subscribed are controlled by the parameters in
      the subscription message listed below.
  sub-ack: &sub-ack
    description: |
      After subscribing, the server sends :
      - an acknowledgement
      - then an initial snapshot with the latest 100 trades upon subscription.
      - followed by incremental updates.
    messages:
      - $ref: "#/channels/data/messages/subscribe-ack"
      - $ref: "#/channels/data/messages/subscribe-msg-0"
      - $ref: "#/channels/data/messages/subscribe-msg-1"

  props-topic-asset: &props-topic-asset
    params:
      type: object
      required:
        - topic
        - symbol
      properties:
        topic:
          type: string
          description: \"anonymousTrades\"
          example: "anonymousTrades"
        symbol:
          type: string
          description: Market symbol, such as BTCUSD or ETHUSDC
          example: "BTCUSD"

  props-suback-msg: &props-suback-msg
    example: "Successfully subscribed (anonymousTrades BTCUSD)"
  props-unsub-ack-msg: &props-unsub-ack-msg
    example: "Successfully unsubscribed (anonymousTrades BTCUSD)"

  tds-type: &tds-type
    dataType:
      type: string
      description: \"V1TAAnonymousTradeUpdate\"
      example: "V1TAAnonymousTradeUpdate"
  tds-header: &tds-header
    symbol:
      type: string
      description: Market symbol
    createdAtDatetime:
      type: string
      description: Denotes the time the latest order was ACK'd by the exchange, ISO 8601 with millisecond as string
    publishedAtTimestamp:
      type: string
      description: Denotes the time the update was broadcasted to connected WebSockets
  tds-schema: &tds-schema
    type: array
    items:
      type: object
      properties:
        tradeId:
          type: string
          description: Unique trade id
        symbol:
          type: string
          description: Market symbol
        price:
          type: string
          description: Price, see asset value format
        quantity:
          type: string
          description: Quantity, see asset value format
        side:
          type: string
          description: Order side
        isTaker:
          type: boolean
          description: Denotes whether this is a taker's trade
        otcMatchId:
          type: string
          description: Unique OTC match id
        otcTradeId:
          type: string
          description: Unique Bullish OTC trade id
        clientOtcTradeId:
          type: string
          description: Unique client OTC trade id
        createdAtTimestamp:
          type: string
          description: Denotes the time the order was ACK'd by the exchange
        createdAtDatetime:
          type: string
          description: Denotes the time the order was ACK'd by the exchange, ISO 8601 with millisecond as string
        publishedAtTimestamp:
          type: string
          description: Denotes the time the update was broadcasted to connected WebSockets
        auctionId:
          type: string
          description: Unique Bullish auction identifier. Present only for auction trades
  tds-example: &tds-example
    "tradeId": "100069000000063765"
    "isTaker": true
    "price": "23404.8636"
    "createdAtTimestamp": "1721879160353"
    "quantity": "0.00029411"
    "publishedAtTimestamp": "1721879162124"
    "side": "SELL"
    "createdAtDatetime": "2024-07-25T03:46:00.353Z"
    "symbol": "BTCUSDC"
    "otcMatchId": "1"
    "otcTradeId": "200069000000063765"
    "clientOtcTradeId": "300069000000063765"
  props-subscribe-msg-0: &props-subscribe-msg-0
    title: Snapshot
    summary: Initial full state of the subscribed trade data
    payload:
      type: object
      properties:
        type:
          type: string
          description: \"snapshot\"
          example: "snapshot"
        <<: *tds-type
        data:
          type: object
          properties:
            <<: *tds-header
            trades:
              <<: *tds-schema
              description: List of trades
              example:
                - <<: *tds-example
                - "tradeId": "100069000000063764"
                  "isTaker": false
                  "price": "23104.8636"
                  "createdAtTimestamp": "1721879160355"
                  "quantity": "0.00029412"
                  "publishedAtTimestamp": "1721879162125"
                  "side": "BUY"
                  "createdAtDatetime": "2024-07-25T03:46:00.355Z"
                  "symbol": "ETHUSDC"
                  "otcMatchId": "2"
                  "otcTradeId": "200069000000063766"
                  "clientOtcTradeId": "300069000000063766"
  props-subscribe-msg-1: &props-subscribe-msg-1
    title: Update
    summary: Incremental update to the subscribed trade data
    payload:
      type: object
      properties:
        type:
          type: string
          description: \"update\"
          example: "update"
        <<: *tds-type
        data:
          type: object
          properties:
            <<: *tds-header
            trades:
              <<: *tds-schema
              description: Singleton-List of trades
              example:
                - <<: *tds-example

  props-json-rpc-required: &props-json-rpc-required
    type: object
    required:
      - id
      - method
      - params
  props-json-rpc: &props-json-rpc
    id:
      type: string
      description: ID returned by server in the acknowledgement
      example: "1611082473000"
    jsonrpc:
      description: Version of the Json RPC protocol
      example: "2.0"
  props-cmd: &props-cmd
    type:
      description: \"command\"
      example: "command"
  props-result: &props-result
    responseCodeName:
      type: string
      description: \"OK\"
      example: "OK"
  props-result-str: &props-result-str
    responseCode:
      type: string
      description: "200"
      example: "200"
  props-result-int: &props-result-int
    responseCode:
      type: integer
      description: "200"
      example: 200
  props-rejection: &props-rejection
    payload:
      type: object
      properties:
        <<: *props-json-rpc
        error:
          type: object
          properties:
            code:
              type: string
              description: a high-level code for the error
              example: "-32602"
            errorCode:
              type: string
              description: a precise typed error code
              example: "29013"
            errorCodeName:
              type: string
              description: An explanation of which value was invalid
              example: "'abcde' is not a valid topic"

  op-send: &op-send
    action: send
    channel:
      $ref: "#/channels/data"
  op-receive: &op-receive
    action: receive
    channel:
      $ref: "#/channels/data"

asyncapi: 3.0.0
info:
  title: "Anonymous Trades"
  version: "1.0.0"
  description: |
    This allows simultaneous trade subscriptions to multiple markets. Additionally, instead of sending trades one by one, trades are sent in batches.

    Upon subscribing to a market, the client will first receive a snapshot of the latest 100 trades, followed by batches of trade updates.

    Anonymous trades from different markets to be subscribed to are controlled by the parameters in the subscription message listed below.

    ```
    /trading-api/v1/market-data/trades
    ```

servers:
  prod-public:
    host: api.exchange.bullish.com
    protocol: wss
    description: Production / Public
  prod-registered:
    host: registered.api.exchange.bullish.com
    protocol: wss
    description: Production / Registered
  prod-direct:
    host: prod.access.bullish.com
    protocol: wss
    description: Production / Direct Connect
  simnext-public:
    host: api.simnext.bullish-test.com
    protocol: wss
    description: SimNext / Public
  simnext-registered:
    host: registered.api.simnext.bullish-test.com
    protocol: wss
    description: SimNext / Registered
  simnext-direct:
    host: simnext.access.bullish.com
    protocol: wss
    description: SimNext / Direct Connect

channels:
  data:
    address: /trading-api/v1/market-data/trades
    messages:
      subscribe:
        title: Subscription
        summary: Let you subscribe to a given topic
        payload:
          <<: *props-json-rpc-required
          properties:
            method:
              type: string
              description: \"subscribe\"
              example: "subscribe"
            <<: [*props-json-rpc, *props-cmd, *props-topic-asset]
      subscribe-ack:
        title: Acknowledgment
        summary: Confirm the topic being subscribed
        payload:
          type: object
          properties:
            <<: *props-json-rpc
            result:
              type: object
              properties:
                <<: [*props-result, *props-result-str]
                message:
                  type: string
                  description: Confirmation of what has been subscribed
                  <<: *props-suback-msg
      subscribe-msg-0:
        <<: *props-subscribe-msg-0
      subscribe-msg-1:
        <<: *props-subscribe-msg-1
      subscribe-nack:
        title: Rejection
        summary: Explain why the topic could not be subscribed
        <<: *props-rejection
      keepalive-ping:
        title: Keepalive Ping
        payload:
          <<: *props-json-rpc-required
          properties:
            method:
              type: string
              description: \"keepalivePing\"
              example: "keepalivePing"
            params:
              type: object
            <<: [*props-json-rpc, *props-cmd]
      keepalive-pong:
        title: Keepalive Pong
        payload:
          type: object
          properties:
            <<: *props-json-rpc
            result:
              type: object
              properties:
                <<: [*props-result, *props-result-int]
                message:
                  type: string
                  description: \"Keep alive pong\"
                  example: "Keep alive pong"
      unsubscribe:
        title: Unsubscription
        summary: Let you unsubscribe to a given index
        payload:
          <<: *props-json-rpc-required
          properties:
            method:
              type: string
              description: \"unsubscribe\"
              example: "unsubscribe"
            <<: [*props-json-rpc, *props-cmd, *props-topic-asset]
      unsubscribe-ack:
        title: Acknowledgment
        summary: Confirm the topic being unsubscribed
        payload:
          type: object
          properties:
            <<: *props-json-rpc
            result:
              type: object
              properties:
                <<: [*props-result, *props-result-str]
                message:
                  type: string
                  description: Confirmation of what has been unsubscribed
                  <<: *props-unsub-ack-msg
      unsubscribe-nack:
        title: Rejection
        summary: Explain why the topic could not be unsubscribed
        <<: *props-rejection

operations:
  subscribe:
    <<: [*op-send, *sub-send]
    messages:
      - $ref: "#/channels/data/messages/subscribe"
  subscribe-ack:
    <<: [*op-receive, *sub-ack]
  subscribe-nack:
    <<: *op-receive
    description: In case of *invalid* subscription message, an error rejection would be sent.
    messages:
      - $ref: "#/channels/data/messages/subscribe-nack"

  keepalive-ping:
    <<: *op-send
    description: |
      ## Keepalive
      In case nothing is subscribed to, keep the websocket connection alive.
    messages:
      - $ref: "#/channels/data/messages/keepalive-ping"
  keepalive-pong:
    <<: *op-receive
    description: |
      Acknowledgement returned by the server in response to a keepalive-ping.
    messages:
      - $ref: "#/channels/data/messages/keepalive-pong"

  unsubscribe:
    <<: *op-send
    description: |
      ## Unsubscribe
      Let you unsubscribe a specific topic while keeping your websocket opened.
    messages:
      - $ref: "#/channels/data/messages/unsubscribe"
  unsubscribe-ack:
    <<: *op-receive
    description: After unsubscribing, the server sends an acknowledgement.
    messages:
      - $ref: "#/channels/data/messages/unsubscribe-ack"
  unsubscribe-nack:
    <<: *op-receive
    description: In case of *invalid* unsubscription message, an error rejection would be sent.
    messages:
      - $ref: "#/channels/data/messages/unsubscribe-nack"
