🤖Example - Trading Bot
This example demonstrates how to create an intelligent trading bot specifically designed for Yoink bonding curve tokens, with features for monitoring market conditions, price movements, and automated trading strategies using the real SDK.
Overview
This bot will:
Monitor bonding curve tokens across the Yoink protocol
Track market cap, buyer activity, and price movements
Execute buy orders based on momentum and market conditions
Implement stop-loss and take-profit strategies with slippage protection
Log all trading activity with detailed analytics
Send notifications for important price movements
Prerequisites
Yoink SDK installed:
npm install yoink-sdkFunded wallet with SOL for trading
Basic understanding of bonding curves and trading concepts
Script Code
import { YoinkSDK } from "yoink-sdk";
import { Connection, Keypair, LAMPORTS_PER_SOL, PublicKey } from "@solana/web3.js";
import { AnchorProvider } from "@coral-xyz/anchor";
import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
import { getAccount, getAssociatedTokenAddress } from "@solana/spl-token";
interface BotConfig {
// Target Token Settings
targetTokens: string[]; // Specific token mints to monitor
maxMarketCap: number; // SOL - max market cap to trade
minBuyers: number; // Minimum number of buyers required
onlyIncompleteCarves: boolean; // Only trade incomplete bonding curves
// Trading Parameters
buyAmount: number; // SOL amount per buy
maxSlippage: number; // Slippage tolerance in basis points
maxPriceImpact: number; // Maximum price impact percentage
profitTarget: number; // Take profit percentage
stopLoss: number; // Stop loss percentage
// Bot Behavior
checkInterval: number; // Check interval in milliseconds
maxPositions: number; // Maximum concurrent positions
enableMomentumTrading: boolean; // Enable momentum-based trading
}
interface Position {
mint: string;
balance: number;
entryPrice: number;
entryTime: number;
entryMarketCap: number;
stopLossPrice: number;
takeProfitPrice: number;
}
class BondingCurveTradingBot {
private sdk: YoinkSDK;
private keypair: Keypair;
private config: BotConfig;
private positions: Map<string, Position>;
private isRunning: boolean = false;
private marketData: Map<string, any[]> = new Map(); // Price history
constructor(keypair: Keypair, config: Partial<BotConfig>) {
// Initialize connection and provider
const connection = new Connection(config.rpcUrl || "https://staging-rpc.dev2.eclipsenetwork.xyz");
const wallet = new NodeWallet(keypair);
const provider = new AnchorProvider(connection, wallet, { commitment: "confirmed" });
this.sdk = new YoinkSDK(provider);
this.keypair = keypair;
this.positions = new Map();
this.config = {
targetTokens: config.targetTokens || [],
maxMarketCap: config.maxMarketCap || 50, // 50 SOL max market cap
minBuyers: config.minBuyers || 10,
onlyIncompleteCarves: config.onlyIncompleteCarves !== false,
buyAmount: config.buyAmount || 0.01, // 0.01 SOL per trade
maxSlippage: config.maxSlippage || 500, // 5%
maxPriceImpact: config.maxPriceImpact || 3, // 3%
profitTarget: config.profitTarget || 25, // 25% profit target
stopLoss: config.stopLoss || -15, // 15% stop loss
checkInterval: config.checkInterval || 10000, // 10 seconds
maxPositions: config.maxPositions || 5,
enableMomentumTrading: config.enableMomentumTrading !== false,
}
async start() {
console.log('🤖 Starting Bonding Curve Trading Bot...');
console.log('Wallet:', this.keypair.publicKey.toBase58());
try {
// Test connection
const global = await this.sdk.getGlobalAccount();
console.log('✅ Connected to Yoink protocol');
console.log('Protocol fee:', Number(global.feeBasisPoints) / 100, '%');
console.log('📊 Bot Configuration:');
console.log(' Max Market Cap:', this.config.maxMarketCap, 'SOL');
console.log(' Min Buyers:', this.config.minBuyers);
console.log(' Buy Amount:', this.config.buyAmount, 'SOL');
console.log(' Profit Target:', this.config.profitTarget, '%');
console.log(' Stop Loss:', this.config.stopLoss, '%');
console.log(' Max Positions:', this.config.maxPositions);
this.isRunning = true;
await this.monitorAndTrade();
} catch (error) {
console.error('❌ Failed to start bot:', error);
}
}
async monitorAndTrade() {
while (this.isRunning) {
try {
console.log('🔍 Scanning market...');
// Check existing positions first
await this.checkExistingPositions();
// Look for new opportunities
if (this.positions.size < this.config.maxPositions) {
await this.scanForOpportunities();
}
await this.sleep(this.config.checkInterval);
} catch (error) {
console.error('❌ Monitoring error:', error);
await this.sleep(5000);
}
}
async checkExistingPositions() {
for (const [mintStr, position] of this.positions.entries()) {
try {
const mint = new PublicKey(mintStr);
const curve = await this.sdk.getBondingCurveAccount(mint);
if (!curve) continue;
const currentPrice = curve.getPricePerToken();
const profitLoss = ((currentPrice - position.entryPrice) / position.entryPrice) * 100;
console.log(`📈 ${mintStr.slice(0, 8)}... P&L: ${profitLoss.toFixed(2)}%`);
// Check exit conditions
const shouldSell =
profitLoss >= this.config.profitTarget ||
profitLoss <= this.config.stopLoss ||
curve.complete;
if (shouldSell) {
const reason = curve.complete ? 'Curve completed' :
profitLoss >= this.config.profitTarget ? 'Profit target hit' :
'Stop loss triggered';
console.log(`💰 Selling ${mintStr.slice(0, 8)}... (${reason})`);
await this.sellPosition(mint, position);
}
} catch (error) {
console.error(`❌ Error checking position ${mintStr}:`, error);
}
}
}
async scanForOpportunities() {
for (const mintStr of this.config.targetTokens) {
try {
const mint = new PublicKey(mintStr);
await this.analyzeToken(mint);
} catch (error) {
console.error(`❌ Error analyzing ${mintStr}:`, error);
}
}
}
async analyzeToken(mint: PublicKey) {
try {
const curve = await this.sdk.getBondingCurveAccount(mint);
if (!curve) return;
const marketCap = Number(curve.getMarketCapSOL()) / LAMPORTS_PER_SOL;
const totalBuyers = Number(curve.totalBuyers);
const isComplete = curve.complete;
const currentPrice = curve.getPricePerToken();
// Store price history for momentum analysis
const history = this.marketData.get(mint.toBase58()) || [];
history.push({
timestamp: Date.now(),
price: currentPrice,
marketCap,
buyers: totalBuyers
});
// Keep only last 20 data points
if (history.length > 20) history.shift();
this.marketData.set(mint.toBase58(), history);
console.log(`🔍 ${mint.toBase58().slice(0, 8)}...`);
console.log(` Market Cap: ${marketCap.toFixed(4)} SOL`);
console.log(` Buyers: ${totalBuyers}`);
console.log(` Complete: ${isComplete}`);
// Check if we should buy
const shouldBuy = this.shouldBuyToken(curve, history);
if (shouldBuy && !this.positions.has(mint.toBase58())) {
await this.buyToken(mint, curve);
}
} catch (error) {
console.error(`❌ Analysis error for ${mint.toBase58()}:`, error);
}
}
shouldBuyToken(curve: any, history: any[]): boolean {
const marketCap = Number(curve.getMarketCapSOL()) / LAMPORTS_PER_SOL;
const totalBuyers = Number(curve.totalBuyers);
// Basic filters
if (marketCap > this.config.maxMarketCap) return false;
if (totalBuyers < this.config.minBuyers) return false;
if (this.config.onlyIncompleteCarves && curve.complete) return false;
// Momentum analysis
if (this.config.enableMomentumTrading && history.length >= 3) {
const recent = history.slice(-3);
const buyerGrowth = recent[2].buyers - recent[0].buyers;
const priceGrowth = ((recent[2].price - recent[0].price) / recent[0].price) * 100;
// Look for positive momentum
if (buyerGrowth > 2 && priceGrowth > 5) {
console.log(`📈 Momentum detected: +${buyerGrowth} buyers, +${priceGrowth.toFixed(2)}% price`);
return true;
}
}
// Basic entry conditions
return marketCap < 20 && totalBuyers > 15; // Conservative entry
}
async buyToken(mint: PublicKey, curve: any) {
try {
const buyAmount = BigInt(this.config.buyAmount * LAMPORTS_PER_SOL);
// Get quote first
const quote = await this.sdk.getBuyQuote(mint, buyAmount, BigInt(this.config.maxSlippage));
if (quote.priceImpact > this.config.maxPriceImpact) {
console.log(`⚠️ Price impact too high: ${quote.priceImpact.toFixed(2)}%`);
return;
}
console.log(`🟢 Buying ${mint.toBase58().slice(0, 8)}...`);
console.log(` Quote: ${quote.tokenAmount} tokens`);
console.log(` Price impact: ${quote.priceImpact.toFixed(2)}%`);
const result = await this.sdk.buy(
this.keypair,
mint,
buyAmount,
BigInt(this.config.maxSlippage),
{ unitLimit: 400000, unitPrice: 100000 }
);
if (result.success) {
const position: Position = {
mint: mint.toBase58(),
balance: Number(quote.tokenAmount) / Math.pow(10, 6),
entryPrice: curve.getPricePerToken(),
entryTime: Date.now(),
entryMarketCap: Number(curve.getMarketCapSOL()) / LAMPORTS_PER_SOL,
stopLossPrice: curve.getPricePerToken() * (1 + this.config.stopLoss / 100),
takeProfitPrice: curve.getPricePerToken() * (1 + this.config.profitTarget / 100),
};
this.positions.set(mint.toBase58(), position);
console.log(`✅ Position opened! Signature: ${result.signature}`);
} else {
console.error(`❌ Buy failed:`, result.error);
}
} catch (error) {
console.error('❌ Buy execution error:', error);
}
}
async sellPosition(mint: PublicKey, position: Position) {
try {
const tokenAmount = BigInt(Math.floor(position.balance * Math.pow(10, 6)));
const result = await this.sdk.sell(
this.keypair,
mint,
tokenAmount,
BigInt(this.config.maxSlippage)
);
if (result.success) {
const curve = await this.sdk.getBondingCurveAccount(mint);
const exitPrice = curve?.getPricePerToken() || 0;
const profitLoss = ((exitPrice - position.entryPrice) / position.entryPrice) * 100;
const holdTime = (Date.now() - position.entryTime) / 1000 / 60; // minutes
console.log(`✅ Position closed! Signature: ${result.signature}`);
console.log(`💰 Final P&L: ${profitLoss.toFixed(2)}%`);
console.log(`⏱️ Hold time: ${holdTime.toFixed(1)} minutes`);
this.positions.delete(mint.toBase58());
} else {
console.error(`❌ Sell failed:`, result.error);
}
} catch (error) {
console.error('❌ Sell execution error:', error);
}
}
displayStatus() {
console.log('\\n📊 Bot Status:');
console.log(`Active positions: ${this.positions.size}/${this.config.maxPositions}`);
console.log(`Monitoring ${this.config.targetTokens.length} tokens`);
if (this.positions.size > 0) {
console.log('\\n💼 Current Positions:');
this.positions.forEach(position => {
const holdTime = (Date.now() - position.entryTime) / 1000 / 60;
console.log(` ${position.mint.slice(0, 8)}... (${holdTime.toFixed(1)}m ago)`);
});
}
console.log('─'.repeat(50));
}
stop() {
console.log('🛑 Stopping trading bot...');
this.isRunning = false;
}
sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
// Usage Example
async function main() {
const keypair = Keypair.generate(); // Use your funded keypair
const bot = new BondingCurveTradingBot(keypair, {
targetTokens: [
"9BSxAV9iRuiT3W7kwhFEkmzfoMo7xZTBdFGRF793JRbC",
// Add more token mints to monitor
],
maxMarketCap: 30, // Max 30 SOL market cap
minBuyers: 8, // Min 8 buyers
onlyIncompleteCarves: true, // Only trade incomplete curves
buyAmount: 0.005, // 0.005 SOL per trade
maxSlippage: 400, // 4% slippage
maxPriceImpact: 2.5, // 2.5% max price impact
profitTarget: 20, // 20% profit target
stopLoss: -12, // 12% stop loss
checkInterval: 8000, // Check every 8 seconds
maxPositions: 3, // Max 3 concurrent positions
enableMomentumTrading: true, // Enable momentum analysis
});
await bot.start();
// Display status every 30 seconds
setInterval(() => {
bot.displayStatus();
}, 30000);
// Stop after 2 hours (for demo)
setTimeout(() => {
bot.stop();
}, 2 * 60 * 60 * 1000);
}
main().catch(console.error);Configuration Options
targetTokens
Array
[]
Token mint addresses to monitor
maxMarketCap
Number
50
Maximum market cap in SOL
minBuyers
Number
10
Minimum number of buyers required
onlyIncompleteCarves
Boolean
true
Only trade incomplete bonding curves
buyAmount
Number
0.01
SOL amount per trade
maxSlippage
Number
500
Maximum slippage in basis points
maxPriceImpact
Number
3
Maximum price impact percentage
profitTarget
Number
25
Profit target percentage
stopLoss
Number
-15
Stop loss percentage
maxPositions
Number
5
Maximum concurrent positions
enableMomentumTrading
Boolean
true
Enable momentum analysis
Bot Features
Real Market Analysis: Uses actual bonding curve data for decision making
Momentum Detection: Analyzes buyer growth and price trends
Risk Management: Automatic stop-loss and take-profit execution
Position Tracking: Comprehensive position management
Slippage Protection: Built-in price impact and slippage controls
Market Cap Filtering: Focuses on tokens within specified market cap range
Safety Features
Max Position Limits: Prevents over-exposure
Price Impact Checks: Avoids high-impact trades
Stop Loss Protection: Automatic risk management
Curve Completion Detection: Exits positions when curves complete
Comprehensive Logging: Detailed trade history and performance
Running the Bot
Set up your keypair and configuration
Add target token mints to monitor
Adjust risk parameters for your strategy
Run with
npx ts-node trading-bot.ts
⚠️ Important: Test thoroughly on testnet before using real funds!
Safety Features
Slippage Protection: 5% maximum slippage on all trades
Error Handling: Continues monitoring even if individual trades fail
Position Tracking: Prevents duplicate orders
Logging: Comprehensive trade logging for analysis
Running the Script
Install dependencies:
npm install yoink-sdk @solana/web3.jsConfigure your settings:
Replace
yourWalletAdapterwith your actual wallet adapterAdd real token addresses to monitor
Adjust thresholds and amounts for your strategy
Run the script:
node trading-bot.js
Next Steps
Last updated
