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.