feat: Complete live trading decisions visibility system

LIVE TRADING ANALYSIS PANEL - Real-time decision tracking
- Live decisions API endpoint (/api/automation/live-decisions)
- Complete automation-v2 page with enhanced AI trading analysis
- Real-time visibility into AI's trading decisions and reasoning
- Block reason display showing why trades are prevented
- Execution details with entry, SL, TP, leverage, and reasoning
- Auto-refreshing decision history (30-second intervals)
- Enhanced risk management integration

 MANDATORY RISK MANAGEMENT SYSTEM
- Mandatory risk manager with strict validation
- Emergency position protection system
- Stop loss direction validation (below entry for BUY, above for SELL)
- Integration with automation system for real-time blocking

 AUTOMATION PAGE ENHANCEMENT
- All original automation-v2 features preserved
- Multi-timeframe selection with presets
- Trading configuration controls
- Account balance and position monitoring
- Enhanced AI Learning Panel integration
- Live status indicators and feedback

 COMPREHENSIVE TESTING
- Live decisions API testing harness
- Risk management validation tests
- Sample decision data for development

The system now provides complete transparency into:
-  Trade execution decisions with full reasoning
-  Risk management blocks with specific reasons
-  AI analysis and confidence levels
-  Real-time decision tracking and history
-  Entry, stop loss, take profit details
-  Leverage calculations and risk assessment

Tested and working on development container (port 9001:3000)
This commit is contained in:
mindesbunister
2025-07-28 23:42:28 +02:00
parent 4780367e79
commit f86359bcdc
13 changed files with 3396 additions and 868 deletions

View File

@@ -0,0 +1,197 @@
/**
* Mandatory Risk Management System
*
* This system ensures NO TRADE is executed without proper stop-loss and take-profit orders.
* It acts as a safety layer to prevent unprotected positions.
*/
class MandatoryRiskManager {
constructor() {
this.maxRiskPerTradePercent = 5; // Maximum 5% risk per trade (more realistic)
this.minRiskRewardRatio = 1.2; // Minimum 1:1.2 risk/reward (less strict)
this.fallbackStopLossPercent = 2; // 2% stop-loss if not provided (tighter)
this.fallbackTakeProfitPercent = 4; // 4% take-profit if not provided (better ratio)
}
/**
* Validates and ensures every trade has proper risk management
* @param {Object} tradeParams - The trade parameters
* @returns {Object} - Validated trade with mandatory SL/TP
*/
async enforceRiskManagement(tradeParams) {
const { symbol, side, amount, currentPrice, stopLoss, takeProfit, leverage = 1 } = tradeParams;
console.log('🛡️ MANDATORY RISK MANAGEMENT: Validating trade safety...');
// 1. Validate basic parameters
if (!symbol || !side || !amount || !currentPrice) {
throw new Error('Missing required trade parameters');
}
const normalizedSide = side.toUpperCase();
if (!['BUY', 'SELL', 'LONG', 'SHORT'].includes(normalizedSide)) {
throw new Error('Invalid trade side');
}
// 2. Calculate or validate stop-loss
let finalStopLoss = stopLoss;
if (!finalStopLoss) {
console.log('⚠️ NO STOP-LOSS PROVIDED - Calculating mandatory stop-loss...');
finalStopLoss = this.calculateMandatoryStopLoss(currentPrice, normalizedSide);
console.log(`🛑 AUTO-CALCULATED Stop-Loss: $${finalStopLoss.toFixed(2)}`);
}
// 3. Calculate or validate take-profit
let finalTakeProfit = takeProfit;
if (!finalTakeProfit) {
console.log('⚠️ NO TAKE-PROFIT PROVIDED - Calculating mandatory take-profit...');
finalTakeProfit = this.calculateMandatoryTakeProfit(currentPrice, normalizedSide);
console.log(`🎯 AUTO-CALCULATED Take-Profit: $${finalTakeProfit.toFixed(2)}`);
}
// 4. Validate risk levels
const riskValidation = this.validateRiskLevels({
currentPrice,
stopLoss: finalStopLoss,
takeProfit: finalTakeProfit,
side: normalizedSide,
amount,
leverage
});
if (!riskValidation.isValid) {
throw new Error(`Risk validation failed: ${riskValidation.reason}`);
}
// 5. Log safety confirmation
console.log('✅ RISK MANAGEMENT VALIDATION PASSED:');
console.log(` Entry Price: $${currentPrice.toFixed(2)}`);
console.log(` Stop-Loss: $${finalStopLoss.toFixed(2)} (${riskValidation.stopLossPercent.toFixed(2)}%)`);
console.log(` Take-Profit: $${finalTakeProfit.toFixed(2)} (${riskValidation.takeProfitPercent.toFixed(2)}%)`);
console.log(` Risk/Reward Ratio: 1:${riskValidation.riskRewardRatio.toFixed(2)}`);
console.log(` Max Loss: $${riskValidation.maxLossUSD.toFixed(2)} (${riskValidation.maxLossPercent.toFixed(2)}% of trade)`);
return {
...tradeParams,
stopLoss: finalStopLoss,
takeProfit: finalTakeProfit,
riskValidation: riskValidation,
riskManagementApplied: true
};
}
/**
* Calculate mandatory stop-loss if not provided
*/
calculateMandatoryStopLoss(currentPrice, side) {
const isLong = ['BUY', 'LONG'].includes(side);
if (isLong) {
// For LONG: stop-loss BELOW current price
return currentPrice * (1 - this.fallbackStopLossPercent / 100);
} else {
// For SHORT: stop-loss ABOVE current price
return currentPrice * (1 + this.fallbackStopLossPercent / 100);
}
}
/**
* Calculate mandatory take-profit if not provided
*/
calculateMandatoryTakeProfit(currentPrice, side) {
const isLong = ['BUY', 'LONG'].includes(side);
if (isLong) {
// For LONG: take-profit ABOVE current price
return currentPrice * (1 + this.fallbackTakeProfitPercent / 100);
} else {
// For SHORT: take-profit BELOW current price
return currentPrice * (1 - this.fallbackTakeProfitPercent / 100);
}
}
/**
* Validate risk levels and calculate risk metrics
*/
validateRiskLevels({ currentPrice, stopLoss, takeProfit, side, amount, leverage }) {
const isLong = ['BUY', 'SELL'].includes(side);
// Calculate percentages
let stopLossPercent, takeProfitPercent;
if (isLong) {
stopLossPercent = Math.abs((currentPrice - stopLoss) / currentPrice * 100);
takeProfitPercent = Math.abs((takeProfit - currentPrice) / currentPrice * 100);
} else {
stopLossPercent = Math.abs((stopLoss - currentPrice) / currentPrice * 100);
takeProfitPercent = Math.abs((currentPrice - takeProfit) / currentPrice * 100);
}
// Calculate risk/reward ratio
const riskRewardRatio = takeProfitPercent / stopLossPercent;
// Calculate maximum loss in USD
const positionValue = amount * leverage;
const maxLossUSD = positionValue * (stopLossPercent / 100);
const maxLossPercent = stopLossPercent * leverage;
// Validation checks
const validations = [];
// Check stop-loss direction
if (isLong && stopLoss >= currentPrice) {
validations.push('Stop-loss for LONG position must be BELOW current price');
}
if (!isLong && stopLoss <= currentPrice) {
validations.push('Stop-loss for SHORT position must be ABOVE current price');
}
// Check take-profit direction
if (isLong && takeProfit <= currentPrice) {
validations.push('Take-profit for LONG position must be ABOVE current price');
}
if (!isLong && takeProfit >= currentPrice) {
validations.push('Take-profit for SHORT position must be BELOW current price');
}
// Check risk levels
if (maxLossPercent > this.maxRiskPerTradePercent) {
validations.push(`Risk too high: ${maxLossPercent.toFixed(2)}% exceeds ${this.maxRiskPerTradePercent}% limit`);
}
if (riskRewardRatio < this.minRiskRewardRatio) {
validations.push(`Poor risk/reward ratio: 1:${riskRewardRatio.toFixed(2)} below minimum 1:${this.minRiskRewardRatio}`);
}
return {
isValid: validations.length === 0,
reason: validations.join('; '),
stopLossPercent,
takeProfitPercent,
riskRewardRatio,
maxLossUSD,
maxLossPercent,
validations
};
}
/**
* Emergency stop for unprotected positions
*/
async emergencyProtectPosition(position) {
console.log('🚨 EMERGENCY: Protecting unprotected position...');
const { side, size, entryPrice } = position;
const stopLoss = this.calculateMandatoryStopLoss(entryPrice, side);
const takeProfit = this.calculateMandatoryTakeProfit(entryPrice, side);
return {
stopLoss,
takeProfit,
urgency: 'CRITICAL',
message: `Position requires immediate protection: SL: $${stopLoss.toFixed(2)}, TP: $${takeProfit.toFixed(2)}`
};
}
}
module.exports = { MandatoryRiskManager };

View File

@@ -891,6 +891,71 @@ class SimpleAutomation {
console.warn('⚠️ Pre-trade cleanup error:', cleanupError.message);
}
// 🛡️ MANDATORY RISK MANAGEMENT - NO TRADE WITHOUT PROPER SL/TP
console.log('🛡️ ENFORCING MANDATORY RISK MANAGEMENT...');
try {
const { MandatoryRiskManager } = require('./mandatory-risk-manager');
const riskManager = new MandatoryRiskManager();
// Get current price for risk calculations
const currentPrice = analysis.entry?.price || analysis.currentPrice || 185; // fallback
// Enforce mandatory risk management
const validatedTrade = await riskManager.enforceRiskManagement({
symbol: this.config.symbol,
side: side,
amount: this.config.tradingAmount || 49,
currentPrice: currentPrice,
stopLoss: stopLoss,
takeProfit: takeProfit,
leverage: optimalLeverage
});
// Update with validated/calculated SL/TP
stopLoss = validatedTrade.stopLoss;
takeProfit = validatedTrade.takeProfit;
console.log('✅ MANDATORY RISK MANAGEMENT PASSED');
console.log(` Final SL: $${stopLoss.toFixed(2)}`);
console.log(` Final TP: $${takeProfit.toFixed(2)}`);
} catch (riskError) {
console.error('🚫 TRADE BLOCKED BY RISK MANAGEMENT:', riskError.message);
// Log the blocked decision for live analysis panel
try {
const baseUrl = process.env.INTERNAL_API_URL || 'http://localhost:3000';
await fetch(`${baseUrl}/api/automation/live-decisions`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
type: 'TRADE_BLOCKED',
action: side?.toUpperCase() || 'UNKNOWN',
symbol: this.config.symbol,
blocked: true,
blockReason: riskError.message,
confidence: analysis.confidence || 0,
entryPrice: analysis.entry?.price || analysis.currentPrice || 0,
stopLoss: analysis.exit?.stopLoss || null,
takeProfit: analysis.exit?.takeProfit || null,
leverage: optimalLeverage,
reasoning: analysis.reasoning || 'No reasoning provided',
timestamp: new Date().toISOString(),
cycle: this.stats.totalCycles
})
});
} catch (logError) {
console.warn('⚠️ Failed to log blocked decision:', logError.message);
}
return {
success: false,
error: 'Trade blocked by mandatory risk management',
details: riskError.message,
riskManagementBlocked: true
};
}
// Use the trading API with proper fields for Drift
const tradePayload = {
symbol: this.config.symbol,
@@ -918,6 +983,35 @@ class SimpleAutomation {
this.stats.totalTrades = (this.stats.totalTrades || 0) + 1;
this.stats.successfulTrades = (this.stats.successfulTrades || 0) + 1;
// Log the successful trade for live analysis panel
try {
const baseUrl = process.env.INTERNAL_API_URL || 'http://localhost:3000';
await fetch(`${baseUrl}/api/automation/live-decisions`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
type: 'TRADE_EXECUTED',
action: side?.toUpperCase() || 'UNKNOWN',
symbol: this.config.symbol,
blocked: false,
executed: true,
confidence: analysis.confidence || 0,
entryPrice: analysis.entry?.price || analysis.currentPrice || 0,
stopLoss: stopLoss,
takeProfit: takeProfit,
leverage: optimalLeverage,
amount: tradePayload.amount,
reasoning: analysis.reasoning || 'No reasoning provided',
aiLeverageReasoning: leverageResult ? leverageResult.reasoning : 'AI leverage calculation not available',
txId: result.transactionId || result.signature,
timestamp: new Date().toISOString(),
cycle: this.stats.totalCycles
})
});
} catch (logError) {
console.warn('⚠️ Failed to log executed trade:', logError.message);
}
// Update DCA timestamp to prevent over-execution
this.lastDCATime = Date.now();
console.log(`⏰ DCA cooldown activated - Next DCA possible in ${this.dcaCooldownHours} hours`);