# Settlement

Resolves a market when you say so: cancels its resting orders, pays the winning side and writes the settlement history.

The simulator settles a market when you call `POST /_settle`, so your test decides when a market resolves.

**Differs from Kalshi:** Kalshi settles a market on its own clock. The simulator settles one only when `POST /_settle` is called.

The `holding_long` scenario starts `member` with 50 YES contracts on `KXDEMO-26-A`, so settling it pays out:

```bash
export RYSTIC_URL=$(rystic run kalshi-twin -d --port 0 --name settle --scenario holding_long --json | jq -r .data.url)
curl -s "$RYSTIC_URL/trade-api/v2/portfolio/balance" | jq -c '{balance_dollars}'
# -> {"balance_dollars":"10000.0000"}
curl -s -X POST "$RYSTIC_URL/_settle" -H 'Content-Type: application/json' -d '{"ticker":"KXDEMO-26-A","result":"yes"}'
# -> {"accounts_settled":1,"orders_canceled":2,"paid_dollars":"50.0000","result":"yes","ticker":"KXDEMO-26-A"}
curl -s "$RYSTIC_URL/trade-api/v2/portfolio/balance" | jq -c '{balance_dollars}'
# -> {"balance_dollars":"10050.0000"}
curl -s "$RYSTIC_URL/trade-api/v2/portfolio/settlements" | jq -c '.settlements[] | {ticker, market_result, yes_count_fp}'
# -> {"ticker":"KXDEMO-26-A","market_result":"yes","yes_count_fp":"50.00"}
```

Send the body as JSON, `{"ticker", "result"}`, with `result` set to `yes` or `no`. The call declares the result, then:

- cancels every resting order on the market
- pays $1.00 per contract to the winning side
- zeroes positions and folds balances
- writes the settlement history that `GET /trade-api/v2/portfolio/settlements` reads

`accounts_settled` counts the accounts that held a position, and `orders_canceled` counts every resting order on the market, whoever owns it.

### What settling changes

- **The market becomes `finalized`**, Kalshi's word for a settled market, on an empty book. `yes_bid_dollars` reads `0.0000`, `yes_ask_dollars` reads `1.0000` and the recorded `expiration_value` is published. Creating an order on it then returns `404 market_not_found`, exactly as for a ticker that doesn't exist. Canceling still works, because risk-reducing operations are never gated on market status.
- **The resting orders are canceled for real.** Your quotes get `user_orders` cancel frames and the book deltas print.
- **On a replayed tape the later frames leave the settled market alone.** On `btc15m_tape`, the scenario's only market stays empty until `POST /_rystic/scenario` puts the scenario back.
- **`market_lifecycle_v2` subscribers receive two events.** Events, in order: `determined` → `settled`.

### Repeating a settlement

Settlement is idempotent, so no repeat pays twice:

| You send | The simulator returns |
|---|---|
| the same result again | `200` with `"already_settled":true` and zero counts |
| the opposite result | `409` with `{"error":{"code":"settlement_conflict","message":"market already settled with result yes"}}`, and the recorded result never flips |
| an unknown ticker | `404` with `market_not_found` |

A body not sent as `Content-Type: application/json` returns `400` with `settle requires ticker and result (yes|no)`.

---

Source: https://www.rystic.ai/docs/simulators/kalshi/features/settlement · Markdown: https://www.rystic.ai/docs/simulators/kalshi/features/settlement.md
