Risk & safety
Read the /risk dashboard — drawdown, daily-loss and per-trade gauges, the kill-switch, circuit breakers, recovery state — and know when to escalate.
The Risk & Safety page (/risk) is the single screen where you watch every guardrail that stands between a strategy and your capital. It shows the live state of the kill-switch, the daily-loss halt, per-trade exposure, the exchange circuit breakers, and any active position recovery. This page is for operators: it tells you what each field means, what a healthy reading looks like, and when a value should make you stop and intervene.
Most of these controls only bite in live trading. In beta the app hard-locks to paper — publicly the "candidate" stage — so the gauges still populate, but no real orders are ever placed. Read this page now so the controls are familiar before any of them matter.
Forven is a research tool. Nothing here is a prediction, a recommendation, or financial advice. Risk controls limit downside; they do not create an edge, and no setting guarantees against loss.
Where this lives
- UI: the
/riskpage. A condensed version is embedded in the home dashboard for a quick glance. - Data: a single read-only endpoint,
GET /api/risk, returns the whole state in one payload. The page is a view over it — operator actions (resetting the kill-switch) are separate POST endpoints.
The risk view is read-only by design. Every field below is something you observe; the few actions you can take from this page (reset kill-switch, emergency halt) are explicit, confirmed buttons.
How to read each field
The sections below map one-to-one to what /api/risk returns and what the page renders.
Execution mode
execution_mode is either paper or live. In beta this always reads paper — the lock is applied where the mode is read, so even a stale live value in config.json can never take effect. If you see paper here, no order can reach the exchange regardless of any other setting. See execution modes for the full paper-vs-live distinction.
System pause
Shows whether the system is paused or running. A pause stops the scanner and execution loops entirely. This is distinct from the kill-switch: a pause is a deliberate operator "stop everything" from ops; the kill-switch is an automatic reaction to drawdown.
Kill-switch
The kill-switch is the drawdown circuit breaker. It is the most important field on the page.
kill_switch_active—trueonce the switch has tripped. While active,is_trading_allowed()returns false and no new positions open.kill_switch_triggered_at— the timestamp of the trip, so you know when the breach happened.
It trips automatically when portfolio drawdown reaches max_drawdown_pct (default 10%, illustrative — configurable in the range 1–30). On trip, the system runs an emergency-close loop over every live position, halts trading, and waits for you. Drawdown is measured against the high-water mark (HWM) — the peak equity since the last reset — as 1 - current_equity / HWM.
A tripped kill-switch is the clearest "escalate now" signal on the page. See risk controls for how the switch interacts with the other limits.
Daily-loss halt
daily_loss_halt—truewhen same-day realized PnL has fallen pastmax_daily_loss_pct(default 5%, illustrative, range 0.5–10).daily_start_equity— the equity snapshot the day's loss is measured from.daily_date— the UTC day the halt applies to.
A daily-loss halt blocks new trades for the rest of the current UTC day. It clears on its own at UTC midnight when the day's start-of-day equity resets — there is no manual reset, and no action needed unless the halt is firing daily, which suggests a strategy worth reviewing rather than a control to override.
Portfolio summary
Account-level numbers, read from the wallet in live mode: current equity, margin used, withdrawable, and the active network (testnet or mainnet). account.network and recovery_network should agree; a mismatch is worth investigating.
Risk limits
The configured caps, shown so you can see the active policy at a glance: max_drawdown, daily_loss, per_trade, portfolio_budget, and min_risk_reward_ratio. These are the limits, not the current usage. Change them in Settings → Trading; the next portfolio-risk check reads the new values.
Current per-trade risk
current_per_trade_risk is the risk percentage of the largest open position — your single most exposed trade right now, measured against max_risk_per_trade_pct (default 2%, illustrative). Every order is checked against this cap at submit time via can_open(), and oversized orders are rejected fails-closed with risk_limit_exceeded. If this gauge sits near the limit, you have little headroom for the next signal.
Open positions
Two counts, deliberately separated:
open_positions— live positions in the shared HyperLiquid wallet.open_positions_paper— positions across isolated paper sessions.
These do not add together. Live execution pools every active strategy into one wallet, so max_concurrent_positions applies globally to the live pool. Paper sessions stay isolated per session and never share capital with live trading.
Circuit breakers
Three exchange-health circuit breakers guard calls to HyperLiquid. Each shows a state in the CLOSED → OPEN → HALF_OPEN machine:
| Breaker | Watches | Trips after | Timeout |
|---|---|---|---|
hl_price | price-feed reads | 5 failures | 20s |
hl_trade | order submission | 3 failures | 30s |
hl_account | account / wallet reads | 4 failures | 25s |
- CLOSED — healthy, requests flow normally.
- OPEN — tripped; calls are short-circuited until the timeout elapses.
- HALF_OPEN — one test request is allowed; success closes the breaker, failure re-opens it immediately.
Crucially, a 429 rate-limit does not trip a breaker on signed order submits — those retry with bounded backoff (0.5s up to 4s). Only true outages (5xx, connection errors) open a breaker. This is intentional: it keeps the emergency-close path alive during rate-limit bursts. A breaker stuck OPEN after its timeout means the exchange link is genuinely unhealthy — escalate.
Recovery status
When the system reconciles its records against the exchange, the recovery fields populate: recovery_active, recovery_status, recovery_position_count, recovery_discrepancy_count, a batch ID, and recovery_network. Phantom recovery runs at startup and periodically (about every 30 minutes). It reads HyperLiquid orders and positions, compares them to the local trade records, and fixes mismatches — creating a trade record for a filled position that has none (a phantom position), or aging out a stale pending_open_reconcile trade after the slot-free window (180s, illustrative). A non-zero recovery_discrepancy_count that does not clear on the next cycle is your cue to look closer; a recovered phantom trade is not linked to a strategy and may need manual review.
Operator actions from this page
Reset the kill-switch
Once you have understood why drawdown breached and you are ready to allow trading again, reset the switch. This calls POST /api/ops/reset-kill-switch, which clears kill_switch_active and re-baselines the high-water mark to current equity.
# Reset the kill-switch (operator-only; requires confirmation in the UI)
Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:8003/api/ops/reset-kill-switch"Resetting is destructive to drawdown tracking. Re-baselining the HWM to current equity means the next kill-switch threshold is measured from the reset point, not the original peak. If you reset after a 20% drawdown, a further 10% fall from there is a 28% fall from the original peak before the switch fires again. Reset only when you have addressed the cause, not to silence the alarm.
Emergency halt
The page exposes an emergency-halt action that disables all trading immediately. Treat it as the manual companion to the automatic kill-switch — pull it when something is wrong and you want everything to stop while you investigate. It requires confirmation.
When to escalate
Use this quick triage when the page is not all green:
- Kill-switch active → trading is already halted. Find the drawdown cause before you reset; reset re-baselines the HWM (see above).
- A close failed during a kill-switch sweep (
close_reason='kill_switch_close_fail') → a position stayed open after retries. This needs a human: review and close it manually. - Circuit breaker stuck OPEN past its timeout → the exchange link is unhealthy, not just rate-limited. Check HyperLiquid connectivity.
- Recovery discrepancies that don't clear → a phantom or mismatched position. Review the recovered trade; it may be unlinked to any strategy.
- Per-trade risk pinned at the limit → no headroom; expect new entries to be rejected as
risk_limit_exceeded. - Daily-loss halt firing repeatedly → not an emergency, but a signal the live strategy is leaking. Review it rather than overriding.
Caveats
- In beta, execution is paper-locked. Live-only fields (real equity, live position counts, recovery) will be empty or zero until live trading is unlocked.
- Paper PnL is not a proxy for live PnL. Paper trades fill at local candle prices, carry no exchange order ID, and are never reconciled against the exchange.
- The kill-switch only triggers when the HWM is known. If the high-water mark is unset or zero, drawdown cannot be computed and the switch will not fire — HWM is synced from the account at startup.
- Defaults quoted here (10% drawdown, 5% daily loss, 2% per trade, 180s recovery window) are illustrative defaults, not recommendations. Tune them to your own risk budget.
Related
- Risk controls — the hard limits behind these gauges and how they interact.
- Circuit breakers — the exchange-health state machine in depth.
- Going live safely — the checklist before any real capital.
- Live trading — monitoring real positions once a strategy graduates.
Live trading
Monitor live positions, strategy containers, and trading gates on the /trades workspace — what each panel shows and how to act on real capital safely.
Approvals
The operator review queue that gates code changes and capital-tier promotions — pending vs history, the smart classifier, approval modes, and bulk actions.