openapi: 3.1.0
info:
  title: Book Event Schema Reference
  version: "2.0.1"
  description: >
    OpenAPI-style schema reference for the serde-compatible YAML shape of
    `BookEventEnvelope` and `BookEvent`.

x-notes:
  - BookEvent uses an externally tagged enum representation.
  - Newtype IDs serialize as scalar integers or strings, not wrapper objects.
  - timestamp is RFC 3339 UTC text.
  - Money is stored in integer quanta where 10000 == 1.0000 USD.
  - OddsX10000 is stored as a fixed-point integer where 25000 == 2.5000.

components:
  schemas:
    MarketId:
      type: integer
      format: uint64
      minimum: 0
      description: Unique market identifier.

    RunnerId:
      type: integer
      format: uint32
      minimum: 0
      description: Unique runner identifier within a market.

    AccountId:
      type: string
      description: Account identifier that owns an order.

    OrderId:
      type: integer
      format: uint64
      minimum: 0
      description: Unique order identifier.

    CorrelationId:
      type:
        - string
        - "null"
      description: Optional client-provided correlation key for tracing.

    CancelledOrderEntry:
      type: object
      additionalProperties: false
      required: [order_id, account_id, correlation_id]
      properties:
        order_id:
          $ref: "#/components/schemas/OrderId"
        account_id:
          $ref: "#/components/schemas/AccountId"
        correlation_id:
          $ref: "#/components/schemas/CorrelationId"

    OrderCancellationCursor:
      type: object
      additionalProperties: false
      required: [order_id, account_id]
      properties:
        order_id:
          $ref: "#/components/schemas/OrderId"
        account_id:
          $ref: "#/components/schemas/AccountId"

    DateTime:
      type: string
      format: date-time
      description: UTC timestamp serialized as RFC 3339 text.

    Money:
      type: integer
      format: int64
      description: Signed integer money amount in engine quanta (10000 == 1.0000 currency units).
      x-money-scale: 10000
      x-money-note: 10000 == 1.0000 USD

    OddsX10000:
      type: integer
      format: uint32
      minimum: 0
      description: Fixed-point decimal odds with 4 implied decimal places (25000 == 2.5000).
      x-odds-scale: 10000
      x-odds-note: 25000 == 2.5000 odds

    Quantity:
      type: integer
      format: uint64
      minimum: 0
      description: Unsigned quantity used by fill-or-kill minimum fill.

    EventMetadata:
      description: Optional free-form metadata copied from the originating command.
      anyOf:
        - type: object
          additionalProperties: true
        - type: array
          items: {}
        - type: string
        - type: integer
        - type: number
        - type: boolean
        - type: "null"

    Side:
      type: string
      enum: [YES, NO]
      description: Order side; YES maps to back/buy and NO maps to lay/sell.

    Persistence:
      type: string
      enum: [LAPSE, PERSIST, MARKET_ON_CLOSE]
      description: What should happen to unmatched size when state changes.

    TradeRole:
      type: string
      enum: [MAKER, TAKER]
      description: Whether the order supplied resting liquidity or took liquidity.

    CancelCause:
      type: string
      enum:
        - USER_CANCEL
        - REPLACE
        - FOK_REMAINDER
        - BATCH_CANCEL
        - CLOSE_CANCEL
        - SUSPEND_LAPSE
        - IN_PLAY_LAPSE
        - MARKET_VOID
        - RUNNER_REMOVED
        - ADMIN
      description: Canonical reason why one or more orders were cancelled.

    RejectReason:
      type: string
      enum:
        - MARKET_HALTED
        - MARKET_ALREADY_HALTED
        - MARKET_NOT_HALTED
        - MARKET_NOT_FOUND
        - MARKET_ALREADY_EXISTS
        - MARKET_ID_MISMATCH
        - RUNNER_NOT_FOUND
        - RUNNER_ALREADY_REMOVED
        - MARKET_NOT_OPEN
        - MARKET_IN_PLAY_NOT_SUPPORTED
        - MARKET_TERMINAL
        - MARKET_NOT_SUSPENDED
        - MARKET_ALREADY_VOIDED
        - INVALID_ODDS
        - INVALID_STAKE
        - MAX_LIABILITY_EXCEEDED
        - ORDER_NOT_FOUND
        - NOT_ORDER_OWNER
        - ORDER_NOT_LIVE
        - WOULD_NOT_FILL_FOK
        - MARKET_NOT_CLOSED
        - DUPLICATE_RUNNER
        - INCOMPLETE_RESULTS
        - QUEUE_BACKPRESSURE
        - INVALID_BATCH_SIZE
        - MARKET_CLOSING
        - MARKET_NOT_CLOSING
        - MARKET_BATCH_CANCELLING
        - MARKET_NOT_BATCH_CANCELLING
        - INVALID_MARKET_CONFIG
        - CASHOUT_INVALID_PERCENT
        - CASHOUT_NO_EXPOSURE
        - CASHOUT_NO_LIQUIDITY
        - CASHOUT_ODDS_CHANGED
        - CASHOUT_NOT_SUPPORTED
        - INVALID_PRICE_TICKS
        - INVALID_QTY_SHARES
        - MARKET_MODEL_MISMATCH
        - MARKET_NOT_TERMINAL
        - INTERNAL_ERROR
        - DUPLICATE
        - NO_CHANGE
      description: Canonical reason why an order or command was rejected.

    BookMarketState:
      type: string
      enum: [OPEN, SUSPENDED, HALTED, CLOSED, VOIDED, SETTLED]
      description: Book-local lifecycle state of the market.

    MarketPhase:
      type: string
      enum: [PRE, LIVE]
      description: Trading phase of the market while open.

    RunnerResult:
      type: string
      enum: [Winner, Loser, Removed, RemovedVacant]
      description: Settlement result assigned to a runner.

    MarketKind:
      type: string
      enum: [PRE_EVENT_ONLY, IN_PLAY_CAPABLE, LIVE_ONLY]
      description: Which initial phases and phase transitions the market supports.

    ExchangeOddsMarketModel:
      type: string
      const: EXCHANGE_ODDS
      description: Odds-based runner market model.

    BinaryYesMarketModel:
      type: object
      additionalProperties: false
      description: Canonical YES-only prediction market model.
      required: [BINARY_YES]
      properties:
        BINARY_YES:
          type: object
          additionalProperties: false
          required: [max_price_ticks]
          properties:
            max_price_ticks:
              type: integer
              format: uint16
              minimum: 0
              description: Maximum binary price denominator in ticks.

    MarketModel:
      oneOf:
        - $ref: "#/components/schemas/ExchangeOddsMarketModel"
        - $ref: "#/components/schemas/BinaryYesMarketModel"
      description: Matching and pricing model used by the market.

    GtcTimeInForce:
      type: string
      const: GTC
      description: Good-til-cancelled order policy.

    FillOrKillTimeInForce:
      type: object
      additionalProperties: false
      description: Fill-or-kill order policy with optional minimum fill.
      required: [FILL_OR_KILL]
      properties:
        FILL_OR_KILL:
          type: object
          additionalProperties: false
          required: [min_fill]
          properties:
            min_fill:
              anyOf:
                - $ref: "#/components/schemas/Quantity"
                - type: "null"
              description: Optional minimum quantity that must fill immediately.

    TimeInForce:
      oneOf:
        - $ref: "#/components/schemas/GtcTimeInForce"
        - $ref: "#/components/schemas/FillOrKillTimeInForce"
      description: Execution policy for a new order.

    MarketCreatedPayload:
      type: object
      additionalProperties: false
      description: Initializes a market in the event stream.
      required:
        - correlation_id
        - name
        - market_model
        - market_kind
        - market_phase
        - runner_ids
        - runner_labels
      properties:
        correlation_id:
          $ref: "#/components/schemas/CorrelationId"
        name:
          type: string
          description: Human-readable market name.
        market_model:
          $ref: "#/components/schemas/MarketModel"
        market_kind:
          $ref: "#/components/schemas/MarketKind"
        market_phase:
          $ref: "#/components/schemas/MarketPhase"
        runner_ids:
          type: array
          description: Declared runner IDs; empty means dynamic runner set.
          items:
            $ref: "#/components/schemas/RunnerId"
        runner_labels:
          type: array
          description: Display labels corresponding to runner_ids.
          items:
            type: string

    MarketStateChangedPayload:
      type: object
      additionalProperties: false
      description: Records a market state transition.
      required: [to, reason]
      properties:
        to:
          $ref: "#/components/schemas/BookMarketState"
        reason:
          type: string
          description: Human-readable reason for the state change.

    MarketPhaseChangedPayload:
      type: object
      additionalProperties: false
      description: Records a market phase transition.
      required: [to, reason]
      properties:
        to:
          $ref: "#/components/schemas/MarketPhase"
        reason:
          type: string
          description: Human-readable reason for the phase change.

    OrderAcceptedPayload:
      type: object
      additionalProperties: false
      description: Confirms an exchange-style order was accepted into the book.
      required:
        - correlation_id
        - order_id
        - account_id
        - runner_id
        - runner_label
        - side
        - price
        - stake
        - persistence
        - time_in_force
      properties:
        correlation_id:
          $ref: "#/components/schemas/CorrelationId"
        order_id:
          $ref: "#/components/schemas/OrderId"
        account_id:
          $ref: "#/components/schemas/AccountId"
        runner_id:
          $ref: "#/components/schemas/RunnerId"
        runner_label:
          type: string
          description: Stable configured label for the addressed runner.
        side:
          $ref: "#/components/schemas/Side"
        price:
          $ref: "#/components/schemas/OddsX10000"
          description: Limit odds in OddsX10000 units; 25000 means 2.5000.
        stake:
          $ref: "#/components/schemas/Money"
          description: Backer stake in Money quanta; 125000 means 12.5000.
        persistence:
          $ref: "#/components/schemas/Persistence"
        time_in_force:
          $ref: "#/components/schemas/TimeInForce"

    BinaryOrderAcceptedPayload:
      type: object
      additionalProperties: false
      description: Confirms a binary-market order was accepted into the book.
      required:
        - correlation_id
        - order_id
        - account_id
        - side
        - price_ticks
        - qty_shares
        - time_in_force
      properties:
        correlation_id:
          $ref: "#/components/schemas/CorrelationId"
        order_id:
          $ref: "#/components/schemas/OrderId"
        account_id:
          $ref: "#/components/schemas/AccountId"
        side:
          $ref: "#/components/schemas/Side"
        price_ticks:
          type: integer
          format: uint16
          minimum: 0
          description: Binary price expressed in integer ticks, not x10000 money/odds units.
        qty_shares:
          type: integer
          format: uint64
          minimum: 0
          description: Number of shares accepted into the book, not scaled by 10000.
        time_in_force:
          $ref: "#/components/schemas/TimeInForce"

    OrderCancelledPayload:
      type: object
      additionalProperties: false
      description: Cancels a single live order using a typed per-order entry.
      required:
        - cancelled_order
        - cancel_cause
        - cause_detail
      properties:
        cancelled_order:
          $ref: "#/components/schemas/CancelledOrderEntry"
        cancel_cause:
          $ref: "#/components/schemas/CancelCause"
        cause_detail:
          type:
            - string
            - "null"
          description: Optional human-readable detail for the cancellation.

    OrderCancelledBatchedPayload:
      type: object
      additionalProperties: false
      description: Cancels one or more live orders using typed per-order entries.
      required:
        - cancelled_orders
        - cursor_after
        - cancel_cause
        - cause_detail
      properties:
        cancelled_orders:
          type: array
          description: Cancelled order entries in stream order.
          items:
            $ref: "#/components/schemas/CancelledOrderEntry"
        cursor_after:
          anyOf:
            - $ref: "#/components/schemas/OrderCancellationCursor"
            - type: "null"
          description: Pagination cursor for batched cancellation flows.
        cancel_cause:
          $ref: "#/components/schemas/CancelCause"
        cause_detail:
          type:
            - string
            - "null"
          description: Optional human-readable detail for the cancellation.

    TradeMatchedPayload:
      type: object
      additionalProperties: false
      description: Records a matched trade for exchange-style orders.
      required:
        - correlation_id
        - order_id
        - account_id
        - role
        - runner_id
        - runner_label
        - side
        - market_phase
        - price
        - stake
        - counter_party
        - counter_party_account_id
        - remaining_stake
        - matched_delta
      properties:
        correlation_id:
          $ref: "#/components/schemas/CorrelationId"
        order_id:
          $ref: "#/components/schemas/OrderId"
        account_id:
          $ref: "#/components/schemas/AccountId"
        role:
          $ref: "#/components/schemas/TradeRole"
        runner_id:
          $ref: "#/components/schemas/RunnerId"
        runner_label:
          type: string
          description: Stable configured label for the addressed runner.
        side:
          $ref: "#/components/schemas/Side"
        market_phase:
          $ref: "#/components/schemas/MarketPhase"
          description: Market trading phase when this match was emitted.
        price:
          $ref: "#/components/schemas/OddsX10000"
          description: Executed odds in OddsX10000 units; 25000 means 2.5000.
        stake:
          $ref: "#/components/schemas/Money"
          description: Original order stake in Money quanta; 125000 means 12.5000.
        counter_party:
          $ref: "#/components/schemas/OrderId"
        counter_party_account_id:
          $ref: "#/components/schemas/AccountId"
        remaining_stake:
          $ref: "#/components/schemas/Money"
          description: Remaining unmatched stake in Money quanta after this match.
        matched_delta:
          $ref: "#/components/schemas/Money"
          description: Stake matched by this event in Money quanta.

    BinaryTradeMatchedPayload:
      type: object
      additionalProperties: false
      description: Records a matched trade for binary YES/NO orders.
      required:
        - correlation_id
        - order_id
        - account_id
        - role
        - side
        - market_phase
        - price_ticks
        - counter_party
        - counter_party_account_id
        - remaining_qty_shares
        - matched_delta_shares
      properties:
        correlation_id:
          $ref: "#/components/schemas/CorrelationId"
        order_id:
          $ref: "#/components/schemas/OrderId"
        account_id:
          $ref: "#/components/schemas/AccountId"
        role:
          $ref: "#/components/schemas/TradeRole"
        side:
          $ref: "#/components/schemas/Side"
        market_phase:
          $ref: "#/components/schemas/MarketPhase"
          description: Market trading phase when this match was emitted.
        price_ticks:
          type: integer
          format: uint16
          minimum: 0
          description: Matched binary price in ticks, not x10000 money/odds units.
        counter_party:
          $ref: "#/components/schemas/OrderId"
        counter_party_account_id:
          $ref: "#/components/schemas/AccountId"
        remaining_qty_shares:
          type: integer
          format: uint64
          minimum: 0
          description: Remaining unfilled shares on this order after the match, not scaled by 10000.
        matched_delta_shares:
          type: integer
          format: uint64
          minimum: 0
          description: Shares exchanged by this order in this match, not scaled by 10000.

    VoidTradesFromTimePayload:
      type: object
      additionalProperties: false
      description: Administrative marker that downstream systems should void later trades.
      required: [from_matched_at_inclusive, reason]
      properties:
        from_matched_at_inclusive:
          $ref: "#/components/schemas/DateTime"
        reason:
          type: string
          description: Human-readable reason for the void action.

    RunnerRemovedPayload:
      type: object
      additionalProperties: false
      description: Indicates a runner was withdrawn or removed from the market.
      required: [runner_id, runner_label, reduction_factor_bps]
      properties:
        runner_id:
          $ref: "#/components/schemas/RunnerId"
        runner_label:
          type: string
          description: Stable configured label for the removed runner.
        reduction_factor_bps:
          anyOf:
            - type: integer
              format: uint32
              minimum: 0
            - type: "null"
          description: Optional reduction factor in basis points for downstream adjustment.

    RunnerResultEntry:
      type: object
      additionalProperties: false
      description: Settlement outcome for one runner.
      required: [runner_id, runner_label, result]
      properties:
        runner_id:
          $ref: "#/components/schemas/RunnerId"
        runner_label:
          type: string
          description: Stable configured label for the settled runner.
        result:
          $ref: "#/components/schemas/RunnerResult"

    MarketSettledPayload:
      type: object
      additionalProperties: false
      description: Records final settlement results for the market.
      required: [runner_results, dead_heat_divisor]
      properties:
        runner_results:
          type: array
          description: Settlement outcome for each runner.
          items:
            $ref: "#/components/schemas/RunnerResultEntry"
        dead_heat_divisor:
          anyOf:
            - type: integer
              format: uint32
              minimum: 0
            - type: "null"
          description: Optional dead-heat divisor applied to winner payouts.

    BatchCancelStartedPayload:
      type: object
      additionalProperties: false
      description: Marks the deterministic start of a batched cancellation process.
      required:
        - batch_max_events
        - started_at_ms
        - from_created_at_inclusive_ms
        - to_created_at_inclusive_ms
        - account_filter
        - runner_filter
        - reason
        - final_event_metadata_json
      properties:
        batch_max_events:
          type: integer
          format: uint16
          minimum: 0
          description: Maximum number of events allowed in each batch.
        started_at_ms:
          type: integer
          format: int64
          description: UTC start time in unix milliseconds.
        from_created_at_inclusive_ms:
          type:
            - integer
            - "null"
          format: int64
          description: Optional lower bound on order creation time included in the batch.
        to_created_at_inclusive_ms:
          type:
            - integer
            - "null"
          format: int64
          description: Optional upper bound on order creation time included in the batch.
        account_filter:
          anyOf:
            - $ref: "#/components/schemas/AccountId"
            - type: "null"
          description: Optional account filter applied to the cancellation batch.
        runner_filter:
          anyOf:
            - $ref: "#/components/schemas/RunnerId"
            - type: "null"
          description: Optional runner filter applied to the cancellation batch.
        reason:
          type: string
          description: Human-readable reason for starting the batch process.
        final_event_metadata_json:
          type:
            - string
            - "null"
          description: Optional JSON string to attach as metadata to the final event.

    BatchProcessCompletedPayload:
      type: object
      additionalProperties: false
      description: Marks completion of a batched cancellation or close process.
      required: [cancel_cause]
      properties:
        cancel_cause:
          $ref: "#/components/schemas/CancelCause"

    MarketRemovedPayload:
      type: object
      additionalProperties: false
      description: Engine-level terminal cleanup event for removing a market from memory.
      required: [reason]
      properties:
        reason:
          type: string
          description: Human-readable reason for removal.

    MarketCreatedEvent:
      type: object
      additionalProperties: false
      required: [MARKET_CREATED]
      properties:
        MARKET_CREATED:
          $ref: "#/components/schemas/MarketCreatedPayload"

    MarketStateChangedEvent:
      type: object
      additionalProperties: false
      required: [MARKET_STATE_CHANGED]
      properties:
        MARKET_STATE_CHANGED:
          $ref: "#/components/schemas/MarketStateChangedPayload"

    MarketPhaseChangedEvent:
      type: object
      additionalProperties: false
      required: [MARKET_PHASE_CHANGED]
      properties:
        MARKET_PHASE_CHANGED:
          $ref: "#/components/schemas/MarketPhaseChangedPayload"

    OrderAcceptedEvent:
      type: object
      additionalProperties: false
      required: [ORDER_ACCEPTED]
      properties:
        ORDER_ACCEPTED:
          $ref: "#/components/schemas/OrderAcceptedPayload"

    BinaryOrderAcceptedEvent:
      type: object
      additionalProperties: false
      required: [BINARY_ORDER_ACCEPTED]
      properties:
        BINARY_ORDER_ACCEPTED:
          $ref: "#/components/schemas/BinaryOrderAcceptedPayload"

    OrderCancelledEvent:
      type: object
      additionalProperties: false
      required: [ORDER_CANCELLED]
      properties:
        ORDER_CANCELLED:
          $ref: "#/components/schemas/OrderCancelledPayload"

    OrderCancelledBatchedEvent:
      type: object
      additionalProperties: false
      required: [ORDER_CANCELLED_BATCHED]
      properties:
        ORDER_CANCELLED_BATCHED:
          $ref: "#/components/schemas/OrderCancelledBatchedPayload"

    TradeMatchedEvent:
      type: object
      additionalProperties: false
      required: [TRADE_MATCHED]
      properties:
        TRADE_MATCHED:
          $ref: "#/components/schemas/TradeMatchedPayload"

    BinaryTradeMatchedEvent:
      type: object
      additionalProperties: false
      required: [BINARY_TRADE_MATCHED]
      properties:
        BINARY_TRADE_MATCHED:
          $ref: "#/components/schemas/BinaryTradeMatchedPayload"

    VoidTradesFromTimeEvent:
      type: object
      additionalProperties: false
      required: [VOID_TRADES_FROM_TIME]
      properties:
        VOID_TRADES_FROM_TIME:
          $ref: "#/components/schemas/VoidTradesFromTimePayload"

    RunnerRemovedEvent:
      type: object
      additionalProperties: false
      required: [RUNNER_REMOVED]
      properties:
        RUNNER_REMOVED:
          $ref: "#/components/schemas/RunnerRemovedPayload"

    MarketSettledEvent:
      type: object
      additionalProperties: false
      required: [MARKET_SETTLED]
      properties:
        MARKET_SETTLED:
          $ref: "#/components/schemas/MarketSettledPayload"

    BatchCancelStartedEvent:
      type: object
      additionalProperties: false
      required: [BATCH_CANCEL_STARTED]
      properties:
        BATCH_CANCEL_STARTED:
          $ref: "#/components/schemas/BatchCancelStartedPayload"

    BatchProcessCompletedEvent:
      type: object
      additionalProperties: false
      required: [BATCH_PROCESS_COMPLETED]
      properties:
        BATCH_PROCESS_COMPLETED:
          $ref: "#/components/schemas/BatchProcessCompletedPayload"

    MarketRemovedEvent:
      type: object
      additionalProperties: false
      required: [MARKET_REMOVED]
      properties:
        MARKET_REMOVED:
          $ref: "#/components/schemas/MarketRemovedPayload"

    BookEvent:
      oneOf:
        - $ref: "#/components/schemas/MarketCreatedEvent"
        - $ref: "#/components/schemas/MarketStateChangedEvent"
        - $ref: "#/components/schemas/MarketPhaseChangedEvent"
        - $ref: "#/components/schemas/OrderAcceptedEvent"
        - $ref: "#/components/schemas/BinaryOrderAcceptedEvent"
        - $ref: "#/components/schemas/OrderCancelledEvent"
        - $ref: "#/components/schemas/OrderCancelledBatchedEvent"
        - $ref: "#/components/schemas/TradeMatchedEvent"
        - $ref: "#/components/schemas/BinaryTradeMatchedEvent"
        - $ref: "#/components/schemas/VoidTradesFromTimeEvent"
        - $ref: "#/components/schemas/RunnerRemovedEvent"
        - $ref: "#/components/schemas/MarketSettledEvent"
        - $ref: "#/components/schemas/BatchCancelStartedEvent"
        - $ref: "#/components/schemas/BatchProcessCompletedEvent"
        - $ref: "#/components/schemas/MarketRemovedEvent"
      description: Externally tagged event payload with exactly one event variant key.

    BookEventEnvelope:
      type: object
      additionalProperties: false
      description: Per-market event wrapper emitted by the book.
      required: [market_id, market_name, market_seq, timestamp, metadata, event]
      properties:
        market_id:
          $ref: "#/components/schemas/MarketId"
        market_name:
          type: string
          description: Market name carried on every emitted envelope.
        market_seq:
          type: integer
          format: uint64
          minimum: 0
          description: Monotonic per-market event sequence starting at 1.
        timestamp:
          $ref: "#/components/schemas/DateTime"
        metadata:
          $ref: "#/components/schemas/EventMetadata"
        event:
          $ref: "#/components/schemas/BookEvent"

  examples:
    BookEventEnvelopeSchema:
      summary: Generic envelope shape
      value:
        market_id: 1001
        market_name: "Example Market"
        market_seq: 1
        timestamp: "2026-03-09T12:34:56Z"
        metadata: null
        event:
          MARKET_STATE_CHANGED:
            to: OPEN
            reason: market created and opened

    MarketCreated:
      value:
        market_id: 1001
        market_name: "Match Odds"
        market_seq: 1
        timestamp: "2026-03-09T12:00:00Z"
        metadata: null
        event:
          MARKET_CREATED:
            correlation_id: create-market-1001
            name: Match Odds
            market_model: EXCHANGE_ODDS
            market_kind: PRE_EVENT_ONLY
            market_phase: PRE
            runner_ids: [11, 22, 33]
            runner_labels: [Home, Away, Draw]

    MarketCreatedBinaryYes:
      value:
        market_id: 2001
        market_name: "Will candidate A win?"
        market_seq: 1
        timestamp: "2026-03-09T12:00:00Z"
        metadata: null
        event:
          MARKET_CREATED:
            correlation_id: create-market-2001
            name: Will candidate A win?
            market_model:
              BINARY_YES:
                max_price_ticks: 10000
            market_kind: IN_PLAY_CAPABLE
            market_phase: PRE
            runner_ids: []
            runner_labels: []

    MarketStateChanged:
      value:
        market_id: 1001
        market_name: "Match Odds"
        market_seq: 2
        timestamp: "2026-03-09T12:01:00Z"
        metadata: null
        event:
          MARKET_STATE_CHANGED:
            to: SUSPENDED
            reason: pre-off suspend

    MarketPhaseChanged:
      value:
        market_id: 1001
        market_name: "Match Odds"
        market_seq: 3
        timestamp: "2026-03-09T12:01:30Z"
        metadata: null
        event:
          MARKET_PHASE_CHANGED:
            to: LIVE
            reason: off

    OrderAccepted:
      value:
        market_id: 1001
        market_name: "Match Odds"
        market_seq: 4
        timestamp: "2026-03-09T12:02:00Z"
        metadata: null
        event:
          ORDER_ACCEPTED:
            correlation_id: place-order-1
            order_id: 9001
            account_id: "acct-501"
            runner_id: 11
            runner_label: Home
            side: YES
            price: 25000
            stake: 125000
            persistence: LAPSE
            time_in_force: GTC

    BinaryOrderAccepted:
      value:
        market_id: 2001
        market_name: "Will candidate A win?"
        market_seq: 2
        timestamp: "2026-03-09T12:02:05Z"
        metadata: null
        event:
          BINARY_ORDER_ACCEPTED:
            correlation_id: place-binary-order-1
            order_id: 9101
            account_id: "acct-777"
            side: NO
            price_ticks: 6300
            qty_shares: 250
            time_in_force:
              FILL_OR_KILL:
                min_fill: 100

    OrderCancelled:
      value:
        market_id: 1001
        market_name: "Match Odds"
        market_seq: 5
        timestamp: "2026-03-09T12:03:00Z"
        metadata: null
        event:
          ORDER_CANCELLED:
            cancelled_order:
              order_id: 9001
              account_id: "acct-501"
              correlation_id: "cancel-order-1"
            cancel_cause: USER_CANCEL
            cause_detail: USER_CANCEL

    OrderCancelledBatched:
      value:
        market_id: 1001
        market_name: "Match Odds"
        market_seq: 6
        timestamp: "2026-03-09T12:03:30Z"
        metadata: null
        event:
          ORDER_CANCELLED_BATCHED:
            cancelled_orders:
              - order_id: 9002
                account_id: "acct-501"
                correlation_id: "place-order-2"
              - order_id: 9003
                account_id: "acct-888"
                correlation_id: null
            cursor_after:
              order_id: 9003
              account_id: "acct-888"
            cancel_cause: BATCH_CANCEL
            cause_detail: cancelled during market close

    TradeMatched:
      value:
        market_id: 1001
        market_name: "Match Odds"
        market_seq: 7
        timestamp: "2026-03-09T12:04:00Z"
        metadata: null
        event:
          TRADE_MATCHED:
            correlation_id: place-order-1
            order_id: 9001
            account_id: "acct-501"
            role: MAKER
            runner_id: 11
            runner_label: Home
            side: YES
            market_phase: PRE
            price: 25000
            stake: 125000
            counter_party: 9004
            counter_party_account_id: "acct-999"
            remaining_stake: 25000
            matched_delta: 100000

    BinaryTradeMatched:
      value:
        market_id: 2001
        market_name: "Will candidate A win?"
        market_seq: 4
        timestamp: "2026-03-09T12:04:10Z"
        metadata: null
        event:
          BINARY_TRADE_MATCHED:
            correlation_id: place-binary-order-1
            order_id: 9101
            account_id: "acct-777"
            role: MAKER
            side: NO
            market_phase: PRE
            price_ticks: 6300
            counter_party: 9102
            counter_party_account_id: "acct-999"
            remaining_qty_shares: 0
            matched_delta_shares: 250

    VoidTradesFromTime:
      value:
        market_id: 1001
        market_name: "Match Odds"
        market_seq: 8
        timestamp: "2026-03-09T12:05:00Z"
        metadata: null
        event:
          VOID_TRADES_FROM_TIME:
            from_matched_at_inclusive: "2026-03-09T12:04:00Z"
            reason: pricing incident

    RunnerRemoved:
      value:
        market_id: 1001
        market_name: "Match Odds"
        market_seq: 9
        timestamp: "2026-03-09T12:06:00Z"
        metadata: null
        event:
          RUNNER_REMOVED:
            runner_id: 33
            runner_label: Draw
            reduction_factor_bps: 500

    MarketSettled:
      value:
        market_id: 1001
        market_name: "Match Odds"
        market_seq: 10
        timestamp: "2026-03-09T12:10:00Z"
        metadata: null
        event:
          MARKET_SETTLED:
            runner_results:
              - runner_id: 11
                runner_label: Home
                result: Winner
              - runner_id: 22
                runner_label: Away
                result: Loser
              - runner_id: 33
                runner_label: Draw
                result: Removed
            dead_heat_divisor: null

    BatchCancelStarted:
      value:
        market_id: 1001
        market_name: "Match Odds"
        market_seq: 11
        timestamp: "2026-03-09T12:11:00Z"
        metadata: null
        event:
          BATCH_CANCEL_STARTED:
            batch_max_events: 100
            started_at_ms: 1773058260000
            from_created_at_inclusive_ms: null
            to_created_at_inclusive_ms: null
            account_filter: null
            runner_filter: null
            reason: market close batch cancel
            final_event_metadata_json: '{"origin":"close-process"}'

    BatchProcessCompleted:
      value:
        market_id: 1001
        market_name: "Match Odds"
        market_seq: 12
        timestamp: "2026-03-09T12:12:00Z"
        metadata: null
        event:
          BATCH_PROCESS_COMPLETED:
            cancel_cause: CLOSE_CANCEL

    MarketRemoved:
      value:
        market_id: 1001
        market_name: "Match Odds"
        market_seq: 13
        timestamp: "2026-03-09T12:13:00Z"
        metadata: null
        event:
          MARKET_REMOVED:
            reason: evicted after terminal processing
