Hedging the house's position
How exposure is measured, the three modes and who may switch them, how a hedge is sized, sent, followed and booked, the error rule that never sends an order twice, freezes and auto-pauses, the caps, and what your exchange must support.
Admin → Convert → Hedges (/admin/convert/hedge). Viewing needs
view.convert.hedge; resolving a hedge in review, unfreezing a currency and
reopening quoting need manage.convert.hedge, which no role holds until you
grant it.
After a user converts BTC into ETH, the house holds more BTC and less ETH than it meant to. Hedging sells the BTC and buys the ETH back on your exchange, with the house's own Spot balances, so the house returns to its targets and keeps the spread. It is off by default and needs an exchange provider.
Exposure
Exposure is recomputed from balances every time, never accumulated, so it survives crashes, restarts and missed events. For each currency:
E = house Spot balance (balance + in order)
+ what open hedges have yet to deliver
+ what house movements have in flight
− targetA positive E means the house is long and the hedger sells; a negative E means it is short and the hedger buys back. USDT is the currency every hedge trades against, so it is measured and reported, never hedged itself. A hedge in review counts as if it had filled until someone says otherwise, because that is the side that never hedges the same exposure twice.
Where hedging is enabled on both a currency's Spot and Ecosystem asset rows, its Ecosystem balance is folded in: the hedger trades the whole position on the exchange, and house movements carry coins between the two sides. Otherwise the Ecosystem side stays its own row, is never hedged out of Spot inventory (that would empty the Spot side with nothing to refill it) and is only capped.
The three modes
| Mode | What the hedge cycle does |
|---|---|
Off (off, the default) |
Measures exposure, so the dashboard, the caps and the disable check can read it. Plans and sends nothing. |
Monitor only (monitor) |
Measures, plans every currency and records what it would send. Trades nothing. Run this first. |
Automatic (auto) |
Plans, then sends market orders on your exchange with the house's funds. |
Pause hedging (convertHedgePause) stops every new hedge order, and every new
house movement, without changing the mode. Orders already sent are still
followed and booked.
The mode, the pause and the house-movement switch are edited in one place only: the core house page, Instant Convert house, which the House inventory button on Finance → Transaction Management → Pool Backing opens. It needs the Super Admin role and a fresh two-factor code, and works while the addon is disabled or unlicensed. The Convert settings page and the Controls tab here show them read-only with a link there. The limits beside them (threshold, caps, slippage, failures) are edited on the Convert settings page.
When and how much
The hedge job beats every 15 seconds and measures exposure on every
beat (the dashboard, the unhedged caps and the disable check read that
measurement). It goes on to plan and send only every
convertHedgeIntervalSeconds (default 15, so every beat; accepted 15 to 3600
seconds): after a run that planned, the next beats only measure until the
interval has passed. An exposure over the threshold is therefore hedged at the
next such run, never sooner. The job's own beat is the shortest interval
possible.
Each planning run, per currency, in Automatic mode:
- Whether. Only when |E| is worth at least
convertHedgeThresholdUsd(default $50). Smaller positions carry forward, which saves venue fees on dust. In drain mode the threshold does not apply: a drain runs until flat. - Which way. Always against USDT, never a direct pair: one direct order would move two currencies at once past a lock that only guards one.
- How much. Exactly |E|, never more, cut to the per-order cap, to what is left of the hourly cap, to the market's maximum and to what the house actually holds to spend, then truncated to the market's amount step. Below the market's minimum amount or cost, it waits.
- Reduce only. In every mode an order that would not shrink |E| is refused, so a stale plan or a sign that flipped under a convert can never grow the position.
What stops a dispatch: another cycle still running, the mode, a core below Convert level 2 and the hedge interval not yet passed; then, per currency, its asset's Hedging switch, a freeze, an auto-pause and the threshold; then the pause, an exchange ban or Convert's breaker, and a venue that charged a fee in a third currency the house cannot pay; and last, per currency, the caps and another hedge of it or of USDT in flight.
Sending an order, and never sending it twice
- Claim. In one transaction: lock rows for the currency and USDT, re-read E
under the locks, write the hedge row as
PLANNEDwith its client order ID (derived from the row id), and hold what the order will spend on the house's wallet. The venue's free balance includes your customers' coins, so it can never bound a hedge; the house's own balance does. - Top up the trading account where the venue splits accounts (KuCoin main to trade, OKX funding to trading). A refusal here sent nothing: the row fails, the hold goes back and the failure is counted.
- Stamp the row Sent (
DISPATCHED). From here the order may exist, and the row is never failed without proof. - Send a market order with the client order ID. The answer decides:
- a definite refusal before the order existed (insufficient funds, an invalid order or symbol, authentication, permission, rate limit): the row fails, the hold is returned, the failure is counted;
- anything else (a timeout, a 5xx, Binance's "execution status unknown"): the order may exist. It is never re-issued. On KuCoin, Binance and OKX the engine looks it up by client order ID and adopts it. On any other venue, or when the lookup finds nothing (which does not prove it is absent), the row goes to review and its currency is frozen on every venue.
- Follow. A market order is usually closed at once and is booked in the same run. One still open is left to the booking job.
Booking a fill
The booking job (every 15 seconds, and it keeps running while the addon is
disabled) books each fill exactly once, in the transaction that marks the row
Filled or Partly filled (FILLED, PARTIAL): the hold is settled, the
proceeds are credited to the house, the fee is taken, the locks are released.
- The fee comes from the fills in the order's own answer, else from the order's trades, never from the fetched order alone, which on Binance carries no fee. A fill whose fee is unknown on a venue that charges fees is never booked: it goes to review.
- A fee in the base or quote currency is netted. A fee in a third
currency (BNB) is debited from the house's own Spot BNB wallet, and that
debit is recorded as a house cost in the Profit & loss
(no
admin_profitrow: the house's wallet paid it). If the house holds no BNB, the fill goes to review and new hedges on that venue stop until it does. - Partly filled (
PARTIAL) is written only once the venue reports the order finished (closed, cancelled, expired, rejected). The booking job does not wait for ever: a market order still open 5 minutes after it was sent is cancelled and read back, and what filled is booked; one that still does not read as finished goes to review. An order the venue still cannot be asked about 30 minutes after it was sent goes to review, as does one sent to a venue that is no longer the platform's exchange. An order that ended with nothing filled is marked failed, its hold returned, and it counts towards the failures in a row. A hedge left Planned because its dispatcher stopped before stamping it Sent is marked failed after 2 minutes, its hold returned: nothing was ordered. - Hedges write no exchange-order rows, so the nightly venue-fee job never books their fee a second time.
Review, freeze and unfreeze
A hedge in Needs review keeps its currency frozen: nothing new is sent for it on any venue until a person decides. The review dialog shows the venue's recorded answer and offers three decisions:
| Decision | When | What you enter |
|---|---|---|
| Confirm fill | the venue shows the order finished | the final filled amount, the cost, the fee and its currency exactly as the venue's trade history shows them (or tick no fee); a price far from the mid at dispatch needs a tick to confirm you checked it |
| Mark failed | the venue shows no such order | a reason of at least ten characters and the client order ID typed back. Refused once any part is booked as filled |
| Look it up again | you want the engine to search the venue by client order ID again | nothing. If it finds the order it books it; if not the row stays in review |
Marking an order failed returns its hold and lets the hedger trade that currency again. If the order did execute, its position is left unbooked and is hedged a second time.
Once no hedge of a currency is in review, Unfreeze it on the Exposure tab. That clears the freeze, any auto-pause, the failure count and any quoting closure; the next cycle may send an order for it. Unfreeze is refused while any hedge of the currency is still in review (for USDT, while any hedge at all is).
Automatic stops
- Failures in a row. After
convertHedgeMaxFailures(default 3) failed hedges in a row (a definite refusal by the venue, a trading-account top-up that failed before any order was sent, or an order that ended with nothing filled), hedging of that currency pauses for one hour and lifts on its own, or when someone unfreezes it. A booked fill resets the count; the count survives the pause, so one more failure pauses it again at once. - Slippage. A fill whose average is worse than the mid captured at dispatch
by more than
convertHedgeMaxSlippageBps(default 100 bps) pauses hedging of that currency for an hour and closes quoting of it: the book the house prices from is not the market it trades in. A fill better than the mid never trips it. - Quoting closed (the Exposure tab's Converts closed badge) also follows unacknowledged pool-backing drift on the currency: a quote or a convert finds it at once, and the quote-cleanup job every five minutes. A closure is a latch: it stays until someone uses Reopen quoting on the Exposure tab, or Unfreeze where the currency's hedging is also frozen or paused (Unfreeze lifts the closure with the freeze). Reopen quoting is refused until the drift is acknowledged under Finance → Transaction Management → Pool Backing; Unfreeze is not, but while the drift is still unacknowledged the currency closes again at the next quote or cleanup run. Acknowledging the drift does not reopen quoting by itself.
Caps
| Setting | Default | Effect |
|---|---|---|
convertMaxHedgeUsdPerOrder |
$5,000 | No single hedge order is worth more. 0 stops hedging. Super Admin only. |
convertMaxHedgeUsdPerHour |
$50,000 | All hedge orders in any rolling hour. 0 stops hedging. Super Admin only. |
convertMaxUnhedgedUsd |
$25,000 | Converts that would take the house's total unhedged exposure past this are refused; one that reduces it is always allowed. Super Admin only. |
| an asset's Max unhedged (USD) | none | The same cap for one currency. |
A convert refused by an exposure cap reads Convert to ETH is temporarily unavailable, the same sentence as an empty inventory, so the refusal tells a user nothing about your position. Size the unhedged cap above your largest single convert, with room for a cycle's worth of flow.
What your exchange must support
- It must be the platform's active exchange provider. Hedges trade on the same account and connection Spot trading uses.
- Market orders on each hedged currency against USDT, and the ability to read an order and its trades back.
- Adoption by client order ID works on KuCoin, Binance and OKX only. On any other venue an ambiguous answer to an order goes straight to review and freezes the currency until someone checks the venue by hand. Hedging still works there; it needs a person more often.
- A fee paid in a third currency needs the house to hold that currency on Spot.
- There is no sandbox. Start in Monitor only for a day. Then switch to
Automatic with a small
convertMaxHedgeUsdPerOrderand watch the journal for an hour of real converts before raising it.
Draining before you switch off
Mode → Drain (Settings, General tab) closes quoting and lets the hedger run until every currency is flat, ignoring the threshold and only ever reducing exposure. Run it before disabling the addon, so it is not switched off holding a position nobody is watching. The Hedges page carries a notice while drain is on.