Skip to content

Risk Controls

The kill-switch dialog, the manual escape hatch when something has gone wrong

The OMS calls POST /check on the Risk Engine synchronously before routing every order. If any check fails, the order is rejected with a specific reason code. If the Risk Engine is unreachable (3s timeout), the order is rejected. Real firms halt trading rather than bypass pre-trade risk.

| # | Check | Code | Default | What it prevents | | --- | --- | --- | --- | --- | | 1 | Fat-finger price collar | FAT_FINGER_PRICE | 5% from mid | Typo prices | | 2 | Duplicate order detection | DUPLICATE_ORDER | 500ms window | Double-clicks | | 3 | Max open orders per user | MAX_OPEN_ORDERS | 50 orders | Runaway algos | | 4 | Self-cross prevention | SELF_CROSS | (none) | Own BUY crossing own SELL | | 5 | Order size vs ADV | ORDER_SIZE_VS_ADV | 10% of ADV | Market impact | | 6 | Rate limiting | RATE_LIMIT | 10 orders/sec | Algo floods |

All thresholds are runtime-editable via PUT /config with no restart:

{
"fatFingerPct": 5.0,
"maxOpenOrders": 50,
"duplicateWindowMs": 500,
"maxOrdersPerSecond": 10,
"maxAdvPct": 10.0
}

The Risk Engine tracks positions from orders.filled bus events in real-time.

  • GET /positions/:userId: per-symbol net qty, avg price, mark price, unrealised/realised/total P&L
  • GET /positions: all users' positions
  • Unrealised: netQty * (markPrice - avgPrice), updated on every price refresh (5s)
  • Realised: accumulated when fills reduce or flip a position
  • Total: unrealised + realised
  • Risk Dashboard (risk-manager, desk-head, admin, compliance): firm-wide view with per-user rolled-up P&L

    Risk Dashboard panel showing positions and P&L across all desks

  • My Positions (all traders): authenticated user's own positions with total row

    My Positions panel for an individual trader