Margin and liquidation
Each market holds its own collateral. Margin in the MON market does not support a position in the ETH market. The two markets use the same test risk constants.
Source: contracts/src/Market.sol, especially _exposure, _margin, accountState, withdraw, and liquidate.
Test constants
The margin constants, the return cap, and the seven-day horizon are test inputs. They are not approved launch parameters. They need separate calibration for each asset before use with real funds.
Account values
accountState(address) returns these values. The API returns the same fields in GET /account.
| Field | Meaning |
|---|---|
cash | Deposits, minus withdrawals, plus realized profit, plus funding, minus fees |
position | The book position in contracts. Positive is long. |
entry | The average entry price of the book position |
fundedPosition | The funding position. See delayed funding activation. |
funding, realized, fees | Cumulative totals of the account |
equity | cash + position * 100 * (mark - entry) |
initialMargin, maintenanceMargin | The two requirements below |
freeCollateral | The smaller of cash and equity - initialMargin, or zero |
liquidating | True while a liquidation of the account is not complete |
An account read includes the funding that is not yet stored. The contract stores it in cash when the account is next used.
Exposure
Margin uses the worst exposure of the account, not only the book position.
long exposure = max(position + resting buys, funding position, 0)
short exposure = max(resting sells - position, -funding position, 0)
exposure = max(long exposure, short exposure)Resting buys and resting sells include real orders, live ladder levels, and queued requests. A closed book position does not remove its funding position from this calculation.
Maintenance margin uses the book position and the funding position only. It does not include resting orders.
The margin formula
Margin has two parts: a reserve for a change of the mark, and a buffer for funding.
mark reserve = exposure * 100 * (0.25 + 0.5 * mark)
long loss = charge * gap limit / 31536000
funding loss = max(long exposure * long loss, short exposure * 0.0025)
funding buffer = funding loss * 100 * (365 / 7) * B| Requirement | Mark reserve | Buffer observations B |
|---|---|---|
| Initial margin | 100% of the mark reserve | 3 |
| Maintenance margin | 60% of the mark reserve | 1 |
A long reserves the fixed charge for the largest permitted gap. A short reserves the capped return. The gap limit is three observation intervals. Margin calculations round up.
Example
Take 41 contracts, a mark and a charge of 1.573, and a 60-second market. The gap limit is 180 seconds.
| Value | Long 41 | Short 41 |
|---|---|---|
| Mark reserve | 4,249.65 | 4,249.65 |
| Funding buffer, initial | 5.76 | 1,603.39 |
| Initial margin | 4,255.41 | 5,853.04 |
| Funding buffer, maintenance | 1.92 | 534.46 |
| Maintenance margin | 2,551.71 | 3,084.25 |
Values are in USDC before integer rounding. The short needs more margin, because one capped observation can cost the short much more than one interval of charge costs the long.
Checks at an order
| Moment | Check |
|---|---|
| Before matching | The full order size is added to the exposure. The exposure must be within the position limit, and the equity must cover initial margin. An order that only reduces the position skips the margin check. |
| At each fill, for the maker and the taker | The account after the fill must cover initial margin at the mark. During a mark freeze, it must also cover it at the execution price. |
| Before the remainder rests | The account must cover initial margin with the resting remainder. If not, the contract cancels the remainder. |
The position limit is 1,000 contracts for each account and direction. A session has its own lower limit. See Wallet and sessions.
Withdrawal
A withdrawal needs all of these conditions:
- The oracle is not halted, and no observation is due.
- The mark is valid after an update in the same call.
- The account is not in liquidation.
- The cash covers the amount.
- The equity after the withdrawal covers initial margin.
A positive freeCollateral value does not bypass the oracle gate or the mark gate. A closed book position can keep a funding position for one more observation. Its margin becomes free after that observation.
Liquidation
Any address can call liquidate(account, maxMatches).
- The call waits if the oracle is halted, an observation is due, or the mark is not valid. It then emits
LiquidationAttemptwithwaitingset. - An account with a book position must have equity below maintenance margin, or a
liquidatingflag from an earlier call. If not, the call reverts withHEALTHY. - The contract sets the
liquidatingflag, cancels the resting orders of the account, and takes its ladders out of the book. - The contract sends an IOC order that closes the book position against real book depth. The price limit is 25% from the current mark.
- A forced fill can only reduce the position. A full close clears the
liquidatingflag.
Liquidation can fill a part of the position, or it can find no liquidity. Call it again when depth is available. While the flag is set, the account cannot place orders or withdraw.
Liquidation reduces the book position. It cannot remove the funding position that the account keeps until the next observation.
No insurance fund
A deficit stays visible. LiquidationAttempt reports negative equity as a deficit. The build has no insurance fund and no rule that allocates bad debt. Positive equity in a market with deficits has no guarantee of payment.
The keeper command liquidate checks an account, simulates the call, and sends it. See Scripts and keeper commands.
Fees
The trade fee is 0.05% of size * 100 * execution price for each side of a fill. The contract records fees in the market. It has no fee withdrawal function.