/** * Enhanced Risk Management System * * Addresses the core issues that caused 47% account loss: * 1. Proper position sizing based on account balance and risk tolerance * 2. Dynamic stop losses based on market volatility (ATR) * 3. Timeframe-appropriate risk management * 4. Anti-overtrading mechanisms * 5. Emergency stop loss protection */ // import { getDB } from './db' export interface RiskAssessment { accountBalance: number currentRisk: number // Percentage of account at risk maxPositionSize: number // Maximum $ amount for next trade recommendedSize: number // Recommended $ amount for next trade stopLossDistance: number // Distance to stop loss in $ riskRewardRatio: number leverageRecommendation: number timeframeRisk: 'LOW' | 'MEDIUM' | 'HIGH' | 'EXTREME' coolingOffRequired: boolean riskWarnings: string[] } export interface TradeRiskParameters { symbol: string direction: 'LONG' | 'SHORT' entryPrice: number stopLoss: number takeProfit: number timeframe: string currentBalance: number recentLosses: number // Recent consecutive losses } export class EnhancedRiskManager { private readonly MAX_RISK_PER_TRADE = 1.0 // 1% max risk per trade private readonly MAX_TOTAL_RISK = 5.0 // 5% max total account risk private readonly COOLING_OFF_HOURS = 24 // Hours to wait after 2 consecutive losses private readonly MAX_CONSECUTIVE_LOSSES = 2 // ATR multipliers for different timeframes private readonly ATR_MULTIPLIERS: Record = { '5': 1.0, // 5m: Tight stops '15': 1.5, // 15m: Moderate stops '30': 2.0, // 30m: Wider stops '60': 2.5, // 1h: Standard stops '240': 3.0, // 4h: Wide stops 'D': 4.0 // Daily: Very wide stops } // Risk level based on timeframe private readonly TIMEFRAME_RISK: Record = { '5': 'EXTREME', '15': 'HIGH', '30': 'HIGH', '60': 'MEDIUM', '240': 'LOW', 'D': 'LOW' } async assessTradeRisk(params: TradeRiskParameters): Promise { const { symbol, direction, entryPrice, stopLoss, takeProfit, timeframe, currentBalance, recentLosses } = params console.log('🛡️ Enhanced Risk Assessment Starting...') console.log(`💰 Account Balance: $${currentBalance}`) console.log(`📊 Trade: ${direction} ${symbol} @ $${entryPrice}`) console.log(`🛑 Stop Loss: $${stopLoss}`) console.log(`🎯 Take Profit: $${takeProfit}`) console.log(`⏰ Timeframe: ${timeframe}`) console.log(`📉 Recent Losses: ${recentLosses}`) const warnings: string[] = [] // Calculate stop loss distance const stopLossDistance = Math.abs(entryPrice - stopLoss) const stopLossPercentage = (stopLossDistance / entryPrice) * 100 // Calculate risk/reward ratio const takeProfitDistance = Math.abs(takeProfit - entryPrice) const riskRewardRatio = takeProfitDistance / stopLossDistance console.log(`📏 Stop Loss Distance: $${stopLossDistance.toFixed(2)} (${stopLossPercentage.toFixed(2)}%)`) console.log(`📈 Risk/Reward Ratio: 1:${riskRewardRatio.toFixed(2)}`) // Check if cooling off period is required const coolingOffRequired = recentLosses >= this.MAX_CONSECUTIVE_LOSSES if (coolingOffRequired) { warnings.push(`🚨 COOLING OFF: ${recentLosses} consecutive losses detected. Wait ${this.COOLING_OFF_HOURS}h before next trade.`) } // Get timeframe risk level const timeframeRisk = this.TIMEFRAME_RISK[timeframe] || 'HIGH' // Adjust max risk based on timeframe and recent performance let adjustedMaxRisk = this.MAX_RISK_PER_TRADE if (timeframeRisk === 'EXTREME') { adjustedMaxRisk = 0.5 // 0.5% for very short timeframes warnings.push('⚠️ EXTREME RISK: Very short timeframe detected. Risk reduced to 0.5%') } else if (timeframeRisk === 'HIGH') { adjustedMaxRisk = 0.75 // 0.75% for high risk timeframes warnings.push('⚠️ HIGH RISK: Short timeframe detected. Risk reduced to 0.75%') } // Further reduce risk after losses if (recentLosses >= 1) { adjustedMaxRisk *= 0.5 // Halve risk after any recent loss warnings.push(`📉 Risk halved due to ${recentLosses} recent loss(es)`) } // Calculate position sizes const riskAmount = currentBalance * (adjustedMaxRisk / 100) const maxPositionSize = currentBalance * 0.1 // Never more than 10% of account const recommendedSize = Math.min(riskAmount / (stopLossPercentage / 100), maxPositionSize) console.log(`💵 Risk Amount: $${riskAmount.toFixed(2)} (${adjustedMaxRisk}% of balance)`) console.log(`📦 Max Position Size: $${maxPositionSize.toFixed(2)}`) console.log(`✅ Recommended Size: $${recommendedSize.toFixed(2)}`) // Risk/Reward validation if (riskRewardRatio < 1.5) { warnings.push(`⚠️ POOR R:R: Risk/Reward ${riskRewardRatio.toFixed(2)} is below minimum 1.5`) } // Stop loss distance validation if (stopLossPercentage > 5) { warnings.push(`⚠️ WIDE STOP: ${stopLossPercentage.toFixed(2)}% stop loss is very wide`) } // Calculate current account risk const currentRisk = await this.calculateCurrentAccountRisk(currentBalance) if (currentRisk > this.MAX_TOTAL_RISK) { warnings.push(`🚨 MAX RISK: Current account risk ${currentRisk.toFixed(1)}% exceeds maximum ${this.MAX_TOTAL_RISK}%`) } // Leverage recommendation based on timeframe and risk let leverageRecommendation = 1 if (timeframeRisk === 'LOW' && riskRewardRatio >= 2) { leverageRecommendation = 2 } else if (timeframeRisk === 'MEDIUM' && riskRewardRatio >= 2.5) { leverageRecommendation = 1.5 } const assessment: RiskAssessment = { accountBalance: currentBalance, currentRisk, maxPositionSize, recommendedSize, stopLossDistance, riskRewardRatio, leverageRecommendation, timeframeRisk: timeframeRisk as any, coolingOffRequired, riskWarnings: warnings } console.log('🛡️ Risk Assessment Complete:') console.log(` Current Risk: ${currentRisk.toFixed(1)}%`) console.log(` Recommended Size: $${recommendedSize.toFixed(2)}`) console.log(` R:R Ratio: 1:${riskRewardRatio.toFixed(2)}`) console.log(` Timeframe Risk: ${timeframeRisk}`) console.log(` Warnings: ${warnings.length}`) return assessment } async calculateCurrentAccountRisk(currentBalance: number): Promise { try { // For now, return 0 as a safe default // TODO: Implement database integration when available console.log('📊 Current Account Risk: Database not available, returning 0%') return 0 } catch (error) { console.error('❌ Error calculating account risk:', error) return 0 } } async getRecentLossCount(): Promise { try { // For now, return 0 as a safe default // TODO: Implement database integration when available console.log('📉 Recent consecutive losses: Database not available, returning 0') return 0 } catch (error) { console.error('❌ Error getting recent loss count:', error) return 0 } } calculateDynamicStopLoss( entryPrice: number, direction: 'LONG' | 'SHORT', timeframe: string, atr?: number ): number { // Use ATR if available, otherwise use percentage-based stop const atrMultiplier = this.ATR_MULTIPLIERS[timeframe] || 2.0 let stopDistance: number if (atr && atr > 0) { stopDistance = atr * atrMultiplier console.log(`📏 ATR-based stop: ${atr} * ${atrMultiplier} = ${stopDistance}`) } else { // Fallback to percentage-based stops const percentageStop = timeframe === '5' ? 0.5 : timeframe === '15' ? 1.0 : timeframe === '60' ? 1.5 : 2.0 stopDistance = entryPrice * (percentageStop / 100) console.log(`📏 Percentage-based stop: ${percentageStop}% = ${stopDistance}`) } const stopLoss = direction === 'LONG' ? entryPrice - stopDistance : entryPrice + stopDistance console.log(`🛑 Dynamic Stop Loss: $${stopLoss.toFixed(2)} (${direction})`) return parseFloat(stopLoss.toFixed(2)) } async shouldAllowTrade(params: TradeRiskParameters): Promise<{ allowed: boolean reason: string riskAssessment: RiskAssessment }> { const riskAssessment = await this.assessTradeRisk(params) // Check cooling off period if (riskAssessment.coolingOffRequired) { return { allowed: false, reason: 'Cooling off period required after consecutive losses', riskAssessment } } // Check if account risk is too high if (riskAssessment.currentRisk > this.MAX_TOTAL_RISK) { return { allowed: false, reason: `Total account risk ${riskAssessment.currentRisk.toFixed(1)}% exceeds maximum ${this.MAX_TOTAL_RISK}%`, riskAssessment } } // Check risk/reward ratio if (riskAssessment.riskRewardRatio < 1.5) { return { allowed: false, reason: `Risk/Reward ratio ${riskAssessment.riskRewardRatio.toFixed(2)} is below minimum 1.5`, riskAssessment } } // Check if recommended size is too small if (riskAssessment.recommendedSize < 10) { return { allowed: false, reason: 'Recommended position size too small - market conditions may be unsuitable', riskAssessment } } return { allowed: true, reason: 'Trade approved by risk management', riskAssessment } } async recordTradeDecision( decision: 'APPROVED' | 'REJECTED', reason: string, riskAssessment: RiskAssessment ): Promise { try { // For now, just log the decision // TODO: Implement database integration when available console.log(`📝 Risk decision recorded: ${decision} - ${reason}`) console.log(` Account Balance: $${riskAssessment.accountBalance}`) console.log(` Current Risk: ${riskAssessment.currentRisk}%`) console.log(` Recommended Size: $${riskAssessment.recommendedSize}`) console.log(` R:R Ratio: 1:${riskAssessment.riskRewardRatio}`) } catch (error) { console.error('❌ Error recording risk decision:', error) } } } export const enhancedRiskManager = new EnhancedRiskManager()