Calculating liquidation price

Learn how to calculate any trade's liquidation price

Note: This guide works on Arbitrum Sepolia and requires exact beta SDK version of 0.2.12-rc15

To calculate liquidation price, we need to use SDK's getLiquidationPrice() function.

getLiquidationPrice: (trade: Trade, fee: Fee, initialAccFees: InitialAccFees, context: GetLiquidationPriceContext) => number;

TradeContainer

To calculate trade's liquidation price, we need to find a trade and its TradeContainer first. TradeContainer is unique object per single trade and is containing all its information.

By inspecting allTrades of backend's /trading-variables response, we're able to find all open trades & orders (each represented by single, unique TradingContainerBackend object). Lets pick last market trade (trade.type = 0 ) at time of writing this guide, which is:

{
    "trade": {
        "user": "0xa110CC27a19f6853e9Aa8Bb8e2C603D7b02ea2df",
        "index": "350",
        "pairIndex": "103",
        "leverage": "45000",
        "long": true,
        "isOpen": true,
        "collateralIndex": "3",
        "tradeType": "0",
        "collateralAmount": "1938800000",
        "openPrice": "47781798348",
        "tp": "57338158017",
        "sl": "0"
    },
    "tradeInfo": {
        "createdBlock": "72595369",
        "tpLastUpdatedBlock": "72595369",
        "slLastUpdatedBlock": "72595369",
        "maxSlippageP": "0",
        "lastOiUpdateTs": "0",
        "collateralPriceUsd": "0",
        "contractsVersion": "1",
        "lastPosIncreaseBlock": "72595369"
    },
    "liquidationParams": {
        "maxLiqSpreadP": "500000000",
        "startLiqThresholdP": "900000000000",
        "endLiqThresholdP": "650000000000",
        "startLeverage": "25000",
        "endLeverage": "60000"
    },
    "initialAccFees": {
        "accPairFee": "1461579560",
        "accGroupFee": "828216663",
        "block": "72595369"
    }
}

This response is of TradeContainerBackend type, therefore we need to properly convert it to TradeContainer type first (SDK uses client types). Converted and normalised trade will look like this:

{
    "trade": {
        "user": "0xa110CC27a19f6853e9Aa8Bb8e2C603D7b02ea2df",
        "index": 350,
        "pairIndex": 103,
        "leverage": 45,
        "long": true,
        "isOpen": true,
        "collateralIndex": 3,
        "tradeType": 0,
        "collateralAmount": 1938.8,
        "openPrice": 4.7781798348,
        "sl": 0,
        "tp": 5.7338158017
    },
    "tradeInfo": {
        "createdBlock": 72595369,
        "tpLastUpdatedBlock": 72595369,
        "slLastUpdatedBlock": 72595369,
        "maxSlippageP": 1,
        "lastOiUpdateTs": 1724162804,
        "collateralPriceUsd": 1.0000162,
        "contractsVersion": 1,
        "lastPosIncreaseBlock": 72595369
    },
    "liquidationParams": {
        "maxLiqSpreadP": 0.0005,
        "startLiqThresholdP": 0.9,
        "endLiqThresholdP": 0.65,
        "startLeverage": 25,
        "endLeverage": 60
    },
    "initialAccFees": {
        "accPairFee": 0.146157956,
        "accGroupFee": 0.0828216663,
        "block": 72595369
    }
}

Respective trade and initialAccFees objects will be used as first and third arguments of SDK's getLiquidationPrice() while liquidationParams and tradeInfo will be helpful when crafting fourth argument (context).

Fee

Lets focus on second getLiquidationPrice() argument now, which is Fee.

To find proper Fee object, we need to compute feeIndex for given trade first. By calling backend's /trading-variables we're getting pairs and fees arrays.

Remember that backend values should be normalised, see Pair vs PairBackend and Fee vs FeeBackend

With pairs and trade's pairIndex we compute feeIndex:

pairs[trade.pairIndex].feeIndex

Now we are able to find our Fee by simply accessing fees[feeIndex]. Resulting object should look similar to this:

{
    "openFeeP": 0.0003,
    "closeFeeP": 0.0006,
    "minPositionSizeUsd": 10000,
    "triggerOrderFeeP": 0.0002
}

Context

We've now covered 3 arguments and are left with last one, the GetLiquidationPriceContext.

There are few context parameters that we can pass here. All of them are coming from backend's /trading-variables endpoint or TradeContainer discussed above.

type GetLiquidationPriceContext = {
    currentBlock: number;
    groups: BorrowingFeeGroup[];
    pairs: BorrowingFeePair[];
    liquidationParams: LiquidationParams | undefined;
    pairSpreadP: number | undefined;
    collateralPriceUsd: number | undefined;
    contractsVersion: ContractsVersion | undefined;
}

currentBlock

Its current block of underlying network. Use any valid block or backend's /trading-variables response:

tradingVariables.currentBlock

groups and pairs

To get groups and pairs we need to inspect collaterals backend /trading-variables response. It is an array of objects corresponding to each supported collateral. Use trade.collateralIndex to select proper collateral object, then access its borrowingFees:

tradingVariables.collaterals[trade.collateralIndex - 1].borrowingFees

Remember that backend values should be normalised, see PairParamsBorrowingFees vs PairParamsBorrowingFeesBackend

liquidationParams

Available directly on TradeContainer

pairSpreadP

To get pairSpreadP inspect pairs key of backends /trading-variables response. It is an array of objects corresponding to each pair. Use trade.pairIndex to select proper pair:

tradingVariables.pairs[trade.pairIndex].spreadP

Should be normalised, see Pair vs PairBackend

collateralPriceUsd

Its similar to getting groups and pairs but select prices key after accessing proper collaterals entry:

tradingVariables.collaterals[trade.collateralIndex - 1].prices.collateralPriceUsd

contractsVersion

Available on TradeContainer:

tradeInfo.contractsVersion

At the end, the context passed to getLiquidationPrice() should look similar to this:

{
    "currentBlock": 72867071,
    "groups": [...],
    "pairs": [...],
    "liquidationParams": {
        "maxLiqSpreadP": 0.0005,
        "startLiqThresholdP": 0.9,
        "endLiqThresholdP": 0.65,
        "startLeverage": 25,
        "endLeverage": 60
    },
    "pairSpreadP": 0,
    "collateralPriceUsd": 1.0000328,
    "contractsVersion": 1
}

Calculate liquidation price

Wrapping all of the above, we should pass trade, fee, initialAccFees and context to SDK's getLiquidationPrice(). This should return single, float number. Per example above the return liquidation price is:

4.702126243307295

which matches gTrade's UI:

Last updated