Overview

This document provides detailed specs and math behind critical protocol functions.

Table of contents

Change List

<aside> 🚧 August 25, 2021 revised freeCollateral and buyingPower . Modeled all three configurations for different insolvency risk tolerance: conservative, moderate, aggressive. Currently we are using the conservative one

September 3, 2021 added pending funding payment to the model. Fixed realizedPnl should not use unrealizedPnl as its dependency. Minor fixes to all vQuote, vBase formulas

September 5, 2021 renamed vQuotePoolDebt to openNotionalFraction to match the naming in source codes. Added missing definitions for variables vQuoteLiquidity and vQuoteOwedFee. Revised market spec descriptions. Add references to Uniswap v3 whitepaper

September 14, 2021 merged avail and debt into balance. You can find the older version here

September 17, 2021 renamed totalImReq to openOrderMarginReq. Removed positionValue from openOrderMarginReq so traders could open new position when his existing position value increases in his favor. Revise criteria for cancelExcessOrders() and introduced two types of freeCollateral

September 27, 2021 revised cancelExcessOrder so a maker's open orders can always be cancelled when he is about to be liquidated

October 3, 2021 added an interactive chart for learning margin specs

October 19, 2021 add specs for liquidation fee, exchange fee, insurance fund fee and accounting

November 2, 2021 update quote debt spec to current implementation (calculate account debt instead of individual market debt)

November 4, 2021 added maker/taker position specs

November 9, 2021 update maker/taker position specs with detailed states during add/remove liquidity and swap

November 10, 2021 update buying power specs. It should depend on market and the direction of open positions

November 11, 2021 update realizedPnl spec to be based on taker position. Add missing specs for reversing position

April 21, 2023 update the spec to MarkPrice and update PositionValue is calculated based on Mark Price

</aside>

Migration from V1

Interactive Charts

Margin Specs

MarkPrice Specs

$$ \begin{aligned}

t &:= \text{epoch time in seconds} \\

d &:= \text{duration of time segment} \\\\

iTwap(t, d) &:= \text{index TWAP at the time point }t \text{ with duration } d\\\\

mTwap(t, d) &:= \text{market TWAP at the time point }t \text{ with duration } d\\\\

iP(t) &:= \text{index price at the time point }t \\\\

mP(t) &:= \text{market price at the time point }t \\\\

premium(t, d) &:= \text{premium at the time point }t \\ &= mTwap(t, d) - iTwap(t, d) \\\\

indexPrem(t, d) &:= iP(t) + premium(t, d) \\\\

markPrice(t) &:= median \space of \begin{cases} mTwap(t, 30\space mins) \\ indexPrem(t, 15 \space mins)\\ mP(t) \\ \end{cases}

\end{aligned} $$

Account Specs

$$ \begin{aligned} collateral &:= \text{balance of USDC in vault} \\\\ \text{settling } collateral &:= \begin{cases} collateral &\leftarrow collateral + owedRealizedPnl \\owedRealizedPnl &\leftarrow 0 \end{cases} \\\\ owedRealizedPnl &:= \text{realized PnL (in USD) that hasn't been settled(include funding payment and collected maker fees)} \\\\ \text{settling } funding &:= \begin{cases} owedRealizedPnl &\leftarrow owedRealizedPnl + pendingFundingPayment \\pendingFundingPayment &\leftarrow 0 \end{cases} \\\\ pendingFundingPayment &:= \text{funding payment (in USD) that hasn't been settled} \\\\ accountValue &= \underbrace{collateral + owedRealizedPnl + pendingFundingPayment + pendingFee}{totalCollateralValue} + \underbrace{\sum{market}{unrealizedPnl_{market}}}{totalUnrealizedPnl} \\&= collateral + owedRealizedPnl + pendingFundingPayment + pendingFee + \underbrace{\sum{market}{positionValue_{market}}}{totalPositionValue} + netQuoteBalance \\\\ netQuoteBalance &:= \text{quote position/exposure of this account(does not include pending fee or collected fees)} \\&= vQuote{balance} + vQuote_{inPool} \\ vQuote_{balance} &:= \text{unused (positive) or owed(negative) quote token of this account in a specific market} \\&= \sum_{market}{vQuote_{balance,market}} \\vQuote_{inPool} &= \sum_{market}{vQuote_{liquidity,market} + vQuote_{owedFee,market}} \\vQuote_{liquidity,market} &:= \text{amount of quote tokens the trader added to the market pool} \\vQuote_{owedFee,market} &:= \text{amount of the trader's unclaimed quote tokens as pool fees} \\\\ openOrderMarginReq(ratio) &:= \text{open order margin requirement (total collateral locked due to open orders)} \\&= (\sum_{market}{vBaseValue_{debt,market}} + vQuoteValue_{debt}) \times ratio \\\\ vBaseValue_{debt,market} &= vBase_{debt,market} \times vBaseMarkPrice_{market} \\vQuoteValue_{debt} &= vQuote_{debt} \times 1 \\vQuote_{debt} &= abs(min(0, \sum_{market}{vQuote_{balance,market}}))\\\\ imRatio &:= \text{initial margin requirement ratio} \\\\ freeCollateral_{withdrawal} &:= \text{amount of collateral available for withdrawal or opening new positions/orders} \\ &= freeCollateral(imRatio) \\\\ freeCollateral_{cancelOrder} &:= \text{negative means excess orders and can be cancelled} \\ &= freeCollateral(mmRatio) \\\\ freeCollateral(ratio) &= \begin{cases} min(totalCollateralValue, accountValue) - openOrderMarginReq(ratio), &\text{conservative, currently in use}\\ min(totalCollateralValue, accountValue - openOrderMarginReq(ratio)), &\text{moderate, Perp v1}\\ accountValue - openOrderMarginReq(ratio), &\text{aggresive, FTX}\end{cases} \\\\ buyingPower_{market,increasePosition} &= \frac{freeCollateral_{withdrawal}}{imRatio} \\buyingPower_{market,reversePosition} &= |positionValue_{market}| + buyingPower_{market,closed} \\buyingPower_{market,closed} &:= \text{estimated buying power after the current position is closed} \end{aligned} $$

Liquidation

$$ \begin{aligned}

accountMarginRatio &= \frac{accountValue}{\sum_{market}{|positionValue_{market}|}}\\\\

mmRatio &:= \text{maintenance margin ratio (account will be liquidated if its margin ratio falls below)} \\ accountMarginRatio &< accountMaintenanceMarginRatio \implies \text{liquidation (any market)!} \\\\ accountMaintenanceMarginRatio &= \frac{\sum_{market}{mmRatio_{market} \times |positionValue_{market}|}}{\sum_{market}{|positionValue_{market}|}} \\ &= \frac{mmRatio \times \sum_{market}{|positionValue_{market}|}}{\sum_{market}{|positionValue_{market}|}}, \text{ since currently all markets share the same mmRatio} \\ &= mmRatio \\\\

liquidationPenaltyRatio &:= \text{percentage paid by the trader to the liquidator when being liquidated} \\ liquidationFee &:= \text{actual amount paid by the trader to the liquidator} \\ &= exchangePositionNotional \times liquidationPenaltyRatio

\end{aligned} $$

<aside> 💡 Note regarding cross-margin:

Currently our system has a unified mmRatio for all markets (similarly to imRatio as mentioned below) so the calculation is relatively simpler. In the future, when mmRatio differs from market to market, consider the following:

When you have multiple positions in different markets (ex. ETH & BTC), your accountMaintenanceMarginRatio is based on the average of each market's mmRatio weighted by your positionValue. This means estimating liquidation prices might be tricky if you have many positions on different markets that performs differently. In other words, your specific position might get liquidated below or above its market's own mmRatio because it is influenced by the performance of your other positions.

Refer to our simulations below for more examples (look for the "cross-margin" tab).

Since our liquidation specs are similar to FTX's, you can refer to their article "How can I determine my liquidation risk?" for more details.

</aside>

<aside> 💡 TODO:

</aside>

Open Orders & Cancel Excess Orders