@quantara/sdk
Version:
JavaScript/TypeScript SDK for interacting with Quantara Protocol on Neura Testnet
133 lines (132 loc) • 5.93 kB
JavaScript
import { BASIS_POINTS_DIVISOR_BIGINT, DEFAULT_ACCEPTABLE_PRICE_IMPACT_BUFFER } from "../configs/factors";
import { OrderType } from "../types/orders";
import { TriggerThresholdType } from "../types/trade";
import { bigMath } from "./bigmath";
import { getPriceImpactByAcceptablePrice } from "./fees";
import { getCappedPositionImpactUsd } from "./fees";
import { expandDecimals, getBasisPoints } from "./numbers";
import { roundUpMagnitudeDivision } from "./numbers";
import { applyFactor } from "./numbers";
import { convertToTokenAmount } from "./tokens";
export function getMarkPrice(p) {
const { prices, isIncrease, isLong } = p;
const shouldUseMaxPrice = getShouldUseMaxPrice(isIncrease, isLong);
return shouldUseMaxPrice ? prices.maxPrice : prices.minPrice;
}
export function getShouldUseMaxPrice(isIncrease, isLong) {
return isIncrease ? isLong : !isLong;
}
export function getOrderThresholdType(orderType, isLong) {
// limit increase order
if (orderType === OrderType.LimitIncrease) {
return isLong ? TriggerThresholdType.Below : TriggerThresholdType.Above;
}
// stop market order
if (orderType === OrderType.StopIncrease) {
return isLong ? TriggerThresholdType.Above : TriggerThresholdType.Below;
}
// take profit order
if (orderType === OrderType.LimitDecrease) {
return isLong ? TriggerThresholdType.Above : TriggerThresholdType.Below;
}
// stop loss order
if (orderType === OrderType.StopLossDecrease) {
return isLong ? TriggerThresholdType.Below : TriggerThresholdType.Above;
}
return undefined;
}
export function getAcceptablePriceInfo(p) {
const { marketInfo, isIncrease, isLong, indexPrice, sizeDeltaUsd, maxNegativePriceImpactBps } = p;
const { indexToken } = marketInfo;
const values = {
acceptablePrice: 0n,
acceptablePriceDeltaBps: 0n,
priceImpactDeltaAmount: 0n,
priceImpactDeltaUsd: 0n,
priceImpactDiffUsd: 0n,
};
if (sizeDeltaUsd <= 0 || indexPrice == 0n) {
return values;
}
const shouldFlipPriceImpact = getShouldUseMaxPrice(p.isIncrease, p.isLong);
// For Limit / Trigger orders
if (maxNegativePriceImpactBps !== undefined && maxNegativePriceImpactBps > 0) {
let priceDelta = bigMath.mulDiv(indexPrice, maxNegativePriceImpactBps, BASIS_POINTS_DIVISOR_BIGINT);
priceDelta = shouldFlipPriceImpact ? priceDelta * -1n : priceDelta;
values.acceptablePrice = indexPrice - priceDelta;
values.acceptablePriceDeltaBps = maxNegativePriceImpactBps * -1n;
const priceImpact = getPriceImpactByAcceptablePrice({
sizeDeltaUsd,
acceptablePrice: values.acceptablePrice,
indexPrice,
isLong,
isIncrease,
});
values.priceImpactDeltaUsd = priceImpact.priceImpactDeltaUsd;
values.priceImpactDeltaAmount = priceImpact.priceImpactDeltaAmount;
return values;
}
values.priceImpactDeltaUsd = getCappedPositionImpactUsd(marketInfo, isIncrease ? sizeDeltaUsd : sizeDeltaUsd * -1n, isLong, {
fallbackToZero: !isIncrease,
});
if (!isIncrease && values.priceImpactDeltaUsd < 0) {
const minPriceImpactUsd = applyFactor(sizeDeltaUsd, marketInfo.maxPositionImpactFactorNegative) * -1n;
if (values.priceImpactDeltaUsd < minPriceImpactUsd) {
values.priceImpactDiffUsd = minPriceImpactUsd - values.priceImpactDeltaUsd;
values.priceImpactDeltaUsd = minPriceImpactUsd;
}
}
if (values.priceImpactDeltaUsd > 0) {
values.priceImpactDeltaAmount = convertToTokenAmount(values.priceImpactDeltaUsd, indexToken.decimals, indexToken.prices.maxPrice);
}
else {
values.priceImpactDeltaAmount = roundUpMagnitudeDivision(values.priceImpactDeltaUsd * expandDecimals(1, indexToken.decimals), indexToken.prices.minPrice);
}
const acceptablePriceValues = getAcceptablePriceByPriceImpact({
isIncrease,
isLong,
indexPrice,
sizeDeltaUsd,
priceImpactDeltaUsd: values.priceImpactDeltaUsd,
});
values.acceptablePrice = acceptablePriceValues.acceptablePrice;
values.acceptablePriceDeltaBps = acceptablePriceValues.acceptablePriceDeltaBps;
return values;
}
export function getAcceptablePriceByPriceImpact(p) {
const { indexPrice, sizeDeltaUsd, priceImpactDeltaUsd } = p;
if (sizeDeltaUsd <= 0 || indexPrice == 0n) {
return {
acceptablePrice: indexPrice,
acceptablePriceDeltaBps: 0n,
priceDelta: 0n,
};
}
const shouldFlipPriceImpact = getShouldUseMaxPrice(p.isIncrease, p.isLong);
const priceImpactForPriceAdjustment = shouldFlipPriceImpact ? priceImpactDeltaUsd * -1n : priceImpactDeltaUsd;
const acceptablePrice = bigMath.mulDiv(indexPrice, sizeDeltaUsd + priceImpactForPriceAdjustment, sizeDeltaUsd);
const priceDelta = (indexPrice - acceptablePrice) * (shouldFlipPriceImpact ? 1n : -1n);
const acceptablePriceDeltaBps = getBasisPoints(priceDelta, p.indexPrice);
return {
acceptablePrice,
acceptablePriceDeltaBps,
priceDelta,
};
}
export function getDefaultAcceptablePriceImpactBps(p) {
const { indexPrice, sizeDeltaUsd, priceImpactDeltaUsd, acceptablePriceImapctBuffer = DEFAULT_ACCEPTABLE_PRICE_IMPACT_BUFFER, } = p;
if (priceImpactDeltaUsd > 0) {
return BigInt(acceptablePriceImapctBuffer);
}
const baseAcceptablePriceValues = getAcceptablePriceByPriceImpact({
isIncrease: p.isIncrease,
isLong: p.isLong,
indexPrice,
sizeDeltaUsd,
priceImpactDeltaUsd,
});
if (baseAcceptablePriceValues.acceptablePriceDeltaBps < 0) {
return bigMath.abs(baseAcceptablePriceValues.acceptablePriceDeltaBps) + BigInt(acceptablePriceImapctBuffer);
}
return BigInt(acceptablePriceImapctBuffer);
}