diff --git a/dealer/src/Dealer.ts b/dealer/src/Dealer.ts index 0e7de69c..aff8417e 100644 --- a/dealer/src/Dealer.ts +++ b/dealer/src/Dealer.ts @@ -204,13 +204,15 @@ export class Dealer { if (usdLiability < hedgingBounds.MINIMUM_POSITIVE_LIABILITY_USD) { logger.debug( { usdLiability }, - "No liabilities to hedge, skipping the order loop", + "No liabilities to hedge, skipping the order loop and closing position if any", ) addAttributesToCurrentSpan({ [`${SemanticAttributes.CODE_FUNCTION}.results.orderLoopSkipped`]: true, }) + await this.strategy.closePosition() + result.updatePositionSkipped = true } else { logger.debug("starting with order loop") diff --git a/dealer/src/DealerRemoteWallet.ts b/dealer/src/DealerRemoteWallet.ts index e754f267..137f7bfa 100644 --- a/dealer/src/DealerRemoteWallet.ts +++ b/dealer/src/DealerRemoteWallet.ts @@ -108,21 +108,21 @@ export class DealerRemoteWallet implements GaloyWallet { (wallet) => wallet?.id === "BTCWallet", ) const btcWalletId = btcWallet?.id - const btcWalletBalance = btcWallet?.balance ?? NaN + const btcWalletBalance: number = btcWallet?.balance ?? NaN const usdWallet = result.data.wallets?.find( (wallet) => wallet?.id === "USDWallet", ) const usdWalletId = usdWallet?.id - const usdWalletBalance = usdWallet?.balance ?? NaN + const usdWalletBalance: number = usdWallet?.balance ?? NaN addAttributesToCurrentSpan({ [`${SemanticAttributes.CODE_FUNCTION}.results.btcWalletId`]: btcWalletId, [`${SemanticAttributes.CODE_FUNCTION}.results.btcWalletBalance`]: - btcWalletBalance, + String(btcWalletBalance), [`${SemanticAttributes.CODE_FUNCTION}.results.usdWalletId`]: usdWalletId, [`${SemanticAttributes.CODE_FUNCTION}.results.usdWalletBalance`]: - usdWalletBalance, + String(usdWalletBalance), }) return { diff --git a/dealer/src/DealerRemoteWalletV2.ts b/dealer/src/DealerRemoteWalletV2.ts index 6f54fdd2..164383a5 100644 --- a/dealer/src/DealerRemoteWalletV2.ts +++ b/dealer/src/DealerRemoteWalletV2.ts @@ -109,25 +109,25 @@ export class DealerRemoteWalletV2 implements GaloyWallet { (wallet) => wallet?.__typename === "BTCWallet", ) const btcWalletId = btcWallet?.id - const btcWalletBalance = (btcWallet?.balance ?? NaN) - btcBalanceOffset + const btcWalletBalance: number = (btcWallet?.balance ?? NaN) - btcBalanceOffset const usdWallet = me?.defaultAccount?.wallets?.find( (wallet) => wallet?.__typename === "UsdWallet", ) const usdWalletId = usdWallet?.id - const usdWalletBalance = (usdWallet?.balance ?? NaN) - usdBalanceOffset + const usdWalletBalance: number = (usdWallet?.balance ?? NaN) - usdBalanceOffset addAttributesToCurrentSpan({ [`${SemanticAttributes.CODE_FUNCTION}.results.btcWalletId`]: btcWalletId, [`${SemanticAttributes.CODE_FUNCTION}.results.btcWalletBalance`]: - btcWalletBalance, + String(btcWalletBalance), [`${SemanticAttributes.CODE_FUNCTION}.results.btcBalanceOffset`]: - btcBalanceOffset, + String(btcBalanceOffset), [`${SemanticAttributes.CODE_FUNCTION}.results.usdWalletId`]: usdWalletId, [`${SemanticAttributes.CODE_FUNCTION}.results.usdWalletBalance`]: - usdWalletBalance, + String(usdWalletBalance), [`${SemanticAttributes.CODE_FUNCTION}.results.usdBalanceOffset`]: - usdBalanceOffset, + String(usdBalanceOffset), }) return { diff --git a/dealer/src/DealerSimulatedWallet.ts b/dealer/src/DealerSimulatedWallet.ts index b5b88b25..ced4bf89 100644 --- a/dealer/src/DealerSimulatedWallet.ts +++ b/dealer/src/DealerSimulatedWallet.ts @@ -108,21 +108,21 @@ export class DealerSimulatedWallet implements GaloyWallet { (wallet) => wallet?.id === "BTCWallet", ) const btcWalletId = btcWallet?.id - const btcWalletBalance = btcWallet?.balance ?? NaN + const btcWalletBalance: number = btcWallet?.balance ?? NaN const usdWallet = result.data.wallets?.find( (wallet) => wallet?.id === "USDWallet", ) const usdWalletId = usdWallet?.id - const usdWalletBalance = usdWallet?.balance ?? NaN + const usdWalletBalance: number = usdWallet?.balance ?? NaN addAttributesToCurrentSpan({ [`${SemanticAttributes.CODE_FUNCTION}.results.btcWalletId`]: btcWalletId, [`${SemanticAttributes.CODE_FUNCTION}.results.btcWalletBalance`]: - btcWalletBalance, + String(btcWalletBalance), [`${SemanticAttributes.CODE_FUNCTION}.results.usdWalletId`]: usdWalletId, [`${SemanticAttributes.CODE_FUNCTION}.results.usdWalletBalance`]: - usdWalletBalance, + String(usdWalletBalance), }) return { diff --git a/dealer/src/ExchangeBase.ts b/dealer/src/ExchangeBase.ts index 0b9d7a61..8adc2e55 100644 --- a/dealer/src/ExchangeBase.ts +++ b/dealer/src/ExchangeBase.ts @@ -730,6 +730,8 @@ export abstract class ExchangeBase { btcPriceInUsd: number, ): Promise> + abstract closePosition(instrumentId: string): Promise> + abstract getInstrumentDetails(): Promise> abstract getPublicFundingRate(): Promise> diff --git a/dealer/src/HedgingStrategyTypes.ts b/dealer/src/HedgingStrategyTypes.ts index df9a97c0..7eab896e 100644 --- a/dealer/src/HedgingStrategyTypes.ts +++ b/dealer/src/HedgingStrategyTypes.ts @@ -64,6 +64,7 @@ export interface HedgingStrategy { isDepositCompleted(address: string, amountInSats: number): Promise> isWithdrawalCompleted(address: string, amountInSats: number): Promise> + closePosition(): Promise> updatePosition( liabilityInUsd: number, btcPriceInUsd: number, diff --git a/dealer/src/OkexExchange.ts b/dealer/src/OkexExchange.ts index cf9ef768..fdef0c90 100644 --- a/dealer/src/OkexExchange.ts +++ b/dealer/src/OkexExchange.ts @@ -140,12 +140,63 @@ export class OkexExchange extends ExchangeBase { return ret as Result } + public async closePosition(instrumentId: string): Promise> { + const ret = await asyncRunInSpan( + "app.okexExchange.closePosition", + { + [SemanticAttributes.CODE_FUNCTION]: "closePosition", + [SemanticAttributes.CODE_NAMESPACE]: "app.okexExchange", + [`${SemanticAttributes.CODE_FUNCTION}.params.instrumentId`]: instrumentId, + [`${SemanticAttributes.CODE_FUNCTION}.sub.method`]: + "privatePostTradeClosePosition", + }, + async () => { + try { + const config = this.exchangeConfig as OkexExchangeConfiguration + const params = { + instId: instrumentId, + mgnMode: config.marginMode, + autoCxl: true, + } + + addAttributesToCurrentSpan({ + [`${SemanticAttributes.CODE_FUNCTION}.sub.params`]: JSON.stringify(params), + }) + + const response = await this.exchange.privatePostTradeClosePosition(params) + this.logger.debug( + { config, params, response }, + "exchange.privatePostTradeClosePosition({params}) returned: {response}", + ) + + addAttributesToCurrentSpan({ + [`${SemanticAttributes.CODE_FUNCTION}.results.result`]: + JSON.stringify(response), + }) + + return { + ok: true, + value: true, + } + } catch (error) { + recordExceptionInCurrentSpan({ error, level: ErrorLevel.Warn }) + return { ok: true, value: true } + } + }, + ) + return ret as Result + } + public async getInstrumentDetails(): Promise> { const ret = await asyncRunInSpan( "app.okexExchange.getInstrumentDetails", { [SemanticAttributes.CODE_FUNCTION]: "getInstrumentDetails", [SemanticAttributes.CODE_NAMESPACE]: "app.okexExchange", + [`${SemanticAttributes.CODE_FUNCTION}.sub.method`]: "publicGetPublicInstruments", + [`${SemanticAttributes.CODE_FUNCTION}.sub.params.instType`]: + SupportedInstrumentType.Swap, + [`${SemanticAttributes.CODE_FUNCTION}.sub.params.instId`]: this.instrumentId, }, async () => { try { @@ -157,6 +208,12 @@ export class OkexExchange extends ExchangeBase { { instrumentId: this.instrumentId, response }, "publicGetPublicInstruments({instrumentId}) returned: {response}", ) + + addAttributesToCurrentSpan({ + [`${SemanticAttributes.CODE_FUNCTION}.sub.results.result`]: + JSON.stringify(response), + }) + assert(response, ApiError.UNSUPPORTED_API_RESPONSE) assert( response.data[0].ctValCcy === TradeCurrency.USD, @@ -193,6 +250,8 @@ export class OkexExchange extends ExchangeBase { { [SemanticAttributes.CODE_FUNCTION]: "getPublicFundingRate", [SemanticAttributes.CODE_NAMESPACE]: "app.okexExchange", + [`${SemanticAttributes.CODE_FUNCTION}.sub.method`]: "publicGetPublicFundingRate", + [`${SemanticAttributes.CODE_FUNCTION}.sub.params.instId`]: this.instrumentId, }, async () => { try { @@ -203,6 +262,12 @@ export class OkexExchange extends ExchangeBase { { instrumentId: this.instrumentId, response }, "exchange.publicGetPublicFundingRate({instrumentId}) returned: {response}", ) + + addAttributesToCurrentSpan({ + [`${SemanticAttributes.CODE_FUNCTION}.sub.results.result`]: + JSON.stringify(response), + }) + assert(response, ApiError.UNSUPPORTED_API_RESPONSE) assert( response.data[0].instId === this.instrumentId, @@ -241,6 +306,10 @@ export class OkexExchange extends ExchangeBase { { [SemanticAttributes.CODE_FUNCTION]: "getPublicMarkPrice", [SemanticAttributes.CODE_NAMESPACE]: "app.okexExchange", + [`${SemanticAttributes.CODE_FUNCTION}.sub.method`]: "publicGetPublicMarkPrice", + [`${SemanticAttributes.CODE_FUNCTION}.sub.params.instType`]: + SupportedInstrumentType.Swap, + [`${SemanticAttributes.CODE_FUNCTION}.sub.params.instId`]: this.instrumentId, }, async () => { try { @@ -252,6 +321,12 @@ export class OkexExchange extends ExchangeBase { { instrumentId: this.instrumentId, response }, "exchange.publicGetPublicMarkPrice({instrumentId}) returned: {response}", ) + + addAttributesToCurrentSpan({ + [`${SemanticAttributes.CODE_FUNCTION}.sub.results.result`]: + JSON.stringify(response), + }) + assert(response, ApiError.UNSUPPORTED_API_RESPONSE) assert( response?.data[0]?.instType === SupportedInstrumentType.Swap, @@ -290,6 +365,9 @@ export class OkexExchange extends ExchangeBase { { [SemanticAttributes.CODE_FUNCTION]: "getMarketIndexTickers", [SemanticAttributes.CODE_NAMESPACE]: "app.okexExchange", + [`${SemanticAttributes.CODE_FUNCTION}.sub.method`]: "publicGetMarketIndexTickers", + [`${SemanticAttributes.CODE_FUNCTION}.sub.params.instId`]: + SupportedInstrument.OKEX_BTC_USD_SPOT, }, async () => { try { @@ -300,6 +378,12 @@ export class OkexExchange extends ExchangeBase { { instrumentId: this.instrumentId, response }, "exchange.publicGetMarketIndexTickers({instrumentId}) returned: {response}", ) + + addAttributesToCurrentSpan({ + [`${SemanticAttributes.CODE_FUNCTION}.sub.results.result`]: + JSON.stringify(response), + }) + assert(response, ApiError.UNSUPPORTED_API_RESPONSE) assert( response?.data[0]?.instId === SupportedInstrument.OKEX_BTC_USD_SPOT, @@ -436,6 +520,8 @@ export class OkexExchange extends ExchangeBase { [SemanticAttributes.CODE_FUNCTION]: "withdrawOnLightning", [SemanticAttributes.CODE_NAMESPACE]: "app.okexExchange", [`${SemanticAttributes.CODE_FUNCTION}.params.args`]: JSON.stringify(args), + [`${SemanticAttributes.CODE_FUNCTION}.sub.method`]: + "privatePostAssetWithdrawalLightning", }, async () => { try { @@ -444,11 +530,22 @@ export class OkexExchange extends ExchangeBase { invoice: args.invoice, pwd: this.fundingPassword, } + + addAttributesToCurrentSpan({ + [`${SemanticAttributes.CODE_FUNCTION}.sub.params`]: JSON.stringify(params), + }) + const response = await this.exchange.privatePostAssetWithdrawalLightning(params) this.logger.debug( { params, response }, "privatePostAssetWithdrawalLightning({params}) returned: {response}", ) + + addAttributesToCurrentSpan({ + [`${SemanticAttributes.CODE_FUNCTION}.sub.results.result`]: + JSON.stringify(response), + }) + assert(response, ApiError.UNSUPPORTED_API_RESPONSE) assert(response.code === "0", ApiError.UNSUPPORTED_API_RESPONSE) assert(response.data[0].wdId, ApiError.UNSUPPORTED_API_RESPONSE) @@ -483,6 +580,8 @@ export class OkexExchange extends ExchangeBase { [SemanticAttributes.CODE_FUNCTION]: "depositOnLightning", [SemanticAttributes.CODE_NAMESPACE]: "app.okexExchange", [`${SemanticAttributes.CODE_FUNCTION}.params.args`]: JSON.stringify(args), + [`${SemanticAttributes.CODE_FUNCTION}.sub.method`]: + "privateGetAssetDepositLightning", }, async () => { try { @@ -491,11 +590,22 @@ export class OkexExchange extends ExchangeBase { amt: args.amountInSats, to: AccountTypeToId.Trading, } + + addAttributesToCurrentSpan({ + [`${SemanticAttributes.CODE_FUNCTION}.sub.params`]: JSON.stringify(params), + }) + const response = await this.exchange.privateGetAssetDepositLightning(params) this.logger.debug( { params, response }, "privateGetAssetDepositLightning({params}) returned: {response}", ) + + addAttributesToCurrentSpan({ + [`${SemanticAttributes.CODE_FUNCTION}.sub.results.result`]: + JSON.stringify(response), + }) + assert(response, ApiError.UNSUPPORTED_API_RESPONSE) assert(response.data[0].invoice, ApiError.UNSUPPORTED_API_RESPONSE) diff --git a/dealer/src/OkexPerpetualSwapStrategy.ts b/dealer/src/OkexPerpetualSwapStrategy.ts index 2b5f8d60..e1445224 100644 --- a/dealer/src/OkexPerpetualSwapStrategy.ts +++ b/dealer/src/OkexPerpetualSwapStrategy.ts @@ -253,6 +253,16 @@ export class OkexPerpetualSwapStrategy implements HedgingStrategy { return { ok: true, value: false } } + public async closePosition(): Promise> { + const instrumentId = this.instrumentId + const result = await this.exchange.closePosition(instrumentId) + this.logger.debug( + { instrumentId, result }, + "exchange.closePosition({instrumentId}) returned: {result}", + ) + return result + } + public async updatePosition( liabilityInUsd: number, btcPriceInUsd: number,