/** * Hybrid Trading Strategies Module * Implements various hybrid crypto trading strategies */ /** * Strategy configurations with detailed indicator parameters */ export const HYBRID_STRATEGIES = { 'trend-rsi-macd': { name: 'Trend + RSI + MACD', description: 'Combines trend analysis with momentum indicators', indicators: ['EMA20', 'EMA50', 'RSI', 'MACD'], timeframes: ['4h', '1d'], riskLevel: 'medium', scientific: true, }, 'bb-rsi': { name: 'Bollinger Bands + RSI', description: 'Mean reversion strategy with volatility bands', indicators: ['BB', 'RSI', 'Volume'], timeframes: ['1h', '4h'], riskLevel: 'low', scientific: true, }, 'ema-volume-rsi': { name: 'EMA + Volume + RSI', description: 'Momentum strategy with volume confirmation', indicators: ['EMA12', 'EMA26', 'Volume', 'RSI'], timeframes: ['1h', '4h', '1d'], riskLevel: 'medium', scientific: true, }, 'sr-fibonacci': { name: 'Support/Resistance + Fibonacci', description: 'Price action with Fibonacci retracement levels', indicators: ['S/R', 'Fibonacci', 'Volume'], timeframes: ['4h', '1d', '1w'], riskLevel: 'high', scientific: true, }, 'macd-stoch-ema': { name: 'MACD + Stochastic + EMA', description: 'Triple momentum confirmation strategy', indicators: ['MACD', 'Stochastic', 'EMA9', 'EMA21'], timeframes: ['1h', '4h'], riskLevel: 'medium', scientific: true, }, 'ensemble-multitimeframe': { name: 'Ensemble Multi-Timeframe', description: 'Advanced: Combines multiple timeframes with ensemble voting', indicators: ['RSI', 'MACD', 'EMA', 'Volume', 'BB'], timeframes: ['15m', '1h', '4h', '1d'], riskLevel: 'medium', scientific: true, advanced: true, }, 'volume-profile-orderflow': { name: 'Volume Profile + Order Flow', description: 'Advanced: Price action with volume analysis and order flow', indicators: ['Volume', 'OBV', 'VWAP', 'Price Action'], timeframes: ['1h', '4h', '1d'], riskLevel: 'high', scientific: true, advanced: true, }, 'adaptive-breakout': { name: 'Adaptive Breakout Strategy', description: 'Advanced: Dynamic breakout detection with volatility adjustment', indicators: ['ATR', 'BB', 'Volume', 'Support/Resistance'], timeframes: ['4h', '1d'], riskLevel: 'medium', scientific: true, advanced: true, }, 'mean-reversion-momentum': { name: 'Mean Reversion + Momentum Filter', description: 'Advanced: Mean reversion with momentum confirmation filter', indicators: ['RSI', 'Stochastic', 'MACD', 'EMA'], timeframes: ['1h', '4h'], riskLevel: 'low', scientific: true, advanced: true, }, 'sr-breakout-confirmation': { name: 'S/R Breakout with Confirmation', description: 'Advanced: Support/Resistance breakout with multi-indicator confirmation', indicators: ['S/R', 'Volume', 'RSI', 'MACD', 'EMA'], timeframes: ['4h', '1d'], riskLevel: 'high', scientific: true, advanced: true, }, 'pre-breakout-scalping': { name: 'Pre-Breakout Scalping', description: 'Scalping: Detects entry points before breakout occurs', indicators: ['Volume', 'RSI', 'BB', 'Price Action', 'Momentum'], timeframes: ['1m', '5m', '15m'], riskLevel: 'very-high', scientific: true, advanced: true, scalping: true, }, 'liquidity-zone-scalping': { name: 'Liquidity Zone Scalping', description: 'Scalping: Identifies liquidity zones before price moves', indicators: ['Volume Profile', 'Order Flow', 'Support/Resistance', 'RSI'], timeframes: ['1m', '5m'], riskLevel: 'very-high', scientific: true, advanced: true, scalping: true, }, 'momentum-accumulation-scalping': { name: 'Momentum Accumulation Scalping', description: 'Scalping: Detects momentum buildup before bullish/bearish moves', indicators: ['RSI', 'MACD', 'Volume', 'EMA', 'Momentum'], timeframes: ['1m', '5m', '15m'], riskLevel: 'very-high', scientific: true, advanced: true, scalping: true, }, 'volume-spike-breakout': { name: 'Volume Spike Breakout Scalping', description: 'Scalping: Volume spike detection before breakout', indicators: ['Volume', 'OBV', 'Price Action', 'RSI', 'BB'], timeframes: ['1m', '5m'], riskLevel: 'very-high', scientific: true, advanced: true, scalping: true, }, 'order-flow-imbalance-scalping': { name: 'Order Flow Imbalance Scalping', description: 'Scalping: Detects order flow imbalance before price moves', indicators: ['Order Flow', 'Volume', 'Price Action', 'Momentum'], timeframes: ['1m', '5m'], riskLevel: 'very-high', scientific: true, advanced: true, scalping: true, }, }; /** * Analyzes market using selected hybrid strategy with fallback * @param {string} symbol - Trading symbol * @param {string} strategyKey - Strategy identifier * @param {Object} marketData - Current market data * @returns {Object} Analysis results with signals */ export function analyzeWithStrategy(symbol, strategyKey, marketData) { try { const strategy = HYBRID_STRATEGIES[strategyKey]; if (!strategy) { console.warn(`[Strategies] Unknown strategy: ${strategyKey}, using fallback`); return analyzeWithFallback(symbol, marketData); } if (!marketData || typeof marketData !== 'object') { throw new Error('Invalid market data: not an object'); } const price = parseFloat(marketData.price); const volume = parseFloat(marketData.volume || 0) || 0; const high24h = parseFloat(marketData.high24h || marketData.high_24h || 0) || 0; const low24h = parseFloat(marketData.low24h || marketData.low_24h || 0) || 0; if (isNaN(price) || price <= 0) { throw new Error('Invalid market data: missing or invalid price'); } // Validate high/low relationships const validHigh24h = (high24h > 0 && high24h >= price) ? high24h : price * 1.05; const validLow24h = (low24h > 0 && low24h <= price) ? low24h : price * 0.95; if (validHigh24h < validLow24h) { throw new Error('Invalid market data: high24h < low24h'); } const indicators = calculateIndicators(price, volume, validHigh24h, validLow24h); const signal = generateSignal(strategyKey, indicators, price, marketData); const levels = calculateSupportResistance(price, high24h, low24h); const isScalping = strategy.scalping || false; const riskReward = calculateRiskReward(price, signal.signal, levels, isScalping); return { strategy: strategy.name, signal: signal.signal, strength: signal.strength, confidence: signal.confidence, indicators, levels, riskReward, takeProfitLevels: riskReward.takeProfits, stopLoss: riskReward.stopLoss, timestamp: new Date().toISOString(), strategyType: strategy.scalping ? 'scalping' : strategy.advanced ? 'advanced' : 'standard', isScalping: isScalping, }; } catch (error) { console.error(`[Strategies] Error in ${strategyKey}:`, error); return analyzeWithFallback(symbol, marketData); } } /** * Fallback analysis when primary strategy fails */ function analyzeWithFallback(symbol, marketData) { if (!marketData || typeof marketData !== 'object') { marketData = {}; } const price = parseFloat(marketData.price) || 0; const volume = parseFloat(marketData.volume || 0) || 0; const high24h = (price > 0 && parseFloat(marketData.high24h || marketData.high_24h) > 0) ? parseFloat(marketData.high24h || marketData.high_24h) : (price > 0 ? price * 1.05 : 0); const low24h = (price > 0 && parseFloat(marketData.low24h || marketData.low_24h) > 0) ? parseFloat(marketData.low24h || marketData.low_24h) : (price > 0 ? price * 0.95 : 0); if (price <= 0) { // Return minimal fallback return { strategy: 'Basic Analysis (Fallback)', signal: 'hold', strength: 'weak', confidence: 0, indicators: { rsi: 50, macd: 'neutral', trend: 'neutral' }, levels: { support: [], resistance: [] }, riskReward: { stopLoss: 0, takeProfits: [], riskRewardRatio: '1:1', riskPercentage: '0.00' }, takeProfitLevels: [], stopLoss: 0, timestamp: new Date().toISOString(), strategyType: 'fallback', }; } const validHigh24h = (high24h > 0 && high24h >= price) ? high24h : price * 1.05; const validLow24h = (low24h > 0 && low24h <= price) ? low24h : price * 0.95; const indicators = calculateIndicators(price, volume, validHigh24h, validLow24h); const levels = calculateSupportResistance(price, validHigh24h, validLow24h); return { strategy: 'Basic Analysis (Fallback)', signal: 'hold', strength: 'weak', confidence: 50, indicators, levels, riskReward: { stopLoss: price * 0.95, takeProfits: [ { level: price * 1.02, type: 'TP1', percentage: 50 }, { level: price * 1.05, type: 'TP2', percentage: 50 }, ], riskRewardRatio: '1:2', riskPercentage: '5.00', }, takeProfitLevels: [ { level: price * 1.02, type: 'TP1', percentage: 50 }, { level: price * 1.05, type: 'TP2', percentage: 50 }, ], stopLoss: price * 0.95, timestamp: new Date().toISOString(), strategyType: 'fallback', }; } /** * Calculates technical indicators with error handling */ function calculateIndicators(price, volume, high24h, low24h) { try { if (typeof price !== 'number' || isNaN(price) || price <= 0) { throw new Error('Invalid price'); } const validVolume = (typeof volume === 'number' && !isNaN(volume) && volume >= 0) ? volume : 0; const validHigh = (typeof high24h === 'number' && !isNaN(high24h) && high24h >= price) ? high24h : price * 1.05; const validLow = (typeof low24h === 'number' && !isNaN(low24h) && low24h <= price && low24h > 0) ? low24h : price * 0.95; if (validHigh < validLow) { throw new Error('Invalid range: high < low'); } const range = Math.max(validHigh - validLow, price * 0.01); const position = range > 0 ? Math.max(0, Math.min(1, (price - validLow) / range)) : 0.5; const rsi = 30 + position * 40; const macd = position > 0.6 ? 'bullish' : position < 0.4 ? 'bearish' : 'neutral'; const trend = position > 0.5 ? 'up' : 'down'; const volatility = range / price; const bbUpper = price * (1 + Math.max(0.01, volatility * 1.5)); const bbLower = price * (1 - Math.max(0.01, volatility * 1.5)); const bbPosition = position > 0.8 ? 'upper' : position < 0.2 ? 'lower' : 'middle'; const stochastic = Math.round(position * 100); const atr = range; const obv = volume * (trend === 'up' ? 1 : -1); return { rsi: parseFloat(rsi.toFixed(2)), macd, trend, bollingerBands: { upper: parseFloat(bbUpper.toFixed(2)), lower: parseFloat(bbLower.toFixed(2)), position: bbPosition, width: parseFloat((bbUpper - bbLower).toFixed(2)), }, stochastic, volume: volume || 0, atr: parseFloat(atr.toFixed(2)), obv: obv || 0, volatility: parseFloat((volatility * 100).toFixed(2)), }; } catch (error) { console.error('[Strategies] Error calculating indicators:', error); return { rsi: 50, macd: 'neutral', trend: 'neutral', bollingerBands: { upper: price * 1.02, lower: price * 0.98, position: 'middle', width: price * 0.04 }, stochastic: 50, volume: 0, atr: 0, obv: 0, volatility: 0, }; } } /** * Validate market data structure * @param {Object} marketData - Market data to validate * @returns {Object} Validation result */ export function validateMarketData(marketData) { if (!marketData || typeof marketData !== 'object') { return { valid: false, error: 'Market data is not an object' }; } const price = parseFloat(marketData.price); if (isNaN(price) || price <= 0) { return { valid: false, error: 'Invalid or missing price' }; } const volume = parseFloat(marketData.volume || marketData.volume_24h || 0); if (isNaN(volume) || volume < 0) { return { valid: false, error: 'Invalid volume' }; } const high24h = parseFloat(marketData.high24h || marketData.high_24h || price * 1.05); const low24h = parseFloat(marketData.low24h || marketData.low_24h || price * 0.95); if (isNaN(high24h) || high24h < price) { return { valid: false, error: 'Invalid high24h' }; } if (isNaN(low24h) || low24h > price || low24h <= 0) { return { valid: false, error: 'Invalid low24h' }; } if (high24h < low24h) { return { valid: false, error: 'high24h < low24h' }; } return { valid: true }; } /** * Generates trading signal based on strategy */ function generateSignal(strategyKey, indicators, price, marketData = {}) { let signal = 'hold'; let strength = 'medium'; let confidence = 50; try { switch (strategyKey) { case 'trend-rsi-macd': if (indicators.trend === 'up' && indicators.rsi < 70 && indicators.macd === 'bullish') { signal = 'buy'; strength = 'strong'; confidence = 85; } else if (indicators.trend === 'down' && indicators.rsi > 30 && indicators.macd === 'bearish') { signal = 'sell'; strength = 'strong'; confidence = 85; } break; case 'bb-rsi': if (indicators.bollingerBands.position === 'lower' && indicators.rsi < 30) { signal = 'buy'; strength = 'strong'; confidence = 80; } else if (indicators.bollingerBands.position === 'upper' && indicators.rsi > 70) { signal = 'sell'; strength = 'strong'; confidence = 80; } break; case 'ema-volume-rsi': if (indicators.trend === 'up' && indicators.rsi < 65 && indicators.volume > 0) { signal = 'buy'; strength = 'medium'; confidence = 75; } else if (indicators.trend === 'down' && indicators.rsi > 35 && indicators.volume > 0) { signal = 'sell'; strength = 'medium'; confidence = 75; } break; case 'sr-fibonacci': if (indicators.rsi < 35) { signal = 'buy'; strength = 'strong'; confidence = 82; } else if (indicators.rsi > 65) { signal = 'sell'; strength = 'strong'; confidence = 82; } break; case 'macd-stoch-ema': if (indicators.macd === 'bullish' && indicators.stochastic < 20 && indicators.trend === 'up') { signal = 'buy'; strength = 'strong'; confidence = 88; } else if (indicators.macd === 'bearish' && indicators.stochastic > 80 && indicators.trend === 'down') { signal = 'sell'; strength = 'strong'; confidence = 88; } break; case 'ensemble-multitimeframe': signal = generateEnsembleSignal(indicators, marketData); strength = 'strong'; confidence = 90; break; case 'volume-profile-orderflow': signal = generateVolumeProfileSignal(indicators, marketData); strength = 'strong'; confidence = 87; break; case 'adaptive-breakout': signal = generateAdaptiveBreakoutSignal(indicators, marketData); strength = 'strong'; confidence = 85; break; case 'mean-reversion-momentum': signal = generateMeanReversionMomentumSignal(indicators); strength = 'medium'; confidence = 83; break; case 'sr-breakout-confirmation': signal = generateSRBreakoutSignal(indicators, marketData); strength = 'strong'; confidence = 89; break; case 'pre-breakout-scalping': signal = generatePreBreakoutScalpingSignal(indicators, marketData); strength = 'strong'; confidence = 92; break; case 'liquidity-zone-scalping': signal = generateLiquidityZoneScalpingSignal(indicators, marketData); strength = 'strong'; confidence = 90; break; case 'momentum-accumulation-scalping': signal = generateMomentumAccumulationSignal(indicators, marketData); strength = 'strong'; confidence = 91; break; case 'volume-spike-breakout': signal = generateVolumeSpikeBreakoutSignal(indicators, marketData); strength = 'strong'; confidence = 93; break; case 'order-flow-imbalance-scalping': signal = generateOrderFlowImbalanceSignal(indicators, marketData); strength = 'strong'; confidence = 90; break; } } catch (error) { console.error(`[Strategies] Error generating signal for ${strategyKey}:`, error); signal = 'hold'; strength = 'weak'; confidence = 50; } return { signal, strength, confidence }; } /** * Advanced: Ensemble multi-timeframe signal */ function generateEnsembleSignal(indicators, marketData) { const votes = { buy: 0, sell: 0, hold: 0 }; if (indicators.trend === 'up' && indicators.rsi < 70) votes.buy++; if (indicators.trend === 'down' && indicators.rsi > 30) votes.sell++; if (indicators.macd === 'bullish') votes.buy++; if (indicators.macd === 'bearish') votes.sell++; if (indicators.stochastic < 30) votes.buy++; if (indicators.stochastic > 70) votes.sell++; if (votes.buy >= 2) return 'buy'; if (votes.sell >= 2) return 'sell'; return 'hold'; } /** * Advanced: Volume profile and order flow signal */ function generateVolumeProfileSignal(indicators, marketData) { const { volume = 0 } = marketData; const volumeThreshold = volume * 1.2; if (indicators.rsi < 40 && volume > volumeThreshold && indicators.trend === 'up') { return 'buy'; } if (indicators.rsi > 60 && volume > volumeThreshold && indicators.trend === 'down') { return 'sell'; } return 'hold'; } /** * Advanced: Adaptive breakout signal */ function generateAdaptiveBreakoutSignal(indicators, marketData) { const bb = indicators.bollingerBands; const volatility = (bb.upper - bb.lower) / marketData.price; if (bb.position === 'upper' && volatility > 0.02 && indicators.rsi > 60) { return 'sell'; } if (bb.position === 'lower' && volatility > 0.02 && indicators.rsi < 40) { return 'buy'; } return 'hold'; } /** * Advanced: Mean reversion with momentum filter */ function generateMeanReversionMomentumSignal(indicators) { const isOversold = indicators.rsi < 30 && indicators.stochastic < 20; const isOverbought = indicators.rsi > 70 && indicators.stochastic > 80; const momentumUp = indicators.macd === 'bullish' && indicators.trend === 'up'; const momentumDown = indicators.macd === 'bearish' && indicators.trend === 'down'; if (isOversold && momentumUp) return 'buy'; if (isOverbought && momentumDown) return 'sell'; return 'hold'; } /** * Advanced: S/R breakout with confirmation */ function generateSRBreakoutSignal(indicators, marketData) { const { price = 0, high24h = 0, low24h = 0 } = marketData; const nearResistance = price > high24h * 0.98; const nearSupport = price < low24h * 1.02; if (nearResistance && indicators.rsi > 65 && indicators.macd === 'bearish') { return 'sell'; } if (nearSupport && indicators.rsi < 35 && indicators.macd === 'bullish') { return 'buy'; } return 'hold'; } /** * Scalping: Pre-breakout detection algorithm * Identifies entry points before breakout occurs */ function generatePreBreakoutScalpingSignal(indicators, marketData) { const { price = 0, volume = 0, high24h = 0, low24h = 0 } = marketData; const bb = indicators.bollingerBands; const range = high24h - low24h; const position = range > 0 ? (price - low24h) / range : 0.5; const nearUpperBB = price > bb.upper * 0.995 && price < bb.upper * 1.005; const nearLowerBB = price > bb.lower * 0.995 && price < bb.lower * 1.005; const volumeSpike = volume > (marketData.avgVolume || volume * 1.5); const rsiOversold = indicators.rsi < 35; const rsiOverbought = indicators.rsi > 65; if (nearLowerBB && rsiOversold && volumeSpike && indicators.macd === 'bullish') { return 'buy'; } if (nearUpperBB && rsiOverbought && volumeSpike && indicators.macd === 'bearish') { return 'sell'; } if (position < 0.2 && indicators.rsi < 40 && volumeSpike) { return 'buy'; } if (position > 0.8 && indicators.rsi > 60 && volumeSpike) { return 'sell'; } return 'hold'; } /** * Scalping: Liquidity zone detection * Identifies areas of high liquidity before price moves */ function generateLiquidityZoneScalpingSignal(indicators, marketData) { const { price = 0, volume = 0, high24h = 0, low24h = 0 } = marketData; const range = high24h - low24h; const position = range > 0 ? (price - low24h) / range : 0.5; const highVolume = volume > (marketData.avgVolume || volume * 1.3); const lowVolatility = indicators.volatility < 2; const liquidityZoneBuy = position < 0.3 && highVolume && lowVolatility && indicators.rsi < 45; const liquidityZoneSell = position > 0.7 && highVolume && lowVolatility && indicators.rsi > 55; if (liquidityZoneBuy && indicators.macd === 'bullish') { return 'buy'; } if (liquidityZoneSell && indicators.macd === 'bearish') { return 'sell'; } return 'hold'; } /** * Scalping: Momentum accumulation detection * Detects momentum buildup before major moves */ function generateMomentumAccumulationSignal(indicators, marketData) { const { volume = 0 } = marketData; const volumeIncreasing = volume > (marketData.prevVolume || volume * 0.8); const rsiDivergenceBullish = indicators.rsi < 50 && indicators.rsi > 30 && indicators.trend === 'up'; const rsiDivergenceBearish = indicators.rsi > 50 && indicators.rsi < 70 && indicators.trend === 'down'; const macdBullish = indicators.macd === 'bullish'; const macdBearish = indicators.macd === 'bearish'; const momentumAccumulationBuy = rsiDivergenceBullish && macdBullish && volumeIncreasing && indicators.stochastic < 50; const momentumAccumulationSell = rsiDivergenceBearish && macdBearish && volumeIncreasing && indicators.stochastic > 50; if (momentumAccumulationBuy) { return 'buy'; } if (momentumAccumulationSell) { return 'sell'; } return 'hold'; } /** * Scalping: Volume spike breakout detection * Detects volume spikes before breakout */ function generateVolumeSpikeBreakoutSignal(indicators, marketData) { const { price = 0, volume = 0 } = marketData; const volumeSpike = volume > (marketData.avgVolume || volume * 2); const strongVolumeSpike = volume > (marketData.avgVolume || volume * 3); const bb = indicators.bollingerBands; const nearBBMiddle = price > bb.lower * 1.01 && price < bb.upper * 0.99; const rsiNeutral = indicators.rsi > 40 && indicators.rsi < 60; if (strongVolumeSpike && nearBBMiddle && rsiNeutral && indicators.macd === 'bullish') { return 'buy'; } if (strongVolumeSpike && nearBBMiddle && rsiNeutral && indicators.macd === 'bearish') { return 'sell'; } if (volumeSpike && indicators.rsi < 45 && indicators.trend === 'up') { return 'buy'; } if (volumeSpike && indicators.rsi > 55 && indicators.trend === 'down') { return 'sell'; } return 'hold'; } /** * Scalping: Order flow imbalance detection * Detects order flow imbalance before price moves */ function generateOrderFlowImbalanceSignal(indicators, marketData) { const { price = 0, volume = 0 } = marketData; const obv = indicators.obv || 0; const obvIncreasing = obv > 0; const obvDecreasing = obv < 0; const volumeImbalance = volume > (marketData.avgVolume || volume * 1.5); const buyImbalance = obvIncreasing && volumeImbalance && indicators.rsi < 55 && indicators.macd === 'bullish'; const sellImbalance = obvDecreasing && volumeImbalance && indicators.rsi > 45 && indicators.macd === 'bearish'; if (buyImbalance && indicators.stochastic < 60) { return 'buy'; } if (sellImbalance && indicators.stochastic > 40) { return 'sell'; } return 'hold'; } /** * Calculates support and resistance levels */ function calculateSupportResistance(price, high24h, low24h) { const resistance1 = high24h; const resistance2 = price + (high24h - price) * 1.5; const resistance3 = price + (high24h - price) * 2; const support1 = low24h; const support2 = price - (price - low24h) * 1.5; const support3 = price - (price - low24h) * 2; return { resistance: [ { level: resistance1, strength: 'strong' }, { level: resistance2, strength: 'medium' }, { level: resistance3, strength: 'weak' }, ], support: [ { level: support1, strength: 'strong' }, { level: Math.max(support2, 0), strength: 'medium' }, { level: Math.max(support3, 0), strength: 'weak' }, ], }; } /** * Calculates risk/reward ratio and TP/SL levels * For scalping strategies, uses tighter stops and faster targets */ function calculateRiskReward(price, signal, levels, isScalping = false) { let stopLoss = price; let takeProfits = []; let riskRewardRatio = '1:2'; if (isScalping) { if (signal === 'buy') { stopLoss = price * 0.995; const riskAmount = price - stopLoss; takeProfits = [ { level: price + riskAmount * 2, type: 'TP1', percentage: 40 }, { level: price + riskAmount * 3, type: 'TP2', percentage: 35 }, { level: price + riskAmount * 5, type: 'TP3', percentage: 25 }, ]; riskRewardRatio = '1:3'; } else if (signal === 'sell') { stopLoss = price * 1.005; const riskAmount = stopLoss - price; takeProfits = [ { level: price - riskAmount * 2, type: 'TP1', percentage: 40 }, { level: price - riskAmount * 3, type: 'TP2', percentage: 35 }, { level: price - riskAmount * 5, type: 'TP3', percentage: 25 }, ]; riskRewardRatio = '1:3'; } else { stopLoss = price * 0.998; takeProfits = [ { level: price * 1.003, type: 'TP1', percentage: 60 }, { level: price * 1.005, type: 'TP2', percentage: 40 }, ]; } } else { if (signal === 'buy') { stopLoss = levels.support[0].level * 0.98; const riskAmount = price - stopLoss; takeProfits = [ { level: price + riskAmount * 1.5, type: 'TP1', percentage: 33 }, { level: price + riskAmount * 2, type: 'TP2', percentage: 33 }, { level: price + riskAmount * 3, type: 'TP3', percentage: 34 }, ]; riskRewardRatio = '1:2.5'; } else if (signal === 'sell') { stopLoss = levels.resistance[0].level * 1.02; const riskAmount = stopLoss - price; takeProfits = [ { level: price - riskAmount * 1.5, type: 'TP1', percentage: 33 }, { level: price - riskAmount * 2, type: 'TP2', percentage: 33 }, { level: price - riskAmount * 3, type: 'TP3', percentage: 34 }, ]; riskRewardRatio = '1:2.5'; } else { stopLoss = price * 0.95; takeProfits = [ { level: price * 1.02, type: 'TP1', percentage: 50 }, { level: price * 1.05, type: 'TP2', percentage: 50 }, ]; } } return { stopLoss: parseFloat(stopLoss.toFixed(2)), takeProfits, riskRewardRatio, riskPercentage: Math.abs(((stopLoss - price) / price) * 100).toFixed(2), }; }