/** * Trading Bot v4 - Configuration * * Optimized for 5-minute scalping with 10x leverage on Drift Protocol */ export interface TradingConfig { // Position sizing positionSize: number // USD amount to trade leverage: number // Leverage multiplier // Risk management (as percentages of entry price) stopLossPercent: number // Negative number (e.g., -1.5) takeProfit1Percent: number // Positive number (e.g., 0.7) takeProfit2Percent: number // Positive number (e.g., 1.5) emergencyStopPercent: number // Hard stop (e.g., -2.0) // Dual Stop System (Advanced) useDualStops: boolean // Enable dual stop system softStopPercent: number // Soft stop trigger (e.g., -1.5) softStopBuffer: number // Buffer for soft stop limit (e.g., 0.4) hardStopPercent: number // Hard stop trigger (e.g., -2.5) // Dynamic adjustments breakEvenTriggerPercent: number // When to move SL to breakeven profitLockTriggerPercent: number // When to lock in profit profitLockPercent: number // How much profit to lock // Trailing stop for runner (after TP2) useTrailingStop: boolean // Enable trailing stop for remaining position trailingStopPercent: number // Trail by this % below peak trailingStopActivation: number // Activate when runner profits exceed this % // DEX specific priceCheckIntervalMs: number // How often to check prices slippageTolerance: number // Max acceptable slippage (%) // Risk limits maxDailyDrawdown: number // USD stop trading threshold maxTradesPerHour: number // Limit overtrading minTimeBetweenTrades: number // Cooldown period (seconds) // Execution useMarketOrders: boolean // true = instant execution confirmationTimeout: number // Max time to wait for confirmation // Take profit size splits (percentages of position to close at TP1/TP2) takeProfit1SizePercent: number takeProfit2SizePercent: number } export interface MarketConfig { symbol: string // e.g., 'SOL-PERP' driftMarketIndex: number pythPriceFeedId: string minOrderSize: number tickSize: number } // Default configuration for 5-minute scalping with $1000 capital and 10x leverage export const DEFAULT_TRADING_CONFIG: TradingConfig = { // Position sizing positionSize: 50, // $50 base capital (SAFE FOR TESTING) leverage: 10, // 10x leverage = $500 position size // Risk parameters (wider for DEX slippage/wicks) stopLossPercent: -1.5, // -1.5% price = -15% account loss (closes 100%) takeProfit1Percent: 0.7, // +0.7% price = +7% account gain (closes 50%) takeProfit2Percent: 1.5, // +1.5% price = +15% account gain (closes 50%) emergencyStopPercent: -2.0, // -2% hard stop = -20% account loss // Dual Stop System useDualStops: false, // Disabled by default softStopPercent: -1.5, // Soft stop (TRIGGER_LIMIT) softStopBuffer: 0.4, // 0.4% buffer (limit at -1.9%) hardStopPercent: -2.5, // Hard stop (TRIGGER_MARKET) // Dynamic adjustments breakEvenTriggerPercent: 0.4, // Move SL to this profit level after TP1 hits profitLockTriggerPercent: 1.0, // Lock profit at +1.0% profitLockPercent: 0.4, // Lock +0.4% profit // Trailing stop for runner (after TP2) useTrailingStop: true, // Enable trailing stop for remaining position after TP2 trailingStopPercent: 0.3, // Trail by 0.3% below peak price trailingStopActivation: 0.5, // Activate trailing when runner is +0.5% in profit // DEX settings priceCheckIntervalMs: 2000, // Check every 2 seconds slippageTolerance: 1.0, // 1% max slippage on market orders // Risk limits maxDailyDrawdown: -150, // Stop trading if daily loss exceeds $150 (-15%) maxTradesPerHour: 6, // Max 6 trades per hour minTimeBetweenTrades: 600, // 10 minutes cooldown // Execution useMarketOrders: true, // Use market orders for reliable fills confirmationTimeout: 30000, // 30 seconds max wait takeProfit1SizePercent: 75, // Close 75% at TP1 to lock in profit takeProfit2SizePercent: 80, // Close 80% of remaining 25% at TP2 (leaves 5% as runner) } // Supported markets on Drift Protocol export const SUPPORTED_MARKETS: Record = { 'SOL-PERP': { symbol: 'SOL-PERP', driftMarketIndex: 0, pythPriceFeedId: '0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d', minOrderSize: 0.1, // 0.1 SOL minimum tickSize: 0.0001, }, 'BTC-PERP': { symbol: 'BTC-PERP', driftMarketIndex: 1, pythPriceFeedId: '0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43', minOrderSize: 0.001, // 0.001 BTC minimum tickSize: 0.01, }, 'ETH-PERP': { symbol: 'ETH-PERP', driftMarketIndex: 2, pythPriceFeedId: '0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace', minOrderSize: 0.01, // 0.01 ETH minimum tickSize: 0.01, }, } // Map TradingView symbols to Drift markets export function normalizeTradingViewSymbol(tvSymbol: string): string { const upper = tvSymbol.toUpperCase() if (upper.includes('SOL')) return 'SOL-PERP' if (upper.includes('BTC')) return 'BTC-PERP' if (upper.includes('ETH')) return 'ETH-PERP' // Default to SOL if unknown console.warn(`Unknown symbol ${tvSymbol}, defaulting to SOL-PERP`) return 'SOL-PERP' } // Get market configuration export function getMarketConfig(symbol: string): MarketConfig { const config = SUPPORTED_MARKETS[symbol] if (!config) { throw new Error(`Unsupported market: ${symbol}`) } return config } // Validate trading configuration export function validateTradingConfig(config: TradingConfig): void { if (config.positionSize <= 0) { throw new Error('Position size must be positive') } if (config.leverage < 1 || config.leverage > 20) { throw new Error('Leverage must be between 1 and 20') } if (config.stopLossPercent >= 0) { throw new Error('Stop loss must be negative') } if (config.takeProfit1Percent <= 0 || config.takeProfit2Percent <= 0) { throw new Error('Take profit values must be positive') } if (config.takeProfit1Percent >= config.takeProfit2Percent) { throw new Error('TP2 must be greater than TP1') } if (config.slippageTolerance < 0 || config.slippageTolerance > 10) { throw new Error('Slippage tolerance must be between 0 and 10%') } } // Environment-based configuration export function getConfigFromEnv(): Partial { return { positionSize: process.env.MAX_POSITION_SIZE_USD ? parseFloat(process.env.MAX_POSITION_SIZE_USD) : undefined, leverage: process.env.LEVERAGE ? parseInt(process.env.LEVERAGE) : undefined, stopLossPercent: process.env.STOP_LOSS_PERCENT ? parseFloat(process.env.STOP_LOSS_PERCENT) : undefined, useDualStops: process.env.USE_DUAL_STOPS ? process.env.USE_DUAL_STOPS === 'true' : undefined, softStopPercent: process.env.SOFT_STOP_PERCENT ? parseFloat(process.env.SOFT_STOP_PERCENT) : undefined, softStopBuffer: process.env.SOFT_STOP_BUFFER ? parseFloat(process.env.SOFT_STOP_BUFFER) : undefined, hardStopPercent: process.env.HARD_STOP_PERCENT ? parseFloat(process.env.HARD_STOP_PERCENT) : undefined, takeProfit1Percent: process.env.TAKE_PROFIT_1_PERCENT ? parseFloat(process.env.TAKE_PROFIT_1_PERCENT) : undefined, takeProfit2Percent: process.env.TAKE_PROFIT_2_PERCENT ? parseFloat(process.env.TAKE_PROFIT_2_PERCENT) : undefined, takeProfit1SizePercent: process.env.TAKE_PROFIT_1_SIZE_PERCENT ? parseFloat(process.env.TAKE_PROFIT_1_SIZE_PERCENT) : undefined, takeProfit2SizePercent: process.env.TAKE_PROFIT_2_SIZE_PERCENT ? parseFloat(process.env.TAKE_PROFIT_2_SIZE_PERCENT) : undefined, breakEvenTriggerPercent: process.env.BREAKEVEN_TRIGGER_PERCENT ? parseFloat(process.env.BREAKEVEN_TRIGGER_PERCENT) : undefined, profitLockTriggerPercent: process.env.PROFIT_LOCK_TRIGGER_PERCENT ? parseFloat(process.env.PROFIT_LOCK_TRIGGER_PERCENT) : undefined, profitLockPercent: process.env.PROFIT_LOCK_PERCENT ? parseFloat(process.env.PROFIT_LOCK_PERCENT) : undefined, useTrailingStop: process.env.USE_TRAILING_STOP ? process.env.USE_TRAILING_STOP === 'true' : undefined, trailingStopPercent: process.env.TRAILING_STOP_PERCENT ? parseFloat(process.env.TRAILING_STOP_PERCENT) : undefined, trailingStopActivation: process.env.TRAILING_STOP_ACTIVATION ? parseFloat(process.env.TRAILING_STOP_ACTIVATION) : undefined, maxDailyDrawdown: process.env.MAX_DAILY_DRAWDOWN ? parseFloat(process.env.MAX_DAILY_DRAWDOWN) : undefined, maxTradesPerHour: process.env.MAX_TRADES_PER_HOUR ? parseInt(process.env.MAX_TRADES_PER_HOUR) : undefined, } } // Merge configurations export function getMergedConfig( overrides?: Partial ): TradingConfig { const envConfig = getConfigFromEnv() const config = { ...DEFAULT_TRADING_CONFIG, ...envConfig, ...overrides, } validateTradingConfig(config) return config }