The Settlement Service orchestrates the liquidation lifecycle — from margin call escalation through position closeout via the normal Order → Matching pipeline. It does not directly mutate positions or wallets; instead it creates system liquidation orders that flow through the standard execution path.
- Liquidation Orchestration: Receive liquidation triggers from the Position Service, create system liquidation orders routed through Order Service → Matching Engine.
- Margin Call Handling: Escalate margin calls, provide grace period, and proceed to liquidation if not resolved.
- Settlement Record Keeping: Persist every settlement action with full audit trail.
- ADL / Insurance Fund Fallback: When liquidation orders can’t fill at bankruptcy price, use Auto-Deleveraging (ADL) or insurance fund to cover shortfall.
- Compliance-Grade Audit: Every liquidation produces a compliance-grade record with timestamps, prices, and reasons.
The Settlement Service is an orchestrator only — it does not have direct DB access to positions, wallets, or order books. All mutations flow through the respective service APIs.
graph TB
PosSvc[Position Service] -->|risk.liquidation.trigger.v1| Kafka[Kafka]
RiskSvc[Risk Service] -->|risk.liquidation.v1| Kafka
Kafka --> Settlement[Settlement Service]
Settlement -->|gRPC InitiateLiquidation| OrderSvc[Order Service]
OrderSvc --> ME[Matching Engine]
ME -->|engine.event.v1| Kafka2[Kafka]
Kafka2 --> Settlement
Settlement -->|gRPC| Wallet[Wallet Service]
Settlement -->|Stores| PG[(PostgreSQL)]
Settlement -->|Events| Kafka3[Kafka]
| Field | Type | Description |
|---|
id | UUID (PK) | Settlement record ID |
user_id | UUID | Account being settled |
symbol | VARCHAR(32) | Instrument symbol |
settlement_type | ENUM(liquidation, margin_call, expiry, manual_closeout) | Type of settlement |
status | ENUM(initiated, pending_fill, partially_filled, completed, failed, abl_triggered) | Settlement status |
position_size | NUMERIC(24,12) | Position size at time of settlement |
entry_price | NUMERIC(24,12) | Position entry price |
mark_price_at_trigger | NUMERIC(24,12) | Mark price when triggered |
bankruptcy_price | NUMERIC(24,12) | Bankruptcy price (no margin left) |
liquidation_price | NUMERIC(24,12) | Liquidation trigger price |
fill_price | NUMERIC(24,12) | Actual fill price (weighted avg) |
filled_qty | NUMERIC(24,12) | Quantity filled |
shortfall | NUMERIC(24,12) | Shortfall if fill worse than bankruptcy (covered by insurance/ADL) |
insurance_fund_used | NUMERIC(24,12) | Amount covered by insurance fund |
adl_triggered | BOOLEAN | Whether ADL was used |
reason | TEXT | Human-readable reason |
initiated_at | TIMESTAMPTZ | When settlement was triggered |
completed_at | TIMESTAMPTZ | When settlement completed |
| Field | Type | Description |
|---|
id | UUID (PK) | Liquidation order ID |
settlement_id | UUID (FK) | References settlement_records |
order_id | UUID | Order ID in Order Service |
side | ENUM(buy, sell) | Close direction |
quantity | NUMERIC(24,12) | Order quantity |
price | NUMERIC(24,12) | Limit price (bankruptcy price) |
status | ENUM(submitted, accepted, partially_filled, filled, failed) | Order status |
created_at | TIMESTAMPTZ | Submission time |
updated_at | TIMESTAMPTZ | Last status update |
| RPC | Description | Called By |
|---|
InitiateSettlement(user_id, symbol, settlement_type, reason) | Begin settlement process | Risk Service, Admin |
GetSettlementStatus(settlement_id) | Query settlement status | Admin, Monitoring |
ProcessMarginCall(user_id, symbol, margin_shortfall) | Handle margin call | Position Service |
| Method | Endpoint | Description |
|---|
GET | /v1/settlements | List settlement records (paginated) |
GET | /v1/settlements/{id} | Get settlement details |
POST | /v1/settlements/manual-closeout | Initiate manual closeout |
GET | /v1/settlements/insurance-fund | Get insurance fund balance |
| Topic | Description |
|---|
risk.liquidation.trigger.v1 | Liquidation needed (from Position Service) |
risk.liquidation.v1 | Liquidation confirmed (from Risk Service) |
risk.margin_call.v1 | Margin call (from Risk Service) |
engine.event.v1 | Liquidation order fill events |
| Topic | Description |
|---|
settlement.initiated.v1 | Settlement process started |
settlement.completed.v1 | Settlement completed (position closed) |
settlement.failed.v1 | Settlement failed (requires manual intervention) |
settlement.adl.triggered.v1 | Auto-deleveraging activated |
settlement.insurance.used.v1 | Insurance fund used to cover shortfall |
- Receive
risk.liquidation.trigger.v1 for (user_id, symbol)
- Create
settlement_records row (status = initiated)
- Compute bankruptcy price from position data
- Create liquidation order: IOC sell (for longs) or IOC buy (for shorts) at bankruptcy price
- Submit order via Order Service gRPC →
CreateOrder(system_liquidation_order)
- Order flows through normal pipeline: Order Service → Matching Engine
- Create
liquidation_orders row tracking the order
- Update status to
pending_fill
- Consume
engine.event.v1 matching the liquidation order
- Update
liquidation_orders.status and settlement_records.filled_qty
- If fully filled:
- Calculate shortfall:
fill_price vs bankruptcy_price
- If no shortfall: complete settlement
- If shortfall: trigger insurance fund / ADL
- If partially filled: keep monitoring, may submit additional orders
- Emit
settlement.completed.v1
If liquidation order fills at a price worse than bankruptcy:
- Insurance Fund First: Draw from insurance fund to cover shortfall
- ADL Second: If insurance fund insufficient:
- Identify most profitable counterparties on the opposite side
- Force-reduce their positions proportionally (Auto-Deleveraging)
- Create settlement records for ADL participants
- Emit
settlement.adl.triggered.v1
- Receive
risk.margin_call.v1
- Notify user (via Notification Service)
- Start grace period timer (e.g., 30 minutes)
- During grace period: monitor if user adds margin or reduces position
- If margin restored: cancel margin call
- If grace period expires without resolution: escalate to liquidation
- Settlement keyed by
(user_id, symbol, settlement_cycle_timestamp)
- Prevents duplicate liquidation for the same position in the same cycle
- If settlement already in progress: skip new trigger
- ❌ Directly modify positions or position tables
- ❌ Directly modify wallet balances
- ❌ Directly modify order books
- ❌ Bypass the Order Service → Matching Engine pipeline
- ❌ Execute market orders (uses IOC limit at bankruptcy price)
- ✅ Routes liquidation orders through the normal Order → Matching pipeline
- ✅ Records every action in
settlement_records with full audit trail
- ✅ Uses insurance fund before ADL
- ✅ Notifies users before and after liquidation
- ✅ Requires manual intervention for failed settlements
| Metric | Target |
|---|
| Liquidation order submission (p95) | < 500 ms after trigger |
| Settlement completion (p95) | < 5 seconds |
| Insurance fund accuracy | 100% |
| ADL fairness (proportional to profit) | 100% |
| Settlement record completeness | 100% |
| Variable | Description | Default |
|---|
POSTGRES_URL | PostgreSQL connection string | Required |
KAFKA_BROKERS | Kafka broker addresses | Required |
ORDER_SERVICE_GRPC_URL | Order Service gRPC endpoint | Required |
WALLET_SERVICE_GRPC_URL | Wallet Service gRPC endpoint | Required |
MARGIN_CALL_GRACE_PERIOD_MIN | Grace period before liquidation | 30 |
INSURANCE_FUND_MIN_BALANCE | Minimum insurance fund balance | Configurable |