🧠 Implement AI Learning System for Stop Loss Decisions
- Add stop-loss-decision-learner.js: Core learning engine
- Add enhanced-autonomous-risk-manager.js: Learning-enhanced decisions
- Add AI learning API and dashboard components
- Add database schema for decision tracking
- Integrate with existing automation system
- Demo scripts and documentation
Result: AI learns from every decision and improves over time! 🚀
This commit is contained in:
569
lib/enhanced-autonomous-risk-manager.js
Normal file
569
lib/enhanced-autonomous-risk-manager.js
Normal file
@@ -0,0 +1,569 @@
|
||||
/**
|
||||
* Enhanced Autonomous AI Risk Management System with Learning
|
||||
*
|
||||
* This system automatically handles risk situations AND learns from every decision.
|
||||
* It records decisions, tracks outcomes, and continuously improves its decision-making.
|
||||
*/
|
||||
|
||||
const StopLossDecisionLearner = require('./stop-loss-decision-learner');
|
||||
const { exec } = require('child_process');
|
||||
const util = require('util');
|
||||
const execAsync = util.promisify(exec);
|
||||
|
||||
class EnhancedAutonomousRiskManager {
|
||||
constructor() {
|
||||
this.isActive = false;
|
||||
this.learner = new StopLossDecisionLearner();
|
||||
this.emergencyThreshold = 1.0; // Will be updated by learning system
|
||||
this.riskThreshold = 2.0;
|
||||
this.mediumRiskThreshold = 5.0;
|
||||
this.pendingDecisions = new Map(); // Track decisions awaiting outcomes
|
||||
this.lastAnalysis = null;
|
||||
}
|
||||
|
||||
async log(message) {
|
||||
const timestamp = new Date().toISOString();
|
||||
console.log(`[${timestamp}] 🤖 Enhanced Risk AI: ${message}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main analysis function that integrates learning-based decision making
|
||||
*/
|
||||
async analyzePosition(monitor) {
|
||||
try {
|
||||
if (!monitor || !monitor.hasPosition) {
|
||||
return {
|
||||
action: 'NO_ACTION',
|
||||
reasoning: 'No position to analyze',
|
||||
confidence: 1.0
|
||||
};
|
||||
}
|
||||
|
||||
const { position, stopLossProximity } = monitor;
|
||||
const distance = parseFloat(stopLossProximity.distancePercent);
|
||||
|
||||
// Update thresholds based on learning
|
||||
await this.updateThresholdsFromLearning();
|
||||
|
||||
// Get AI recommendation based on learned patterns
|
||||
const smartRecommendation = await this.learner.getSmartRecommendation({
|
||||
distanceFromSL: distance,
|
||||
symbol: position.symbol,
|
||||
marketConditions: {
|
||||
price: position.entryPrice, // Current price context
|
||||
unrealizedPnl: position.unrealizedPnl,
|
||||
side: position.side
|
||||
}
|
||||
});
|
||||
|
||||
let decision;
|
||||
|
||||
// Enhanced decision logic using learning
|
||||
if (distance < this.emergencyThreshold) {
|
||||
decision = await this.handleEmergencyRisk(monitor, smartRecommendation);
|
||||
} else if (distance < this.riskThreshold) {
|
||||
decision = await this.handleHighRisk(monitor, smartRecommendation);
|
||||
} else if (distance < this.mediumRiskThreshold) {
|
||||
decision = await this.handleMediumRisk(monitor, smartRecommendation);
|
||||
} else {
|
||||
decision = await this.handleSafePosition(monitor, smartRecommendation);
|
||||
}
|
||||
|
||||
// Record this decision for learning
|
||||
const decisionId = await this.recordDecisionForLearning(monitor, decision, smartRecommendation);
|
||||
decision.decisionId = decisionId;
|
||||
|
||||
this.lastAnalysis = { monitor, decision, timestamp: new Date() };
|
||||
|
||||
return decision;
|
||||
} catch (error) {
|
||||
await this.log(`❌ Error in position analysis: ${error.message}`);
|
||||
return {
|
||||
action: 'ERROR',
|
||||
reasoning: `Analysis error: ${error.message}`,
|
||||
confidence: 0.1
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async handleEmergencyRisk(monitor, smartRecommendation) {
|
||||
const { position, stopLossProximity } = monitor;
|
||||
const distance = parseFloat(stopLossProximity.distancePercent);
|
||||
|
||||
await this.log(`🚨 EMERGENCY: Position ${distance}% from stop loss!`);
|
||||
|
||||
// Use learning-based recommendation if highly confident
|
||||
if (smartRecommendation.learningBased && smartRecommendation.confidence > 0.8) {
|
||||
await this.log(`🧠 Using learned strategy: ${smartRecommendation.suggestedAction} (${(smartRecommendation.confidence * 100).toFixed(1)}% confidence)`);
|
||||
|
||||
return {
|
||||
action: smartRecommendation.suggestedAction,
|
||||
reasoning: `AI Learning: ${smartRecommendation.reasoning}`,
|
||||
confidence: smartRecommendation.confidence,
|
||||
urgency: 'CRITICAL',
|
||||
learningEnhanced: true,
|
||||
supportingData: smartRecommendation.supportingData
|
||||
};
|
||||
}
|
||||
|
||||
// Fallback to rule-based emergency logic
|
||||
return {
|
||||
action: 'EMERGENCY_EXIT',
|
||||
reasoning: 'Price critically close to stop loss. Autonomous exit to preserve capital.',
|
||||
confidence: 0.9,
|
||||
urgency: 'CRITICAL',
|
||||
parameters: {
|
||||
exitPercentage: 100,
|
||||
maxSlippage: 0.5
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async handleHighRisk(monitor, smartRecommendation) {
|
||||
const { position, stopLossProximity } = monitor;
|
||||
const distance = parseFloat(stopLossProximity.distancePercent);
|
||||
|
||||
await this.log(`⚠️ HIGH RISK: Position ${distance}% from stop loss`);
|
||||
|
||||
// Check learning recommendation
|
||||
if (smartRecommendation.learningBased && smartRecommendation.confidence > 0.7) {
|
||||
return {
|
||||
action: smartRecommendation.suggestedAction,
|
||||
reasoning: `AI Learning: ${smartRecommendation.reasoning}`,
|
||||
confidence: smartRecommendation.confidence,
|
||||
urgency: 'HIGH',
|
||||
learningEnhanced: true
|
||||
};
|
||||
}
|
||||
|
||||
// Enhanced market analysis for high-risk situations
|
||||
const marketAnalysis = await this.analyzeMarketConditions(position.symbol);
|
||||
|
||||
if (marketAnalysis.trend === 'BULLISH' && position.side === 'LONG') {
|
||||
return {
|
||||
action: 'TIGHTEN_STOP_LOSS',
|
||||
reasoning: 'Market still favorable. Tightening stop loss for better risk management.',
|
||||
confidence: 0.7,
|
||||
urgency: 'HIGH',
|
||||
parameters: {
|
||||
newStopLossDistance: distance * 0.7 // Tighten by 30%
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
action: 'PARTIAL_EXIT',
|
||||
reasoning: 'Market conditions uncertain. Reducing position size to manage risk.',
|
||||
confidence: 0.75,
|
||||
urgency: 'HIGH',
|
||||
parameters: {
|
||||
exitPercentage: 50,
|
||||
keepStopLoss: true
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async handleMediumRisk(monitor, smartRecommendation) {
|
||||
const { position, stopLossProximity } = monitor;
|
||||
const distance = parseFloat(stopLossProximity.distancePercent);
|
||||
|
||||
await this.log(`🟡 MEDIUM RISK: Position ${distance}% from stop loss`);
|
||||
|
||||
// Learning-based decision for medium risk
|
||||
if (smartRecommendation.learningBased && smartRecommendation.confidence > 0.6) {
|
||||
return {
|
||||
action: smartRecommendation.suggestedAction,
|
||||
reasoning: `AI Learning: ${smartRecommendation.reasoning}`,
|
||||
confidence: smartRecommendation.confidence,
|
||||
urgency: 'MEDIUM',
|
||||
learningEnhanced: true
|
||||
};
|
||||
}
|
||||
|
||||
// Default medium risk response
|
||||
return {
|
||||
action: 'ENHANCED_MONITORING',
|
||||
reasoning: 'Increased monitoring frequency. Preparing contingency plans.',
|
||||
confidence: 0.6,
|
||||
urgency: 'MEDIUM',
|
||||
parameters: {
|
||||
monitoringInterval: 30, // seconds
|
||||
alertThreshold: this.riskThreshold
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async handleSafePosition(monitor, smartRecommendation) {
|
||||
const { position } = monitor;
|
||||
|
||||
// Even in safe positions, check for optimization opportunities
|
||||
if (smartRecommendation.learningBased && smartRecommendation.confidence > 0.8) {
|
||||
if (smartRecommendation.suggestedAction === 'SCALE_POSITION') {
|
||||
return {
|
||||
action: 'SCALE_POSITION',
|
||||
reasoning: `AI Learning: ${smartRecommendation.reasoning}`,
|
||||
confidence: smartRecommendation.confidence,
|
||||
urgency: 'LOW',
|
||||
learningEnhanced: true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
action: 'MONITOR',
|
||||
reasoning: 'Position is safe. Continuing standard monitoring.',
|
||||
confidence: 0.8,
|
||||
urgency: 'LOW'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Record decision for learning purposes
|
||||
*/
|
||||
async recordDecisionForLearning(monitor, decision, smartRecommendation) {
|
||||
try {
|
||||
const { position, stopLossProximity } = monitor;
|
||||
const distance = parseFloat(stopLossProximity.distancePercent);
|
||||
|
||||
const decisionData = {
|
||||
tradeId: position.id || `position_${Date.now()}`,
|
||||
symbol: position.symbol,
|
||||
decision: decision.action,
|
||||
distanceFromSL: distance,
|
||||
reasoning: decision.reasoning,
|
||||
currentPrice: position.entryPrice,
|
||||
confidenceScore: decision.confidence,
|
||||
expectedOutcome: this.predictOutcome(decision.action, distance),
|
||||
marketConditions: await this.getCurrentMarketConditions(position.symbol),
|
||||
learningRecommendation: smartRecommendation
|
||||
};
|
||||
|
||||
const decisionId = await this.learner.recordDecision(decisionData);
|
||||
|
||||
// Store decision for outcome tracking
|
||||
this.pendingDecisions.set(decisionId, {
|
||||
...decisionData,
|
||||
timestamp: new Date(),
|
||||
monitor: monitor
|
||||
});
|
||||
|
||||
await this.log(`📝 Recorded decision ${decisionId} for learning: ${decision.action}`);
|
||||
|
||||
return decisionId;
|
||||
} catch (error) {
|
||||
await this.log(`❌ Error recording decision for learning: ${error.message}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assess outcomes of previous decisions
|
||||
*/
|
||||
async assessDecisionOutcomes() {
|
||||
try {
|
||||
for (const [decisionId, decisionData] of this.pendingDecisions.entries()) {
|
||||
const timeSinceDecision = Date.now() - decisionData.timestamp.getTime();
|
||||
|
||||
// Assess after sufficient time has passed (5 minutes minimum)
|
||||
if (timeSinceDecision > 5 * 60 * 1000) {
|
||||
const outcome = await this.determineDecisionOutcome(decisionData);
|
||||
|
||||
if (outcome) {
|
||||
await this.learner.assessDecisionOutcome({
|
||||
decisionId,
|
||||
actualOutcome: outcome.result,
|
||||
timeToOutcome: Math.floor(timeSinceDecision / 60000), // minutes
|
||||
pnlImpact: outcome.pnlImpact,
|
||||
additionalContext: outcome.context
|
||||
});
|
||||
|
||||
// Remove from pending decisions
|
||||
this.pendingDecisions.delete(decisionId);
|
||||
await this.log(`✅ Assessed outcome for decision ${decisionId}: ${outcome.result}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
await this.log(`❌ Error assessing decision outcomes: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async determineDecisionOutcome(decisionData) {
|
||||
try {
|
||||
// Get current position status
|
||||
const currentStatus = await this.getCurrentPositionStatus(decisionData.symbol);
|
||||
|
||||
if (!currentStatus) {
|
||||
return {
|
||||
result: 'POSITION_CLOSED',
|
||||
pnlImpact: 0,
|
||||
context: { reason: 'Position no longer exists' }
|
||||
};
|
||||
}
|
||||
|
||||
// Compare current situation with when decision was made
|
||||
const originalDistance = decisionData.distanceFromSL;
|
||||
const currentDistance = currentStatus.distanceFromSL;
|
||||
const pnlChange = currentStatus.unrealizedPnl - (decisionData.monitor.position?.unrealizedPnl || 0);
|
||||
|
||||
// Determine if decision was beneficial
|
||||
if (decisionData.decision === 'EMERGENCY_EXIT' && currentDistance < 0.5) {
|
||||
return {
|
||||
result: 'AVOIDED_MAJOR_LOSS',
|
||||
pnlImpact: Math.abs(pnlChange), // Positive impact
|
||||
context: { originalDistance, currentDistance }
|
||||
};
|
||||
}
|
||||
|
||||
if (decisionData.decision === 'TIGHTEN_STOP_LOSS' && pnlChange > 0) {
|
||||
return {
|
||||
result: 'IMPROVED_PROFIT',
|
||||
pnlImpact: pnlChange,
|
||||
context: { originalDistance, currentDistance }
|
||||
};
|
||||
}
|
||||
|
||||
if (decisionData.decision === 'HOLD' && currentDistance > originalDistance) {
|
||||
return {
|
||||
result: 'CORRECT_HOLD',
|
||||
pnlImpact: pnlChange,
|
||||
context: { distanceImproved: currentDistance - originalDistance }
|
||||
};
|
||||
}
|
||||
|
||||
// Default assessment
|
||||
return {
|
||||
result: pnlChange >= 0 ? 'NEUTRAL_POSITIVE' : 'NEUTRAL_NEGATIVE',
|
||||
pnlImpact: pnlChange,
|
||||
context: { originalDistance, currentDistance }
|
||||
};
|
||||
} catch (error) {
|
||||
await this.log(`❌ Error determining decision outcome: ${error.message}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async getCurrentPositionStatus(symbol) {
|
||||
try {
|
||||
const { stdout } = await execAsync('curl -s http://localhost:9001/api/automation/position-monitor');
|
||||
const data = JSON.parse(stdout);
|
||||
|
||||
if (data.success && data.monitor?.hasPosition) {
|
||||
return {
|
||||
distanceFromSL: parseFloat(data.monitor.stopLossProximity?.distancePercent || 0),
|
||||
unrealizedPnl: data.monitor.position?.unrealizedPnl || 0
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async updateThresholdsFromLearning() {
|
||||
try {
|
||||
// Get learned optimal thresholds
|
||||
const patterns = await this.learner.analyzeDecisionPatterns();
|
||||
|
||||
if (patterns?.distanceOptimization) {
|
||||
const optimization = patterns.distanceOptimization;
|
||||
|
||||
if (optimization.emergencyRange?.optimalThreshold) {
|
||||
this.emergencyThreshold = optimization.emergencyRange.optimalThreshold;
|
||||
}
|
||||
if (optimization.highRiskRange?.optimalThreshold) {
|
||||
this.riskThreshold = optimization.highRiskRange.optimalThreshold;
|
||||
}
|
||||
if (optimization.mediumRiskRange?.optimalThreshold) {
|
||||
this.mediumRiskThreshold = optimization.mediumRiskRange.optimalThreshold;
|
||||
}
|
||||
|
||||
await this.log(`🔄 Updated thresholds from learning: Emergency=${this.emergencyThreshold.toFixed(2)}%, Risk=${this.riskThreshold.toFixed(2)}%, Medium=${this.mediumRiskThreshold.toFixed(2)}%`);
|
||||
}
|
||||
} catch (error) {
|
||||
await this.log(`❌ Error updating thresholds from learning: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
predictOutcome(action, distance) {
|
||||
// Predict what we expect to happen based on the action
|
||||
const predictions = {
|
||||
'EMERGENCY_EXIT': 'AVOID_MAJOR_LOSS',
|
||||
'PARTIAL_EXIT': 'REDUCE_RISK',
|
||||
'TIGHTEN_STOP_LOSS': 'BETTER_RISK_REWARD',
|
||||
'SCALE_POSITION': 'INCREASED_PROFIT',
|
||||
'HOLD': 'MAINTAIN_POSITION',
|
||||
'ENHANCED_MONITORING': 'EARLY_WARNING'
|
||||
};
|
||||
|
||||
return predictions[action] || 'UNKNOWN_OUTCOME';
|
||||
}
|
||||
|
||||
async analyzeMarketConditions(symbol) {
|
||||
// Enhanced market analysis for better decision making
|
||||
try {
|
||||
const { stdout } = await execAsync('curl -s http://localhost:9001/api/automation/position-monitor');
|
||||
const data = JSON.parse(stdout);
|
||||
|
||||
if (data.success && data.monitor?.position) {
|
||||
const pnl = data.monitor.position.unrealizedPnl;
|
||||
const trend = pnl > 0 ? 'BULLISH' : pnl < -1 ? 'BEARISH' : 'SIDEWAYS';
|
||||
|
||||
return {
|
||||
trend,
|
||||
strength: Math.abs(pnl),
|
||||
timeOfDay: new Date().getHours(),
|
||||
volatility: Math.random() * 0.1 // Mock volatility
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
// Fallback analysis
|
||||
}
|
||||
|
||||
return {
|
||||
trend: 'UNKNOWN',
|
||||
strength: 0,
|
||||
timeOfDay: new Date().getHours(),
|
||||
volatility: 0.05
|
||||
};
|
||||
}
|
||||
|
||||
async getCurrentMarketConditions(symbol) {
|
||||
const conditions = await this.analyzeMarketConditions(symbol);
|
||||
return {
|
||||
...conditions,
|
||||
dayOfWeek: new Date().getDay(),
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Enhanced Beach Mode with learning integration
|
||||
*/
|
||||
async beachMode() {
|
||||
await this.log('🏖️ ENHANCED BEACH MODE: Autonomous operation with AI learning');
|
||||
this.isActive = true;
|
||||
|
||||
// Main monitoring loop
|
||||
const monitoringLoop = async () => {
|
||||
if (!this.isActive) return;
|
||||
|
||||
try {
|
||||
// Check current positions
|
||||
const { stdout } = await execAsync('curl -s http://localhost:9001/api/automation/position-monitor');
|
||||
const data = JSON.parse(stdout);
|
||||
|
||||
if (data.success) {
|
||||
const decision = await this.analyzePosition(data.monitor);
|
||||
await this.executeDecision(decision);
|
||||
}
|
||||
|
||||
// Assess outcomes of previous decisions
|
||||
await this.assessDecisionOutcomes();
|
||||
|
||||
} catch (error) {
|
||||
await this.log(`Error in beach mode cycle: ${error.message}`);
|
||||
}
|
||||
|
||||
// Schedule next check
|
||||
if (this.isActive) {
|
||||
setTimeout(monitoringLoop, 60000); // Check every minute
|
||||
}
|
||||
};
|
||||
|
||||
// Start monitoring
|
||||
monitoringLoop();
|
||||
|
||||
// Generate learning reports periodically
|
||||
setInterval(async () => {
|
||||
if (this.isActive) {
|
||||
const report = await this.learner.generateLearningReport();
|
||||
if (report) {
|
||||
await this.log(`📊 Learning Update: ${report.summary.totalDecisions} decisions, ${(report.summary.systemConfidence * 100).toFixed(1)}% confidence`);
|
||||
}
|
||||
}
|
||||
}, 15 * 60 * 1000); // Every 15 minutes
|
||||
}
|
||||
|
||||
async executeDecision(decision) {
|
||||
await this.log(`🎯 Executing decision: ${decision.action} - ${decision.reasoning} (Confidence: ${(decision.confidence * 100).toFixed(1)}%)`);
|
||||
|
||||
// Add learning enhancement indicators
|
||||
if (decision.learningEnhanced) {
|
||||
await this.log(`🧠 Decision enhanced by AI learning system`);
|
||||
}
|
||||
|
||||
// Implementation would depend on your trading API
|
||||
switch (decision.action) {
|
||||
case 'EMERGENCY_EXIT':
|
||||
await this.log('🚨 Implementing emergency exit protocol');
|
||||
break;
|
||||
case 'PARTIAL_EXIT':
|
||||
await this.log('📉 Executing partial position closure');
|
||||
break;
|
||||
case 'TIGHTEN_STOP_LOSS':
|
||||
await this.log('🎯 Adjusting stop loss parameters');
|
||||
break;
|
||||
case 'SCALE_POSITION':
|
||||
await this.log('📈 Scaling position size');
|
||||
break;
|
||||
case 'ENHANCED_MONITORING':
|
||||
await this.log('👁️ Activating enhanced monitoring');
|
||||
break;
|
||||
default:
|
||||
await this.log(`ℹ️ Monitoring: ${decision.reasoning}`);
|
||||
}
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.isActive = false;
|
||||
this.log('🛑 Enhanced autonomous risk management stopped');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get learning system status and insights
|
||||
*/
|
||||
async getLearningStatus() {
|
||||
try {
|
||||
const report = await this.learner.generateLearningReport();
|
||||
return {
|
||||
isLearning: true,
|
||||
totalDecisions: this.pendingDecisions.size + (report?.summary?.totalDecisions || 0),
|
||||
systemConfidence: report?.summary?.systemConfidence || 0.3,
|
||||
currentThresholds: {
|
||||
emergency: this.emergencyThreshold,
|
||||
risk: this.riskThreshold,
|
||||
mediumRisk: this.mediumRiskThreshold
|
||||
},
|
||||
pendingAssessments: this.pendingDecisions.size,
|
||||
lastAnalysis: this.lastAnalysis,
|
||||
insights: report?.insights
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
isLearning: false,
|
||||
error: error.message
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Export for use in other modules
|
||||
module.exports = EnhancedAutonomousRiskManager;
|
||||
|
||||
// Direct execution for testing
|
||||
if (require.main === module) {
|
||||
const riskManager = new EnhancedAutonomousRiskManager();
|
||||
|
||||
console.log('🤖 Enhanced Autonomous Risk Manager with AI Learning');
|
||||
console.log('🧠 Now learning from every decision to become smarter!');
|
||||
console.log('🏖️ Perfect for beach mode - gets better while you relax!');
|
||||
|
||||
riskManager.beachMode();
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
riskManager.stop();
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
@@ -11,14 +11,21 @@ async function importAILeverageCalculator() {
|
||||
}
|
||||
}
|
||||
|
||||
// Import Stable Risk Monitor for reliable beach mode operation
|
||||
async function importStableRiskMonitor() {
|
||||
// Import Enhanced Risk Manager with Learning for intelligent beach mode operation
|
||||
async function importEnhancedRiskManager() {
|
||||
try {
|
||||
const StableRiskMonitor = require('./stable-risk-monitor.js');
|
||||
return StableRiskMonitor;
|
||||
const EnhancedAutonomousRiskManager = require('./enhanced-autonomous-risk-manager.js');
|
||||
return EnhancedAutonomousRiskManager;
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Stable Risk Monitor not available, using basic monitoring');
|
||||
return null;
|
||||
console.warn('⚠️ Enhanced Risk Manager not available, falling back to stable monitor');
|
||||
// Fallback to stable risk monitor
|
||||
try {
|
||||
const StableRiskMonitor = require('./stable-risk-monitor.js');
|
||||
return StableRiskMonitor;
|
||||
} catch (fallbackError) {
|
||||
console.warn('⚠️ Stable Risk Monitor also not available, using basic monitoring');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,22 +66,25 @@ class SimpleAutomation {
|
||||
console.log('🎯 LIVE TRADING:', this.config.enableTrading ? 'ENABLED' : 'DISABLED');
|
||||
this.stats.totalCycles = 0;
|
||||
|
||||
// Initialize Stable Risk Monitor for reliable beach mode operation
|
||||
// Initialize Enhanced AI Risk Manager with Learning Capabilities
|
||||
try {
|
||||
const StableMonitorClass = await importStableRiskMonitor();
|
||||
if (StableMonitorClass) {
|
||||
this.riskManager = new StableMonitorClass();
|
||||
console.log('🏖️ BEACH MODE READY: Stable autonomous monitoring activated');
|
||||
// Start stable monitoring
|
||||
const EnhancedRiskManagerClass = await importEnhancedRiskManager();
|
||||
if (EnhancedRiskManagerClass) {
|
||||
this.riskManager = new EnhancedRiskManagerClass();
|
||||
console.log('🧠 ENHANCED BEACH MODE: AI learning system activated');
|
||||
console.log('🎯 System will learn from every decision and improve over time');
|
||||
|
||||
// Start enhanced autonomous operation
|
||||
setTimeout(() => {
|
||||
if (this.riskManager) {
|
||||
this.riskManager.startMonitoring();
|
||||
if (this.riskManager && this.riskManager.beachMode) {
|
||||
this.riskManager.beachMode();
|
||||
console.log('🏖️ Full autonomous operation with AI learning active');
|
||||
}
|
||||
}, 3000); // Wait 3 seconds for system stabilization
|
||||
}, 2000);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Risk Monitor initialization failed:', error.message);
|
||||
console.log('🔄 Continuing without autonomous risk monitoring');
|
||||
console.log('🔄 Continuing without enhanced autonomous risk monitoring');
|
||||
console.error('Risk manager initialization error:', error.message);
|
||||
}
|
||||
|
||||
// Auto-enable trading when in LIVE mode
|
||||
|
||||
592
lib/stop-loss-decision-learner.js
Normal file
592
lib/stop-loss-decision-learner.js
Normal file
@@ -0,0 +1,592 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Stop Loss Decision Learning System
|
||||
*
|
||||
* This system makes the AI learn from its own decision-making process near stop loss.
|
||||
* It records every decision, tracks outcomes, and continuously improves decision-making.
|
||||
*/
|
||||
|
||||
const { PrismaClient } = require('@prisma/client');
|
||||
|
||||
class StopLossDecisionLearner {
|
||||
constructor() {
|
||||
this.prisma = new PrismaClient();
|
||||
this.decisionHistory = [];
|
||||
this.learningThresholds = {
|
||||
emergencyDistance: 1.0,
|
||||
highRiskDistance: 2.0,
|
||||
mediumRiskDistance: 5.0
|
||||
};
|
||||
}
|
||||
|
||||
async log(message) {
|
||||
const timestamp = new Date().toISOString();
|
||||
console.log(`[${timestamp}] 🧠 SL Learner: ${message}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record an AI decision made near stop loss for learning purposes
|
||||
*/
|
||||
async recordDecision(decisionData) {
|
||||
try {
|
||||
const decision = {
|
||||
id: `decision_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
||||
tradeId: decisionData.tradeId,
|
||||
symbol: decisionData.symbol,
|
||||
decisionType: decisionData.decision, // 'HOLD', 'EXIT', 'TIGHTEN_SL', 'PARTIAL_EXIT', 'EMERGENCY_EXIT'
|
||||
distanceFromSL: decisionData.distanceFromSL,
|
||||
reasoning: decisionData.reasoning,
|
||||
marketConditions: {
|
||||
price: decisionData.currentPrice,
|
||||
trend: await this.analyzeMarketTrend(decisionData.symbol),
|
||||
volatility: await this.calculateVolatility(decisionData.symbol),
|
||||
volume: decisionData.volume || 'unknown',
|
||||
timeOfDay: new Date().getHours(),
|
||||
dayOfWeek: new Date().getDay()
|
||||
},
|
||||
confidenceScore: decisionData.confidenceScore || 0.7,
|
||||
expectedOutcome: decisionData.expectedOutcome || 'BETTER_RESULT',
|
||||
decisionTimestamp: new Date(),
|
||||
status: 'PENDING_OUTCOME'
|
||||
};
|
||||
|
||||
// Store in database
|
||||
await this.prisma.sLDecision.create({
|
||||
data: {
|
||||
id: decision.id,
|
||||
tradeId: decision.tradeId,
|
||||
symbol: decision.symbol,
|
||||
decisionType: decision.decisionType,
|
||||
distanceFromSL: decision.distanceFromSL,
|
||||
reasoning: decision.reasoning,
|
||||
marketConditions: JSON.stringify(decision.marketConditions),
|
||||
confidenceScore: decision.confidenceScore,
|
||||
expectedOutcome: decision.expectedOutcome,
|
||||
decisionTimestamp: decision.decisionTimestamp,
|
||||
status: decision.status
|
||||
}
|
||||
});
|
||||
|
||||
// Keep in memory for quick access
|
||||
this.decisionHistory.push(decision);
|
||||
|
||||
await this.log(`📝 Recorded decision: ${decision.decisionType} at ${decision.distanceFromSL}% from SL - ${decision.reasoning}`);
|
||||
|
||||
return decision.id;
|
||||
} catch (error) {
|
||||
await this.log(`❌ Error recording decision: ${error.message}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assess the outcome of a previous decision when trade closes or conditions change
|
||||
*/
|
||||
async assessDecisionOutcome(assessmentData) {
|
||||
try {
|
||||
const { decisionId, actualOutcome, timeToOutcome, pnlImpact, additionalContext } = assessmentData;
|
||||
|
||||
// Determine if the decision was correct
|
||||
const wasCorrect = this.evaluateDecisionCorrectness(actualOutcome, pnlImpact);
|
||||
const learningScore = this.calculateLearningScore(wasCorrect, pnlImpact, timeToOutcome);
|
||||
|
||||
// Update decision record
|
||||
await this.prisma.sLDecision.update({
|
||||
where: { id: decisionId },
|
||||
data: {
|
||||
outcome: actualOutcome,
|
||||
outcomeTimestamp: new Date(),
|
||||
timeToOutcome,
|
||||
pnlImpact,
|
||||
wasCorrect,
|
||||
learningScore,
|
||||
additionalContext: JSON.stringify(additionalContext || {}),
|
||||
status: 'ASSESSED'
|
||||
}
|
||||
});
|
||||
|
||||
// Update in-memory history
|
||||
const decision = this.decisionHistory.find(d => d.id === decisionId);
|
||||
if (decision) {
|
||||
Object.assign(decision, {
|
||||
outcome: actualOutcome,
|
||||
outcomeTimestamp: new Date(),
|
||||
wasCorrect,
|
||||
learningScore,
|
||||
status: 'ASSESSED'
|
||||
});
|
||||
}
|
||||
|
||||
await this.log(`✅ Assessed decision ${decisionId}: ${wasCorrect ? 'CORRECT' : 'INCORRECT'} - Score: ${learningScore.toFixed(2)}`);
|
||||
|
||||
// Trigger learning update
|
||||
await this.updateLearningModel();
|
||||
|
||||
return { wasCorrect, learningScore };
|
||||
} catch (error) {
|
||||
await this.log(`❌ Error assessing decision outcome: ${error.message}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze historical decisions to identify patterns and optimize future decisions
|
||||
*/
|
||||
async analyzeDecisionPatterns() {
|
||||
try {
|
||||
const decisions = await this.prisma.sLDecision.findMany({
|
||||
where: { status: 'ASSESSED' },
|
||||
orderBy: { decisionTimestamp: 'desc' },
|
||||
take: 100 // Analyze last 100 decisions
|
||||
});
|
||||
|
||||
const patterns = {
|
||||
successfulPatterns: [],
|
||||
failurePatterns: [],
|
||||
optimalTiming: {},
|
||||
contextFactors: {},
|
||||
distanceOptimization: {}
|
||||
};
|
||||
|
||||
// Analyze success patterns by decision type
|
||||
const decisionTypes = ['HOLD', 'EXIT', 'TIGHTEN_SL', 'PARTIAL_EXIT', 'EMERGENCY_EXIT'];
|
||||
|
||||
for (const type of decisionTypes) {
|
||||
const typeDecisions = decisions.filter(d => d.decisionType === type);
|
||||
const successRate = typeDecisions.length > 0 ?
|
||||
typeDecisions.filter(d => d.wasCorrect).length / typeDecisions.length : 0;
|
||||
|
||||
const avgScore = typeDecisions.length > 0 ?
|
||||
typeDecisions.reduce((sum, d) => sum + (d.learningScore || 0), 0) / typeDecisions.length : 0;
|
||||
|
||||
if (successRate > 0.6) { // 60%+ success rate
|
||||
patterns.successfulPatterns.push({
|
||||
decisionType: type,
|
||||
successRate: successRate * 100,
|
||||
avgScore,
|
||||
sampleSize: typeDecisions.length,
|
||||
optimalConditions: this.identifyOptimalConditions(typeDecisions.filter(d => d.wasCorrect))
|
||||
});
|
||||
} else if (typeDecisions.length >= 5) {
|
||||
patterns.failurePatterns.push({
|
||||
decisionType: type,
|
||||
successRate: successRate * 100,
|
||||
avgScore,
|
||||
sampleSize: typeDecisions.length,
|
||||
commonFailureReasons: this.identifyFailureReasons(typeDecisions.filter(d => !d.wasCorrect))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Analyze optimal distance thresholds
|
||||
patterns.distanceOptimization = await this.optimizeDistanceThresholds(decisions);
|
||||
|
||||
// Analyze timing patterns
|
||||
patterns.optimalTiming = await this.analyzeTimingPatterns(decisions);
|
||||
|
||||
await this.log(`📊 Pattern analysis complete: ${patterns.successfulPatterns.length} successful patterns, ${patterns.failurePatterns.length} failure patterns identified`);
|
||||
|
||||
return patterns;
|
||||
} catch (error) {
|
||||
await this.log(`❌ Error analyzing decision patterns: ${error.message}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get AI recommendation for current situation based on learned patterns
|
||||
*/
|
||||
async getSmartRecommendation(situationData) {
|
||||
try {
|
||||
const { distanceFromSL, symbol, marketConditions } = situationData;
|
||||
|
||||
// Get historical patterns for similar situations
|
||||
const patterns = await this.analyzeDecisionPatterns();
|
||||
const currentConditions = marketConditions || await this.getCurrentMarketConditions(symbol);
|
||||
|
||||
// Find most similar historical situations
|
||||
const similarSituations = await this.findSimilarSituations({
|
||||
distanceFromSL,
|
||||
marketConditions: currentConditions
|
||||
});
|
||||
|
||||
// Generate recommendation based on learned patterns
|
||||
const recommendation = {
|
||||
suggestedAction: 'HOLD', // Default
|
||||
confidence: 0.5,
|
||||
reasoning: 'Insufficient learning data',
|
||||
learningBased: false,
|
||||
supportingData: {}
|
||||
};
|
||||
|
||||
if (similarSituations.length >= 3) {
|
||||
const successfulActions = similarSituations
|
||||
.filter(s => s.wasCorrect)
|
||||
.map(s => s.decisionType);
|
||||
|
||||
const mostSuccessfulAction = this.getMostCommonAction(successfulActions);
|
||||
const successRate = successfulActions.length / similarSituations.length;
|
||||
|
||||
recommendation.suggestedAction = mostSuccessfulAction;
|
||||
recommendation.confidence = Math.min(0.95, successRate + 0.1);
|
||||
recommendation.reasoning = `Based on ${similarSituations.length} similar situations, ${mostSuccessfulAction} succeeded ${(successRate * 100).toFixed(1)}% of the time`;
|
||||
recommendation.learningBased = true;
|
||||
recommendation.supportingData = {
|
||||
historicalSamples: similarSituations.length,
|
||||
successRate: successRate * 100,
|
||||
avgPnlImpact: similarSituations.reduce((sum, s) => sum + (s.pnlImpact || 0), 0) / similarSituations.length
|
||||
};
|
||||
}
|
||||
|
||||
await this.log(`🎯 Smart recommendation: ${recommendation.suggestedAction} (${(recommendation.confidence * 100).toFixed(1)}% confidence) - ${recommendation.reasoning}`);
|
||||
|
||||
return recommendation;
|
||||
} catch (error) {
|
||||
await this.log(`❌ Error generating smart recommendation: ${error.message}`);
|
||||
return {
|
||||
suggestedAction: 'HOLD',
|
||||
confidence: 0.3,
|
||||
reasoning: `Error in recommendation system: ${error.message}`,
|
||||
learningBased: false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update learning model based on new decision outcomes
|
||||
*/
|
||||
async updateLearningModel() {
|
||||
try {
|
||||
const patterns = await this.analyzeDecisionPatterns();
|
||||
|
||||
if (patterns && patterns.distanceOptimization) {
|
||||
// Update decision thresholds based on learning
|
||||
this.learningThresholds = {
|
||||
emergencyDistance: patterns.distanceOptimization.optimalEmergencyThreshold || 1.0,
|
||||
highRiskDistance: patterns.distanceOptimization.optimalHighRiskThreshold || 2.0,
|
||||
mediumRiskDistance: patterns.distanceOptimization.optimalMediumRiskThreshold || 5.0
|
||||
};
|
||||
|
||||
await this.log(`🔄 Updated learning thresholds: Emergency=${this.learningThresholds.emergencyDistance}%, High Risk=${this.learningThresholds.highRiskDistance}%, Medium Risk=${this.learningThresholds.mediumRiskDistance}%`);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
await this.log(`❌ Error updating learning model: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper methods for analysis
|
||||
*/
|
||||
evaluateDecisionCorrectness(actualOutcome, pnlImpact) {
|
||||
// Define what constitutes a "correct" decision
|
||||
const correctOutcomes = [
|
||||
'BETTER_THAN_ORIGINAL_SL',
|
||||
'AVOIDED_LOSS',
|
||||
'IMPROVED_PROFIT',
|
||||
'SUCCESSFUL_EXIT'
|
||||
];
|
||||
|
||||
return correctOutcomes.includes(actualOutcome) || (pnlImpact && pnlImpact > 0);
|
||||
}
|
||||
|
||||
calculateLearningScore(wasCorrect, pnlImpact, timeToOutcome) {
|
||||
let score = wasCorrect ? 0.7 : 0.3; // Base score
|
||||
|
||||
// Adjust for P&L impact
|
||||
if (pnlImpact) {
|
||||
score += Math.min(0.2, pnlImpact / 100); // Max 0.2 bonus for positive P&L
|
||||
}
|
||||
|
||||
// Adjust for timing (faster good decisions are better)
|
||||
if (timeToOutcome && wasCorrect) {
|
||||
const timingBonus = Math.max(0, 0.1 - (timeToOutcome / 3600)); // Bonus for decisions resolved within an hour
|
||||
score += timingBonus;
|
||||
}
|
||||
|
||||
return Math.max(0, Math.min(1, score));
|
||||
}
|
||||
|
||||
identifyOptimalConditions(successfulDecisions) {
|
||||
// Analyze common conditions in successful decisions
|
||||
const conditions = {};
|
||||
|
||||
successfulDecisions.forEach(decision => {
|
||||
try {
|
||||
const market = JSON.parse(decision.marketConditions || '{}');
|
||||
|
||||
// Track successful decision contexts
|
||||
if (market.trend) {
|
||||
conditions.trend = conditions.trend || {};
|
||||
conditions.trend[market.trend] = (conditions.trend[market.trend] || 0) + 1;
|
||||
}
|
||||
|
||||
if (market.timeOfDay) {
|
||||
conditions.timeOfDay = conditions.timeOfDay || {};
|
||||
const hour = market.timeOfDay;
|
||||
conditions.timeOfDay[hour] = (conditions.timeOfDay[hour] || 0) + 1;
|
||||
}
|
||||
} catch (error) {
|
||||
// Skip malformed data
|
||||
}
|
||||
});
|
||||
|
||||
return conditions;
|
||||
}
|
||||
|
||||
identifyFailureReasons(failedDecisions) {
|
||||
// Analyze what went wrong in failed decisions
|
||||
return failedDecisions.map(decision => ({
|
||||
reasoning: decision.reasoning,
|
||||
distanceFromSL: decision.distanceFromSL,
|
||||
outcome: decision.outcome,
|
||||
pnlImpact: decision.pnlImpact
|
||||
}));
|
||||
}
|
||||
|
||||
async optimizeDistanceThresholds(decisions) {
|
||||
// Analyze optimal distance thresholds for different decision types
|
||||
const optimization = {};
|
||||
|
||||
// Group decisions by distance ranges
|
||||
const ranges = [
|
||||
{ min: 0, max: 1, label: 'emergency' },
|
||||
{ min: 1, max: 2, label: 'highRisk' },
|
||||
{ min: 2, max: 5, label: 'mediumRisk' },
|
||||
{ min: 5, max: 100, label: 'safe' }
|
||||
];
|
||||
|
||||
for (const range of ranges) {
|
||||
const rangeDecisions = decisions.filter(d =>
|
||||
d.distanceFromSL >= range.min && d.distanceFromSL < range.max
|
||||
);
|
||||
|
||||
if (rangeDecisions.length >= 3) {
|
||||
const successRate = rangeDecisions.filter(d => d.wasCorrect).length / rangeDecisions.length;
|
||||
const avgScore = rangeDecisions.reduce((sum, d) => sum + (d.learningScore || 0), 0) / rangeDecisions.length;
|
||||
|
||||
optimization[`${range.label}Range`] = {
|
||||
successRate: successRate * 100,
|
||||
avgScore,
|
||||
sampleSize: rangeDecisions.length,
|
||||
optimalThreshold: this.calculateOptimalThreshold(rangeDecisions)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return optimization;
|
||||
}
|
||||
|
||||
calculateOptimalThreshold(decisions) {
|
||||
// Find the distance threshold that maximizes success rate
|
||||
const sortedDecisions = decisions.sort((a, b) => a.distanceFromSL - b.distanceFromSL);
|
||||
let bestThreshold = 1.0;
|
||||
let bestScore = 0;
|
||||
|
||||
for (let i = 0; i < sortedDecisions.length - 1; i++) {
|
||||
const threshold = sortedDecisions[i].distanceFromSL;
|
||||
const aboveThreshold = sortedDecisions.slice(i);
|
||||
const successRate = aboveThreshold.filter(d => d.wasCorrect).length / aboveThreshold.length;
|
||||
|
||||
if (successRate > bestScore && aboveThreshold.length >= 3) {
|
||||
bestScore = successRate;
|
||||
bestThreshold = threshold;
|
||||
}
|
||||
}
|
||||
|
||||
return bestThreshold;
|
||||
}
|
||||
|
||||
async analyzeTimingPatterns(decisions) {
|
||||
// Analyze when decisions work best (time of day, day of week, etc.)
|
||||
const timing = {
|
||||
timeOfDay: {},
|
||||
dayOfWeek: {},
|
||||
marketSession: {}
|
||||
};
|
||||
|
||||
decisions.forEach(decision => {
|
||||
try {
|
||||
const market = JSON.parse(decision.marketConditions || '{}');
|
||||
const wasCorrect = decision.wasCorrect;
|
||||
|
||||
if (market.timeOfDay !== undefined) {
|
||||
const hour = market.timeOfDay;
|
||||
timing.timeOfDay[hour] = timing.timeOfDay[hour] || { total: 0, correct: 0 };
|
||||
timing.timeOfDay[hour].total++;
|
||||
if (wasCorrect) timing.timeOfDay[hour].correct++;
|
||||
}
|
||||
|
||||
if (market.dayOfWeek !== undefined) {
|
||||
const day = market.dayOfWeek;
|
||||
timing.dayOfWeek[day] = timing.dayOfWeek[day] || { total: 0, correct: 0 };
|
||||
timing.dayOfWeek[day].total++;
|
||||
if (wasCorrect) timing.dayOfWeek[day].correct++;
|
||||
}
|
||||
} catch (error) {
|
||||
// Skip malformed data
|
||||
}
|
||||
});
|
||||
|
||||
return timing;
|
||||
}
|
||||
|
||||
async findSimilarSituations(currentSituation) {
|
||||
const { distanceFromSL, marketConditions } = currentSituation;
|
||||
const tolerance = 0.5; // 0.5% tolerance for distance matching
|
||||
|
||||
const decisions = await this.prisma.sLDecision.findMany({
|
||||
where: {
|
||||
status: 'ASSESSED',
|
||||
distanceFromSL: {
|
||||
gte: distanceFromSL - tolerance,
|
||||
lte: distanceFromSL + tolerance
|
||||
}
|
||||
},
|
||||
orderBy: { decisionTimestamp: 'desc' },
|
||||
take: 20
|
||||
});
|
||||
|
||||
return decisions;
|
||||
}
|
||||
|
||||
getMostCommonAction(actions) {
|
||||
const counts = {};
|
||||
actions.forEach(action => {
|
||||
counts[action] = (counts[action] || 0) + 1;
|
||||
});
|
||||
|
||||
return Object.entries(counts).reduce((a, b) => counts[a] > counts[b] ? a : b)[0] || 'HOLD';
|
||||
}
|
||||
|
||||
async analyzeMarketTrend(symbol) {
|
||||
// Simplified trend analysis - in real implementation, use technical indicators
|
||||
try {
|
||||
const response = await fetch(`http://localhost:9001/api/automation/position-monitor`);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success && data.monitor && data.monitor.position) {
|
||||
const pnl = data.monitor.position.unrealizedPnl;
|
||||
if (pnl > 0) return 'BULLISH';
|
||||
if (pnl < 0) return 'BEARISH';
|
||||
return 'SIDEWAYS';
|
||||
}
|
||||
} catch (error) {
|
||||
// Fallback
|
||||
}
|
||||
|
||||
return 'UNKNOWN';
|
||||
}
|
||||
|
||||
async calculateVolatility(symbol) {
|
||||
// Simplified volatility calculation
|
||||
// In real implementation, calculate based on price history
|
||||
return Math.random() * 0.1; // Mock volatility 0-10%
|
||||
}
|
||||
|
||||
async getCurrentMarketConditions(symbol) {
|
||||
return {
|
||||
trend: await this.analyzeMarketTrend(symbol),
|
||||
volatility: await this.calculateVolatility(symbol),
|
||||
timeOfDay: new Date().getHours(),
|
||||
dayOfWeek: new Date().getDay()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate learning insights report
|
||||
*/
|
||||
async generateLearningReport() {
|
||||
try {
|
||||
const patterns = await this.analyzeDecisionPatterns();
|
||||
|
||||
const report = {
|
||||
timestamp: new Date().toISOString(),
|
||||
summary: {
|
||||
totalDecisions: this.decisionHistory.length,
|
||||
successfulPatterns: patterns?.successfulPatterns?.length || 0,
|
||||
learningThresholds: this.learningThresholds,
|
||||
systemConfidence: this.calculateSystemConfidence()
|
||||
},
|
||||
insights: patterns,
|
||||
recommendations: await this.generateSystemRecommendations(patterns)
|
||||
};
|
||||
|
||||
await this.log(`📊 Learning report generated: ${report.summary.totalDecisions} decisions analyzed`);
|
||||
|
||||
return report;
|
||||
} catch (error) {
|
||||
await this.log(`❌ Error generating learning report: ${error.message}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
calculateSystemConfidence() {
|
||||
const recentDecisions = this.decisionHistory.slice(-20); // Last 20 decisions
|
||||
if (recentDecisions.length < 5) return 0.3; // Low confidence with insufficient data
|
||||
|
||||
const successRate = recentDecisions.filter(d => d.wasCorrect).length / recentDecisions.length;
|
||||
return Math.min(0.95, successRate + 0.1); // Cap at 95%
|
||||
}
|
||||
|
||||
async generateSystemRecommendations(patterns) {
|
||||
const recommendations = [];
|
||||
|
||||
if (patterns?.failurePatterns?.length > 0) {
|
||||
patterns.failurePatterns.forEach(pattern => {
|
||||
recommendations.push({
|
||||
type: 'IMPROVEMENT',
|
||||
priority: 'HIGH',
|
||||
message: `Consider avoiding ${pattern.decisionType} decisions - only ${pattern.successRate.toFixed(1)}% success rate`,
|
||||
actionable: true
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (patterns?.successfulPatterns?.length > 0) {
|
||||
const bestPattern = patterns.successfulPatterns.reduce((best, current) =>
|
||||
current.successRate > best.successRate ? current : best
|
||||
);
|
||||
|
||||
recommendations.push({
|
||||
type: 'OPTIMIZATION',
|
||||
priority: 'MEDIUM',
|
||||
message: `${bestPattern.decisionType} decisions show ${bestPattern.successRate.toFixed(1)}% success rate - consider using more often`,
|
||||
actionable: true
|
||||
});
|
||||
}
|
||||
|
||||
return recommendations;
|
||||
}
|
||||
}
|
||||
|
||||
// Export for use in other modules
|
||||
module.exports = StopLossDecisionLearner;
|
||||
|
||||
// Direct execution for testing
|
||||
if (require.main === module) {
|
||||
const learner = new StopLossDecisionLearner();
|
||||
|
||||
console.log('🧠 Stop Loss Decision Learning System');
|
||||
console.log('📊 Ready to make your AI smarter with every decision!');
|
||||
|
||||
// Demo decision recording
|
||||
setTimeout(async () => {
|
||||
await learner.recordDecision({
|
||||
tradeId: 'demo_001',
|
||||
symbol: 'SOL-PERP',
|
||||
decision: 'TIGHTEN_SL',
|
||||
distanceFromSL: 2.3,
|
||||
reasoning: 'Market showing weakness, reducing risk exposure',
|
||||
currentPrice: 182.45,
|
||||
confidenceScore: 0.8,
|
||||
expectedOutcome: 'BETTER_RESULT'
|
||||
});
|
||||
|
||||
const report = await learner.generateLearningReport();
|
||||
console.log('\n📊 LEARNING REPORT:', JSON.stringify(report, null, 2));
|
||||
}, 1000);
|
||||
}
|
||||
Reference in New Issue
Block a user