mirror of
https://github.com/mortdeus/legacy-cc.git
synced 2026-09-28 14:55:15 +00:00
325 lines
12 KiB
JavaScript
325 lines
12 KiB
JavaScript
import { newlunched_subscribeCommand, stopNewLaunch } from "./grpc.js";
|
|
import { token_buy, token_sell, getSplTokenBalance, getPublicKeyFromPrivateKey } from "./fuc.js";
|
|
import { getBalance } from "./swap.js";
|
|
import { config, validateConfig } from "./config.js";
|
|
import logger from "./utils/logger.js";
|
|
import notificationService from "./services/notifications.js";
|
|
import riskManager from "./services/riskManager.js";
|
|
import chalk from "chalk";
|
|
|
|
// Trading configuration from config service
|
|
const tradingConfig = config.trading;
|
|
|
|
// Track active positions
|
|
const activePositions = new Map();
|
|
|
|
export const pump_geyser = async () => {
|
|
try {
|
|
// Validate configuration
|
|
validateConfig();
|
|
|
|
const walletKey = getPublicKeyFromPrivateKey();
|
|
|
|
// Log startup banner
|
|
console.log(chalk.magentaBright(`
|
|
██████╗██████╗ ██╗ ██╗██████╗ ████████╗ ██████╗ ██╗ ██╗██╗███╗ ██╗ ██████╗
|
|
██╔════╝██╔══██╗██║ ██║██╔══██╗╚══██╔══╝██╔═══██╗██║ ██╔╝██║████╗ ██║██╔════╝
|
|
██║ ██████╔╝ ██║ ██╔╝██████╔╝ ██║ ██║ ██║█████╔╝ ██║██╔██╗ ██║██║ ██╗
|
|
██║ ██╔══██╗ ██╔═╝ ██╔═══╝ ██║ ██║ ██║██╔═██╗ ██║██║╚██╗██║██║ ██║
|
|
╚██████╗██║ ██║ ██║ ██║ ██║ ╚██████╔╝██║ ██╗██║██║ ╚████║╚██████╔╝
|
|
╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
|
`));
|
|
|
|
logger.info("🚀 Starting Solana Raydium Sniper Bot...");
|
|
logger.info(`🔑 Wallet Public Key: ${walletKey}`);
|
|
logger.info(`💰 Sniper Amount: ${tradingConfig.sniperAmount} SOL`);
|
|
logger.info(`🎯 Profit Target: ${tradingConfig.profitTarget}x`);
|
|
logger.info(`🛑 Stop Loss: ${tradingConfig.stopLoss}x`);
|
|
logger.info(`⏱️ Max Hold Time: ${tradingConfig.maxHoldTime/1000}s`);
|
|
logger.info(`📊 Max Positions: ${tradingConfig.maxPositions}`);
|
|
|
|
// Log configuration
|
|
logger.debug("Trading configuration loaded", tradingConfig);
|
|
logger.debug("Pool filters", config.pools);
|
|
logger.debug("Risk management settings", config.risk);
|
|
|
|
// Send startup notification
|
|
await notificationService.notifyBotStatus("Started", {
|
|
wallet: walletKey,
|
|
config: tradingConfig,
|
|
});
|
|
|
|
// Start monitoring for new token launches
|
|
await newlunched_subscribeCommand();
|
|
|
|
// Set up position monitoring
|
|
setInterval(monitorPositions, 5000); // Check positions every 5 seconds
|
|
|
|
// Set up risk monitoring
|
|
setInterval(monitorRisk, 10000); // Check risk metrics every 10 seconds
|
|
|
|
// Set up graceful shutdown
|
|
process.on('SIGINT', async () => {
|
|
logger.warn("🛑 Shutting down sniper bot...");
|
|
stopNewLaunch();
|
|
|
|
// Close all positions before exit
|
|
await closeAllPositions();
|
|
|
|
// Send shutdown notification
|
|
await notificationService.notifyBotStatus("Shutdown", {
|
|
reason: "SIGINT received",
|
|
finalStats: riskManager.getDailyStats(),
|
|
});
|
|
|
|
process.exit(0);
|
|
});
|
|
|
|
// Handle other shutdown signals
|
|
process.on('SIGTERM', async () => {
|
|
logger.warn("🛑 SIGTERM received, shutting down...");
|
|
await handleGracefulShutdown("SIGTERM");
|
|
});
|
|
|
|
process.on('uncaughtException', async (error) => {
|
|
logger.error("Uncaught exception", error);
|
|
await notificationService.notifyError(error, "Uncaught Exception");
|
|
await handleGracefulShutdown("Uncaught Exception");
|
|
});
|
|
|
|
process.on('unhandledRejection', async (reason, promise) => {
|
|
logger.error("Unhandled rejection", { reason, promise });
|
|
await notificationService.notifyError(new Error(reason), "Unhandled Rejection");
|
|
});
|
|
|
|
} catch (error) {
|
|
logger.error("Error in pump_geyser", error);
|
|
await notificationService.notifyError(error, "Bot Startup");
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
// Monitor active positions for profit taking or stop loss
|
|
async function monitorPositions() {
|
|
try {
|
|
const positions = riskManager.getActivePositions();
|
|
|
|
for (const position of positions) {
|
|
try {
|
|
const currentBalance = await getSplTokenBalance(position.mint);
|
|
if (!currentBalance || currentBalance <= 0) {
|
|
logger.warn(`⚠️ No balance for ${position.mint}, removing from active positions`);
|
|
riskManager.activePositions.delete(position.mint);
|
|
continue;
|
|
}
|
|
|
|
// Update position price (you'll need to implement price fetching)
|
|
// const currentPrice = await getCurrentPrice(position.mint);
|
|
// riskManager.updatePositionPrice(position.mint, currentPrice);
|
|
|
|
// Check if position should be closed
|
|
const shouldClose = riskManager.shouldClosePosition(position.mint);
|
|
if (shouldClose.shouldClose) {
|
|
logger.info(`Position closure triggered for ${position.mint}: ${shouldClose.reason}`);
|
|
await closePosition(position.mint, position, shouldClose.reason);
|
|
}
|
|
} catch (error) {
|
|
logger.error(`Error monitoring position ${position.mint}`, error);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
logger.error("Error in position monitoring", error);
|
|
}
|
|
}
|
|
|
|
// Monitor risk metrics
|
|
async function monitorRisk() {
|
|
try {
|
|
const riskMetrics = riskManager.getRiskMetrics();
|
|
|
|
// Log risk metrics periodically
|
|
if (riskMetrics.riskLevel === 'HIGH') {
|
|
logger.warn("High risk level detected", riskMetrics);
|
|
await notificationService.sendNotification(
|
|
"🚨 High risk level detected - review positions and consider reducing exposure",
|
|
"warning",
|
|
riskMetrics
|
|
);
|
|
}
|
|
|
|
// Log daily stats every hour
|
|
const now = new Date();
|
|
if (now.getMinutes() === 0) {
|
|
logger.info("Hourly risk summary", riskMetrics);
|
|
}
|
|
|
|
} catch (error) {
|
|
logger.error("Error in risk monitoring", error);
|
|
}
|
|
}
|
|
|
|
// Close a specific position
|
|
async function closePosition(mint, position, reason = 'manual') {
|
|
try {
|
|
logger.info(`Closing position for ${mint}`, { reason, position });
|
|
|
|
// Get current token balance
|
|
const currentBalance = await getSplTokenBalance(mint);
|
|
if (!currentBalance || currentBalance <= 0) {
|
|
logger.warn(`No balance to sell for ${mint}`);
|
|
riskManager.activePositions.delete(mint);
|
|
return;
|
|
}
|
|
|
|
// Execute sell transaction
|
|
const sellResult = await token_sell(mint, currentBalance);
|
|
|
|
if (sellResult && sellResult.txHash) {
|
|
logger.info(`Position closed successfully for ${mint}`, {
|
|
txHash: sellResult.txHash,
|
|
reason,
|
|
balance: currentBalance,
|
|
});
|
|
|
|
// Record the trade
|
|
riskManager.recordTrade('sell', mint, currentBalance, position.currentPrice || 0, sellResult.txHash);
|
|
|
|
// Send notification
|
|
await notificationService.notifyPositionUpdate('closed', mint, {
|
|
reason,
|
|
txHash: sellResult.txHash,
|
|
balance: currentBalance,
|
|
});
|
|
} else {
|
|
logger.error(`Failed to close position for ${mint}`);
|
|
}
|
|
} catch (error) {
|
|
logger.error(`Error closing position for ${mint}`, error);
|
|
await notificationService.notifyError(error, `Position Closure - ${mint}`);
|
|
}
|
|
}
|
|
|
|
// Close all active positions
|
|
async function closeAllPositions() {
|
|
try {
|
|
const positions = riskManager.getActivePositions();
|
|
logger.info(`Closing ${positions.length} active positions...`);
|
|
|
|
const results = [];
|
|
|
|
for (const position of positions) {
|
|
try {
|
|
await closePosition(position.mint, position, 'shutdown');
|
|
results.push({ mint: position.mint, status: 'closed' });
|
|
} catch (error) {
|
|
logger.error(`Error closing position ${position.mint}`, error);
|
|
results.push({ mint: position.mint, status: 'error', error: error.message });
|
|
}
|
|
}
|
|
|
|
logger.info("Position closure summary", { results });
|
|
return results;
|
|
} catch (error) {
|
|
logger.error("Error in closeAllPositions", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// Handle graceful shutdown
|
|
async function handleGracefulShutdown(reason) {
|
|
try {
|
|
logger.warn(`Graceful shutdown initiated: ${reason}`);
|
|
|
|
// Stop gRPC monitoring
|
|
stopNewLaunch();
|
|
|
|
// Close all positions
|
|
await closeAllPositions();
|
|
|
|
// Send final notification
|
|
await notificationService.notifyBotStatus("Shutdown", {
|
|
reason,
|
|
finalStats: riskManager.getDailyStats(),
|
|
});
|
|
|
|
logger.info("Graceful shutdown completed");
|
|
process.exit(0);
|
|
} catch (error) {
|
|
logger.error("Error during graceful shutdown", error);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
// Handle new token launch detected by gRPC
|
|
async function handleNewTokenLaunch(tokenMint, poolStatus, context) {
|
|
try {
|
|
logger.info(`New token launch detected: ${tokenMint}`, {
|
|
poolStatus,
|
|
context,
|
|
timestamp: new Date().toISOString(),
|
|
});
|
|
|
|
// Check if we can execute a trade
|
|
const tradeCheck = riskManager.canExecuteTrade(config.trading.sniperAmount, tokenMint);
|
|
if (!tradeCheck.allowed) {
|
|
logger.warn(`Trade blocked for ${tokenMint}`, { reasons: tradeCheck.errors });
|
|
return;
|
|
}
|
|
|
|
// Execute the sniper trade
|
|
logger.info(`Executing sniper trade for ${tokenMint}`);
|
|
|
|
// Get current SOL balance
|
|
const solBalance = await getBalance();
|
|
if (solBalance < config.trading.sniperAmount) {
|
|
logger.warn(`Insufficient SOL balance for sniper trade: ${solBalance} SOL`);
|
|
return;
|
|
}
|
|
|
|
// Execute buy transaction
|
|
const buyResult = await token_buy(tokenMint, config.trading.sniperAmount);
|
|
|
|
if (buyResult && buyResult.txHash) {
|
|
logger.info(`Sniper trade executed successfully for ${tokenMint}`, {
|
|
txHash: buyResult.txHash,
|
|
amount: config.trading.sniperAmount,
|
|
poolStatus,
|
|
});
|
|
|
|
// Record the trade
|
|
riskManager.recordTrade('buy', tokenMint, config.trading.sniperAmount, 0, buyResult.txHash);
|
|
|
|
// Send notification
|
|
await notificationService.notifyTradeExecution('buy', tokenMint, config.trading.sniperAmount, 0, buyResult.txHash);
|
|
|
|
// Add to active positions for monitoring
|
|
const position = {
|
|
entryPrice: 0, // Will be updated when we get price data
|
|
entryAmount: config.trading.sniperAmount,
|
|
entryTime: Date.now(),
|
|
entryValue: config.trading.sniperAmount,
|
|
currentPrice: 0,
|
|
poolStatus,
|
|
context,
|
|
};
|
|
|
|
riskManager.activePositions.set(tokenMint, position);
|
|
|
|
logger.info(`Position opened for ${tokenMint}`, position);
|
|
|
|
} else {
|
|
logger.error(`Failed to execute sniper trade for ${tokenMint}`);
|
|
await notificationService.notifyError(
|
|
new Error('Buy transaction failed'),
|
|
`Sniper Trade - ${tokenMint}`
|
|
);
|
|
}
|
|
|
|
} catch (error) {
|
|
logger.error(`Error handling new token launch for ${tokenMint}`, error);
|
|
await notificationService.notifyError(error, `New Token Launch - ${tokenMint}`);
|
|
}
|
|
}
|
|
|
|
// Export functions for external use
|
|
export { closePosition, closeAllPositions, monitorPositions, handleNewTokenLaunch };
|