Skip to Content

Simulators

Settlement

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:

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 sendThe simulator returns
the same result again200 with "already_settled":true and zero counts
the opposite result409 with {"error":{"code":"settlement_conflict","message":"market already settled with result yes"}}, and the recorded result never flips
an unknown ticker404 with market_not_found

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

Last updated on