New Features: - 📊 Detailed Market Analysis Panel (similar to pro trading interface) * Market sentiment, recommendation, resistance/support levels * Detailed trading setup with entry/exit points * Risk management with R:R ratios and confirmation triggers * Technical indicators (RSI, OBV, VWAP) analysis - 🧠 AI Learning Insights Panel * Real-time learning status and success rates * Winner/Loser trade outcome tracking * AI reflection messages explaining what was learned * Current thresholds and pattern recognition data - 🔮 AI Database Integration * Shows what AI learned from previous trades * Current confidence thresholds and risk parameters * Pattern recognition for symbol/timeframe combinations * Next trade adjustments based on learning - 🎓 Intelligent Learning from Outcomes * Automatic trade outcome analysis (winner/loser) * AI generates learning insights from each trade result * Confidence adjustment based on trade performance * Pattern reinforcement or correction based on results - Beautiful gradient panels with color-coded sections - Clear winner/loser indicators with visual feedback - Expandable detailed analysis view - Real-time learning progress tracking - Completely isolated paper trading (no real money risk) - Real market data integration for authentic learning - Safe practice environment with professional analysis tools This provides a complete AI learning trading simulation where users can: 1. Get real market analysis with detailed reasoning 2. Execute safe paper trades with zero risk 3. See immediate feedback on trade outcomes 4. Learn from AI reflections and insights 5. Understand how AI adapts and improves over time
306 lines
10 KiB
TypeScript
306 lines
10 KiB
TypeScript
/**
|
|
* 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<string, number> = {
|
|
'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<string, string> = {
|
|
'5': 'EXTREME',
|
|
'15': 'HIGH',
|
|
'30': 'HIGH',
|
|
'60': 'MEDIUM',
|
|
'240': 'LOW',
|
|
'D': 'LOW'
|
|
}
|
|
|
|
async assessTradeRisk(params: TradeRiskParameters): Promise<RiskAssessment> {
|
|
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<number> {
|
|
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<number> {
|
|
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<void> {
|
|
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()
|