feat: improve exit position logic

This commit is contained in:
Filip Dunder
2024-04-27 17:01:33 +02:00
parent 58eae6bfd8
commit cb91e04d60
5 changed files with 106 additions and 53 deletions

View File

@ -8,7 +8,7 @@ COMMITMENT_LEVEL=confirmed
# Bot # Bot
LOG_LEVEL=trace LOG_LEVEL=trace
ONE_TOKEN_AT_A_TIME=true MAX_TOKENS_AT_THE_TIME=1
PRE_LOAD_EXISTING_MARKETS=false PRE_LOAD_EXISTING_MARKETS=false
CACHE_NEW_MARKETS=false CACHE_NEW_MARKETS=false
# default or warp or jito # default or warp or jito
@ -34,6 +34,8 @@ PRICE_CHECK_INTERVAL=2000
PRICE_CHECK_DURATION=600000 PRICE_CHECK_DURATION=600000
TAKE_PROFIT=40 TAKE_PROFIT=40
STOP_LOSS=20 STOP_LOSS=20
TRAILING_STOP_LOSS=true
SKIP_SELLING_IF_LOST_MORE_THAN=90
SELL_SLIPPAGE=20 SELL_SLIPPAGE=20
# Filters # Filters

View File

@ -36,7 +36,7 @@ You should see the following output:
#### Bot #### Bot
- `LOG_LEVEL` - Set logging level, e.g., `info`, `debug`, `trace`, etc. - `LOG_LEVEL` - Set logging level, e.g., `info`, `debug`, `trace`, etc.
- `ONE_TOKEN_AT_A_TIME` - Set to `true` to process buying one token at a time. - `MAX_TOKENS_AT_A_TIME` - Set to `1` to process buying one token at a time.
- `COMPUTE_UNIT_LIMIT` - Compute limit used to calculate fees. - `COMPUTE_UNIT_LIMIT` - Compute limit used to calculate fees.
- `COMPUTE_UNIT_PRICE` - Compute price used to calculate fees. - `COMPUTE_UNIT_PRICE` - Compute price used to calculate fees.
- `PRE_LOAD_EXISTING_MARKETS` - Bot will load all existing markets in memory on start. - `PRE_LOAD_EXISTING_MARKETS` - Bot will load all existing markets in memory on start.
@ -72,6 +72,9 @@ You should see the following output:
- Take profit is calculated based on quote mint. - Take profit is calculated based on quote mint.
- `STOP_LOSS` - Percentage loss at which to stop the loss. - `STOP_LOSS` - Percentage loss at which to stop the loss.
- Stop loss is calculated based on quote mint. - Stop loss is calculated based on quote mint.
- `TRAILING_STOP_LOSS` - Set to `true` to use trailing stop loss.
- `SKIP_SELLING_IF_LOST_MORE_THAN` - If token loses more than X% of value, bot will not try to sell
- This config is useful if you find yourself in a situation when rugpull happen, and you failed to sell. In this case there is a big loss of value, and sometimes it's more beneficial to keep the token, instead of selling it for almost nothing.
- `SELL_SLIPPAGE` - Slippage %. - `SELL_SLIPPAGE` - Slippage %.
#### Snipe list #### Snipe list

110
bot.ts
View File

@ -19,22 +19,19 @@ import { MarketCache, PoolCache, SnipeListCache } from './cache';
import { PoolFilters } from './filters'; import { PoolFilters } from './filters';
import { TransactionExecutor } from './transactions'; import { TransactionExecutor } from './transactions';
import { createPoolKeys, logger, NETWORK, sleep } from './helpers'; import { createPoolKeys, logger, NETWORK, sleep } from './helpers';
import { Mutex } from 'async-mutex'; import { Semaphore } from 'async-mutex';
import BN from 'bn.js'; import BN from 'bn.js';
import { WarpTransactionExecutor } from './transactions/warp-transaction-executor'; import { WarpTransactionExecutor } from './transactions/warp-transaction-executor';
import { JitoTransactionExecutor } from './transactions/jito-rpc-transaction-executor'; import { JitoTransactionExecutor } from './transactions/jito-rpc-transaction-executor';
export interface BotConfig { export interface BotConfig {
wallet: Keypair; wallet: Keypair;
checkRenounced: boolean;
checkFreezable: boolean;
checkBurned: boolean;
minPoolSize: TokenAmount; minPoolSize: TokenAmount;
maxPoolSize: TokenAmount; maxPoolSize: TokenAmount;
quoteToken: Token; quoteToken: Token;
quoteAmount: TokenAmount; quoteAmount: TokenAmount;
quoteAta: PublicKey; quoteAta: PublicKey;
oneTokenAtATime: boolean; maxTokensAtTheTime: number;
useSnipeList: boolean; useSnipeList: boolean;
autoSell: boolean; autoSell: boolean;
autoBuyDelay: number; autoBuyDelay: number;
@ -45,6 +42,8 @@ export interface BotConfig {
unitPrice: number; unitPrice: number;
takeProfit: number; takeProfit: number;
stopLoss: number; stopLoss: number;
trailingStopLoss: boolean;
skipSellingIfLostMoreThan: number;
buySlippage: number; buySlippage: number;
sellSlippage: number; sellSlippage: number;
priceCheckInterval: number; priceCheckInterval: number;
@ -61,8 +60,9 @@ export class Bot {
private readonly snipeListCache?: SnipeListCache; private readonly snipeListCache?: SnipeListCache;
// one token at the time // one token at the time
private readonly mutex: Mutex; private readonly semaphore: Semaphore;
private sellExecutionCount = 0; private sellExecutionCount = 0;
private readonly stopLoss = new Map<string, TokenAmount>();
public readonly isWarp: boolean = false; public readonly isWarp: boolean = false;
public readonly isJito: boolean = false; public readonly isJito: boolean = false;
@ -76,7 +76,7 @@ export class Bot {
this.isWarp = txExecutor instanceof WarpTransactionExecutor; this.isWarp = txExecutor instanceof WarpTransactionExecutor;
this.isJito = txExecutor instanceof JitoTransactionExecutor; this.isJito = txExecutor instanceof JitoTransactionExecutor;
this.mutex = new Mutex(); this.semaphore = new Semaphore(config.maxTokensAtTheTime);
this.poolFilters = new PoolFilters(connection, { this.poolFilters = new PoolFilters(connection, {
quoteToken: this.config.quoteToken, quoteToken: this.config.quoteToken,
minPoolSize: this.config.minPoolSize, minPoolSize: this.config.minPoolSize,
@ -115,18 +115,18 @@ export class Bot {
await sleep(this.config.autoBuyDelay); await sleep(this.config.autoBuyDelay);
} }
if (this.config.oneTokenAtATime) { const numberOfActionsBeingProcessed =
if (this.mutex.isLocked() || this.sellExecutionCount > 0) { this.config.maxTokensAtTheTime - this.semaphore.getValue() + this.sellExecutionCount;
logger.debug( if (this.semaphore.isLocked() || numberOfActionsBeingProcessed >= this.config.maxTokensAtTheTime) {
{ mint: poolState.baseMint.toString() }, logger.debug(
`Skipping buy because one token at a time is turned on and token is already being processed`, { mint: poolState.baseMint.toString() },
); `Skipping buy because max tokens to process at the same time is ${this.config.maxTokensAtTheTime} and currently ${numberOfActionsBeingProcessed} tokens is being processed`,
return; );
} return;
await this.mutex.acquire();
} }
await this.semaphore.acquire();
try { try {
const [market, mintAta] = await Promise.all([ const [market, mintAta] = await Promise.all([
this.marketStorage.get(poolState.marketId.toString()), this.marketStorage.get(poolState.marketId.toString()),
@ -190,16 +190,12 @@ export class Bot {
} catch (error) { } catch (error) {
logger.error({ mint: poolState.baseMint.toString(), error }, `Failed to buy token`); logger.error({ mint: poolState.baseMint.toString(), error }, `Failed to buy token`);
} finally { } finally {
if (this.config.oneTokenAtATime) { this.semaphore.release();
this.mutex.release();
}
} }
} }
public async sell(accountId: PublicKey, rawAccount: RawAccount) { public async sell(accountId: PublicKey, rawAccount: RawAccount) {
if (this.config.oneTokenAtATime) { this.sellExecutionCount++;
this.sellExecutionCount++;
}
try { try {
logger.trace({ mint: rawAccount.mint }, `Processing new token...`); logger.trace({ mint: rawAccount.mint }, `Processing new token...`);
@ -227,10 +223,14 @@ export class Bot {
const market = await this.marketStorage.get(poolData.state.marketId.toString()); const market = await this.marketStorage.get(poolData.state.marketId.toString());
const poolKeys: LiquidityPoolKeysV4 = createPoolKeys(new PublicKey(poolData.id), poolData.state, market); const poolKeys: LiquidityPoolKeysV4 = createPoolKeys(new PublicKey(poolData.id), poolData.state, market);
await this.priceMatch(tokenAmountIn, poolKeys);
for (let i = 0; i < this.config.maxSellRetries; i++) { for (let i = 0; i < this.config.maxSellRetries; i++) {
try { try {
const shouldSell = await this.waitForSellSignal(tokenAmountIn, poolKeys);
if (!shouldSell) {
return;
}
logger.info( logger.info(
{ mint: rawAccount.mint }, { mint: rawAccount.mint },
`Send sell transaction attempt: ${i + 1}/${this.config.maxSellRetries}`, `Send sell transaction attempt: ${i + 1}/${this.config.maxSellRetries}`,
@ -276,9 +276,7 @@ export class Bot {
} catch (error) { } catch (error) {
logger.error({ mint: rawAccount.mint.toString(), error }, `Failed to sell token`); logger.error({ mint: rawAccount.mint.toString(), error }, `Failed to sell token`);
} finally { } finally {
if (this.config.oneTokenAtATime) { this.sellExecutionCount--;
this.sellExecutionCount--;
}
} }
} }
@ -390,19 +388,27 @@ export class Bot {
return false; return false;
} }
private async priceMatch(amountIn: TokenAmount, poolKeys: LiquidityPoolKeysV4) { private async waitForSellSignal(amountIn: TokenAmount, poolKeys: LiquidityPoolKeysV4) {
if (this.config.priceCheckDuration === 0 || this.config.priceCheckInterval === 0) { if (this.config.priceCheckDuration === 0 || this.config.priceCheckInterval === 0) {
return; return true;
} }
const timesToCheck = this.config.priceCheckDuration / this.config.priceCheckInterval; const timesToCheck = this.config.priceCheckDuration / this.config.priceCheckInterval;
const profitFraction = this.config.quoteAmount.mul(this.config.takeProfit).numerator.div(new BN(100)); const profitFraction = this.config.quoteAmount.mul(this.config.takeProfit).numerator.div(new BN(100));
const profitAmount = new TokenAmount(this.config.quoteToken, profitFraction, true); const profitAmount = new TokenAmount(this.config.quoteToken, profitFraction, true);
const takeProfit = this.config.quoteAmount.add(profitAmount); const takeProfit = this.config.quoteAmount.add(profitAmount);
let stopLoss: TokenAmount;
if (!this.stopLoss.get(poolKeys.baseMint.toString())) {
const lossFraction = this.config.quoteAmount.mul(this.config.stopLoss).numerator.div(new BN(100));
const lossAmount = new TokenAmount(this.config.quoteToken, lossFraction, true);
stopLoss = this.config.quoteAmount.subtract(lossAmount);
this.stopLoss.set(poolKeys.baseMint.toString(), stopLoss);
} else {
stopLoss = this.stopLoss.get(poolKeys.baseMint.toString())!;
}
const lossFraction = this.config.quoteAmount.mul(this.config.stopLoss).numerator.div(new BN(100));
const lossAmount = new TokenAmount(this.config.quoteToken, lossFraction, true);
const stopLoss = this.config.quoteAmount.subtract(lossAmount);
const slippage = new Percent(this.config.sellSlippage, 100); const slippage = new Percent(this.config.sellSlippage, 100);
let timesChecked = 0; let timesChecked = 0;
@ -419,7 +425,39 @@ export class Bot {
amountIn: amountIn, amountIn: amountIn,
currencyOut: this.config.quoteToken, currencyOut: this.config.quoteToken,
slippage, slippage,
}).amountOut; }).amountOut as TokenAmount;
if (this.config.trailingStopLoss) {
const trailingLossFraction = amountOut.mul(this.config.stopLoss).numerator.div(new BN(100));
const trailingLossAmount = new TokenAmount(this.config.quoteToken, trailingLossFraction, true);
const trailingStopLoss = amountOut.subtract(trailingLossAmount);
if (trailingStopLoss.gt(stopLoss)) {
logger.trace(
{ mint: poolKeys.baseMint.toString() },
`Updating trailing stop loss from ${stopLoss.toFixed()} to ${trailingStopLoss.toFixed()}`,
);
this.stopLoss.set(poolKeys.baseMint.toString(), trailingStopLoss);
stopLoss = trailingStopLoss;
}
}
if (this.config.skipSellingIfLostMoreThan > 0) {
const stopSellingFraction = this.config.quoteAmount
.mul(this.config.skipSellingIfLostMoreThan)
.numerator.div(new BN(100));
const stopSellingAmount = new TokenAmount(this.config.quoteToken, stopSellingFraction, true);
if (amountOut.lt(stopSellingAmount)) {
logger.debug(
{ mint: poolKeys.baseMint.toString() },
`Token dropped more than ${this.config.skipSellingIfLostMoreThan}%, sell stopped. Initial: ${this.config.quoteAmount.toFixed()} | Current: ${amountOut.toFixed()}`,
);
this.stopLoss.delete(poolKeys.baseMint.toString());
return false;
}
}
logger.debug( logger.debug(
{ mint: poolKeys.baseMint.toString() }, { mint: poolKeys.baseMint.toString() },
@ -427,10 +465,12 @@ export class Bot {
); );
if (amountOut.lt(stopLoss)) { if (amountOut.lt(stopLoss)) {
this.stopLoss.delete(poolKeys.baseMint.toString());
break; break;
} }
if (amountOut.gt(takeProfit)) { if (amountOut.gt(takeProfit)) {
this.stopLoss.delete(poolKeys.baseMint.toString());
break; break;
} }
@ -441,5 +481,7 @@ export class Bot {
timesChecked++; timesChecked++;
} }
} while (timesChecked < timesToCheck); } while (timesChecked < timesToCheck);
return true;
} }
} }

View File

@ -25,7 +25,7 @@ export const RPC_WEBSOCKET_ENDPOINT = retrieveEnvVariable('RPC_WEBSOCKET_ENDPOIN
// Bot // Bot
export const LOG_LEVEL = retrieveEnvVariable('LOG_LEVEL', logger); export const LOG_LEVEL = retrieveEnvVariable('LOG_LEVEL', logger);
export const ONE_TOKEN_AT_A_TIME = retrieveEnvVariable('ONE_TOKEN_AT_A_TIME', logger) === 'true'; export const MAX_TOKENS_AT_THE_TIME = Number(retrieveEnvVariable('MAX_TOKENS_AT_THE_TIME', logger));
export const COMPUTE_UNIT_LIMIT = Number(retrieveEnvVariable('COMPUTE_UNIT_LIMIT', logger)); export const COMPUTE_UNIT_LIMIT = Number(retrieveEnvVariable('COMPUTE_UNIT_LIMIT', logger));
export const COMPUTE_UNIT_PRICE = Number(retrieveEnvVariable('COMPUTE_UNIT_PRICE', logger)); export const COMPUTE_UNIT_PRICE = Number(retrieveEnvVariable('COMPUTE_UNIT_PRICE', logger));
export const PRE_LOAD_EXISTING_MARKETS = retrieveEnvVariable('PRE_LOAD_EXISTING_MARKETS', logger) === 'true'; export const PRE_LOAD_EXISTING_MARKETS = retrieveEnvVariable('PRE_LOAD_EXISTING_MARKETS', logger) === 'true';
@ -46,9 +46,11 @@ export const AUTO_SELL_DELAY = Number(retrieveEnvVariable('AUTO_SELL_DELAY', log
export const MAX_SELL_RETRIES = Number(retrieveEnvVariable('MAX_SELL_RETRIES', logger)); export const MAX_SELL_RETRIES = Number(retrieveEnvVariable('MAX_SELL_RETRIES', logger));
export const TAKE_PROFIT = Number(retrieveEnvVariable('TAKE_PROFIT', logger)); export const TAKE_PROFIT = Number(retrieveEnvVariable('TAKE_PROFIT', logger));
export const STOP_LOSS = Number(retrieveEnvVariable('STOP_LOSS', logger)); export const STOP_LOSS = Number(retrieveEnvVariable('STOP_LOSS', logger));
export const TRAILING_STOP_LOSS = retrieveEnvVariable('TRAILING_STOP_LOSS', logger) === 'true';
export const PRICE_CHECK_INTERVAL = Number(retrieveEnvVariable('PRICE_CHECK_INTERVAL', logger)); export const PRICE_CHECK_INTERVAL = Number(retrieveEnvVariable('PRICE_CHECK_INTERVAL', logger));
export const PRICE_CHECK_DURATION = Number(retrieveEnvVariable('PRICE_CHECK_DURATION', logger)); export const PRICE_CHECK_DURATION = Number(retrieveEnvVariable('PRICE_CHECK_DURATION', logger));
export const SELL_SLIPPAGE = Number(retrieveEnvVariable('SELL_SLIPPAGE', logger)); export const SELL_SLIPPAGE = Number(retrieveEnvVariable('SELL_SLIPPAGE', logger));
export const SKIP_SELLING_IF_LOST_MORE_THAN = Number(retrieveEnvVariable('SKIP_SELLING_IF_LOST_MORE_THAN', logger));
// Filters // Filters
export const FILTER_CHECK_INTERVAL = Number(retrieveEnvVariable('FILTER_CHECK_INTERVAL', logger)); export const FILTER_CHECK_INTERVAL = Number(retrieveEnvVariable('FILTER_CHECK_INTERVAL', logger));

View File

@ -14,17 +14,12 @@ import {
RPC_WEBSOCKET_ENDPOINT, RPC_WEBSOCKET_ENDPOINT,
PRE_LOAD_EXISTING_MARKETS, PRE_LOAD_EXISTING_MARKETS,
LOG_LEVEL, LOG_LEVEL,
CHECK_IF_MUTABLE,
CHECK_IF_MINT_IS_RENOUNCED,
CHECK_IF_FREEZABLE,
CHECK_IF_BURNED,
QUOTE_MINT, QUOTE_MINT,
MAX_POOL_SIZE, MAX_POOL_SIZE,
MIN_POOL_SIZE, MIN_POOL_SIZE,
QUOTE_AMOUNT, QUOTE_AMOUNT,
PRIVATE_KEY, PRIVATE_KEY,
USE_SNIPE_LIST, USE_SNIPE_LIST,
ONE_TOKEN_AT_A_TIME,
AUTO_SELL_DELAY, AUTO_SELL_DELAY,
MAX_SELL_RETRIES, MAX_SELL_RETRIES,
AUTO_SELL, AUTO_SELL,
@ -45,6 +40,14 @@ import {
FILTER_CHECK_INTERVAL, FILTER_CHECK_INTERVAL,
FILTER_CHECK_DURATION, FILTER_CHECK_DURATION,
CONSECUTIVE_FILTER_MATCHES, CONSECUTIVE_FILTER_MATCHES,
MAX_TOKENS_AT_THE_TIME,
CHECK_IF_MINT_IS_RENOUNCED,
CHECK_IF_FREEZABLE,
CHECK_IF_BURNED,
CHECK_IF_MUTABLE,
CHECK_IF_SOCIALS,
TRAILING_STOP_LOSS,
SKIP_SELLING_IF_LOST_MORE_THAN,
} from './helpers'; } from './helpers';
import { version } from './package.json'; import { version } from './package.json';
import { WarpTransactionExecutor } from './transactions/warp-transaction-executor'; import { WarpTransactionExecutor } from './transactions/warp-transaction-executor';
@ -80,10 +83,8 @@ function printDetails(wallet: Keypair, quoteToken: Token, bot: Bot) {
logger.info(`Wallet: ${wallet.publicKey.toString()}`); logger.info(`Wallet: ${wallet.publicKey.toString()}`);
logger.info('- Bot -'); logger.info('- Bot -');
logger.info(`Using transaction executor: ${TRANSACTION_EXECUTOR}`);
logger.info(
`Using ${TRANSACTION_EXECUTOR} executer: ${bot.isWarp || bot.isJito || (TRANSACTION_EXECUTOR === 'default' ? true : false)}`,
);
if (bot.isWarp || bot.isJito) { if (bot.isWarp || bot.isJito) {
logger.info(`${TRANSACTION_EXECUTOR} fee: ${CUSTOM_FEE}`); logger.info(`${TRANSACTION_EXECUTOR} fee: ${CUSTOM_FEE}`);
} else { } else {
@ -91,7 +92,7 @@ function printDetails(wallet: Keypair, quoteToken: Token, bot: Bot) {
logger.info(`Compute Unit price (micro lamports): ${botConfig.unitPrice}`); logger.info(`Compute Unit price (micro lamports): ${botConfig.unitPrice}`);
} }
logger.info(`Single token at the time: ${botConfig.oneTokenAtATime}`); logger.info(`Max tokens at the time: ${botConfig.maxTokensAtTheTime}`);
logger.info(`Pre load existing markets: ${PRE_LOAD_EXISTING_MARKETS}`); logger.info(`Pre load existing markets: ${PRE_LOAD_EXISTING_MARKETS}`);
logger.info(`Cache new markets: ${CACHE_NEW_MARKETS}`); logger.info(`Cache new markets: ${CACHE_NEW_MARKETS}`);
logger.info(`Log level: ${LOG_LEVEL}`); logger.info(`Log level: ${LOG_LEVEL}`);
@ -112,6 +113,8 @@ function printDetails(wallet: Keypair, quoteToken: Token, bot: Bot) {
logger.info(`Price check duration: ${botConfig.priceCheckDuration} ms`); logger.info(`Price check duration: ${botConfig.priceCheckDuration} ms`);
logger.info(`Take profit: ${botConfig.takeProfit}%`); logger.info(`Take profit: ${botConfig.takeProfit}%`);
logger.info(`Stop loss: ${botConfig.stopLoss}%`); logger.info(`Stop loss: ${botConfig.stopLoss}%`);
logger.info(`Trailing stop loss: ${botConfig.trailingStopLoss}`);
logger.info(`Skip selling if lost more than: ${botConfig.skipSellingIfLostMoreThan}%`);
logger.info('- Snipe list -'); logger.info('- Snipe list -');
logger.info(`Snipe list: ${botConfig.useSnipeList}`); logger.info(`Snipe list: ${botConfig.useSnipeList}`);
@ -125,9 +128,11 @@ function printDetails(wallet: Keypair, quoteToken: Token, bot: Bot) {
logger.info(`Filter check interval: ${botConfig.filterCheckInterval} ms`); logger.info(`Filter check interval: ${botConfig.filterCheckInterval} ms`);
logger.info(`Filter check duration: ${botConfig.filterCheckDuration} ms`); logger.info(`Filter check duration: ${botConfig.filterCheckDuration} ms`);
logger.info(`Consecutive filter matches: ${botConfig.consecutiveMatchCount}`); logger.info(`Consecutive filter matches: ${botConfig.consecutiveMatchCount}`);
logger.info(`Check renounced: ${botConfig.checkRenounced}`); logger.info(`Check renounced: ${CHECK_IF_MINT_IS_RENOUNCED}`);
logger.info(`Check freezable: ${botConfig.checkFreezable}`); logger.info(`Check freezable: ${CHECK_IF_FREEZABLE}`);
logger.info(`Check burned: ${botConfig.checkBurned}`); logger.info(`Check burned: ${CHECK_IF_BURNED}`);
logger.info(`Check mutable: ${CHECK_IF_MUTABLE}`);
logger.info(`Check socials: ${CHECK_IF_SOCIALS}`);
logger.info(`Min pool size: ${botConfig.minPoolSize.toFixed()}`); logger.info(`Min pool size: ${botConfig.minPoolSize.toFixed()}`);
logger.info(`Max pool size: ${botConfig.maxPoolSize.toFixed()}`); logger.info(`Max pool size: ${botConfig.maxPoolSize.toFixed()}`);
} }
@ -165,14 +170,11 @@ const runListener = async () => {
const botConfig = <BotConfig>{ const botConfig = <BotConfig>{
wallet, wallet,
quoteAta: getAssociatedTokenAddressSync(quoteToken.mint, wallet.publicKey), quoteAta: getAssociatedTokenAddressSync(quoteToken.mint, wallet.publicKey),
checkRenounced: CHECK_IF_MINT_IS_RENOUNCED,
checkFreezable: CHECK_IF_FREEZABLE,
checkBurned: CHECK_IF_BURNED,
minPoolSize: new TokenAmount(quoteToken, MIN_POOL_SIZE, false), minPoolSize: new TokenAmount(quoteToken, MIN_POOL_SIZE, false),
maxPoolSize: new TokenAmount(quoteToken, MAX_POOL_SIZE, false), maxPoolSize: new TokenAmount(quoteToken, MAX_POOL_SIZE, false),
quoteToken, quoteToken,
quoteAmount: new TokenAmount(quoteToken, QUOTE_AMOUNT, false), quoteAmount: new TokenAmount(quoteToken, QUOTE_AMOUNT, false),
oneTokenAtATime: ONE_TOKEN_AT_A_TIME, maxTokensAtTheTime: MAX_TOKENS_AT_THE_TIME,
useSnipeList: USE_SNIPE_LIST, useSnipeList: USE_SNIPE_LIST,
autoSell: AUTO_SELL, autoSell: AUTO_SELL,
autoSellDelay: AUTO_SELL_DELAY, autoSellDelay: AUTO_SELL_DELAY,
@ -183,6 +185,8 @@ const runListener = async () => {
unitPrice: COMPUTE_UNIT_PRICE, unitPrice: COMPUTE_UNIT_PRICE,
takeProfit: TAKE_PROFIT, takeProfit: TAKE_PROFIT,
stopLoss: STOP_LOSS, stopLoss: STOP_LOSS,
trailingStopLoss: TRAILING_STOP_LOSS,
skipSellingIfLostMoreThan: SKIP_SELLING_IF_LOST_MORE_THAN,
buySlippage: BUY_SLIPPAGE, buySlippage: BUY_SLIPPAGE,
sellSlippage: SELL_SLIPPAGE, sellSlippage: SELL_SLIPPAGE,
priceCheckInterval: PRICE_CHECK_INTERVAL, priceCheckInterval: PRICE_CHECK_INTERVAL,