Skip to content

Pre-trade check

The core real-time call. Send the order your client is about to place; get back a verdict you render as a warning (or use to gate the confirm button).

This runs the same engine as TradLyt's own extension: rule-based behavioural detectors + the ML bad-trade-risk model (Rafiki) + the Matra position sizer + margin adequacy + a friction level.

POST /pre-trade

Requires the pretrade feature on your account.

Who provides what

The engine needs more than the order. Here's the split — most of it is already covered:

Input Source
Order (instrument, direction, qty, price, …) You send it (request body below).
Broker margin (required + available) You send it — powers the capital check. See Margin.
Today's session state You send it, or we derive it from synced trades. See session_context.
Live market context (India VIX, NIFTY move, underlying LTP) TradLyt fetches it from a shared market feed. You don't provide it.
Behavioural baselines (the client's own history) TradLyt computes it from the trades you've synced (refreshed daily).

Request body

Field Type Required Description
user_ref string ✅ The client placing the order.
instrument string ✅ Trading symbol. EQ: RELIANCE. OPT: SENSEX2671677500PE. FUT: RELIANCE25MAYFUT.
direction enum ✅ BUY or SELL.
quantity number ✅ Units, not lots.
price number ✅ Intended order price.
order_type enum INTRADAY / SWING / CNC / NRML / …
segment enum EQ / FO. Improves accuracy; inferred from symbol when omitted.
instrument_category enum EQ / OPT / FUT. Inferred when omitted.
expiry_date string YYYY-MM-DD (options).
product string MIS / CNC / NRML.
required_margin number Margin this order blocks, from your OMS. See Margin.
available_margin number Client's free margin, from your OMS. See Margin.
session_context object Today's live session state. See session_context.
{
  "user_ref": "CLIENT00423",
  "instrument": "SENSEX2671677500PE",
  "direction": "SELL",
  "quantity": 40,
  "price": 429.95,
  "order_type": "INTRADAY",
  "segment": "FO",
  "instrument_category": "OPT",
  "expiry_date": "2026-07-16",
  "product": "MIS",
  "required_margin": 58000,
  "available_margin": 210000,
  "session_context": {
    "trades_today": 3,
    "session_pnl": -1200,
    "orders_in_last_5_min": 1,
    "recent_order_instruments": ["SENSEX2671677500PE"]
  }
}

session_context

Optional, but it changes the verdict. If omitted, we derive trades_today and session_pnl from the trades you've synced today — which means the state is only as fresh as your last sync, and orders_in_last_5_min cannot be reconstructed from settled fills at all.

The difference is not cosmetic. The same order, for the same client, measured against production:

Request Verdict
No session_context OK · proceed · nudge · 2 checks
With {"trades_today": 6, "session_pnl": -42000, "orders_in_last_5_min": 3, "recent_order_instruments": ["RELIANCE","RELIANCE"]} CRITICAL · abort · speed_bump · 7 checks, incl. Fomo Entry 62% and Averaging Down 52%

A client six trades into a ₹42,000 losing day, firing a third order in five minutes, is the exact case this product exists to catch — and it is invisible to us unless you send it. If you send one optional block, send this one.

Field Type Description
trades_today integer Trades placed today before this one. Drives overtrading detection.
session_pnl float Realised P&L for today so far (₹). Negative = loss. Drives revenge-trade flags.
orders_in_last_5_min integer Orders in the last 5 minutes. Drives rapid-fire / FOMO detection.
recent_order_instruments array Symbols from recent orders, for repeat-entry detection.

Margin

required_margin and available_margin come from your OMS — TradLyt has no broker session of its own for SDK clients. They drive the capital-adequacy check, which fails closed:

You send Behaviour
Both required_margin + available_margin Full check: ok / warning (>80% utilisation) / critical (order exceeds available). A critical result forces risk_level: CRITICAL and recommendation: abort.
required_margin only A yellow "verify capital manually" warning — never a silent approve.
Neither We fall back to quantity × price as the required estimate; if even that isn't computable, the capital check is simply omitted (behavioural + ML checks still run).

Response

{
  "user_ref": "CLIENT00423",
  "risk_level": "WARNING",
  "recommendation": "pause",
  "friction": "hard_warning",
  "friction_countdown": 15,
  "checks": [
    { "id": "revenge_trading", "label": "Revenge Trading", "status": "warning",
      "detail": "You're re-entering 4 min after a ₹1,200 loss." },
    { "id": "capital_check", "label": "Capital adequacy", "status": "ok",
      "detail": "Required margin ₹58,000 — 28% of available" }
  ],
  "danger_score": 61,
  "danger_level": "high",
  "bad_trade_risk": {
    "probability": 0.61, "severity": "warning", "method": "ml", "calibrated": true,
    "reasons": ["position value", "VIX (16)", "trend strength"]
  },
  "dominant_risks": ["revenge_trading"],
  "hold_time": { "p50": 18 },
  "size_suggestion": {
    "factor": 0.5, "action": "half", "p_loss": 0.58,
    "current_qty": 40, "suggested_qty": 20
  },
  "required_margin": 58000,
  "available_margin": 210000,
  "method": "rules+ml",
  "personal_edge": { "win_rate": 0.41 }
}
Field Type Description
risk_level enum OK / WARNING / CRITICAL. Top-level severity. Read this if you read one field.
recommendation enum proceed / pause / abort. The suggested action.
friction enum UX gate — escalates with risk. nudge = passive banner; speed_bump = a warning the client must actively acknowledge before proceeding; hard_warning = block the confirm button for a cool-off.
friction_countdown integer Seconds to hold the confirm button when friction is hard_warning.
checks[] array The specific reasons. Each has id, label, status (ok/warning/critical), and a human-readable detail. Render these.
bad_trade_risk object \| null Rafiki — probability (0–1) this trade ends badly, plus severity, method (ml / rule_based), and reasons: the top contributing features in plain words, e.g. ["position value", "VIX (16)", "trend strength"]. The reasons are safe to show a client. Note the base rate differs sharply by instrument — equity typically scores 0.05–0.10 and option legs 0.30–0.50, so compare a number against its own segment, never across.
dominant_risks array The top firing behaviours (pattern ids).
hold_time object \| null Typical hold-time quantiles for similar setups (guidance, not a target).
size_suggestion object \| null Matra — a de-risked quantity to offer as a one-tap alternative. suggested_qty is what you render; it is never larger than current_qty. action is full / trim / half / quarter, and factor the raw multiplier. Equity orders only — null for F&O, and null until the client has enough history for a baseline.
required_margin / available_margin number \| null Echoed back when the capital check ran.
method enum rules+ml (full), or rules+rules_fallback / rules_only when the ML service is unavailable — the verdict is still valid.
personal_edge object \| null The client's historical edge on this setup (e.g. win_rate).

The response carries a few further keys — danger_score, danger_level, ml_alerts, session_forecast, intent_results, ai_insight, loss_limit_triggered, and sizer (the raw model output behind size_suggestion). They are visible for debugging and may change shape without notice. The table above is the contract; don't couple your UI to anything outside it.

Rendering guidance

  • WARNING → show a dismissible warning with the checks[] reasons, and optionally offer the size_suggestion.
  • CRITICAL → block the order or require an explicit override.
  • Use friction + friction_countdown for the confirm-button cool-off.

Decision support, not an order gate

Treat the verdict as a signal — you own the final order flow. And if TradLyt is ever unreachable, fail open: let the order through rather than block your client on our availability.

Active patterns

The id values in checks[] and dominant_risks (and in stats) come from this set:

ID Description
revenge_trading Trade placed soon after a loss — matches the client's revenge-trade footprint.
fomo_entries Entry within seconds of a sharp move in the underlying.
paper_hands Client historically exits similar setups before they play out.
holding_losers Client tends to hold losers past their typical hold window.
averaging_down Adding to a losing position.
ignoring_stop_loss For options: letting premium decay past the usual exit without acting.
inconsistent_sizing Position size deviates sharply from the client's bucket average.
overtrading Trades today exceeded the client's personal cap.
afternoon_collapse Post-noon win rate significantly worse than morning.
expiry_gambling Buying weekly options on expiry day (0-DTE long premium).

Error reference

Status Cause
401 Missing or invalid subscription key.
403 Account suspended, or the pretrade feature isn't enabled.
404 user_ref not provisioned — call POST /users first.
429 Your account's request ceiling was exceeded — see Authentication.