# 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](#quoteack-rejected-quote-not-accepted) 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.
