fix signal and get position during closing
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Globalization;
|
||||
using Managing.Core;
|
||||
using Managing.Domain.Candles;
|
||||
using Managing.Domain.Users;
|
||||
@@ -34,7 +35,7 @@ namespace Managing.Domain.Strategies
|
||||
StrategyType = strategyType;
|
||||
User = user;
|
||||
|
||||
Identifier = $"{StrategyType}-{direction}-{ticker}-{candle?.Close}-{date:yyyyMMdd-HHmmss}";
|
||||
Identifier = $"{StrategyType}-{direction}-{ticker}-{candle?.Close.ToString(CultureInfo.InvariantCulture)}-{date:yyyyMMdd-HHmmss}";
|
||||
SignalType = signalType;
|
||||
}
|
||||
|
||||
|
||||
@@ -660,7 +660,9 @@ public class EvmManager : IEvmManager
|
||||
{
|
||||
account = account.Key,
|
||||
ticker = ticker.ToString(),
|
||||
direction = direction.ToString(),
|
||||
direction = direction == TradeDirection.Long
|
||||
? TradeDirection.Short.ToString()
|
||||
: TradeDirection.Long.ToString(),
|
||||
});
|
||||
trade = new Trade(
|
||||
DateTime.UtcNow,
|
||||
|
||||
@@ -15,483 +15,481 @@ import {EntryField, SidecarSlTpOrderEntryValid} from "../../types/sidecarOrders.
|
||||
|
||||
/** Base Optional params for helpers, allows to avoid calling markets, tokens and uiFeeFactor methods if they are already passed */
|
||||
interface BaseOptionalParams {
|
||||
marketsInfoData?: MarketsInfoData;
|
||||
tokensData?: TokensData;
|
||||
uiFeeFactor?: bigint;
|
||||
marketsInfoData?: MarketsInfoData;
|
||||
tokensData?: TokensData;
|
||||
uiFeeFactor?: bigint;
|
||||
}
|
||||
|
||||
export type PositionIncreaseParams = (
|
||||
| {
|
||||
/** Increase amounts will be calculated based on collateral amount */
|
||||
payAmount: bigint;
|
||||
}
|
||||
| {
|
||||
/** Increase amounts will be calculated based on position size amount */
|
||||
sizeAmount: bigint;
|
||||
}
|
||||
) & {
|
||||
marketAddress: string;
|
||||
payTokenAddress: string;
|
||||
collateralTokenAddress: string;
|
||||
| {
|
||||
/** Increase amounts will be calculated based on collateral amount */
|
||||
payAmount: bigint;
|
||||
}
|
||||
| {
|
||||
/** Increase amounts will be calculated based on position size amount */
|
||||
sizeAmount: bigint;
|
||||
}
|
||||
) & {
|
||||
marketAddress: string;
|
||||
payTokenAddress: string;
|
||||
collateralTokenAddress: string;
|
||||
|
||||
/** @default 100 */
|
||||
allowedSlippageBps?: number;
|
||||
referralCodeForTxn?: string;
|
||||
/** @default 100 */
|
||||
allowedSlippageBps?: number;
|
||||
referralCodeForTxn?: string;
|
||||
|
||||
leverage?: bigint;
|
||||
/** If presented, then it's limit order */
|
||||
limitPrice?: bigint;
|
||||
acceptablePriceImpactBuffer?: number;
|
||||
fixedAcceptablePriceImpactBps?: bigint;
|
||||
leverage?: bigint;
|
||||
/** If presented, then it's limit order */
|
||||
limitPrice?: bigint;
|
||||
acceptablePriceImpactBuffer?: number;
|
||||
fixedAcceptablePriceImpactBps?: bigint;
|
||||
|
||||
skipSimulation?: boolean;
|
||||
stopLossPrice?: bigint;
|
||||
takeProfitPrice?: bigint;
|
||||
skipSimulation?: boolean;
|
||||
stopLossPrice?: bigint;
|
||||
takeProfitPrice?: bigint;
|
||||
} & BaseOptionalParams;
|
||||
|
||||
async function getAndValidateBaseParams(sdk: GmxSdk, params: BaseOptionalParams) {
|
||||
let tokensData: TokensData | undefined = params.tokensData;
|
||||
let marketsInfoData: MarketsInfoData | undefined = params.marketsInfoData;
|
||||
let tokensData: TokensData | undefined = params.tokensData;
|
||||
let marketsInfoData: MarketsInfoData | undefined = params.marketsInfoData;
|
||||
|
||||
if (!params.marketsInfoData && !params.tokensData) {
|
||||
const result = await sdk.markets.getMarketsInfo();
|
||||
marketsInfoData = result.marketsInfoData;
|
||||
tokensData = result.tokensData;
|
||||
}
|
||||
if (!params.marketsInfoData && !params.tokensData) {
|
||||
const result = await sdk.markets.getMarketsInfo();
|
||||
marketsInfoData = result.marketsInfoData;
|
||||
tokensData = result.tokensData;
|
||||
}
|
||||
|
||||
if (!tokensData) {
|
||||
throw new Error("Tokens data is not available");
|
||||
}
|
||||
if (!tokensData) {
|
||||
throw new Error("Tokens data is not available");
|
||||
}
|
||||
|
||||
if (!marketsInfoData) {
|
||||
throw new Error("Markets info data is not available");
|
||||
}
|
||||
if (!marketsInfoData) {
|
||||
throw new Error("Markets info data is not available");
|
||||
}
|
||||
|
||||
let uiFeeFactor = params.uiFeeFactor;
|
||||
if (!uiFeeFactor) {
|
||||
uiFeeFactor = await sdk.utils.getUiFeeFactor();
|
||||
}
|
||||
let uiFeeFactor = params.uiFeeFactor;
|
||||
if (!uiFeeFactor) {
|
||||
uiFeeFactor = await sdk.utils.getUiFeeFactor();
|
||||
}
|
||||
|
||||
return {
|
||||
tokensData,
|
||||
marketsInfoData,
|
||||
uiFeeFactor,
|
||||
};
|
||||
return {
|
||||
tokensData,
|
||||
marketsInfoData,
|
||||
uiFeeFactor,
|
||||
};
|
||||
}
|
||||
|
||||
export async function increaseOrderHelper(
|
||||
sdk: GmxSdk,
|
||||
params: PositionIncreaseParams & {
|
||||
isLong: boolean;
|
||||
}
|
||||
sdk: GmxSdk,
|
||||
params: PositionIncreaseParams & {
|
||||
isLong: boolean;
|
||||
}
|
||||
) {
|
||||
const { tokensData, marketsInfoData, uiFeeFactor } = await getAndValidateBaseParams(sdk, params);
|
||||
const {tokensData, marketsInfoData, uiFeeFactor} = await getAndValidateBaseParams(sdk, params);
|
||||
|
||||
const isLimit = Boolean(params.limitPrice);
|
||||
const isLimit = Boolean(params.limitPrice);
|
||||
|
||||
const fromToken = tokensData[params.payTokenAddress];
|
||||
const collateralToken = tokensData[params.collateralTokenAddress];
|
||||
const fromToken = tokensData[params.payTokenAddress];
|
||||
const collateralToken = tokensData[params.collateralTokenAddress];
|
||||
|
||||
if (!fromToken) {
|
||||
throw new Error("From token is not available");
|
||||
}
|
||||
if (!fromToken) {
|
||||
throw new Error("From token is not available");
|
||||
}
|
||||
|
||||
if (!collateralToken) {
|
||||
throw new Error("Collateral token is not available");
|
||||
}
|
||||
if (!collateralToken) {
|
||||
throw new Error("Collateral token is not available");
|
||||
}
|
||||
|
||||
const marketInfo = getByKey(marketsInfoData, params.marketAddress);
|
||||
const marketInfo = getByKey(marketsInfoData, params.marketAddress);
|
||||
|
||||
if (!marketInfo) {
|
||||
throw new Error("Market info is not available");
|
||||
}
|
||||
if (!marketInfo) {
|
||||
throw new Error("Market info is not available");
|
||||
}
|
||||
|
||||
const collateralTokenAddress = collateralToken.address;
|
||||
const allowedSlippage = params.allowedSlippageBps ?? 100;
|
||||
const collateralTokenAddress = collateralToken.address;
|
||||
const allowedSlippage = params.allowedSlippageBps ?? 100;
|
||||
|
||||
const graph = getMarketsGraph(Object.values(marketsInfoData));
|
||||
const wrappedFromAddress = getWrappedAddress(sdk.chainId, params.payTokenAddress);
|
||||
const wrappedToAddress = getWrappedAddress(sdk.chainId, collateralTokenAddress);
|
||||
const graph = getMarketsGraph(Object.values(marketsInfoData));
|
||||
const wrappedFromAddress = getWrappedAddress(sdk.chainId, params.payTokenAddress);
|
||||
const wrappedToAddress = getWrappedAddress(sdk.chainId, collateralTokenAddress);
|
||||
|
||||
const allPaths = findAllSwapPaths({
|
||||
chainId: sdk.chainId,
|
||||
fromTokenAddress: params.payTokenAddress,
|
||||
toTokenAddress: collateralTokenAddress,
|
||||
marketsInfoData,
|
||||
graph,
|
||||
wrappedFromAddress,
|
||||
wrappedToAddress,
|
||||
});
|
||||
|
||||
const estimator = createSwapEstimator(marketsInfoData);
|
||||
|
||||
const findSwapPath = createFindSwapPath({
|
||||
chainId: sdk.chainId,
|
||||
fromTokenAddress: params.payTokenAddress,
|
||||
toTokenAddress: collateralTokenAddress,
|
||||
marketsInfoData,
|
||||
estimator,
|
||||
allPaths,
|
||||
});
|
||||
|
||||
const payOrSizeAmount = "payAmount" in params ? params.payAmount : params.sizeAmount;
|
||||
|
||||
const increaseAmounts = getIncreasePositionAmounts({
|
||||
marketInfo,
|
||||
indexToken: marketInfo.indexToken,
|
||||
initialCollateralToken: fromToken,
|
||||
collateralToken,
|
||||
isLong: params.isLong,
|
||||
initialCollateralAmount: payOrSizeAmount,
|
||||
position: undefined,
|
||||
indexTokenAmount: payOrSizeAmount,
|
||||
leverage: params.leverage,
|
||||
triggerPrice: params.limitPrice,
|
||||
limitOrderType: params.limitPrice ? OrderType.LimitIncrease : undefined,
|
||||
userReferralInfo: undefined,
|
||||
strategy: "payAmount" in params ? "leverageByCollateral" : "leverageBySize",
|
||||
findSwapPath: findSwapPath,
|
||||
uiFeeFactor,
|
||||
acceptablePriceImpactBuffer: params.acceptablePriceImpactBuffer,
|
||||
fixedAcceptablePriceImpactBps: params.fixedAcceptablePriceImpactBps,
|
||||
externalSwapQuote: undefined,
|
||||
});
|
||||
|
||||
const createSltpEntries: SidecarSlTpOrderEntryValid[] = [
|
||||
|
||||
]
|
||||
|
||||
let stopLossDecreaseAmounts: DecreasePositionAmounts | undefined;
|
||||
if (params.stopLossPrice) {
|
||||
const stopLossCollateralDeltaUsd = convertToUsd(increaseAmounts.collateralDeltaAmount, collateralToken.decimals, params.stopLossPrice);
|
||||
|
||||
const acceptablePriceInfo = getAcceptablePriceInfo({
|
||||
marketInfo,
|
||||
isIncrease: false,
|
||||
isLong: params.isLong,
|
||||
indexPrice: params.stopLossPrice,
|
||||
sizeDeltaUsd: increaseAmounts.sizeDeltaUsd,
|
||||
maxNegativePriceImpactBps: marketInfo.maxPositionImpactFactorForLiquidations,
|
||||
const allPaths = findAllSwapPaths({
|
||||
chainId: sdk.chainId,
|
||||
fromTokenAddress: params.payTokenAddress,
|
||||
toTokenAddress: collateralTokenAddress,
|
||||
marketsInfoData,
|
||||
graph,
|
||||
wrappedFromAddress,
|
||||
wrappedToAddress,
|
||||
});
|
||||
|
||||
stopLossDecreaseAmounts = {
|
||||
isFullClose: true,
|
||||
sizeDeltaUsd: increaseAmounts.sizeDeltaUsd,
|
||||
sizeDeltaInTokens: increaseAmounts.sizeDeltaInTokens,
|
||||
collateralDeltaUsd: stopLossCollateralDeltaUsd,
|
||||
collateralDeltaAmount: increaseAmounts.collateralDeltaAmount,
|
||||
indexPrice: params.stopLossPrice,
|
||||
collateralPrice: 0n,
|
||||
acceptablePrice: params.isLong ? 2n ** 256n - 1n : 0n,
|
||||
acceptablePriceDeltaBps: acceptablePriceInfo.acceptablePriceDeltaBps,
|
||||
recommendedAcceptablePriceDeltaBps: 0n,
|
||||
estimatedPnl: 0n,
|
||||
estimatedPnlPercentage: 0n,
|
||||
realizedPnl: 0n,
|
||||
realizedPnlPercentage: 0n,
|
||||
positionFeeUsd: 0n,
|
||||
uiFeeUsd: 0n,
|
||||
swapUiFeeUsd: 0n,
|
||||
feeDiscountUsd: 0n,
|
||||
borrowingFeeUsd: 0n,
|
||||
fundingFeeUsd: 0n,
|
||||
swapProfitFeeUsd: 0n,
|
||||
positionPriceImpactDeltaUsd: 0n,
|
||||
priceImpactDiffUsd: 0n,
|
||||
payedRemainingCollateralAmount: 0n,
|
||||
payedOutputUsd: 0n,
|
||||
payedRemainingCollateralUsd: 0n,
|
||||
receiveTokenAmount: 0n,
|
||||
receiveUsd: 0n,
|
||||
decreaseSwapType: DecreasePositionSwapType.SwapPnlTokenToCollateralToken,
|
||||
triggerOrderType: OrderType.StopLossDecrease,
|
||||
triggerPrice: params.stopLossPrice,
|
||||
}
|
||||
const estimator = createSwapEstimator(marketsInfoData);
|
||||
|
||||
const stopLossEntry: SidecarSlTpOrderEntryValid = {
|
||||
decreaseAmounts: stopLossDecreaseAmounts,
|
||||
id: "sl-order",
|
||||
price: {
|
||||
input: params.stopLossPrice?.toString() ?? "",
|
||||
value: params.stopLossPrice,
|
||||
error: null,
|
||||
} as EntryField,
|
||||
sizeUsd: {
|
||||
input: increaseAmounts.sizeDeltaUsd.toString(),
|
||||
value: increaseAmounts.sizeDeltaUsd,
|
||||
error: null,
|
||||
} as EntryField,
|
||||
percentage: {
|
||||
input: "100",
|
||||
value: 100n,
|
||||
error: null,
|
||||
} as EntryField,
|
||||
txnType: "create",
|
||||
mode: "keepSize",
|
||||
order: null,
|
||||
increaseAmounts: undefined
|
||||
}
|
||||
|
||||
createSltpEntries.push(stopLossEntry)
|
||||
}
|
||||
|
||||
let takeProfitDecreaseAmounts: DecreasePositionAmounts | undefined;
|
||||
if (params.takeProfitPrice) {
|
||||
const takeProfitCollateralDeltaUsd = convertToUsd(increaseAmounts.collateralDeltaAmount, collateralToken.decimals, params.takeProfitPrice);
|
||||
|
||||
const acceptablePriceInfo = getAcceptablePriceInfo({
|
||||
marketInfo,
|
||||
isIncrease: false,
|
||||
isLong: params.isLong,
|
||||
indexPrice: params.takeProfitPrice,
|
||||
sizeDeltaUsd: increaseAmounts.sizeDeltaUsd,
|
||||
maxNegativePriceImpactBps: marketInfo.maxPositionImpactFactorForLiquidations,
|
||||
const findSwapPath = createFindSwapPath({
|
||||
chainId: sdk.chainId,
|
||||
fromTokenAddress: params.payTokenAddress,
|
||||
toTokenAddress: collateralTokenAddress,
|
||||
marketsInfoData,
|
||||
estimator,
|
||||
allPaths,
|
||||
});
|
||||
|
||||
takeProfitDecreaseAmounts = {
|
||||
isFullClose: true,
|
||||
sizeDeltaUsd: increaseAmounts.sizeDeltaUsd,
|
||||
sizeDeltaInTokens: increaseAmounts.sizeDeltaInTokens,
|
||||
collateralDeltaUsd: takeProfitCollateralDeltaUsd,
|
||||
collateralDeltaAmount: increaseAmounts.collateralDeltaAmount,
|
||||
indexPrice: params.takeProfitPrice, // Keep original trigger price for indexPrice
|
||||
collateralPrice: 0n, // Consider if this needs calculation
|
||||
acceptablePrice: acceptablePriceInfo.acceptablePrice,
|
||||
acceptablePriceDeltaBps: acceptablePriceInfo.acceptablePriceDeltaBps,
|
||||
recommendedAcceptablePriceDeltaBps: 0n,
|
||||
estimatedPnl: 0n,
|
||||
estimatedPnlPercentage: 0n,
|
||||
realizedPnl: 0n,
|
||||
realizedPnlPercentage: 0n,
|
||||
positionFeeUsd: 0n,
|
||||
uiFeeUsd: 0n,
|
||||
swapUiFeeUsd: 0n,
|
||||
feeDiscountUsd: 0n,
|
||||
borrowingFeeUsd: 0n,
|
||||
fundingFeeUsd: 0n,
|
||||
swapProfitFeeUsd: 0n,
|
||||
positionPriceImpactDeltaUsd: 0n,
|
||||
priceImpactDiffUsd: 0n,
|
||||
payedRemainingCollateralAmount: 0n,
|
||||
payedOutputUsd: 0n,
|
||||
payedRemainingCollateralUsd: 0n,
|
||||
receiveTokenAmount: 0n,
|
||||
receiveUsd: 0n,
|
||||
decreaseSwapType: DecreasePositionSwapType.SwapPnlTokenToCollateralToken,
|
||||
triggerOrderType: OrderType.LimitDecrease,
|
||||
triggerPrice: params.takeProfitPrice,
|
||||
const payOrSizeAmount = "payAmount" in params ? params.payAmount : params.sizeAmount;
|
||||
|
||||
const increaseAmounts = getIncreasePositionAmounts({
|
||||
marketInfo,
|
||||
indexToken: marketInfo.indexToken,
|
||||
initialCollateralToken: fromToken,
|
||||
collateralToken,
|
||||
isLong: params.isLong,
|
||||
initialCollateralAmount: payOrSizeAmount,
|
||||
position: undefined,
|
||||
indexTokenAmount: payOrSizeAmount,
|
||||
leverage: params.leverage,
|
||||
triggerPrice: params.limitPrice,
|
||||
limitOrderType: params.limitPrice ? OrderType.LimitIncrease : undefined,
|
||||
userReferralInfo: undefined,
|
||||
strategy: "payAmount" in params ? "leverageByCollateral" : "leverageBySize",
|
||||
findSwapPath: findSwapPath,
|
||||
uiFeeFactor,
|
||||
acceptablePriceImpactBuffer: params.acceptablePriceImpactBuffer,
|
||||
fixedAcceptablePriceImpactBps: params.fixedAcceptablePriceImpactBps,
|
||||
externalSwapQuote: undefined,
|
||||
});
|
||||
|
||||
const createSltpEntries: SidecarSlTpOrderEntryValid[] = []
|
||||
|
||||
let stopLossDecreaseAmounts: DecreasePositionAmounts | undefined;
|
||||
if (params.stopLossPrice) {
|
||||
const stopLossCollateralDeltaUsd = convertToUsd(increaseAmounts.collateralDeltaAmount, collateralToken.decimals, params.stopLossPrice);
|
||||
|
||||
const acceptablePriceInfo = getAcceptablePriceInfo({
|
||||
marketInfo,
|
||||
isIncrease: false,
|
||||
isLong: params.isLong,
|
||||
indexPrice: params.stopLossPrice,
|
||||
sizeDeltaUsd: increaseAmounts.sizeDeltaUsd,
|
||||
maxNegativePriceImpactBps: marketInfo.maxPositionImpactFactorForLiquidations,
|
||||
});
|
||||
|
||||
stopLossDecreaseAmounts = {
|
||||
isFullClose: true,
|
||||
sizeDeltaUsd: increaseAmounts.sizeDeltaUsd,
|
||||
sizeDeltaInTokens: increaseAmounts.sizeDeltaInTokens,
|
||||
collateralDeltaUsd: stopLossCollateralDeltaUsd,
|
||||
collateralDeltaAmount: increaseAmounts.collateralDeltaAmount,
|
||||
indexPrice: params.stopLossPrice,
|
||||
collateralPrice: 0n,
|
||||
acceptablePrice: params.isLong ? 2n ** 256n - 1n : 0n,
|
||||
acceptablePriceDeltaBps: acceptablePriceInfo.acceptablePriceDeltaBps + 50n,
|
||||
recommendedAcceptablePriceDeltaBps: 50n,
|
||||
estimatedPnl: 0n,
|
||||
estimatedPnlPercentage: 0n,
|
||||
realizedPnl: 0n,
|
||||
realizedPnlPercentage: 0n,
|
||||
positionFeeUsd: 0n,
|
||||
uiFeeUsd: 0n,
|
||||
swapUiFeeUsd: 0n,
|
||||
feeDiscountUsd: 0n,
|
||||
borrowingFeeUsd: 0n,
|
||||
fundingFeeUsd: 0n,
|
||||
swapProfitFeeUsd: 0n,
|
||||
positionPriceImpactDeltaUsd: 0n,
|
||||
priceImpactDiffUsd: 0n,
|
||||
payedRemainingCollateralAmount: 0n,
|
||||
payedOutputUsd: 0n,
|
||||
payedRemainingCollateralUsd: 0n,
|
||||
receiveTokenAmount: 0n,
|
||||
receiveUsd: 0n,
|
||||
decreaseSwapType: DecreasePositionSwapType.SwapPnlTokenToCollateralToken,
|
||||
triggerOrderType: OrderType.StopLossDecrease,
|
||||
triggerPrice: params.stopLossPrice,
|
||||
}
|
||||
|
||||
const stopLossEntry: SidecarSlTpOrderEntryValid = {
|
||||
decreaseAmounts: stopLossDecreaseAmounts,
|
||||
id: "sl-order",
|
||||
price: {
|
||||
input: params.stopLossPrice?.toString() ?? "",
|
||||
value: params.stopLossPrice,
|
||||
error: null,
|
||||
} as EntryField,
|
||||
sizeUsd: {
|
||||
input: increaseAmounts.sizeDeltaUsd.toString(),
|
||||
value: increaseAmounts.sizeDeltaUsd,
|
||||
error: null,
|
||||
} as EntryField,
|
||||
percentage: {
|
||||
input: "100",
|
||||
value: 100n,
|
||||
error: null,
|
||||
} as EntryField,
|
||||
txnType: "create",
|
||||
mode: "keepSize",
|
||||
order: null,
|
||||
increaseAmounts: undefined
|
||||
}
|
||||
|
||||
createSltpEntries.push(stopLossEntry)
|
||||
}
|
||||
|
||||
const takeProfitEntry: SidecarSlTpOrderEntryValid = {
|
||||
decreaseAmounts: takeProfitDecreaseAmounts,
|
||||
id: "tp-order",
|
||||
price: {
|
||||
input: params.takeProfitPrice?.toString() ?? "",
|
||||
value: params.takeProfitPrice,
|
||||
error: null,
|
||||
} as EntryField,
|
||||
sizeUsd: {
|
||||
input: increaseAmounts.sizeDeltaUsd.toString(),
|
||||
value: increaseAmounts.sizeDeltaUsd,
|
||||
error: null,
|
||||
} as EntryField,
|
||||
percentage: {
|
||||
input: "100",
|
||||
value: 100n,
|
||||
error: null,
|
||||
} as EntryField,
|
||||
txnType: "create",
|
||||
mode: "keepSize",
|
||||
order: null,
|
||||
increaseAmounts: undefined
|
||||
let takeProfitDecreaseAmounts: DecreasePositionAmounts | undefined;
|
||||
if (params.takeProfitPrice) {
|
||||
const takeProfitCollateralDeltaUsd = convertToUsd(increaseAmounts.collateralDeltaAmount, collateralToken.decimals, params.takeProfitPrice);
|
||||
|
||||
const acceptablePriceInfo = getAcceptablePriceInfo({
|
||||
marketInfo,
|
||||
isIncrease: false,
|
||||
isLong: params.isLong,
|
||||
indexPrice: params.takeProfitPrice,
|
||||
sizeDeltaUsd: increaseAmounts.sizeDeltaUsd,
|
||||
maxNegativePriceImpactBps: marketInfo.maxPositionImpactFactorForLiquidations,
|
||||
});
|
||||
|
||||
takeProfitDecreaseAmounts = {
|
||||
isFullClose: true,
|
||||
sizeDeltaUsd: increaseAmounts.sizeDeltaUsd,
|
||||
sizeDeltaInTokens: increaseAmounts.sizeDeltaInTokens,
|
||||
collateralDeltaUsd: takeProfitCollateralDeltaUsd,
|
||||
collateralDeltaAmount: increaseAmounts.collateralDeltaAmount,
|
||||
indexPrice: params.takeProfitPrice, // Keep original trigger price for indexPrice
|
||||
collateralPrice: 0n, // Consider if this needs calculation
|
||||
acceptablePrice: acceptablePriceInfo.acceptablePrice,
|
||||
acceptablePriceDeltaBps: acceptablePriceInfo.acceptablePriceDeltaBps + 50n, // Add 0.5% buffer to acceptable price impact
|
||||
recommendedAcceptablePriceDeltaBps: 50n, // Set recommended buffer to 0.5%
|
||||
estimatedPnl: 0n,
|
||||
estimatedPnlPercentage: 0n,
|
||||
realizedPnl: 0n,
|
||||
realizedPnlPercentage: 0n,
|
||||
positionFeeUsd: 0n,
|
||||
uiFeeUsd: 0n,
|
||||
swapUiFeeUsd: 0n,
|
||||
feeDiscountUsd: 0n,
|
||||
borrowingFeeUsd: 0n,
|
||||
fundingFeeUsd: 0n,
|
||||
swapProfitFeeUsd: 0n,
|
||||
positionPriceImpactDeltaUsd: 0n,
|
||||
priceImpactDiffUsd: 0n,
|
||||
payedRemainingCollateralAmount: 0n,
|
||||
payedOutputUsd: 0n,
|
||||
payedRemainingCollateralUsd: 0n,
|
||||
receiveTokenAmount: 0n,
|
||||
receiveUsd: 0n,
|
||||
decreaseSwapType: DecreasePositionSwapType.SwapPnlTokenToCollateralToken,
|
||||
triggerOrderType: OrderType.LimitDecrease,
|
||||
triggerPrice: params.takeProfitPrice,
|
||||
}
|
||||
|
||||
const takeProfitEntry: SidecarSlTpOrderEntryValid = {
|
||||
decreaseAmounts: takeProfitDecreaseAmounts,
|
||||
id: "tp-order",
|
||||
price: {
|
||||
input: params.takeProfitPrice?.toString() ?? "",
|
||||
value: params.takeProfitPrice,
|
||||
error: null,
|
||||
} as EntryField,
|
||||
sizeUsd: {
|
||||
input: increaseAmounts.sizeDeltaUsd.toString(),
|
||||
value: increaseAmounts.sizeDeltaUsd,
|
||||
error: null,
|
||||
} as EntryField,
|
||||
percentage: {
|
||||
input: "100",
|
||||
value: 100n,
|
||||
error: null,
|
||||
} as EntryField,
|
||||
txnType: "create",
|
||||
mode: "keepSize",
|
||||
order: null,
|
||||
increaseAmounts: undefined
|
||||
}
|
||||
|
||||
createSltpEntries.push(takeProfitEntry)
|
||||
}
|
||||
|
||||
createSltpEntries.push(takeProfitEntry)
|
||||
}
|
||||
const createIncreaseOrderParams: Parameters<typeof sdk.orders.createIncreaseOrder>[0] = {
|
||||
marketsInfoData,
|
||||
tokensData,
|
||||
isLimit,
|
||||
marketAddress: params.marketAddress,
|
||||
fromToken: tokensData[params.payTokenAddress],
|
||||
allowedSlippage,
|
||||
collateralToken,
|
||||
referralCodeForTxn: params.referralCodeForTxn,
|
||||
triggerPrice: params.limitPrice,
|
||||
collateralTokenAddress: collateralToken.address,
|
||||
isLong: params.isLong,
|
||||
receiveTokenAddress: collateralTokenAddress,
|
||||
indexToken: marketInfo.indexToken,
|
||||
marketInfo,
|
||||
skipSimulation: params.skipSimulation,
|
||||
increaseAmounts,
|
||||
createSltpEntries: createSltpEntries.length > 0 ? createSltpEntries : undefined,
|
||||
};
|
||||
|
||||
const createIncreaseOrderParams: Parameters<typeof sdk.orders.createIncreaseOrder>[0] = {
|
||||
marketsInfoData,
|
||||
tokensData,
|
||||
isLimit,
|
||||
marketAddress: params.marketAddress,
|
||||
fromToken: tokensData[params.payTokenAddress],
|
||||
allowedSlippage,
|
||||
collateralToken,
|
||||
referralCodeForTxn: params.referralCodeForTxn,
|
||||
triggerPrice: params.limitPrice,
|
||||
collateralTokenAddress: collateralToken.address,
|
||||
isLong: params.isLong,
|
||||
receiveTokenAddress: collateralTokenAddress,
|
||||
indexToken: marketInfo.indexToken,
|
||||
marketInfo,
|
||||
skipSimulation: params.skipSimulation,
|
||||
increaseAmounts,
|
||||
createSltpEntries: createSltpEntries.length > 0 ? createSltpEntries : undefined,
|
||||
};
|
||||
|
||||
return sdk.orders.createIncreaseOrder(createIncreaseOrderParams);
|
||||
return sdk.orders.createIncreaseOrder(createIncreaseOrderParams);
|
||||
}
|
||||
|
||||
function getTriggerRatio({
|
||||
toToken,
|
||||
fromToken,
|
||||
triggerPrice,
|
||||
}: {
|
||||
toToken: TokenData;
|
||||
fromToken: TokenData;
|
||||
triggerPrice: bigint;
|
||||
toToken,
|
||||
fromToken,
|
||||
triggerPrice,
|
||||
}: {
|
||||
toToken: TokenData;
|
||||
fromToken: TokenData;
|
||||
triggerPrice: bigint;
|
||||
}) {
|
||||
const fromTokenPrice = fromToken?.prices.minPrice;
|
||||
const markPrice = toToken.prices.minPrice;
|
||||
const fromTokenPrice = fromToken?.prices.minPrice;
|
||||
const markPrice = toToken.prices.minPrice;
|
||||
|
||||
const markRatio = getTokensRatioByPrice({
|
||||
fromToken,
|
||||
toToken,
|
||||
fromPrice: fromTokenPrice,
|
||||
toPrice: markPrice,
|
||||
});
|
||||
const markRatio = getTokensRatioByPrice({
|
||||
fromToken,
|
||||
toToken,
|
||||
fromPrice: fromTokenPrice,
|
||||
toPrice: markPrice,
|
||||
});
|
||||
|
||||
const triggerRatio: TokensRatio = {
|
||||
ratio: triggerPrice > 0 ? triggerPrice : markRatio.ratio,
|
||||
largestToken: markRatio.largestToken,
|
||||
smallestToken: markRatio.smallestToken,
|
||||
};
|
||||
const triggerRatio: TokensRatio = {
|
||||
ratio: triggerPrice > 0 ? triggerPrice : markRatio.ratio,
|
||||
largestToken: markRatio.largestToken,
|
||||
smallestToken: markRatio.smallestToken,
|
||||
};
|
||||
|
||||
return triggerRatio;
|
||||
return triggerRatio;
|
||||
}
|
||||
|
||||
export type SwapParams = (
|
||||
| {
|
||||
fromAmount: bigint;
|
||||
}
|
||||
| {
|
||||
toAmount: bigint;
|
||||
}
|
||||
) & {
|
||||
fromTokenAddress: string;
|
||||
toTokenAddress: string;
|
||||
allowedSlippageBps?: number;
|
||||
referralCodeForTxn?: string;
|
||||
| {
|
||||
fromAmount: bigint;
|
||||
}
|
||||
| {
|
||||
toAmount: bigint;
|
||||
}
|
||||
) & {
|
||||
fromTokenAddress: string;
|
||||
toTokenAddress: string;
|
||||
allowedSlippageBps?: number;
|
||||
referralCodeForTxn?: string;
|
||||
|
||||
/** If presented, then it's limit swap order */
|
||||
triggerPrice?: bigint;
|
||||
/** If presented, then it's limit swap order */
|
||||
triggerPrice?: bigint;
|
||||
} & BaseOptionalParams;
|
||||
|
||||
export async function swap(sdk: GmxSdk, params: SwapParams) {
|
||||
const { tokensData, marketsInfoData, uiFeeFactor } = await getAndValidateBaseParams(sdk, params);
|
||||
const {tokensData, marketsInfoData, uiFeeFactor} = await getAndValidateBaseParams(sdk, params);
|
||||
|
||||
const fromToken = tokensData[params.fromTokenAddress];
|
||||
const toToken = tokensData[params.toTokenAddress];
|
||||
const fromToken = tokensData[params.fromTokenAddress];
|
||||
const toToken = tokensData[params.toTokenAddress];
|
||||
|
||||
if (!fromToken || !toToken) {
|
||||
throw new Error("From or to token is not available");
|
||||
}
|
||||
if (!fromToken || !toToken) {
|
||||
throw new Error("From or to token is not available");
|
||||
}
|
||||
|
||||
const isLimit = Boolean(params.triggerPrice);
|
||||
const isLimit = Boolean(params.triggerPrice);
|
||||
|
||||
if (!fromToken || !toToken) {
|
||||
return undefined;
|
||||
}
|
||||
if (!fromToken || !toToken) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const graph = getMarketsGraph(Object.values(marketsInfoData));
|
||||
const wrappedFromAddress = getWrappedAddress(sdk.chainId, params.fromTokenAddress);
|
||||
const wrappedToAddress = getWrappedAddress(sdk.chainId, params.toTokenAddress);
|
||||
const graph = getMarketsGraph(Object.values(marketsInfoData));
|
||||
const wrappedFromAddress = getWrappedAddress(sdk.chainId, params.fromTokenAddress);
|
||||
const wrappedToAddress = getWrappedAddress(sdk.chainId, params.toTokenAddress);
|
||||
|
||||
const allPaths = findAllSwapPaths({
|
||||
chainId: sdk.chainId,
|
||||
fromTokenAddress: params.fromTokenAddress,
|
||||
toTokenAddress: params.toTokenAddress,
|
||||
marketsInfoData,
|
||||
graph,
|
||||
wrappedFromAddress,
|
||||
wrappedToAddress,
|
||||
});
|
||||
const allPaths = findAllSwapPaths({
|
||||
chainId: sdk.chainId,
|
||||
fromTokenAddress: params.fromTokenAddress,
|
||||
toTokenAddress: params.toTokenAddress,
|
||||
marketsInfoData,
|
||||
graph,
|
||||
wrappedFromAddress,
|
||||
wrappedToAddress,
|
||||
});
|
||||
|
||||
const estimator = createSwapEstimator(marketsInfoData);
|
||||
const estimator = createSwapEstimator(marketsInfoData);
|
||||
|
||||
const findSwapPath = createFindSwapPath({
|
||||
chainId: sdk.chainId,
|
||||
fromTokenAddress: params.fromTokenAddress,
|
||||
toTokenAddress: params.toTokenAddress,
|
||||
marketsInfoData,
|
||||
estimator,
|
||||
allPaths,
|
||||
});
|
||||
const findSwapPath = createFindSwapPath({
|
||||
chainId: sdk.chainId,
|
||||
fromTokenAddress: params.fromTokenAddress,
|
||||
toTokenAddress: params.toTokenAddress,
|
||||
marketsInfoData,
|
||||
estimator,
|
||||
allPaths,
|
||||
});
|
||||
|
||||
const isWrapOrUnwrap = Boolean(
|
||||
fromToken && toToken && (getIsWrap(fromToken, toToken) || getIsUnwrap(fromToken, toToken))
|
||||
);
|
||||
const isWrapOrUnwrap = Boolean(
|
||||
fromToken && toToken && (getIsWrap(fromToken, toToken) || getIsUnwrap(fromToken, toToken))
|
||||
);
|
||||
|
||||
const swapOptimizationOrder: Parameters<FindSwapPath>[1]["order"] = isLimit ? ["length", "liquidity"] : undefined;
|
||||
const swapOptimizationOrder: Parameters<FindSwapPath>[1]["order"] = isLimit ? ["length", "liquidity"] : undefined;
|
||||
|
||||
let swapAmounts: SwapAmounts | undefined;
|
||||
let swapAmounts: SwapAmounts | undefined;
|
||||
|
||||
const fromTokenPrice = fromToken.prices.minPrice;
|
||||
const triggerRatio = params.triggerPrice
|
||||
? getTriggerRatio({
|
||||
fromToken,
|
||||
toToken,
|
||||
const fromTokenPrice = fromToken.prices.minPrice;
|
||||
const triggerRatio = params.triggerPrice
|
||||
? getTriggerRatio({
|
||||
fromToken,
|
||||
toToken,
|
||||
triggerPrice: params.triggerPrice,
|
||||
})
|
||||
: undefined;
|
||||
|
||||
if (isWrapOrUnwrap) {
|
||||
const tokenAmount = "fromAmount" in params ? params.fromAmount : params.toAmount;
|
||||
const usdAmount = convertToUsd(tokenAmount, fromToken.decimals, fromTokenPrice)!;
|
||||
const price = fromTokenPrice;
|
||||
|
||||
swapAmounts = {
|
||||
amountIn: tokenAmount,
|
||||
usdIn: usdAmount!,
|
||||
amountOut: tokenAmount,
|
||||
usdOut: usdAmount!,
|
||||
swapPathStats: undefined,
|
||||
priceIn: price,
|
||||
priceOut: price,
|
||||
minOutputAmount: tokenAmount,
|
||||
};
|
||||
|
||||
return swapAmounts;
|
||||
} else if ("fromAmount" in params) {
|
||||
swapAmounts = getSwapAmountsByFromValue({
|
||||
tokenIn: fromToken,
|
||||
tokenOut: toToken,
|
||||
amountIn: params.fromAmount,
|
||||
triggerRatio,
|
||||
isLimit,
|
||||
findSwapPath: findSwapPath,
|
||||
uiFeeFactor,
|
||||
swapOptimizationOrder,
|
||||
allowedSwapSlippageBps: isLimit ? BigInt(params.allowedSlippageBps ?? 100) : undefined,
|
||||
});
|
||||
} else {
|
||||
swapAmounts = getSwapAmountsByToValue({
|
||||
tokenIn: fromToken,
|
||||
tokenOut: toToken,
|
||||
amountOut: params.toAmount,
|
||||
triggerRatio,
|
||||
isLimit: isLimit,
|
||||
findSwapPath: findSwapPath,
|
||||
uiFeeFactor,
|
||||
swapOptimizationOrder,
|
||||
allowedSwapSlippageBps: isLimit ? BigInt(params.allowedSlippageBps ?? 100) : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
if (!swapAmounts) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const createSwapOrderParams: Parameters<typeof sdk.orders.createSwapOrder>[0] = {
|
||||
tokensData,
|
||||
fromToken: tokensData[params.fromTokenAddress],
|
||||
toToken: tokensData[params.toTokenAddress],
|
||||
swapAmounts,
|
||||
isLimit,
|
||||
allowedSlippage: params.allowedSlippageBps ?? 100,
|
||||
referralCodeForTxn: params.referralCodeForTxn,
|
||||
triggerPrice: params.triggerPrice,
|
||||
})
|
||||
: undefined;
|
||||
|
||||
if (isWrapOrUnwrap) {
|
||||
const tokenAmount = "fromAmount" in params ? params.fromAmount : params.toAmount;
|
||||
const usdAmount = convertToUsd(tokenAmount, fromToken.decimals, fromTokenPrice)!;
|
||||
const price = fromTokenPrice;
|
||||
|
||||
swapAmounts = {
|
||||
amountIn: tokenAmount,
|
||||
usdIn: usdAmount!,
|
||||
amountOut: tokenAmount,
|
||||
usdOut: usdAmount!,
|
||||
swapPathStats: undefined,
|
||||
priceIn: price,
|
||||
priceOut: price,
|
||||
minOutputAmount: tokenAmount,
|
||||
};
|
||||
|
||||
return swapAmounts;
|
||||
} else if ("fromAmount" in params) {
|
||||
swapAmounts = getSwapAmountsByFromValue({
|
||||
tokenIn: fromToken,
|
||||
tokenOut: toToken,
|
||||
amountIn: params.fromAmount,
|
||||
triggerRatio,
|
||||
isLimit,
|
||||
findSwapPath: findSwapPath,
|
||||
uiFeeFactor,
|
||||
swapOptimizationOrder,
|
||||
allowedSwapSlippageBps: isLimit ? BigInt(params.allowedSlippageBps ?? 100) : undefined,
|
||||
});
|
||||
} else {
|
||||
swapAmounts = getSwapAmountsByToValue({
|
||||
tokenIn: fromToken,
|
||||
tokenOut: toToken,
|
||||
amountOut: params.toAmount,
|
||||
triggerRatio,
|
||||
isLimit: isLimit,
|
||||
findSwapPath: findSwapPath,
|
||||
uiFeeFactor,
|
||||
swapOptimizationOrder,
|
||||
allowedSwapSlippageBps: isLimit ? BigInt(params.allowedSlippageBps ?? 100) : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
if (!swapAmounts) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const createSwapOrderParams: Parameters<typeof sdk.orders.createSwapOrder>[0] = {
|
||||
tokensData,
|
||||
fromToken: tokensData[params.fromTokenAddress],
|
||||
toToken: tokensData[params.toTokenAddress],
|
||||
swapAmounts,
|
||||
isLimit,
|
||||
allowedSlippage: params.allowedSlippageBps ?? 100,
|
||||
referralCodeForTxn: params.referralCodeForTxn,
|
||||
triggerPrice: params.triggerPrice,
|
||||
};
|
||||
|
||||
return sdk.orders.createSwapOrder(createSwapOrderParams);
|
||||
return sdk.orders.createSwapOrder(createSwapOrderParams);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user