Files
qfixdpl/docs/FLOW_8_4_LIST_TRADING.md

16 KiB

Flow 8.4 — List Trading (Dealer Response)

Overview

Flow 8.4 defines how a dealer responds to a client's Request for Quote (RFQ) through Tradeweb (TW) in a List Trading context. The key rule is:

The dealer NEVER sends an ExecutionReport (35=8). Only Tradeweb does.

The dealer's role is limited to:

  • Acknowledging messages (35=AI QuoteStatusReport, 35=BN ExecutionAck)
  • Sending a price quote (35=S)

This document covers the happy path (client accepts) and two alternative flows:

  • Flow 8.6 — Trade Ended: Client cancels before or after receiving the quote
  • QuoteAck Rejected: TW rejects the dealer's quote

Participants

Abbreviation Role
TW Tradeweb — the platform that orchestrates the trade
Dealer Us — responds to RFQs with quotes and acknowledges TW messages
Client The counterparty requesting a quote (we never communicate with them directly)

Message Flow

     TW                                          Dealer
      │                                            │
      │  1. QuoteRequest (35=R)                    │
      │ ─────────────────────────────────────────> │
      │                                            │
      │  2. QuoteStatusReport (35=AI) [ACK]        │
      │ <───────────────────────────────────────── │
      │                                            │
      │  3. Quote (35=S) [price]                   │
      │ <───────────────────────────────────────── │
      │                                            │
      │  4. QuoteAck (35=CW) [ACCEPTED]            │
      │ ─────────────────────────────────────────> │
      │                                            │
      │  5. QuoteResponse (35=AJ) [Hit/Lift]       │
      │ ─────────────────────────────────────────> │
      │                                            │
      │  6. QuoteStatusReport (35=AI) [TRDREQACK]  │
      │ <───────────────────────────────────────── │
      │                                            │
      │  7. ExecutionReport (35=8) [_LISTEND]      │
      │ ─────────────────────────────────────────> │
      │                                            │
      │  8. ExecutionAck (35=BN)                   │
      │ <───────────────────────────────────────── │
      │                                            │
      │  9. ExecutionReport (35=8) [_TRDEND]       │
      │ ─────────────────────────────────────────> │
      │                                            │
      │  10. ExecutionAck (35=BN)                  │
      │ <───────────────────────────────────────── │
      │                                            │
      │  11. ExecutionReport (35=8) [_TRDSUMM]     │
      │ ─────────────────────────────────────────> │
      │                                            │
      │  12. ExecutionAck (35=BN)                  │
      │ <───────────────────────────────────────── │
      │                                            │

Step-by-Step Detail

Step 1 — QuoteRequest (35=R) — TW → Dealer

TW sends an RFQ on behalf of the client. Key fields:

Tag Field Example Notes
131 QuoteReqID LST_20260316_BYMA_CORI_NY1567246.1_1 Always starts with LST_ for List Trading
66 ListID NY1567246.1 Identifies the list/inquiry
48 SecurityID 040114HT0 Bond identifier
22 SecurityIDSource 1 (CUSIP) Could also be 4 (ISIN)
54 Side 2 (SELL) The client's side — if client sells, dealer buys
38 OrderQty 10000 Quantity requested
15 Currency USD Settlement currency
64 SettlDate 20260317 Settlement date
20073 NegotiationType RFQ Must be RFQ for this flow

Validation: The dealer must verify LST_ prefix, non-empty ListID, and NegotiationType=RFQ before proceeding.

Step 2 — QuoteStatusReport (35=AI) — Dealer → TW

The dealer acknowledges receipt of the QuoteRequest.

Tag Field Value
131 QuoteReqID Same as received
117 QuoteID Same as QuoteReqID
297 QuoteStatus 0 (ACCEPTED)

Step 3 — Quote (35=S) — Dealer → TW

The dealer sends a price quote.

Tag Field Example Notes
117 QuoteID Same as QuoteReqID
131 QuoteReqID Same as received
132 BidPx 99.60000000 Set when client side is SELL (dealer bids)
133 OfferPx 99.60000000 Set when client side is BUY (dealer offers)
44 Price 99.60000000 The quote price
423 PriceType 1 (Percentage)
537 QuoteType 211 (SEND_QUOTE)

Step 4 — QuoteAck (35=CW) — TW → Dealer

TW confirms the quote was accepted.

Tag Field Value
1865 QuoteAckStatus 1 (ACCEPTED)

Note: If status is not ACCEPTED, the dealer logs the rejection (including the Text field) and cleans up the trade from memory. See QuoteAck Rejected below.

Step 5 — QuoteResponse (35=AJ) — TW → Dealer

The client has decided to trade (Hit/Lift the quote).

Tag Field Value Notes
694 QuoteRespType 1 (Hit/Lift) 2 would be Counter — that's flow 8.5, not handled here
693 QuoteRespID ..._TRDREQ Always ends with _TRDREQ

Step 6 — QuoteStatusReport (35=AI) — Dealer → TW

The dealer acknowledges the trade request (TRDREQACK).

Tag Field Value
131 QuoteReqID Same as received
693 QuoteRespID Same as received
297 QuoteStatus 0 (ACCEPTED)

Step 7 — ExecutionReport (35=8) _LISTEND — TW → Dealer

TW signals that the due-in window for the list has closed.

Tag Field Value Notes
17 ExecID ..._LISTEND-{timestamp} Contains _LISTEND
150 ExecType A (PendingNew)
39 OrdStatus A (PendingNew)

Dealer action: Send ExecutionAck only. Do NOT send an ExecutionReport back.

Step 8 — ExecutionAck (35=BN) — Dealer → TW

Tag Field Value
37 OrderID Same as received
17 ExecID Same as received
1036 ExecAckStatus 1 (ACCEPTED)

Step 9 — ExecutionReport (35=8) _TRDEND — TW → Dealer

TW sends the trade result.

Tag Field Value Notes
17 ExecID ..._TRDEND-{timestamp} Contains _TRDEND
150 ExecType F (Trade) The trade was executed
39 OrdStatus 2 (Filled)
44 Price 99.6 Final execution price

Dealer action: Send ExecutionAck. Clean up internal trade tracking state.

Step 10 — ExecutionAck (35=BN) — Dealer → TW

Same format as Step 8.

Step 11 — ExecutionReport (35=8) _TRDSUMM — TW → Dealer

TW sends the full trade summary with additional details (parties, settlement info, trade IDs).

Tag Field Value Notes
17 ExecID ..._TRDSUMM-{timestamp} Contains _TRDSUMM
150 ExecType F (Trade)
39 OrdStatus 2 (Filled)
453 NoPartyIDs Party information Counterparty details
526 SecondaryClOrdID TRD_... Tradeweb trade reference
1003 TradeID 20260316.BYMA.CORI.230 Unique trade identifier

Dealer action: Send ExecutionAck. Log the summary for audit/reconciliation.

Step 12 — ExecutionAck (35=BN) — Dealer → TW

Same format as Step 8.


Alternative Flows

Flow 8.6 — Trade Ended (Client Cancels)

The client changes their mind and ends the trade. This can happen at any point after the QuoteRequest — even before the dealer's quote arrives. TW informs the dealer via QuoteResponse (35=AJ) messages with _TRDEND and _TRDSUMM suffixes instead of the ExecutionReport chain.

Critical: The dealer MUST send a QuoteStatusReport (35=AI) ACK for every QuoteResponse. If no ACK is sent, TW will retry the message indefinitely (~every 11 seconds).

     TW                                          Dealer
      │                                            │
      │  1. QuoteRequest (35=R)                    │
      │ ─────────────────────────────────────────> │
      │                                            │
      │  2. QuoteStatusReport (35=AI) [ACK]        │
      │ <───────────────────────────────────────── │
      │                                            │
      │     ┌─── Client ends trade ───┐            │
      │     │  Meanwhile, dealer may  │            │
      │     │  still send Quote (S)   │            │
      │     └─────────────────────────┘            │
      │                                            │
      │  3. QuoteResponse (35=AJ) [_TRDEND]        │
      │     QuoteRespType=7 (End Trade)            │
      │ ─────────────────────────────────────────> │
      │                                            │
      │  4. QuoteStatusReport (35=AI) [ACK]        │
      │ <───────────────────────────────────────── │
      │                                            │
      │  5. QuoteAck (35=CW) [REJECTED]            │
      │     (if quote was sent, TW rejects it)     │
      │ ─────────────────────────────────────────> │
      │                                            │
      │  6. QuoteResponse (35=AJ) [_TRDSUMM]       │
      │     QuoteRespType=7, TradeSummary=Y        │
      │ ─────────────────────────────────────────> │
      │                                            │
      │  7. QuoteStatusReport (35=AI) [ACK]        │
      │ <───────────────────────────────────────── │
      │                                            │

Step 3 — QuoteResponse (35=AJ) _TRDEND — TW → Dealer

TW notifies that the client ended the trade.

Tag Field Value Notes
693 QuoteRespID ..._TRDEND Suffix identifies this as trade end
694 QuoteRespType 7 (End Trade)
131 QuoteReqID Same as original

Dealer action: Send QuoteStatusReport (35=AI) with 693=QuoteRespID and 297=0 (ACCEPTED).

Step 5 — QuoteAck (35=CW) REJECTED — TW → Dealer

If the dealer's Quote (35=S) crossed with the TRDEND, TW rejects it. The QuoteAckStatus will be 2 (REJECTED) with a text like "DPL DLRQUOTE received in an invalid state."

Dealer action: Log the rejection and clean up the trade from memory.

Step 6 — QuoteResponse (35=AJ) _TRDSUMM — TW → Dealer

TW sends the final trade summary confirming the outcome.

Tag Field Value Notes
693 QuoteRespID ..._TRDSUMM Final summary message
694 QuoteRespType 7 (End Trade)
22636 TradeSummary Y Confirms this is the summary

Dealer action: Send QuoteStatusReport (35=AI) ACK. Clean up the trade from memory. This is the terminal message — no more messages will follow for this QuoteReqID.


QuoteAck Rejected (Quote Not Accepted)

If TW rejects the dealer's Quote (35=CW with status != ACCEPTED), the trade is dead from the dealer's perspective.

     TW                                          Dealer
      │                                            │
      │  1-3. (same as happy path)                 │
      │                                            │
      │  4. QuoteAck (35=CW) [REJECTED]            │
      │     QuoteAckStatus != 1                    │
      │ ─────────────────────────────────────────> │
      │                                            │
      │     Trade is terminated.                   │
      │                                            │

Dealer action: Log the rejection (including the Text field with the reason) and remove the trade from memory. No further action needed — TW may or may not send subsequent messages for this QuoteReqID.


QuoteRespID Suffix Routing in handleQuoteResponse

All QuoteResponse (35=AJ) messages are routed by the suffix of the QuoteRespID (tag 693):

QuoteRespID ends with "_TRDREQ"   → Trade request (flow 8.4 happy path) — ACK
QuoteRespID ends with "_TRDEND"   → Trade ended by client (flow 8.6) — ACK
QuoteRespID ends with "_TRDSUMM"  → Trade summary (flow 8.6 final) — ACK + cleanup
QuoteRespID ends with "_LISTEND"  → List ended — ACK
Other suffix                       → Ignored (logged)

Code Reference

The implementation lives in src/client/fix/manager.go:

Handler Triggers on Action
handleQuoteRequest 35=R Sends 35=AI (ack) + 35=S (quote)
handleQuoteAck 35=CW If rejected: logs + cleans up trade. If accepted: logs
handleQuoteResponse 35=AJ Sends 35=AI (ACK). Routes by QuoteRespID suffix. Cleans up on _TRDSUMM
handleExecutionReport 35=8 Sends 35=BN (ack) + routes by ExecID suffix
sendQuoteStatusReport Builds 35=AI for QuoteRequest ack
sendTradeRequestAck Builds 35=AI for QuoteResponse ack (all suffixes)
sendExecutionAck Builds 35=BN for ExecutionReport ack

ExecID Routing in handleExecutionReport

ExecID contains "_LISTEND"  → Log only, await trade result
ExecID contains "_TRDEND"   → Log trade end
ExecID contains "_TRDSUMM"  → Log trade summary + cleanup trade from memory
ExecType = F (fallback)     → Log generic trade result

The order matters: ExecID suffix checks run before ExecType checks, because _TRDEND and _TRDSUMM both have ExecType=F.

Trade Cleanup Paths

A trade is removed from memory in any of these scenarios:

Trigger Message Condition
QuoteAck rejected 35=CW QuoteAckStatus != ACCEPTED
QuoteResponse summary 35=AJ QuoteRespID ends with _TRDSUMM (flow 8.6)
ExecutionReport summary 35=8 ExecID contains _TRDSUMM (flow 8.4)

The loadActiveTrades recovery function replays today's messages and applies the same cleanup rules to reconstruct accurate state on restart.