equation-sdk
Version:
🛠An SDK for building applications on top of Equation.
335 lines (319 loc) • 7.54 kB
text/typescript
import { BASIS_POINTS_DIVISOR, Q96, Side } from '../config';
import Decimal from 'decimal.js';
import {
abs,
div,
isGreaterThan,
isGreaterThanOrEqual,
isLessThan,
isPositive,
minus,
mulDiv,
multipliedBy,
plus
} from '../utils';
export class PositionUtil {
public static MIN_ENTRY_PRICE_X96 = 1;
public static chooseFundingRateGrowthX96(
_longFundingRateGrowthX96: string,
_shortFundingRateGrowthX96: string,
_side: Side
) {
return _side === Side.LONG
? _longFundingRateGrowthX96
: _shortFundingRateGrowthX96;
}
public static calculateMarginRate(
_entryPrice: string,
_size: string,
_price: string,
_liquidationFeeRate: number | string,
_tradingFeeRate: number | string,
_liquidationExecutionFee: string,
_marign: string
) {
const _maintenanceMargin = this.calculateMaintenanceMargin(
_entryPrice,
_size,
_price,
_liquidationFeeRate,
_tradingFeeRate,
_liquidationExecutionFee
);
return div(_maintenanceMargin, _marign);
}
/**
* @param _entryPrice
* @param _size
* @param _price
* @param _liquidationFeeRatePerPosition
* @param _tradingFeeRate
* @param _liquidationExecutionFee
* @returns
*/
public static calculateMaintenanceMargin(
_entryPrice: string,
_size: string,
_price: string,
_liquidationFeeRate: number | string,
_tradingFeeRate: number | string,
_liquidationExecutionFee: string
) {
const _liquidatioFee = plus(
multipliedBy(multipliedBy(_size, _entryPrice), _liquidationFeeRate),
_liquidationExecutionFee
);
const _tradingFee = multipliedBy(
multipliedBy(_size, _price),
_tradingFeeRate
);
return plus(_liquidatioFee, _tradingFee);
}
public static calculateLiqPrice(
_side: Side,
_netMargin: string,
_size: string,
_entryPrice: string,
_liquidationExecutionFee: string,
_liquidationFeeRate: string | number,
_tradingFeeRate: string | number
) {
if (!isPositive(_netMargin) || !isPositive(_size)) {
return '';
}
const openPositionValue = multipliedBy(_entryPrice, _size);
// const totalRate = plus(_liquidationFeeRate, tradingFeeRate);
// const divisor = _long? minus()
let liqPrice;
if (_side === Side.LONG) {
liqPrice = div(
plus(
div(
minus(
plus(
multipliedBy(openPositionValue, _liquidationFeeRate),
_liquidationExecutionFee
),
_netMargin
),
_size
),
_entryPrice
),
minus(1, _tradingFeeRate)
);
} else {
liqPrice = multipliedBy(
div(
minus(
div(
minus(
plus(
multipliedBy(openPositionValue, _liquidationFeeRate),
_liquidationExecutionFee
),
_netMargin
),
_size
),
_entryPrice
),
plus(1, _tradingFeeRate)
),
-1
);
}
return liqPrice;
}
public static calculateLeverage(_netMargin: string, _liquidity: string) {
return div(_liquidity, _netMargin);
}
public static calculateLiquidationPriceX96(
_side: Side,
_positionMargin: string,
_positionSize: string,
_positionLiquidity: string,
_fundingFee: string,
_liquidationFeeRate: string | number,
_tradingFeeRate: string | number,
_liquidationExecutionFee: string
) {
let marginAfter = _positionMargin;
if (isPositive(_fundingFee)) {
marginAfter = plus(marginAfter, _fundingFee);
} else {
const __fundingFee = abs(_fundingFee);
// invariant(isGreaterThanOrEqual(marginAfter, __fundingFee));
marginAfter = minus(marginAfter, __fundingFee);
}
if (_side === Side.LONG) {
let numerator = multipliedBy(
_positionLiquidity,
plus(BASIS_POINTS_DIVISOR, _liquidationFeeRate)
);
if (isGreaterThanOrEqual(marginAfter, _liquidationExecutionFee)) {
const numeratorPart2 = multipliedBy(
minus(marginAfter, _liquidationExecutionFee),
BASIS_POINTS_DIVISOR
);
// invariant(isGreaterThan(numerator, numeratorPart2));
numerator = minus(numerator, numeratorPart2);
} else {
const numeratorPart2 = multipliedBy(
minus(_liquidationExecutionFee, marginAfter),
BASIS_POINTS_DIVISOR
);
numerator = plus(numerator, numeratorPart2);
}
// if (isNegative(numerator)) {
// return '0';
// }
return mulDiv(
numerator,
Q96,
multipliedBy(
_positionSize,
minus(BASIS_POINTS_DIVISOR, _tradingFeeRate)
)
);
} else {
let numerator = multipliedBy(
_positionLiquidity,
minus(BASIS_POINTS_DIVISOR, _liquidationFeeRate)
);
if (isGreaterThanOrEqual(marginAfter, _liquidationExecutionFee)) {
const numeratorPart2 = multipliedBy(
minus(marginAfter, _liquidationExecutionFee),
BASIS_POINTS_DIVISOR
);
numerator = plus(numerator, numeratorPart2);
} else {
const numeratorPart2 = multipliedBy(
minus(_liquidationExecutionFee, marginAfter),
BASIS_POINTS_DIVISOR
);
// invariant(isGreaterThan(numerator, numeratorPart2));
numerator = minus(numerator, numeratorPart2);
}
return mulDiv(
numerator,
Q96,
multipliedBy(_positionSize, plus(BASIS_POINTS_DIVISOR, _tradingFeeRate))
);
}
}
/**
* @param _globalFundingRateGrowthX96
* @param _positionFundingRateGrowthX96
* @param _positionSize
* @returns
*/
public static calculateFundingFee(
_globalFundingRateGrowthX96: string,
_positionFundingRateGrowthX96: string,
_positionSize: string
) {
const fundingRateGrowthDeltaX96 = minus(
_globalFundingRateGrowthX96,
_positionFundingRateGrowthX96
);
if (isGreaterThanOrEqual(fundingRateGrowthDeltaX96, 0)) {
return mulDiv(fundingRateGrowthDeltaX96, _positionSize, Q96);
} else {
return String(
-mulDiv(
-fundingRateGrowthDeltaX96,
_positionSize,
Q96,
Decimal.ROUND_UP
)
);
}
}
/**
* @param _side
* @param _size
* @param _entryPriceX96
* @param _priceX96
* @returns
*/
public static calculateUnrealizedPnLByPriceX96(
_side: Side,
_size: string,
_entryPriceX96: string,
_priceX96: string
) {
if (_side === Side.LONG) {
if (isGreaterThan(_entryPriceX96, _priceX96)) {
return -mulDiv(
_size,
minus(_entryPriceX96, _priceX96),
Q96,
Decimal.ROUND_UP
);
} else {
return mulDiv(
_size,
minus(_priceX96, _entryPriceX96),
Q96,
Decimal.ROUND_DOWN
);
}
} else {
if (isLessThan(_entryPriceX96, _priceX96)) {
return -mulDiv(
_size,
minus(_priceX96, _entryPriceX96),
Q96,
Decimal.ROUND_UP
);
} else {
return mulDiv(
_size,
minus(_entryPriceX96, _priceX96),
Q96,
Decimal.ROUND_DOWN
);
}
}
}
public static calculateUnrealizedPnL(
_side: Side,
_size: string,
_entryPrice: string,
_price: string
) {
if (_side === Side.LONG) {
if (isGreaterThan(_entryPrice, _price)) {
return -multipliedBy(_size, minus(_entryPrice, _price));
} else {
return multipliedBy(_size, minus(_price, _entryPrice));
}
} else {
if (isLessThan(_entryPrice, _price)) {
return -multipliedBy(_size, minus(_price, _entryPrice));
} else {
return multipliedBy(_size, minus(_entryPrice, _price));
}
}
}
/**
* @param _isGradeThan
* @param _size
* @param _entryPrice
* @param _price
* @returns
*/
public static calculateTakeProfitStopLossPrice(
_isGradeThan: boolean,
_size: string,
_entryPrice: string,
_price: string
) {
if (_isGradeThan) {
return plus(div(_price, _size), _entryPrice);
} else {
return minus(_entryPrice, div(_price, _size));
}
}
}