Skip to content

Risk Controls

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 sooner halt trading than bypass pre-trade risk.

#CheckCodeDefaultWhat it prevents
1Fat-finger price collarFAT_FINGER_PRICE5% from midTypo prices
2Duplicate order detectionDUPLICATE_ORDER500ms windowDouble-clicks
3Max open orders per userMAX_OPEN_ORDERS50 ordersRunaway algos
4Self-cross preventionSELF_CROSSOwn BUY crossing own SELL
5Order size vs ADVORDER_SIZE_VS_ADV10% of ADVMarket impact
6Rate limitingRATE_LIMIT10 orders/secAlgo 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
  • My Positions (all traders): authenticated user’s own positions with total row