Running the desk

The operator's daily screens — the risk desk, client accounts and the kill-switch, orders and positions, the immutable deals ledger, manual adjustments and withdrawal approvals.

6 min readUpdated 6 August 2026admin, risk, exposure, ledger, withdrawals, kill-switch

The admin lives at /admin/forex-trading and is organised the way a desk actually works: the risk desk first, then the book, then the money, then setup.

Screen Path What it answers
Risk Desk /admin/forex-trading Am I about to lose money
Accounts /admin/forex-trading/account Who is trading and can I stop them
Positions /admin/forex-trading/position What is open right now
Orders /admin/forex-trading/order What is waiting to happen
Deals Ledger /admin/forex-trading/deal Where did the money go
Withdrawals /admin/forex-trading/withdraw What is waiting on me
Execution /admin/forex-trading/execution Is my hedging healthy
Market Data /admin/forex-trading/provider and below Setup
Settings /admin/forex-trading/settings Policy

The Risk Desk

The operator risk snapshot, polled by the dashboard

This is the B-book survival dashboard, and on a desk carrying its own risk it is the screen to leave open.

Net exposure by symbol. Client longs minus shorts, in lots and USD notional, per instrument. On a pure B-book install every unit of that is your exposure — if clients are net long 40 lots of gold and gold rises, you pay. With A-book routing enabled the same block splits into the internal net (yours) and the external net (hedged one-for-one at a broker), plus the broker-side net and the delta between them, taken from the reconciler's exposure snapshot when it is fresh. A snapshot older than five minutes is not shown inline rather than masquerading as live data.

Accounts at risk. Every account near its margin-call or stop-out level, sorted worst first. Two things put an account on this list: a margin level approaching the tier's threshold, and holding a position on a symbol that is not currently quoting — the second one is the dangerous case, because that account's equity cannot be marked and its stop-out cannot fire.

Client balances against equity. Aggregate balance versus aggregate equity across the book. A widening gap in your favour is unrealised client losses; the reverse is unrealised client profit you will eventually have to pay.

Quoting health. Every instrument with its current state and the age of its last tick. This is where a dying feed shows up before customers notice.

Hedge monitor. A-book installs only. One card per enabled execution provider with its NAV, margin used, margin-use ratio, closeout percentage, how long ago it was synced, whether it is degraded, and how many alerts on it are unacknowledged. Providers that have been disabled but still carry open external positions appear here too, marked as draining — so "am I hedged" stays answerable mid-drain.

Everything on this screen is aggregated in SQL. No query returns a row per open position, which is what keeps it usable on a busy book.

The daily routine

  1. Open the Risk Desk. Read net exposure first. If one symbol dominates, decide whether you are comfortable carrying it, or widen that group's spread, or route it externally.

  2. Work the at-risk list. Anything holding positions on a non-quoting symbol is an incident, not a data point — fix the feed.

  3. Clear the withdrawal queue. Approvals are the only step in the money path that waits on a human.

  4. Check the alert inbox if you run A-book. Unacknowledged critical alerts are the ones that cost money.

  5. Scan the deals ledger for ADJUSTMENT and NBP_CORRECTION entries you did not expect.

Client accounts

Paginated browser over every trading account with owner context
Admin controls on one account

From the account row you can change:

  • Trading enabled — the kill-switch. Setting it false blocks every new order on that account while still allowing closes. It is the correct response to suspected abuse, a disputed fill or a compliance hold, and it does not trap the customer's money.
  • Leverage — the account's own knob. Remember effective leverage is the minimum of this, the symbol group and the account tier cap.
  • Account group — move a customer between risk tiers.
  • Withdraw limits — daily and monthly, per account.
  • Swap-free — the Islamic-account flag, honoured on groups where swapFreeAllowed is true.

Balance is deliberately not editable here.

Manual adjustments

Books a reason-coded manual adjustment through the ledger

Goodwill credits, error corrections and compensation all go through this endpoint, which writes an ADJUSTMENT deal.

The account balance is a denormalisation of the deals ledger. The reconciler verifies that the ledger sums to the balance every five minutes and raises a critical ledger drift alert — by email, to every Super Admin — when it does not. A direct UPDATE fx_account SET balance will set that alarm off within five minutes and leave you unable to tell a real accounting problem from your own edit.

Orders and positions

All orders across every account
All positions across every account

Order statuses you will see:

Status Meaning
OPEN A pending order resting, waiting for its level
TRIGGERED Level crossed, fill in progress
ROUTING A-book only — intent journaled, awaiting broker confirmation
FILLED Done
CANCELLED Cancelled by the customer
REJECTED Refused at trigger, usually on margin, or refused by the venue
EXPIRED A GTD or DAY order that ran out of time

Positions are OPEN, CLOSED or LIQUIDATED, and every close records why. Six reasons are ever written:

closeReason Written by
SL The risk engine, when the customer's stop loss is hit
TP The risk engine, when the take profit is hit
TRAILING The risk engine, when the trailing stop is hit
STOP_OUT The same engine's stop-out loop; the position also ends LIQUIDATED
ADMIN Force-close below, the orphan book late action, and the reconciler booking a close your broker made server-side
MANUAL Everything else — it is the default in utils/engine/execution.ts for any close that does not name a reason, so an ordinary customer close lands here

The validator on models/ext/forex-trading/fxPosition.ts also accepts GAP, DELISTED and CORPORATE_ACTION. No code path produces any of them. GAP is a member of the reason union in utils/engine/execution.ts with no caller; DELISTED and CORPORATE_ACTION appear nowhere in the backend as a close reason at all — DELISTED elsewhere is an instrument status, which is a different column on a different table.

They are left in place because they are real enum values a row could carry, so you may still meet one in the database. If you do, the platform did not write it: it came from an import, another system, or a hand-edited row. A delisting or a corporate action is handled today by force-closing the positions, which stamps ADMIN.

Force-closing

Force-closes a position at the current market

Reserved for dispute resolution, toxic flow and corporate actions. It settles through the same execution service a customer close uses, so the deals ledger stays consistent and the close is stamped ADMIN. The customer sees the position close at a real price with real P&L.

The deals ledger

The immutable money ledger, every balance-affecting event

This is the audit source of truth and it is append-only. Each row carries the executed price, the raw feed bid and ask at the moment of the fill, any conversion rate used, and the balance the account was left with.

The raw feed prices are the important part. When a customer claims they were filled at a bad price, the ledger shows both what the provider was quoting and what your markup made of it, in the same row.

Deal kind Written when
OPEN A position opens
CLOSE / PARTIAL_CLOSE A position closes, wholly or partly
COMMISSION Commission charged at open
SWAP Overnight financing at the 17:00 New York rollover
DIVIDEND A dividend on a stock CFD, where the provider supplies them
DEPOSIT / WITHDRAW Transfers to and from the platform wallet
WITHDRAW_REVERSAL A rejected withdrawal refunded
ADJUSTMENT An operator adjustment
NBP_CORRECTION Negative-balance protection zeroing an account

An NBP_CORRECTION is money you have written off. It should be rare; a pattern of them means your stop-out level is too low, your leverage too high, or a symbol is gapping past your stops.

Withdrawal approvals

The pending withdrawal queue
Approve or reject one withdrawal

The money has already left the trading account by the time you see the request — that happened at request time, under the free-margin gate. Your decision moves it the rest of the way, or puts it back.

  • COMPLETED credits the destination platform wallet.
  • REJECTED refunds the trading account with a WITHDRAW_REVERSAL deal.

If the trading account's balance has gone negative since the request — the customer was stopped out while the withdrawal sat in the queue — approving is refused. The response names the deficit and tells you to pass an explicit confirmation to override. In almost every case the right answer is to reject: that refunds the trading account and covers the shortfall.

Approve and reject are guarded by a row lock, so two operators clicking at the same time cannot both apply.

Permissions

Every screen and endpoint is gated. Grant these under Users → Roles & Permissions; nothing is granted by default and Super Admin bypasses the check entirely.

A read-only risk analyst needs view.forex_trading.risk, view.forex_trading.account, view.forex_trading.position, view.forex_trading.order and view.forex_trading.deal.

A dealing-desk operator adds edit.forex_trading.account (the kill-switch), edit.forex_trading.position (force close), create.forex_trading.adjustment and edit.forex_trading.withdraw.

A setup administrator adds the instrument, group, calendar, provider and settings keys. The full list is in the settings reference.

fxTradingExternalRoutingEnabled is rejected with a 403 by the extension's own settings endpoint no matter what permissions the caller holds — it is writable only through the core system settings page, where the protected-keys check enforces Super Admin. That is the switch that starts sending real client flow to a real broker.

Next