diff --git a/Trading-app b/Trading-app new file mode 100644 index 0000000..455e0df --- /dev/null +++ b/Trading-app @@ -0,0 +1,932 @@ +//+------------------------------------------------------------------+ +//| SMC_Pro_EA_v3_BALANCED_STRATEGY.mq5 | +//| Copyright 2025, Balanced Trading Strategy | +//| MORE TRADES WITH SMART RISK MANAGEMENT | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, Balanced Trading Strategy" +#property link "https://www.mql5.com" +#property version "3.10" +#property description "Balanced strategy - More trades with better risk management" + +#include +#include +#include +#include + +//--- CTrade instances +CTrade trade; +CSymbolInfo symbolInfo; +CPositionInfo positionInfo; +CAccountInfo accountInfo; + +//============================================================================ +// === INPUTS === +//============================================================================ + +//--- General Settings +input group "General Settings" +input ulong magicNumber = 54321; // Magic Number +input double lotSize = 0.01; // Fixed Lot Size +input string tradeComment = "BALANCED SMC v3.10"; + +//--- Strategy Settings (More Aggressive) +input group "📈 BALANCED STRATEGY SETTINGS" +input bool USE_TREND_FILTER = false; // Disable strict trend filter +input bool USE_MULTIPLE_SIGNALS = true; // Allow multiple signal types +input int MIN_BARS_BETWEEN_TRADES = 3; // Reduced from 5 +input double MIN_RR_RATIO = 1.2; // Reduced from 1.5 +input double MIN_PRICE_MOVEMENT = 0.0008; // Minimum movement to trigger + +//--- Risk Management (More Flexible) +input group "🛡️ FLEXIBLE RISK MANAGEMENT" +input bool USE_FIXED_LOT = true; // Use fixed lot instead of % risk +input double MAX_RISK_PERCENT = 1.5; // Risk per trade if using % risk +input double BASE_SL_POINTS = 120; // Base SL in points (reduced) +input double TP_MULTIPLIER = 1.8; // Reduced TP multiplier +input bool USE_TIGHT_SL = true; // Use tighter stop losses + +//--- Trailing Stop Settings (More Aggressive) +input group "🎯 AGGRESSIVE TRAILING STOP" +input bool USE_TRAILING_STOP = true; // Enable trailing stop +input double TRAILING_START_POINTS = 60; // Start trailing sooner +input double TRAILING_STEP_POINTS = 30; // Smaller trailing steps +input double TRAILING_STOP_POINTS = 50; // Tighter trailing distance + +//--- Quick Profit Protection +input group "⚡ QUICK PROFIT FEATURES" +input bool USE_BREAKEVEN = true; // Move to breakeven +input double BREAKEVEN_TRIGGER = 50; // Earlier breakeven (was 80) +input bool USE_QUICK_PROFIT = true; // Take quick profits +input double QUICK_PROFIT_POINTS = 80; // Quick profit target +input double QUICK_PROFIT_PERCENT = 30; // % to close early + +//--- Signal Generation (More Opportunities) +input group "🔍 SIGNAL GENERATION" +input bool ENABLE_MOMENTUM_TRADES = true; // Momentum signals +input bool ENABLE_REVERSAL_TRADES = true; // Reversal signals +input bool ENABLE_BREAKOUT_TRADES = true; // Breakout signals +input bool ENABLE_SCALPING_MODE = false; // Extra sensitive mode + +//--- Debug Settings +input group "🔧 Debug Settings" +input bool PRINT_ALL_SIGNALS = true; // Print all signal attempts +input bool PRINT_MARKET_STATE = true; // Print market conditions + +//============================================================================ +// === GLOBAL VARIABLES & STRUCTS === +//============================================================================ + +datetime lastTradeTime = 0; +int totalSignals = 0; +int totalTrades = 0; +int successfulTrades = 0; +long barCounter = 0; +bool trailingActive = false; +double highestProfit = 0; +double lastCloseProfit = 0; + +// Market state tracking +double recentHigh = 0; +double recentLow = 0; + +//--- Trading signal structure +struct TradingSignal +{ + ENUM_ORDER_TYPE orderType; + string reason; + double entry; + double stopLoss; + double takeProfit; + double confidence; + bool isValid; +}; + +//--- Market conditions structure +struct MarketConditions +{ + double currentPrice; + double priceChange; + double volatility; + bool isTrending; + bool isRanging; + double support; + double resistance; + double momentum; + bool nearSupport; + bool nearResistance; +}; + + +//============================================================================ +// === EA EVENT HANDLERS === +//============================================================================ + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + Print("======================================================="); + Print("🚀 BALANCED SMC EA v3.10 - MORE TRADES VERSION"); + Print("======================================================="); + + //--- Initialize trade object + trade.SetExpertMagicNumber(magicNumber); + trade.SetDeviationInPoints(50); // Allow more slippage for aggressive entries + trade.SetTypeFillingBySymbol(Symbol()); + + //--- Perform initial checks + if(!PerformInitialChecks()) + { + return(INIT_FAILED); + } + + //--- Print configuration + Print("✅ Configuration:"); + Print(" Fixed Lot Size: ", USE_FIXED_LOT ? DoubleToString(lotSize, 2) : "Dynamic"); + Print(" Trend Filter: ", USE_TREND_FILTER ? "STRICT" : "FLEXIBLE"); + Print(" Min R:R Ratio: ", MIN_RR_RATIO); + Print(" Base SL: ", BASE_SL_POINTS, " points"); + Print(" Trailing: ", USE_TRAILING_STOP ? "ACTIVE" : "OFF"); + Print(" Signal Types: Mom=", ENABLE_MOMENTUM_TRADES, " Rev=", ENABLE_REVERSAL_TRADES, " Brk=", ENABLE_BREAKOUT_TRADES); + Print("======================================================="); + + //--- Initialize market levels + UpdateMarketLevels(100); // Use 100 bars for initial range + + return(INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) +{ + Print("======================================================="); + Print("📊 BALANCED EA FINAL STATISTICS"); + Print("======================================================="); + Print("Total Bars Processed: ", barCounter); + Print("Total Signals Generated: ", totalSignals); + Print("Total Trades Executed: ", totalTrades); + Print("Successful Trades: ", successfulTrades); + if(totalTrades > 0) + { + Print("Win Rate: ", NormalizeDouble(successfulTrades * 100.0 / totalTrades, 1), "%"); + Print("Signal-to-Trade Ratio: ", NormalizeDouble(totalTrades * 100.0 / MathMax(1, totalSignals), 1), "%"); + } + Print("======================================================="); +} + +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() +{ + //--- Always manage open positions and risks + ManagePositions(); + EmergencyPositionManagement(); + + //--- Update performance stats periodically + UpdatePerformanceStats(); + + //--- Check for trading signals on a new bar or via scalping mode + static datetime lastBarTime = 0; + datetime currentBarTime = (datetime)SeriesInfoInteger(Symbol(), Period(), SERIES_LASTBAR_DATE); + + bool newBar = (currentBarTime != lastBarTime); + if(newBar) + { + lastBarTime = currentBarTime; + barCounter++; + UpdateMarketLevels(100); // Recalculate S/R levels on new bar + ProcessNewBar(); + } + + //--- Check for intra-bar signals if scalping is enabled + if(ENABLE_SCALPING_MODE) + { + CheckIntraBarSignals(); + } +} + +//+------------------------------------------------------------------+ +//| OnTrade function - Called when trade operations occur | +//+------------------------------------------------------------------+ +void OnTrade() +{ + // This event handler helps track when a position is closed. + // The main logic is in ManagePositions, which checks if a position that previously existed is now gone. +} + + +//============================================================================ +// === CORE TRADING LOGIC === +//============================================================================ + +//+------------------------------------------------------------------+ +//| Process new bar logic | +//+------------------------------------------------------------------+ +void ProcessNewBar() +{ + //--- Check if a position is already open for this symbol + if(positionInfo.Select(Symbol()) && positionInfo.Magic() == magicNumber) + { + return; // Don't look for new trades if one is already active + } + + //--- Check minimum time between trades + if(TimeCurrent() - lastTradeTime < MIN_BARS_BETWEEN_TRADES * PeriodSeconds()) + { + return; // Respect the cooldown period + } + + //--- Look for new trading opportunities + AnalyzeAndTrade(); +} + +//+------------------------------------------------------------------+ +//| Main analysis and trading function | +//+------------------------------------------------------------------+ +void AnalyzeAndTrade() +{ + //--- Get price data + MqlRates rates[]; + if(CopyRates(Symbol(), Period(), 0, 30, rates) < 30) + { + if(PRINT_ALL_SIGNALS) Print("❌ Insufficient price data for analysis."); + return; + } + ArraySetAsSeries(rates, true); + + //--- Analyze market conditions + MarketConditions conditions; + AnalyzeMarketConditions(rates, conditions); + + //--- Look for the best signal among enabled strategies + TradingSignal bestSignal; + bestSignal.isValid = false; + bestSignal.confidence = 0; + + if(USE_MULTIPLE_SIGNALS) + { + if(ENABLE_MOMENTUM_TRADES) + { + TradingSignal momentumSignal; + if(FindMomentumSignal(rates, conditions, momentumSignal) && momentumSignal.confidence > bestSignal.confidence) + bestSignal = momentumSignal; + } + if(ENABLE_REVERSAL_TRADES) + { + TradingSignal reversalSignal; + if(FindReversalSignal(rates, conditions, reversalSignal) && reversalSignal.confidence > bestSignal.confidence) + bestSignal = reversalSignal; + } + if(ENABLE_BREAKOUT_TRADES) + { + TradingSignal breakoutSignal; + if(FindBreakoutSignal(rates, conditions, breakoutSignal) && breakoutSignal.confidence > bestSignal.confidence) + bestSignal = breakoutSignal; + } + } + + //--- Execute the best signal found if it meets the confidence threshold + if(bestSignal.isValid && bestSignal.confidence >= 40) // Lowered confidence threshold for more trades + { + totalSignals++; + if(PRINT_ALL_SIGNALS) + { + Print("🎯 SIGNAL #", totalSignals, " FOUND! Reason: ", bestSignal.reason, ", Confidence: ", bestSignal.confidence, "%"); + } + ExecuteBalancedTrade(bestSignal); + } +} + +//+------------------------------------------------------------------+ +//| Execute a trade after validation | +//+------------------------------------------------------------------+ +void ExecuteBalancedTrade(const TradingSignal &signal) +{ + //--- Pre-execution validation + if(!ValidateTradeBeforeExecution(signal)) + { + return; // Stop if validation fails + } + + //--- Calculate lot size + double slDistance = MathAbs(signal.entry - signal.stopLoss); + double tradeLot = CalculateOptimalLotSize(slDistance); + if(tradeLot <= 0) + { + Print("❌ Calculated lot size is invalid: ", tradeLot); + return; + } + + //--- Print trade details + Print("🚀 EXECUTING BALANCED TRADE #", totalTrades + 1); + Print(" Signal: ", signal.reason); + Print(" Type: ", EnumToString(signal.orderType)); + Print(" Entry: ", signal.entry); + Print(" SL: ", signal.stopLoss, " (", NormalizeDouble(slDistance / _Point, 1), " pts)"); + Print(" TP: ", signal.takeProfit, " (", NormalizeDouble(MathAbs(signal.takeProfit - signal.entry) / _Point, 1), " pts)"); + Print(" Lot: ", tradeLot); + Print(" R:R: ", NormalizeDouble(MathAbs(signal.takeProfit - signal.entry) / slDistance, 2)); + + //--- Open the position + bool result = trade.PositionOpen(Symbol(), signal.orderType, tradeLot, + signal.entry, signal.stopLoss, signal.takeProfit, tradeComment); + + //--- Handle the result + HandleTradeResult(result); +} + +//============================================================================ +// === SIGNAL GENERATION === +//============================================================================ + +//+------------------------------------------------------------------+ +//| Analyze market conditions | +//+------------------------------------------------------------------+ +void AnalyzeMarketConditions(const MqlRates &rates[], MarketConditions &conditions) +{ + conditions.currentPrice = rates[0].close; + conditions.priceChange = rates[0].close - rates[4].close; // 5-bar change + + //--- Volatility (ATR-like, using range of last 10 bars) + double high = 0, low = 0; + for(int i = 0; i < 10; i++) + { + if(i == 0 || rates[i].high > high) high = rates[i].high; + if(i == 0 || rates[i].low < low) low = rates[i].low; + } + conditions.volatility = high - low; + + //--- S/R levels are now global (recentHigh, recentLow) + conditions.support = recentLow; + conditions.resistance = recentHigh; + + conditions.nearSupport = (conditions.currentPrice - conditions.support) < conditions.volatility * 0.25; + conditions.nearResistance = (conditions.resistance - conditions.currentPrice) < conditions.volatility * 0.25; + + //--- Momentum (normalized price change) + conditions.momentum = (conditions.volatility > 0) ? conditions.priceChange / conditions.volatility : 0; +} + +//+------------------------------------------------------------------+ +//| Find momentum-based trading signal | +//+------------------------------------------------------------------+ +bool FindMomentumSignal(const MqlRates &rates[], const MarketConditions &conditions, TradingSignal &signal) +{ + signal.isValid = false; + signal.confidence = 0; + + //--- Strong bullish momentum + if(conditions.momentum > 0.3 && rates[0].close > rates[1].close) + { + signal.orderType = ORDER_TYPE_BUY; + signal.reason = "Strong bullish momentum"; + signal.confidence = 50 + (conditions.momentum * 50); + CalculateTradeParameters(rates, conditions, signal); + return signal.isValid; + } + + //--- Strong bearish momentum + if(conditions.momentum < -0.3 && rates[0].close < rates[1].close) + { + signal.orderType = ORDER_TYPE_SELL; + signal.reason = "Strong bearish momentum"; + signal.confidence = 50 + (MathAbs(conditions.momentum) * 50); + CalculateTradeParameters(rates, conditions, signal); + return signal.isValid; + } + return false; +} + +//+------------------------------------------------------------------+ +//| Find reversal-based trading signal | +//+------------------------------------------------------------------+ +bool FindReversalSignal(const MqlRates &rates[], const MarketConditions &conditions, TradingSignal &signal) +{ + signal.isValid = false; + signal.confidence = 0; + + //--- Oversold bounce from support (bullish pin bar) + if(conditions.nearSupport && rates[0].close > rates[0].open && (rates[0].open - rates[0].low) > (rates[0].close - rates[0].open) * 2) + { + signal.orderType = ORDER_TYPE_BUY; + signal.reason = "Support level reversal (Hammer)"; + signal.confidence = 45; + CalculateTradeParameters(rates, conditions, signal); + return signal.isValid; + } + + //--- Overbought rejection from resistance (bearish pin bar) + if(conditions.nearResistance && rates[0].close < rates[0].open && (rates[0].high - rates[0].open) > (rates[0].open - rates[0].close) * 2) + { + signal.orderType = ORDER_TYPE_SELL; + signal.reason = "Resistance level reversal (Shooting Star)"; + signal.confidence = 45; + CalculateTradeParameters(rates, conditions, signal); + return signal.isValid; + } + return false; +} + +//+------------------------------------------------------------------+ +//| Find breakout-based trading signal | +//+------------------------------------------------------------------+ +bool FindBreakoutSignal(const MqlRates &rates[], const MarketConditions &conditions, TradingSignal &signal) +{ + signal.isValid = false; + signal.confidence = 0; + + //--- Breakout above recent high + if(rates[0].close > conditions.resistance && rates[0].close > rates[1].close) + { + signal.orderType = ORDER_TYPE_BUY; + signal.reason = "Breakout above recent high"; + signal.confidence = 48; + CalculateTradeParameters(rates, conditions, signal); + return signal.isValid; + } + + //--- Breakdown below recent low + if(rates[0].close < conditions.support && rates[0].close < rates[1].close) + { + signal.orderType = ORDER_TYPE_SELL; + signal.reason = "Breakdown below recent low"; + signal.confidence = 48; + CalculateTradeParameters(rates, conditions, signal); + return signal.isValid; + } + return false; +} + + +//============================================================================ +// === POSITION & RISK MANAGEMENT === +//============================================================================ + +//+------------------------------------------------------------------+ +//| Manage open positions (trailing, breakeven, etc.) | +//+------------------------------------------------------------------+ +void ManagePositions() +{ + //--- Select position for the current symbol managed by this EA + if(!positionInfo.Select(Symbol()) || positionInfo.Magic() != magicNumber) + { + //--- Check if a trade was just closed and log it + if(lastCloseProfit != 0) + { + if(lastCloseProfit > 0) + { + successfulTrades++; + Print("🎉 PROFITABLE TRADE CLOSED! Profit: $", NormalizeDouble(lastCloseProfit, 2)); + } + else + { + Print("❌ LOSING TRADE CLOSED! Loss: $", NormalizeDouble(lastCloseProfit, 2)); + } + // Reset state for next trade + lastCloseProfit = 0; + trailingActive = false; + highestProfit = 0; + } + return; + } + + //--- Gather position data + double openPrice = positionInfo.PriceOpen(); + double currentSL = positionInfo.StopLoss(); + double profit = positionInfo.Profit(); + lastCloseProfit = profit; // Continuously update potential close profit + + double currentPrice = (positionInfo.PositionType() == POSITION_TYPE_BUY) ? + symbolInfo.Bid() : symbolInfo.Ask(); + + double profitPoints = (positionInfo.PositionType() == POSITION_TYPE_BUY) ? + (currentPrice - openPrice) / _Point : + (openPrice - currentPrice) / _Point; + + //--- Manage Quick Profit Taking, Breakeven, and Trailing Stop + if(USE_QUICK_PROFIT && !trailingActive && profitPoints >= QUICK_PROFIT_POINTS) + { + TakeQuickProfit(); + } + + if(USE_BREAKEVEN && !trailingActive && profitPoints >= BREAKEVEN_TRIGGER) + { + MoveToBreakeven(openPrice, currentSL); + } + + if(USE_TRAILING_STOP && profitPoints >= TRAILING_START_POINTS) + { + ApplyAggressiveTrailing(currentPrice, currentSL); + } +} + +//+------------------------------------------------------------------+ +//| Move stop loss to breakeven | +//+------------------------------------------------------------------+ +void MoveToBreakeven(double openPrice, double currentSL) +{ + double newSL = 0; + bool shouldMove = false; + + if(positionInfo.PositionType() == POSITION_TYPE_BUY && currentSL < openPrice) + { + newSL = openPrice + (2 * _Point); // Small buffer to cover commission/slippage + shouldMove = true; + } + else if(positionInfo.PositionType() == POSITION_TYPE_SELL && currentSL > openPrice) + { + newSL = openPrice - (2 * _Point); + shouldMove = true; + } + + if(shouldMove) + { + if(trade.PositionModify(Symbol(), newSL, positionInfo.TakeProfit())) + { + Print("🛡️ MOVED TO BREAKEVEN. New SL: ", newSL); + trailingActive = true; // Breakeven is the first step of trailing + } + } +} + +//+------------------------------------------------------------------+ +//| Apply aggressive trailing stop | +//+------------------------------------------------------------------+ +void ApplyAggressiveTrailing(double currentPrice, double currentSL) +{ + trailingActive = true; + double newSL = 0; + + if(positionInfo.PositionType() == POSITION_TYPE_BUY) + { + newSL = currentPrice - (TRAILING_STOP_POINTS * _Point); + // Only move SL if new SL is higher than current SL and at least one step away + if(newSL > currentSL && newSL > positionInfo.PriceOpen() && (newSL - currentSL) / _Point >= TRAILING_STEP_POINTS) + { + if(trade.PositionModify(Symbol(), newSL, positionInfo.TakeProfit())) + Print("🎯 TRAILING STOP UPDATED (BUY)! New SL: ", newSL); + } + } + else // SELL position + { + newSL = currentPrice + (TRAILING_STOP_POINTS * _Point); + // Only move SL if new SL is lower than current SL and at least one step away + if(newSL < currentSL && newSL < positionInfo.PriceOpen() && (currentSL - newSL) / _Point >= TRAILING_STEP_POINTS) + { + if(trade.PositionModify(Symbol(), newSL, positionInfo.TakeProfit())) + Print("🎯 TRAILING STOP UPDATED (SELL)! New SL: ", newSL); + } + } +} + +//+------------------------------------------------------------------+ +//| Take partial profit | +//+------------------------------------------------------------------+ +void TakeQuickProfit() +{ + double closePercent = QUICK_PROFIT_PERCENT / 100.0; + double originalVolume = positionInfo.Volume(); + double closeVolume = NormalizeDouble(originalVolume * closePercent, 2); + + //--- Ensure volume is valid + double minLot = symbolInfo.VolumeMin(); + double lotStep = symbolInfo.VolumeStep(); + closeVolume = MathMax(minLot, floor(closeVolume / lotStep) * lotStep); + + if(closeVolume > 0 && closeVolume < originalVolume) + { + if(trade.PositionClosePartial(positionInfo.Ticket(), closeVolume)) + { + Print("💰 QUICK PROFIT TAKEN! Closed ", DoubleToString(closePercent*100,0), "% of position."); + } + } +} + +//+------------------------------------------------------------------+ +//| Emergency position management | +//+------------------------------------------------------------------+ +void EmergencyPositionManagement() +{ + if(!positionInfo.Select(Symbol()) || positionInfo.Magic() != magicNumber) + return; + + double profit = positionInfo.Profit(); + double balance = accountInfo.Balance(); + + //--- 1. Emergency stop if loss exceeds 5% of balance + if(profit < -(balance * 0.05)) + { + Print("🚨 EMERGENCY: Large loss detected! Closing position immediately."); + Print(" Loss: $", NormalizeDouble(profit, 2), " (", NormalizeDouble(MathAbs(profit)/balance*100, 1), "% of balance)"); + if(trade.PositionClose(Symbol())) + Print("✅ Emergency position closure successful."); + else + Print("❌ Emergency closure FAILED! Error: ", trade.ResultRetcodeDescription()); + } + + //--- 2. Timeout protection for losing trades open too long + datetime positionOpenTime = (datetime)positionInfo.Time(); + long hoursOpen = (TimeCurrent() - positionOpenTime) / 3600; + + if(hoursOpen > 24 && profit < 0) + { + Print("⏰ TIMEOUT: Position open for ", (string)hoursOpen, " hours with loss. Closing..."); + if(trade.PositionClose(Symbol())) + Print("✅ Timeout position closure successful."); + else + Print("❌ Timeout closure FAILED! Error: ", trade.ResultRetcodeDescription()); + } +} + +//============================================================================ +// === UTILITY & VALIDATION === +//============================================================================ + +//+------------------------------------------------------------------+ +//| Perform initial checks on EA start | +//+------------------------------------------------------------------+ +bool PerformInitialChecks() +{ + //--- Verify symbol is available and tradeable + if(!symbolInfo.Name(Symbol()) || !symbolInfo.Select()) + { + Print("❌ Cannot select or get info for symbol: ", Symbol()); + return false; + } + if(symbolInfo.TradeMode() == SYMBOL_TRADE_MODE_DISABLED) + { + Print("❌ Trading is not allowed for symbol: ", Symbol()); + return false; + } + + //--- Verify lot size settings + if(USE_FIXED_LOT && (lotSize < symbolInfo.VolumeMin() || lotSize > symbolInfo.VolumeMax())) + { + Print("❌ Invalid lot size: ", lotSize, " (Min: ", symbolInfo.VolumeMin(), ", Max: ", symbolInfo.VolumeMax(), ")"); + return false; + } + + //--- Verify account permissions + if(!accountInfo.TradeAllowed()) + { + Print("❌ Trading not allowed for this account."); + return false; + } + if(!accountInfo.TradeExpert()) + { + Print("❌ Expert Advisor trading not enabled in terminal settings."); + return false; + } + + Print("✅ All initial checks passed successfully."); + return true; +} + +//+------------------------------------------------------------------+ +//| Validate trade conditions before execution | +//+------------------------------------------------------------------+ +bool ValidateTradeBeforeExecution(const TradingSignal &signal) +{ + //--- Check basic trading environment + if(!IsMarketTradeable()) return false; + + //--- Verify price levels are valid + if(signal.entry <= 0 || signal.stopLoss <= 0 || signal.takeProfit <= 0) + { + Print("❌ Invalid price levels in signal. Entry/SL/TP cannot be zero."); + return false; + } + + //--- Check minimum distance for stops (Stops Level) + double minStopPoints = symbolInfo.StopsLevel(); + if(MathAbs(signal.entry - signal.stopLoss) / _Point < minStopPoints || + MathAbs(signal.takeProfit - signal.entry) / _Point < minStopPoints) + { + Print("❌ SL/TP too close to entry. Min distance: ", minStopPoints, " pts"); + return false; + } + + //--- Check available margin + double requiredMargin = 0; + double tradeLot = CalculateOptimalLotSize(MathAbs(signal.entry - signal.stopLoss)); + if(!trade.CheckMargin(signal.orderType, Symbol(), tradeLot, signal.entry, requiredMargin)) + { + Print("❌ Cannot calculate required margin."); + return false; + } + if(requiredMargin > accountInfo.MarginFree() * 0.9) // Leave 10% margin buffer + { + Print("❌ Insufficient free margin. Required: $", NormalizeDouble(requiredMargin, 2), + ", Available: $", NormalizeDouble(accountInfo.MarginFree(), 2)); + return false; + } + + return true; +} + +//+------------------------------------------------------------------+ +//| Check if market environment is suitable for trading | +//+------------------------------------------------------------------+ +bool IsMarketTradeable() +{ + //--- Check spread conditions + double spreadPoints = symbolInfo.Spread() / symbolInfo.Point(); + double maxSpread = BASE_SL_POINTS * 0.3; // Max spread = 30% of base SL + if(spreadPoints > maxSpread) + { + if(PRINT_ALL_SIGNALS) Print("❌ Spread too high: ", NormalizeDouble(spreadPoints, 1), " pts (max allowed: ", NormalizeDouble(maxSpread, 1), " pts)"); + return false; + } + + //--- Check if auto-trading is enabled + if(!accountInfo.TradeExpert()) + { + if(PRINT_ALL_SIGNALS) Print("❌ 'Algo Trading' button is disabled."); + return false; + } + return true; +} + +//+------------------------------------------------------------------+ +//| Calculate optimal lot size based on risk settings | +//+------------------------------------------------------------------+ +double CalculateOptimalLotSize(double slDistanceInPrice) +{ + if(USE_FIXED_LOT) + return lotSize; + + double balance = accountInfo.Balance(); + double riskAmount = balance * (MAX_RISK_PERCENT / 100.0); + double lot = 0; + + //--- Check if money management is possible + if(!trade.CheckMoneyForTrade(Symbol(), 0, slDistanceInPrice, riskAmount, lot)) + { + Print("❌ Failed to calculate lot size with risk %.2f%%. Error: ", MAX_RISK_PERCENT, trade.ResultRetcodeDescription()); + return 0; // Return 0 if calculation fails + } + + //--- Normalize lot size according to symbol specifications + double minLot = symbolInfo.VolumeMin(); + double maxLot = symbolInfo.VolumeMax(); + double lotStep = symbolInfo.VolumeStep(); + + lot = MathMax(minLot, MathMin(maxLot, lot)); + lot = floor(lot / lotStep) * lotStep; + + return NormalizeDouble(lot, 2); +} + +//+------------------------------------------------------------------+ +//| Handle trade execution result | +//+------------------------------------------------------------------+ +void HandleTradeResult(bool success) +{ + if(success) + { + totalTrades++; + lastTradeTime = TimeCurrent(); + trailingActive = false; + highestProfit = 0; + + Print("✅ TRADE EXECUTED SUCCESSFULLY! Order: #", trade.ResultOrder()); + } + else + { + Print("❌ TRADE EXECUTION FAILED! Error: ", trade.ResultRetcode(), " - ", trade.ResultRetcodeDescription()); + // Specific error guidance + uint retcode = trade.ResultRetcode(); + if(retcode == TRADE_RETCODE_INVALID_VOLUME) Print(" → Check lot size settings."); + else if(retcode == TRADE_RETCODE_NO_MONEY) Print(" → Insufficient funds for lot size and SL."); + else if(retcode == TRADE_RETCODE_INVALID_STOPS) Print(" → Invalid SL/TP levels, check min distance."); + else if(retcode == TRADE_RETCODE_TRADE_DISABLED) Print(" → Trading disabled for symbol or account."); + } +} + +//+------------------------------------------------------------------+ +//| Calculate trade parameters (SL, TP) for a signal | +//+------------------------------------------------------------------+ +void CalculateTradeParameters(const MqlRates &rates[], const MarketConditions &conditions, TradingSignal &signal) +{ + double slDistance = (USE_TIGHT_SL) ? + MathMax(conditions.volatility * 0.6, BASE_SL_POINTS * _Point) : + BASE_SL_POINTS * _Point; + + if(signal.orderType == ORDER_TYPE_BUY) + { + signal.entry = symbolInfo.Ask(); + signal.stopLoss = signal.entry - slDistance; + signal.takeProfit = signal.entry + (slDistance * TP_MULTIPLIER); + } + else // ORDER_TYPE_SELL + { + signal.entry = symbolInfo.Bid(); + signal.stopLoss = signal.entry + slDistance; + signal.takeProfit = signal.entry - (slDistance * TP_MULTIPLIER); + } + + //--- Normalize prices and validate R:R ratio + signal.stopLoss = NormalizeDouble(signal.stopLoss, _Digits); + signal.takeProfit = NormalizeDouble(signal.takeProfit, _Digits); + + double rrRatio = MathAbs(signal.takeProfit - signal.entry) / MathAbs(signal.entry - signal.stopLoss); + signal.isValid = (rrRatio >= MIN_RR_RATIO); + + if(!signal.isValid && PRINT_ALL_SIGNALS) + { + Print(" Signal rejected: R:R = ", NormalizeDouble(rrRatio, 2), " (min required: ", MIN_RR_RATIO, ")"); + } +} + + +//============================================================================ +// === REPORTING & SCALPING === +//============================================================================ + +//+------------------------------------------------------------------+ +//| Update recent high and low levels | +//+------------------------------------------------------------------+ +void UpdateMarketLevels(int bars) +{ + MqlRates rates[]; + if(CopyRates(Symbol(), Period(), 0, bars, rates) < bars) return; + + double high = 0, low = 0; + for(int i = 0; i < bars; i++) + { + if(i == 0 || rates[i].high > high) high = rates[i].high; + if(i == 0 || rates[i].low < low) low = rates[i].low; + } + recentHigh = high; + recentLow = low; +} + +//+------------------------------------------------------------------+ +//| Update and print performance statistics periodically | +//+------------------------------------------------------------------+ +void UpdatePerformanceStats() +{ + static datetime lastStatsUpdate = 0; + if(TimeCurrent() - lastStatsUpdate < 3600) // Update every hour + return; + + lastStatsUpdate = TimeCurrent(); + + double winRate = (totalTrades > 0) ? (successfulTrades * 100.0 / totalTrades) : 0; + + Print("----------------- HOURLY PERFORMANCE UPDATE -----------------"); + Print("Time: ", TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES)); + Print("Trading Stats: ", totalTrades, " trades, ", successfulTrades, " wins (", NormalizeDouble(winRate, 1), "%)"); + Print("Account Status: Balance=$", accountInfo.Balance(), ", Equity=$", accountInfo.Equity(), ", Margin Level=", NormalizeDouble(accountInfo.MarginLevel(),1), "%"); + Print("-------------------------------------------------------------"); +} + +//+------------------------------------------------------------------+ +//| Check for intra-bar signals (scalping mode) | +//+------------------------------------------------------------------+ +void CheckIntraBarSignals() +{ + // Implementation for scalping signals would go here. + // For brevity and focus on the core strategy, this is left as a placeholder. + // It would involve detecting rapid price movements between new bars. +} + +//+------------------------------------------------------------------+ +//| Final expert advisor comment and version info | +//+------------------------------------------------------------------+ +/* +======================================================================= + SMC PRO EA v3.10 - BALANCED STRATEGY +======================================================================= + +FEATURES: +✅ Multiple Signal Types (Momentum, Reversal, Breakout) +✅ Advanced Trailing Stop Loss System +✅ Early Breakeven Protection +✅ Partial Profit Taking +✅ Dynamic Risk Management (Fixed or % based) +✅ Emergency Position Management (Large Loss & Timeout) +✅ Comprehensive Error Handling & Pre-Trade Validation +✅ Performance Tracking & Statistics + +IMPROVEMENTS FROM ORIGINAL: +• MORE TRADING OPPORTUNITIES through multiple strategies. +• BETTER WIN RATE through tighter, smarter risk management. +• PROFIT PROTECTION via trailing stops, breakeven, and partial profits. +• REDUCED DRAWDOWN with emergency stops and trade timeouts. +• ENHANCED STABILITY with professional validation and error handling. + +RECOMMENDED SETTINGS: +• USE_TRAILING_STOP = true +• USE_BREAKEVEN = true +• ENABLE_MOMENTUM_TRADES = true +• ENABLE_REVERSAL_TRADES = true +• ENABLE_BREAKOUT_TRADES = true + +Copyright 2025 - Balanced Trading Strategy +======================================================================= +*/