Skip to content

Commit 8b1c481

Browse files
committed
ping-pong: add e.profit based stop-loss
1 parent 6f13d7d commit 8b1c481

File tree

2 files changed

+90
-6
lines changed

2 files changed

+90
-6
lines changed

packages/core/src/strategies/ping-pong.ts

Lines changed: 89 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ export type PingPongStrategyConfig = {
3131
executeAboveExpectedProfitPercent: number;
3232
priorityFeeMicroLamports?: number;
3333
lock?: boolean;
34+
enableExpectedProfitBasedStopLoss?: boolean;
35+
profitBasedStopLossPercent?: number;
36+
onStopLossAction?: "sell&reset" | "shutdown" | "sell&shutdown";
3437
shouldReset?: boolean;
3538
autoReset?: {
3639
enabled: boolean;
@@ -50,6 +53,7 @@ export const PingPongStrategy: Strategy<PingPongStrategyConfig> = {
5053
lock: false,
5154
enableAutoSlippage: false,
5255
enableCompounding: false,
56+
enableExpectedProfitBasedStopLoss: false,
5357
},
5458
uiHook: {},
5559
// dependencies: {
@@ -184,6 +188,7 @@ export const PingPongStrategy: Strategy<PingPongStrategyConfig> = {
184188
}
185189

186190
const initialToken = this.config.tokensInfo[0];
191+
187192
// check if lock is enabled
188193
if (this.config.lock) {
189194
bot.logger.info(
@@ -296,6 +301,11 @@ export const PingPongStrategy: Strategy<PingPongStrategyConfig> = {
296301
return done(this);
297302
}
298303

304+
// reset recentOutAmount to current outAmount if it's 0
305+
if (this.config.outToken.recentOutAmount.equals(0)) {
306+
this.config.outToken.recentOutAmount = outAmountMulti.uiValue.decimal;
307+
}
308+
299309
if (this.config.shouldReset) {
300310
this.config.shouldReset = false;
301311
this.config.outToken.recentOutAmount = outAmountMulti.uiValue.decimal;
@@ -332,10 +342,11 @@ export const PingPongStrategy: Strategy<PingPongStrategyConfig> = {
332342
);
333343
//reset
334344
this.config.outToken.recentOutAmount = outAmountMulti.uiValue.decimal;
345+
bot.reportExpectedProfitPercent(0);
346+
} else {
347+
bot.reportExpectedProfitPercent(expectedProfitPercent.toNumber());
335348
}
336349

337-
bot.reportExpectedProfitPercent(expectedProfitPercent.toNumber());
338-
339350
bot.logger.debug(
340351
{
341352
tradeAmount: tradeAmount,
@@ -354,8 +365,82 @@ export const PingPongStrategy: Strategy<PingPongStrategyConfig> = {
354365
throw new Error("PingPongStrategy:run: no routes found");
355366
}
356367

357-
const shouldExecute =
358-
bot.store.getState().strategies.current.shouldExecute;
368+
let shouldExecute = bot.store.getState().strategies.current.shouldExecute;
369+
370+
/**
371+
* Profit based stop loss
372+
* If expected profit is lower than stop loss percent
373+
* then execute stop loss action
374+
*/
375+
if (
376+
this.config.enableExpectedProfitBasedStopLoss &&
377+
this.config.profitBasedStopLossPercent &&
378+
expectedProfitPercent.toNumber() <
379+
this.config.profitBasedStopLossPercent * -1 &&
380+
isSellSide
381+
) {
382+
bot.setStatus("strategy:stopLossExceeded");
383+
384+
if (this.config.onStopLossAction === "shutdown") {
385+
const msg = `PingPongStrategy:run: profitBasedStopLossPercent ${this.config.profitBasedStopLossPercent} reached, shutting down bot`;
386+
bot.logger.info({ runtimeId }, msg);
387+
console.log("\n\n" + msg + "\n\n");
388+
bot.setStatus("!shutdown");
389+
}
390+
391+
if (this.config.onStopLossAction === "sell&shutdown") {
392+
bot.logger.info(
393+
{ runtimeId },
394+
"PingPongStrategy:run: profitBasedStopLossPercent reached, selling current out token"
395+
);
396+
shouldExecute = true;
397+
398+
bot.store.subscribe(
399+
(s) => s.status.value,
400+
(status) => {
401+
if (status === "history:successfulTx") {
402+
bot.logger.info(
403+
{ runtimeId },
404+
"PingPongStrategy:run: profitBasedStopLossPercent reached, token sold successfully, shutting down bot"
405+
);
406+
bot.setStatus("!shutdown");
407+
}
408+
}
409+
);
410+
}
411+
412+
if (this.config.onStopLossAction === "sell&reset") {
413+
bot.logger.info(
414+
{ runtimeId },
415+
"PingPongStrategy:run: profitBasedStopLossPercent reached, selling current out token, and resetting inToken recentOutAmount"
416+
);
417+
418+
// reset recent out amount for inToken
419+
this.config.inToken.recentOutAmount = new Decimal(0);
420+
421+
shouldExecute = true;
422+
423+
const unsubscribe = bot.store.subscribe(
424+
(s) => s.status.value,
425+
(status) => {
426+
if (status === "history:successfulTx") {
427+
if (!this.config.outToken || !this.config.inToken) {
428+
throw new Error(
429+
"PingPongStrategy:run: this.config.outToken undefined"
430+
);
431+
}
432+
433+
bot.logger.info(
434+
{ runtimeId, outToken: this.config.outToken },
435+
"PingPongStrategy:run: profitBasedStopLossPercent reached, token sold successfully"
436+
);
437+
unsubscribe();
438+
}
439+
}
440+
);
441+
}
442+
}
443+
359444
if (
360445
expectedProfitPercent.toNumber() >
361446
this.config.executeAboveExpectedProfitPercent ||
@@ -380,8 +465,6 @@ export const PingPongStrategy: Strategy<PingPongStrategyConfig> = {
380465
);
381466
}
382467

383-
const initialToken = this.config.tokensInfo[0];
384-
385468
// auto slippage
386469
let customSlippageThreshold: bigint | undefined;
387470

packages/core/src/types/bot-status.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export type BotStatus =
1010
| "strategy:scheduled"
1111
| "strategy:launched"
1212
| "strategy:finished"
13+
| "strategy:stopLossExceeded"
1314
| "strategy:shouldReset"
1415
| "strategies:validating"
1516
| "strategies:initializing"

0 commit comments

Comments
 (0)