diff --git a/apps/arb-solana-bot/src/start.ts b/apps/arb-solana-bot/src/start.ts index da27349..653453b 100644 --- a/apps/arb-solana-bot/src/start.ts +++ b/apps/arb-solana-bot/src/start.ts @@ -67,7 +67,11 @@ export const start = async () => { autoReset?: { enabled: boolean; timeWindowMs: number; - }; + }, + expectedProfitBasedStopLoss?: { + enabled: boolean; + percent: number; + } }; } = JSON.parse(fs.readFileSync("./config.json", "utf8")); @@ -96,6 +100,9 @@ export const start = async () => { enableAutoSlippage: config.strategy.slippage.enableAutoSlippage, enableCompounding: config.strategy.enableCompounding ?? false, autoReset: config.strategy.autoReset, + expectedProfitBasedStopLoss: config.strategy.expectedProfitBasedStopLoss, + onStopLossAction: "sell&reset" + }); const bot = extendBot( diff --git a/packages/core/src/strategies/ping-pong.ts b/packages/core/src/strategies/ping-pong.ts index 9640328..e633ff0 100644 --- a/packages/core/src/strategies/ping-pong.ts +++ b/packages/core/src/strategies/ping-pong.ts @@ -31,8 +31,10 @@ export type PingPongStrategyConfig = { executeAboveExpectedProfitPercent: number; priorityFeeMicroLamports?: number; lock?: boolean; - enableExpectedProfitBasedStopLoss?: boolean; - profitBasedStopLossPercent?: number; + expectedProfitBasedStopLoss?: { + enabled: boolean; + percent: number; + } onStopLossAction?: "sell&reset" | "shutdown" | "sell&shutdown"; shouldReset?: boolean; autoReset?: { @@ -53,7 +55,6 @@ export const PingPongStrategy: Strategy = { lock: false, enableAutoSlippage: false, enableCompounding: false, - enableExpectedProfitBasedStopLoss: false, }, uiHook: {}, // dependencies: { @@ -373,16 +374,16 @@ export const PingPongStrategy: Strategy = { * then execute stop loss action */ if ( - this.config.enableExpectedProfitBasedStopLoss && - this.config.profitBasedStopLossPercent && + this.config.expectedProfitBasedStopLoss?.enabled && + this.config.expectedProfitBasedStopLoss.percent && expectedProfitPercent.toNumber() < - this.config.profitBasedStopLossPercent * -1 && + Math.abs(this.config.expectedProfitBasedStopLoss.percent) * -1 && isSellSide ) { bot.setStatus("strategy:stopLossExceeded"); if (this.config.onStopLossAction === "shutdown") { - const msg = `PingPongStrategy:run: profitBasedStopLossPercent ${this.config.profitBasedStopLossPercent} reached, shutting down bot`; + const msg = `PingPongStrategy:run: profitBasedStopLossPercent ${this.config.expectedProfitBasedStopLoss?.percent} reached, shutting down bot`; bot.logger.info({ runtimeId }, msg); console.log("\n\n" + msg + "\n\n"); bot.setStatus("!shutdown"); diff --git a/packages/wizard/src/run-wizard.ts b/packages/wizard/src/run-wizard.ts index 9db9373..2da2d12 100644 --- a/packages/wizard/src/run-wizard.ts +++ b/packages/wizard/src/run-wizard.ts @@ -219,6 +219,11 @@ export const runWizard = async () => { timeWindowMs: 60_000, }; + let expectedProfitBasedStopLoss = { + enabled: false, + percent: 0, + } + if (experienceLevel !== "beginner") { features = await multiselect({ message: "What features do you want to setup? [spacebar] to select", @@ -228,7 +233,8 @@ export const runWizard = async () => { { value: "executionRateLimiter", label: "Execution rate limiter" }, { value: "iterationsRateLimiter", label: "Iterations rate" }, { value: "aggregatorErrorsRateLimiter", label: "Aggregator errors rate limiter" }, - { value: "autoReset", label: "Auto reset" }, + { value: "autoReset", label: "Auto reset", hint: "experimental" }, + { value: "expectedProfitBasedStopLoss", label: "Stop Loss", hint: "experimental" }, ], required: false, }); @@ -451,6 +457,32 @@ export const runWizard = async () => { }; } } + + if (features.includes("expectedProfitBasedStopLoss")) { + const expectedProfitBasedStopLossPercent = await text({ + message: + "What is the expected profit based stop loss percent?\n· If expected profit reaches this percent then swap back to the initial token & reset.\n· The provided number will always be negative (e.g. 0.5 = -0.5)", + initialValue: "0", + validate: (value) => { + if (value.length === 0) return "Please enter a expected profit based stop loss percent"; + const expectedProfitBasedStopLossPercent = Math.abs(parseFloat(value)); + if (isNaN(expectedProfitBasedStopLossPercent)) return "Please enter a valid number"; + if (expectedProfitBasedStopLossPercent === 0) return "Please enter a non-zero number"; + }, + }); + + if (isCancel(expectedProfitBasedStopLossPercent)) { + cancel("Operation cancelled"); + return process.exit(0); + } + + if (typeof expectedProfitBasedStopLossPercent === "string") { + expectedProfitBasedStopLoss = { + enabled: true, + percent: Math.abs(parseFloat(expectedProfitBasedStopLossPercent)), + }; + } + } } // Arb Protocol BuyBack @@ -517,6 +549,10 @@ export const runWizard = async () => { enabled: boolean; timeWindowMs: number; }; + expectedProfitBasedStopLoss?: { + enabled: boolean; + percent: number; + } }; }; @@ -537,6 +573,7 @@ export const runWizard = async () => { ? priorityFeeMicroLamports : undefined, autoReset, + expectedProfitBasedStopLoss }, maxConcurrent: 1, tui: {