feat: enhance paper trading with comprehensive AI analysis and learning insights
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
This commit is contained in:
423
lib/enhanced-anti-chasing-ai.ts
Normal file
423
lib/enhanced-anti-chasing-ai.ts
Normal file
@@ -0,0 +1,423 @@
|
||||
import OpenAI from 'openai'
|
||||
import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
|
||||
const openai = new OpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
})
|
||||
|
||||
export interface EnhancedAnalysisResult {
|
||||
summary: string
|
||||
marketSentiment: 'BULLISH' | 'BEARISH' | 'NEUTRAL'
|
||||
keyLevels: {
|
||||
support: number[]
|
||||
resistance: number[]
|
||||
}
|
||||
recommendation: 'BUY' | 'SELL' | 'HOLD'
|
||||
confidence: number // 0-100
|
||||
reasoning: string
|
||||
|
||||
// Enhanced Anti-Chasing Analysis
|
||||
momentumStatus: {
|
||||
type: 'BUILDING' | 'EXHAUSTED' | 'NEUTRAL'
|
||||
direction: 'UP' | 'DOWN' | 'SIDEWAYS'
|
||||
exhaustionSignals: string[]
|
||||
reversalProbability: number // 0-100
|
||||
}
|
||||
|
||||
// Multi-Timeframe Validation
|
||||
timeframeAlignment: {
|
||||
trend: '4H' | '1H' | '15M' // Primary trend timeframe
|
||||
alignment: 'STRONG' | 'WEAK' | 'CONFLICTED'
|
||||
conflictWarnings: string[]
|
||||
}
|
||||
|
||||
// Enhanced Entry Conditions
|
||||
entryQuality: {
|
||||
score: number // 0-100
|
||||
requiredConfirmations: string[]
|
||||
missingConfirmations: string[]
|
||||
riskLevel: 'LOW' | 'MEDIUM' | 'HIGH' | 'EXTREME'
|
||||
}
|
||||
|
||||
// Risk-Adjusted Trading Levels
|
||||
entry?: {
|
||||
price: number
|
||||
buffer?: string
|
||||
rationale: string
|
||||
timeframeRisk: 'LOW' | 'MEDIUM' | 'HIGH'
|
||||
}
|
||||
stopLoss?: {
|
||||
price: number
|
||||
rationale: string
|
||||
atrMultiple: number // ATR-based stop calculation
|
||||
}
|
||||
takeProfits?: {
|
||||
tp1?: {
|
||||
price: number
|
||||
description: string
|
||||
probabilityReach: number // 0-100
|
||||
}
|
||||
tp2?: {
|
||||
price: number
|
||||
description: string
|
||||
probabilityReach: number // 0-100
|
||||
}
|
||||
}
|
||||
riskToReward?: string
|
||||
|
||||
// Advanced Confirmations
|
||||
confirmationTrigger?: string
|
||||
invalidationLevel?: number
|
||||
|
||||
// Position Sizing Guidance
|
||||
positionSizing?: {
|
||||
riskPercentage: number // Recommended risk per trade
|
||||
maxPositionSize: number // Maximum recommended position
|
||||
volatilityAdjustment: number // Adjustment for current volatility
|
||||
}
|
||||
}
|
||||
|
||||
export class EnhancedAntiChasingAI {
|
||||
|
||||
async analyzeWithAntiChasing(filenameOrPath: string): Promise<EnhancedAnalysisResult | null> {
|
||||
try {
|
||||
let imagePath: string
|
||||
|
||||
if (path.isAbsolute(filenameOrPath)) {
|
||||
imagePath = filenameOrPath
|
||||
} else {
|
||||
const screenshotsDir = path.join(process.cwd(), 'screenshots')
|
||||
imagePath = path.join(screenshotsDir, filenameOrPath)
|
||||
}
|
||||
|
||||
const imageBuffer = await fs.readFile(imagePath)
|
||||
const base64Image = imageBuffer.toString('base64')
|
||||
|
||||
const prompt = `You are an expert trading analyst specializing in ANTI-MOMENTUM CHASING and HIGH-PROBABILITY setups. Your goal is to prevent losses from entering trades after momentum has exhausted.
|
||||
|
||||
**CRITICAL MISSION: PREVENT MOMENTUM CHASING LOSSES**
|
||||
|
||||
Your analysis must focus on:
|
||||
1. **MOMENTUM EXHAUSTION DETECTION** - Identify when moves are ENDING, not beginning
|
||||
2. **MULTI-TIMEFRAME VALIDATION** - Ensure all timeframes agree before entry
|
||||
3. **HIGH-PROBABILITY REVERSALS** - Only recommend trades with strong reversal signals
|
||||
4. **RISK-ADJUSTED ENTRIES** - Match position size to timeframe risk
|
||||
|
||||
**ANTI-CHASING METHODOLOGY:**
|
||||
|
||||
**MOMENTUM EXHAUSTION SIGNALS:**
|
||||
- **RSI DIVERGENCE**: Price making new highs/lows but RSI showing divergence
|
||||
- **VOLUME EXHAUSTION**: Decreasing volume on continued price movement
|
||||
- **CANDLE PATTERNS**: Doji, shooting stars, hammers at key levels
|
||||
- **MULTIPLE REJECTIONS**: 2+ rejections at support/resistance
|
||||
- **OVEREXTENSION**: Price far from moving averages (>2 ATR)
|
||||
|
||||
**TIMEFRAME RISK ASSESSMENT:**
|
||||
- **15M Charts**: HIGH RISK - Require 85%+ confidence, tight stops
|
||||
- **1H Charts**: MEDIUM RISK - Require 80%+ confidence, moderate stops
|
||||
- **4H Charts**: LOW RISK - Require 75%+ confidence, wider stops
|
||||
- **Daily Charts**: LOWEST RISK - Require 70%+ confidence, structural stops
|
||||
|
||||
**ENTRY QUALITY CHECKLIST:**
|
||||
✅ **Momentum Exhausted**: Not chasing active moves
|
||||
✅ **Multiple Confirmations**: 3+ indicators agree
|
||||
✅ **Structure Support**: Near key support/resistance
|
||||
✅ **Volume Confirmation**: Volume supports the setup
|
||||
✅ **Risk/Reward**: Minimum 1:2 ratio
|
||||
✅ **Invalidation Clear**: Know exactly when wrong
|
||||
|
||||
**FORBIDDEN SETUPS (NEVER RECOMMEND):**
|
||||
❌ **Chasing Breakouts**: Price already moved >2% rapidly
|
||||
❌ **FOMO Entries**: Strong moves without pullbacks
|
||||
❌ **Single Indicator**: Only one confirmation signal
|
||||
❌ **Against Trend**: Counter-trend without clear reversal
|
||||
❌ **Poor R:R**: Risk/Reward worse than 1:2
|
||||
❌ **Unclear Stops**: No obvious stop loss level
|
||||
|
||||
**ANALYSIS PROCESS:**
|
||||
|
||||
1. **IDENTIFY MOMENTUM STATE**:
|
||||
- Is momentum BUILDING (early in move) or EXHAUSTED (late in move)?
|
||||
- Look for divergences, volume patterns, overextension
|
||||
|
||||
2. **CHECK TIMEFRAME ALIGNMENT**:
|
||||
- Do multiple timeframes agree on direction?
|
||||
- Is this the right timeframe for this setup?
|
||||
|
||||
3. **VALIDATE ENTRY QUALITY**:
|
||||
- Count confirmation signals (need 3+ for entry)
|
||||
- Assess risk level and position sizing needs
|
||||
|
||||
4. **CALCULATE RISK-ADJUSTED LEVELS**:
|
||||
- Entry: Based on structure and confirmation
|
||||
- Stop Loss: ATR-based, below/above key structure
|
||||
- Take Profit: Conservative targets with high probability
|
||||
|
||||
**RESPONSE FORMAT** (JSON only):
|
||||
|
||||
{
|
||||
"summary": "Anti-chasing analysis focusing on momentum exhaustion and high-probability setups",
|
||||
"marketSentiment": "BULLISH|BEARISH|NEUTRAL",
|
||||
"keyLevels": {
|
||||
"support": [visible support levels],
|
||||
"resistance": [visible resistance levels]
|
||||
},
|
||||
"recommendation": "BUY|SELL|HOLD",
|
||||
"confidence": 75,
|
||||
"reasoning": "Detailed reasoning focusing on momentum state and entry quality",
|
||||
|
||||
"momentumStatus": {
|
||||
"type": "BUILDING|EXHAUSTED|NEUTRAL",
|
||||
"direction": "UP|DOWN|SIDEWAYS",
|
||||
"exhaustionSignals": ["List specific exhaustion signals seen"],
|
||||
"reversalProbability": 65
|
||||
},
|
||||
|
||||
"timeframeAlignment": {
|
||||
"trend": "4H|1H|15M",
|
||||
"alignment": "STRONG|WEAK|CONFLICTED",
|
||||
"conflictWarnings": ["Any timeframe conflicts"]
|
||||
},
|
||||
|
||||
"entryQuality": {
|
||||
"score": 85,
|
||||
"requiredConfirmations": ["List of confirmations present"],
|
||||
"missingConfirmations": ["List of missing confirmations"],
|
||||
"riskLevel": "LOW|MEDIUM|HIGH|EXTREME"
|
||||
},
|
||||
|
||||
"entry": {
|
||||
"price": 150.50,
|
||||
"buffer": "±0.25",
|
||||
"rationale": "Entry based on exhaustion signals and structure",
|
||||
"timeframeRisk": "LOW|MEDIUM|HIGH"
|
||||
},
|
||||
|
||||
"stopLoss": {
|
||||
"price": 148.00,
|
||||
"rationale": "Stop below key structure level",
|
||||
"atrMultiple": 1.5
|
||||
},
|
||||
|
||||
"takeProfits": {
|
||||
"tp1": {
|
||||
"price": 152.00,
|
||||
"description": "Conservative target at structure",
|
||||
"probabilityReach": 75
|
||||
},
|
||||
"tp2": {
|
||||
"price": 154.00,
|
||||
"description": "Extended target if momentum continues",
|
||||
"probabilityReach": 45
|
||||
}
|
||||
},
|
||||
|
||||
"riskToReward": "1:2.5",
|
||||
"confirmationTrigger": "Wait for specific confirmation before entry",
|
||||
"invalidationLevel": 149.00,
|
||||
|
||||
"positionSizing": {
|
||||
"riskPercentage": 1.0,
|
||||
"maxPositionSize": 10,
|
||||
"volatilityAdjustment": 0.8
|
||||
}
|
||||
}
|
||||
|
||||
**CRITICAL REQUIREMENTS:**
|
||||
- If momentum appears to be chasing, recommend HOLD regardless of other signals
|
||||
- Require minimum 3 confirmations for any BUY/SELL recommendation
|
||||
- Always provide clear invalidation levels
|
||||
- Match position sizing to timeframe risk
|
||||
- Focus on HIGH-PROBABILITY setups only
|
||||
|
||||
Analyze the chart with EXTREME FOCUS on preventing momentum chasing losses.`
|
||||
|
||||
const response = await openai.chat.completions.create({
|
||||
model: "gpt-4o-mini",
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "text", text: prompt },
|
||||
{
|
||||
type: "image_url",
|
||||
image_url: {
|
||||
url: `data:image/png;base64,${base64Image}`,
|
||||
detail: "high"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
max_tokens: 2000,
|
||||
temperature: 0.1
|
||||
})
|
||||
|
||||
const content = response.choices[0]?.message?.content
|
||||
if (!content) return null
|
||||
|
||||
console.log('🛡️ Anti-chasing AI response:', content.substring(0, 200) + '...')
|
||||
|
||||
// Extract JSON from response
|
||||
const match = content.match(/\{[\s\S]*\}/)
|
||||
if (!match) {
|
||||
console.error('No JSON found in anti-chasing response')
|
||||
return null
|
||||
}
|
||||
|
||||
const json = match[0]
|
||||
const result = JSON.parse(json)
|
||||
|
||||
// Validate anti-chasing requirements
|
||||
if (result.entryQuality?.score < 70) {
|
||||
console.log('⚠️ Entry quality too low - overriding to HOLD')
|
||||
result.recommendation = 'HOLD'
|
||||
result.reasoning = `Entry quality score ${result.entryQuality.score} is below minimum threshold. ${result.reasoning}`
|
||||
}
|
||||
|
||||
if (result.momentumStatus?.type === 'EXHAUSTED' && result.confidence > 80) {
|
||||
console.log('✅ High-quality exhaustion setup detected')
|
||||
} else if (result.momentumStatus?.type === 'BUILDING') {
|
||||
console.log('⚠️ Potential momentum chasing detected - increasing requirements')
|
||||
result.confidence = Math.max(0, result.confidence - 20)
|
||||
}
|
||||
|
||||
return result as EnhancedAnalysisResult
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Enhanced anti-chasing analysis failed:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async analyzeMultipleWithAntiChasing(filenamesOrPaths: string[]): Promise<EnhancedAnalysisResult | null> {
|
||||
try {
|
||||
// Read all image files and convert to base64
|
||||
const images = await Promise.all(
|
||||
filenamesOrPaths.map(async (filenameOrPath) => {
|
||||
let imagePath: string
|
||||
|
||||
if (path.isAbsolute(filenameOrPath)) {
|
||||
imagePath = filenameOrPath
|
||||
} else {
|
||||
const screenshotsDir = path.join(process.cwd(), 'screenshots')
|
||||
imagePath = path.join(screenshotsDir, filenameOrPath)
|
||||
}
|
||||
|
||||
const imageBuffer = await fs.readFile(imagePath)
|
||||
const base64Image = imageBuffer.toString('base64')
|
||||
return {
|
||||
type: "image_url" as const,
|
||||
image_url: {
|
||||
url: `data:image/png;base64,${base64Image}`,
|
||||
detail: "high" as const
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
const timeframeInfo = filenamesOrPaths.map(f => {
|
||||
const filename = path.basename(f)
|
||||
if (filename.includes('240')) return '4H'
|
||||
if (filename.includes('60')) return '1H'
|
||||
if (filename.includes('15')) return '15M'
|
||||
return 'Unknown'
|
||||
}).join(', ')
|
||||
|
||||
const prompt = `You are analyzing ${filenamesOrPaths.length} charts (${timeframeInfo}) with ANTI-MOMENTUM CHASING focus.
|
||||
|
||||
**MISSION: PREVENT MOMENTUM CHASING ACROSS MULTIPLE TIMEFRAMES**
|
||||
|
||||
**MULTI-TIMEFRAME ANTI-CHASING RULES:**
|
||||
|
||||
1. **TIMEFRAME HIERARCHY**:
|
||||
- 4H: Primary trend direction (most important)
|
||||
- 1H: Entry confirmation and timing
|
||||
- 15M: Precise entry point and quick confirmations
|
||||
|
||||
2. **ALIGNMENT REQUIREMENTS**:
|
||||
- ALL timeframes must agree on direction for entry
|
||||
- Higher timeframes override lower timeframes
|
||||
- If conflict exists, recommend HOLD
|
||||
|
||||
3. **MOMENTUM EXHAUSTION VALIDATION**:
|
||||
- Check each timeframe for exhaustion signals
|
||||
- Look for divergences across timeframes
|
||||
- Ensure not chasing moves on any timeframe
|
||||
|
||||
4. **MULTI-TIMEFRAME CONFIRMATION**:
|
||||
- Need confirmation on AT LEAST 2 timeframes
|
||||
- Higher timeframe structure + lower timeframe entry
|
||||
- Volume confirmation across timeframes
|
||||
|
||||
**ANALYSIS REQUIREMENTS:**
|
||||
|
||||
For each timeframe:
|
||||
- Identify momentum state (building/exhausted/neutral)
|
||||
- Check for exhaustion signals and reversals
|
||||
- Validate entry quality and confirmations
|
||||
- Assess risk level for that timeframe
|
||||
|
||||
Cross-timeframe validation:
|
||||
- Ensure no conflicts between timeframes
|
||||
- Confirm entry timing on appropriate timeframe
|
||||
- Validate stop loss placement across timeframes
|
||||
|
||||
**FORBIDDEN MULTI-TIMEFRAME SETUPS:**
|
||||
❌ Timeframes pointing in different directions
|
||||
❌ Chasing momentum on any timeframe
|
||||
❌ Entry without multi-timeframe confirmation
|
||||
❌ Risk/reward not suitable for highest timeframe
|
||||
|
||||
Provide comprehensive multi-timeframe anti-chasing analysis in the same JSON format, with additional focus on timeframe alignment and cross-validation.`
|
||||
|
||||
const messages = [
|
||||
{
|
||||
role: "user" as const,
|
||||
content: [
|
||||
{ type: "text" as const, text: prompt },
|
||||
...images
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
console.log(`🛡️ Analyzing ${filenamesOrPaths.length} timeframes with anti-chasing focus...`)
|
||||
|
||||
const response = await openai.chat.completions.create({
|
||||
model: "gpt-4o-mini",
|
||||
messages,
|
||||
max_tokens: 2500,
|
||||
temperature: 0.1
|
||||
})
|
||||
|
||||
const content = response.choices[0]?.message?.content
|
||||
if (!content) {
|
||||
throw new Error('No response from OpenAI')
|
||||
}
|
||||
|
||||
const jsonMatch = content.match(/\{[\s\S]*\}/)
|
||||
if (!jsonMatch) {
|
||||
throw new Error('No JSON found in multi-timeframe response')
|
||||
}
|
||||
|
||||
const analysis = JSON.parse(jsonMatch[0])
|
||||
|
||||
// Enhanced validation for multi-timeframe
|
||||
if (analysis.timeframeAlignment?.alignment === 'CONFLICTED') {
|
||||
console.log('⚠️ Timeframe conflict detected - overriding to HOLD')
|
||||
analysis.recommendation = 'HOLD'
|
||||
analysis.confidence = Math.min(analysis.confidence, 40)
|
||||
}
|
||||
|
||||
console.log('✅ Multi-timeframe anti-chasing analysis complete')
|
||||
return analysis as EnhancedAnalysisResult
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('❌ Multi-timeframe anti-chasing analysis failed:', error.message)
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const enhancedAntiChasingAI = new EnhancedAntiChasingAI()
|
||||
305
lib/enhanced-risk-manager.ts
Normal file
305
lib/enhanced-risk-manager.ts
Normal file
@@ -0,0 +1,305 @@
|
||||
/**
|
||||
* 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()
|
||||
@@ -300,21 +300,19 @@ class SimpleAutomation {
|
||||
// Increment error counter
|
||||
this.stats.consecutiveErrors = (this.stats.consecutiveErrors || 0) + 1;
|
||||
|
||||
// If too many consecutive errors, slow down but NEVER stop completely
|
||||
if (this.stats.consecutiveErrors >= 20) { // Increased from 3 to 20
|
||||
console.warn(`⚠️ HIGH ERROR COUNT: ${this.stats.consecutiveErrors} consecutive failures. Slowing down but continuing...`);
|
||||
// Add extra delay instead of stopping
|
||||
await new Promise(resolve => setTimeout(resolve, 30000)); // 30 second delay
|
||||
// Reset error count to prevent infinite accumulation
|
||||
this.stats.consecutiveErrors = Math.floor(this.stats.consecutiveErrors / 2);
|
||||
} else if (this.stats.consecutiveErrors >= 10) {
|
||||
console.warn(`⚠️ NETWORK ISSUES: ${this.stats.consecutiveErrors} consecutive failures. Adding delay...`);
|
||||
// Add delay for network issues
|
||||
await new Promise(resolve => setTimeout(resolve, 10000)); // 10 second delay
|
||||
// If too many consecutive errors, stop automation
|
||||
if (this.stats.consecutiveErrors >= 3) {
|
||||
console.error('🚨 TOO MANY ERRORS: Stopping automation after', this.stats.consecutiveErrors, 'consecutive failures');
|
||||
this.isRunning = false;
|
||||
this.stats.status = 'Stopped due to errors';
|
||||
|
||||
if (this.intervalId) {
|
||||
clearTimeout(this.intervalId); // Changed from clearInterval to clearTimeout
|
||||
this.intervalId = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// NEVER STOP AUTOMATION - Money Printing Machine must keep running!
|
||||
|
||||
console.log(`⚠️ Error ${this.stats.consecutiveErrors}/3 - Will retry next cycle`);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user