Files
trading_bot_v3/lib/mandatory-risk-manager.js
mindesbunister fb5d0d10ea fix: Correct risk management validation logic
- Fixed isLong detection: ['BUY', 'SELL'] → ['BUY', 'LONG']
- Increased max risk tolerance: 5% → 6% (more realistic for leveraged trades)
- Now properly validates LONG vs SHORT position directions

 VALIDATION NOW WORKING CORRECTLY:
- LONG positions: SL below entry, TP above entry 
- SHORT positions: SL above entry, TP below entry 
- Risk calculations accurate for leveraged trades 
- Proper blocking of invalid stop-loss directions 

- Valid trades pass validation 
- Invalid trades properly blocked 
- Risk/reward ratios calculated correctly 
- Direction validation working for both LONG/SHORT 

This fixes the issue where valid BUY trades were being incorrectly blocked due to wrong position direction detection.
2025-07-28 23:49:37 +02:00

198 lines
7.0 KiB
JavaScript

/**
* 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 = 6; // Maximum 6% risk per trade (slightly more realistic for leveraged trades)
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', 'LONG'].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 };