//+------------------------------------------------------------------+ //| ForexTrader_v4.0_Enhanced_MultiStrategy.mq5 | //| Professional Multi-Strategy EA with Market Regime Logic | //| Adaptive Decision Gating & Dynamic ATR-Based Risk Control | //+------------------------------------------------------------------+ #property copyright "ForexTrader EA v4.0 Enhanced - Professional Production" #property link "https://github.com/simonokwundue-ops/Experienced-FX-Trader" #property version "4.00" #property description "Professional EA with market regime detection & adaptive strategies" #property description "Hierarchical decision gating: selects best strategy per market condition" #property description "Dynamic ATR-based lot sizing and volatility-adjusted SL/TP" #property description "Enhanced signal quality with confluence scoring" #property description "Multi-symbol portfolio with intelligent risk allocation" #property strict #include #include #include //--- Global Objects CTrade trade; CPositionInfo positionInfo; CAccountInfo accountInfo; //+------------------------------------------------------------------+ //| Strategy Enumeration | //+------------------------------------------------------------------+ enum ENUM_STRATEGY_TYPE { STRATEGY_MA = 0, // Moving Average Crossover STRATEGY_RSI = 1, // RSI Reversal STRATEGY_BB = 2, // Bollinger Bands STRATEGY_MACD = 3 // MACD }; //+------------------------------------------------------------------+ //| Market Regime Enumeration (NEW in v4.0) | //+------------------------------------------------------------------+ enum ENUM_MARKET_REGIME { REGIME_STRONG_UPTREND = 0, // Strong Uptrend (Momentum strategies) REGIME_STRONG_DOWNTREND = 1, // Strong Downtrend (Momentum strategies) REGIME_RANGING_LOW_VOL = 2, // Range-bound Low Volatility (Mean reversion) REGIME_RANGING_HIGH_VOL = 3, // Range-bound High Volatility (Cautious) REGIME_NEUTRAL = 4 // Neutral/Transitioning (Reduce activity) }; //+------------------------------------------------------------------+ //| Input Parameters - Multi-Symbol Trading | //+------------------------------------------------------------------+ input group "=== Multi-Symbol Trading (v4.0) ===" input bool TradeMultipleSymbols = true; // Enable Multi-Symbol Trading input string TradingSymbols = "EURUSD,GBPUSD,USDJPY,AUDUSD,USDCAD"; // Trading Symbols (comma-separated) input int MaxPositionsPerSymbol = 2; // Max Positions Per Symbol input bool AllowHedging = true; // Allow Opposite Directions Per Symbol input int MaxTotalPositions = 5; // Max Total Positions (All Symbols) input double MaxFloatingEquityPercent = 5.0; // Max Floating Equity Risk (%) //+------------------------------------------------------------------+ //| Input Parameters - Market Regime Detection (NEW in v4.0) | //+------------------------------------------------------------------+ input group "=== Market Regime Detection (v4.0) ===" input bool UseMarketRegimeFilter = true; // Enable Market Regime Detection input ENUM_TIMEFRAMES RegimeTimeframe = PERIOD_H1; // Regime Analysis Timeframe (H1/H4) input int Regime_FastSMA = 50; // Fast SMA for Trend Detection input int Regime_SlowSMA = 200; // Slow SMA for Trend Detection input double Regime_ADX_Trending = 25.0; // ADX Threshold for Trending Market input double Regime_ADX_Ranging = 20.0; // ADX Threshold for Ranging Market input double Regime_ATR_HighVol_Multiplier = 1.5; // ATR multiplier for high volatility input int Regime_ATR_Period = 100; // ATR average period for volatility //+------------------------------------------------------------------+ //| Input Parameters - Strategy Selection | //+------------------------------------------------------------------+ input group "=== Strategy Selection ===" input bool UseMAStrategy = true; // Use MA Crossover Strategy input bool UseRSIStrategy = true; // Use RSI Strategy input bool UseBBStrategy = true; // Use Bollinger Bands Strategy input bool UseMACDStrategy = true; // Use MACD Strategy input int MinSignalScore = 25; // Minimum Signal Score (0-100) - REDUCED from 35 input bool UseAdaptiveScoring = true; // Use Regime-Adaptive Signal Scoring input double SignalConfluenceBonus = 15.0; // Bonus for multi-strategy confluence //+------------------------------------------------------------------+ //| Input Parameters - Multi-Timeframe | //+------------------------------------------------------------------+ input group "=== Multi-Timeframe Analysis ===" input bool UseMultiTimeframe = true; // Enable Multi-Timeframe Analysis input ENUM_TIMEFRAMES TimeFrame1 = PERIOD_M15; // Fast Timeframe input ENUM_TIMEFRAMES TimeFrame2 = PERIOD_M30; // Medium Timeframe input ENUM_TIMEFRAMES TimeFrame3 = PERIOD_H1; // Slow Timeframe input int MinTFConfirmation = 2; // Min Timeframes for Signal (1-3) //+------------------------------------------------------------------+ //| Input Parameters - MA Strategy | //+------------------------------------------------------------------+ input group "=== Moving Average Strategy ===" input int FastMA_Period = 10; // Fast MA Period input int SlowMA_Period = 50; // Slow MA Period input ENUM_MA_METHOD MA_Method = MODE_EMA; // MA Method input ENUM_APPLIED_PRICE MA_Price = PRICE_CLOSE; // MA Applied Price input double MA_SlopeMinimum = 3.0; // Min MA Slope (Pips) - REDUCED from 5.0 input double MA_DistanceMinimum = 2.0; // Min Distance Between MAs (Pips) - NEW input bool UseMomentumFilter = true; // Use 3-Bar Momentum Filter - NEW input int MomentumBars = 3; // Bars for Momentum Calculation - NEW //+------------------------------------------------------------------+ //| Input Parameters - Breakout Detection (NEW in v4.0) | //+------------------------------------------------------------------+ input group "=== Breakout Detection (v4.0) ===" input bool UseBreakoutDetection = true; // Enable Breakout Detection input int BreakoutBars = 5; // Number of Bars for Range input double BreakoutThresholdPips = 5.0; // Min Breakout Size (Pips) //+------------------------------------------------------------------+ //| Input Parameters - RSI Strategy | //+------------------------------------------------------------------+ input group "=== RSI Strategy ===" input int RSI_Period = 14; // RSI Period input double RSI_Oversold = 30.0; // RSI Oversold Level input double RSI_Overbought = 70.0; // RSI Overbought Level input ENUM_APPLIED_PRICE RSI_Price = PRICE_CLOSE; // RSI Applied Price //+------------------------------------------------------------------+ //| Input Parameters - Bollinger Bands Strategy | //+------------------------------------------------------------------+ input group "=== Bollinger Bands Strategy ===" input int BB_Period = 20; // BB Period input double BB_Deviation = 2.0; // BB Standard Deviation input ENUM_APPLIED_PRICE BB_AppliedPrice = PRICE_CLOSE; // BB Applied Price //+------------------------------------------------------------------+ //| Input Parameters - MACD Strategy | //+------------------------------------------------------------------+ input group "=== MACD Strategy ===" input int MACD_FastEMA = 12; // MACD Fast EMA input int MACD_SlowEMA = 26; // MACD Slow EMA input int MACD_Signal = 9; // MACD Signal Period input ENUM_APPLIED_PRICE MACD_Price = PRICE_CLOSE; // MACD Applied Price //+------------------------------------------------------------------+ //| Input Parameters - Filters | //+------------------------------------------------------------------+ input group "=== Signal Filters ===" input bool UseADXFilter = true; // Use ADX Trend Filter input int ADX_Period = 14; // ADX Period input double ADX_Minimum = 20.0; // Minimum ADX Level input bool UseATRFilter = true; // Use ATR Volatility Filter input int ATR_Period = 14; // ATR Period input double ATR_MinimumPips = 10.0; // Minimum ATR (Pips) input double ATR_MaximumPips = 100.0; // Maximum ATR (Pips) //+------------------------------------------------------------------+ //| Input Parameters - Portfolio Risk Management | //+------------------------------------------------------------------+ input group "=== Portfolio Risk Management ===" input double MaxPortfolioRisk = 10.0; // Max Portfolio Risk (% of Balance) input double BaseRiskPercent = 1.5; // Base Risk Per Trade (%) input bool UseDynamicRisk = true; // Use Win Rate Based Risk input double MinRiskPercent = 0.5; // Minimum Risk Per Trade (%) input double MaxRiskPercent = 3.0; // Maximum Risk Per Trade (%) input double MaxDrawdownPercent = 30.0; // Max Drawdown % (halt trading) input double DailyDrawdownPercent = 5.0; // Daily Drawdown Limit % input bool UseVolatilityAdjustedRisk = true; // Adjust risk by volatility (NEW v4.0) //+------------------------------------------------------------------+ //| Input Parameters - Position Sizing | //+------------------------------------------------------------------+ input group "=== Position Sizing ===" input double StopLossPips = 40.0; // Default Stop Loss (Pips) input double TakeProfitPips = 80.0; // Default Take Profit (Pips) input bool UseATRSizing = true; // Use ATR for Dynamic SL/TP (RECOMMENDED) input double ATR_SL_Multiplier = 2.0; // ATR Multiplier for SL (2.0 = 2x ATR) input double ATR_TP_Multiplier = 4.0; // ATR Multiplier for TP (4.0 = 4x ATR) input double MinSL_Pips = 15.0; // Minimum SL (Pips) - Protection input double MaxSL_Pips = 100.0; // Maximum SL (Pips) - Risk Control input double MaxSpreadPips = 5.0; // Max Spread (Pips) //+------------------------------------------------------------------+ //| Input Parameters - Position Management | //+------------------------------------------------------------------+ input group "=== Position Management ===" input bool UseBreakeven = true; // Move to Breakeven input double BreakevenTriggerPips = 20.0; // Breakeven Trigger (Pips) input double BreakevenOffsetPips = 2.0; // Breakeven Offset (Pips) input bool UsePartialTP = true; // Use Partial Take Profit input double PartialTP_Pips = 40.0; // Partial TP Level (Pips) input double PartialTP_Percent = 50.0; // Partial Close % (0-100) input bool UseTrailingStop = true; // Enable Trailing Stop input double TrailingStopPips = 30.0; // Trailing Distance (Pips) input double TrailingStepPips = 5.0; // Trailing Step (Pips) input double TrailingActivationPips = 20.0; // Trailing Activation (Pips) //+------------------------------------------------------------------+ //| Input Parameters - Trading Controls | //+------------------------------------------------------------------+ input group "=== Trading Controls ===" input int MaxDailyTrades = 100; // Max Trades Per Day (INCREASED for v4.0) input int MaxConcurrentPositions = 5; // Max Concurrent Positions input int CooldownMinutes = 1; // Cooldown Between Trades (Min) - REDUCED to 1 input bool SeparateCooldownByDirection = true; // Separate Buy/Sell Cooldown input int PostCloseCooldownMinutes = 1; // Cooldown After Position Close (Min) - REDUCED //+------------------------------------------------------------------+ //| Input Parameters - Session Filters | //+------------------------------------------------------------------+ input group "=== Session Filters ===" input bool UseSessionFilter = false; // Enable Session Filter - Disabled for 24/7 trading input bool TradeAsianSession = true; // Trade Asian Session input bool TradeLondonSession = true; // Trade London Session input bool TradeNYSession = true; // Trade New York Session input int AsianStartHour = 0; // Asian Start Hour (GMT) input int AsianEndHour = 8; // Asian End Hour (GMT) input int LondonStartHour = 7; // London Start Hour (GMT) input int LondonEndHour = 16; // London End Hour (GMT) input int NYStartHour = 12; // NY Start Hour (GMT) input int NYEndHour = 21; // NY End Hour (GMT) //+------------------------------------------------------------------+ //| Input Parameters - Money Management | //+------------------------------------------------------------------+ input group "=== Money Management ===" input double MaxLotSize = 5.0; // Maximum Lot Size input double MinLotSize = 0.01; // Minimum Lot Size input bool UseCompounding = true; // Use Compounding input bool UseFixedLot = false; // Use Fixed Lot input double FixedLotSize = 0.1; // Fixed Lot Size //+------------------------------------------------------------------+ //| Input Parameters - Advanced Settings | //+------------------------------------------------------------------+ input group "=== Advanced Settings ===" input int MagicNumber = 400000; // Magic Number input string TradeComment = "ForexTrader_v4.0_Enhanced"; // Trade Comment input int Slippage = 30; // Max Slippage (Points) input int MaxRetries = 3; // Max Order Retries input int RetryDelayMs = 1000; // Retry Delay (Ms) //+------------------------------------------------------------------+ //| Multi-Symbol Data Structures | //+------------------------------------------------------------------+ struct SymbolData { string symbol; double point; double tickSize; double tickValue; double lotStep; double minLot; double maxLot; double pipSize; int symbolDigits; // Indicator handles int handleFastMA; int handleSlowMA; int handleADX; int handleATR; int handleRSI; int handleBB; int handleMACD; // Trading state datetime lastBuyTime; datetime lastSellTime; datetime lastCloseTime; int positionCount; }; SymbolData symbolDataArray[]; int totalSymbols = 0; //+------------------------------------------------------------------+ //| Global Variables | //+------------------------------------------------------------------+ // Indicator handles for current timeframe int handleFastMA, handleSlowMA, handleADX, handleATR; int handleRSI, handleBBUpper, handleBBMiddle, handleBBLower, handleMACD; // Multi-timeframe indicator handles int handleFastMA_TF1, handleSlowMA_TF1, handleFastMA_TF2, handleSlowMA_TF2; int handleFastMA_TF3, handleSlowMA_TF3; // Indicator buffers double fastMA[], slowMA[], adxMain[], atrBuffer[]; double rsiBuffer[], bbUpper[], bbMiddle[], bbLower[]; double macdMain[], macdSignal[]; // Symbol properties double point, tickSize, tickValue, lotStep, minLot, maxLot; double pipSize; int symbolDigits; // Daily tracking datetime lastTradeDate = 0; int dailyTradeCount = 0; double startOfDayBalance = 0; double startOfDayEquity = 0; datetime lastBuyTime = 0; datetime lastSellTime = 0; // Strategy performance tracking struct StrategyStats { int totalTrades; int winningTrades; double totalProfit; double winRate; }; StrategyStats maStats, rsiStats, bbStats, macdStats; // Position tracking for partial TP struct PositionTracker { ulong ticket; bool partialTPDone; }; PositionTracker trackedPositions[100]; int trackedPositionCount = 0; //+------------------------------------------------------------------+ //| Market Regime Detection Variables (NEW in v4.0) | //+------------------------------------------------------------------+ ENUM_MARKET_REGIME currentMarketRegime = REGIME_NEUTRAL; int handleRegimeFastSMA, handleRegimeSlowSMA, handleRegimeADX, handleRegimeATR; double regimeFastSMA[], regimeSlowSMA[], regimeADX[], regimeATR[]; datetime lastRegimeUpdate = 0; int regimeUpdateIntervalSeconds = 300; // Update regime every 5 minutes //+------------------------------------------------------------------+ //| Forward Declarations | //+------------------------------------------------------------------+ bool OpenPosition(ENUM_ORDER_TYPE orderType, double price, ENUM_STRATEGY_TYPE strategy); void UpdateMarketRegime(); bool IsStrategyEnabledForRegime(ENUM_STRATEGY_TYPE strategy); int GetRegimeAdjustedThreshold(); int CheckMomentum(string symbol, double pipSz); int CheckBreakout(string symbol, double pipSz); //+------------------------------------------------------------------+ //| Expert Initialization | //+------------------------------------------------------------------+ int OnInit() { //--- Initialize trade object trade.SetExpertMagicNumber(MagicNumber); trade.SetDeviationInPoints(Slippage); trade.SetTypeFilling(ORDER_FILLING_IOC); trade.SetAsyncMode(false); //--- Get symbol properties point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); symbolDigits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); //--- Calculate pip size correctly if(symbolDigits == 3 || symbolDigits == 5) pipSize = point * 10; else pipSize = point; //--- Get trading properties tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE); tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE_PROFIT); if(tickValue == 0) { double contractSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_CONTRACT_SIZE); tickValue = tickSize * contractSize; } lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); //--- Validate inputs if(!ValidateInputs()) return INIT_PARAMETERS_INCORRECT; //--- Create indicators for main timeframe if(UseMAStrategy) { handleFastMA = iMA(_Symbol, PERIOD_CURRENT, FastMA_Period, 0, MA_Method, MA_Price); handleSlowMA = iMA(_Symbol, PERIOD_CURRENT, SlowMA_Period, 0, MA_Method, MA_Price); if(handleFastMA == INVALID_HANDLE || handleSlowMA == INVALID_HANDLE) { Print("Error: Failed to create MA indicators"); return INIT_FAILED; } } if(UseRSIStrategy) { handleRSI = iRSI(_Symbol, PERIOD_CURRENT, RSI_Period, RSI_Price); if(handleRSI == INVALID_HANDLE) { Print("Error: Failed to create RSI indicator"); return INIT_FAILED; } } if(UseBBStrategy) { int bbHandle = iBands(_Symbol, PERIOD_CURRENT, BB_Period, 0, BB_Deviation, BB_AppliedPrice); if(bbHandle == INVALID_HANDLE) { Print("Error: Failed to create BB indicator"); return INIT_FAILED; } handleBBUpper = bbHandle; handleBBMiddle = bbHandle; handleBBLower = bbHandle; } if(UseMACDStrategy) { handleMACD = iMACD(_Symbol, PERIOD_CURRENT, MACD_FastEMA, MACD_SlowEMA, MACD_Signal, MACD_Price); if(handleMACD == INVALID_HANDLE) { Print("Error: Failed to create MACD indicator"); return INIT_FAILED; } } if(UseADXFilter) { handleADX = iADX(_Symbol, PERIOD_CURRENT, ADX_Period); if(handleADX == INVALID_HANDLE) { Print("Error: Failed to create ADX indicator"); return INIT_FAILED; } } if(UseATRFilter || UseATRSizing) { handleATR = iATR(_Symbol, PERIOD_CURRENT, ATR_Period); if(handleATR == INVALID_HANDLE) { Print("Error: Failed to create ATR indicator"); return INIT_FAILED; } } //--- Create multi-timeframe MA indicators if enabled if(UseMultiTimeframe && UseMAStrategy) { handleFastMA_TF1 = iMA(_Symbol, TimeFrame1, FastMA_Period, 0, MA_Method, MA_Price); handleSlowMA_TF1 = iMA(_Symbol, TimeFrame1, SlowMA_Period, 0, MA_Method, MA_Price); handleFastMA_TF2 = iMA(_Symbol, TimeFrame2, FastMA_Period, 0, MA_Method, MA_Price); handleSlowMA_TF2 = iMA(_Symbol, TimeFrame2, SlowMA_Period, 0, MA_Method, MA_Price); handleFastMA_TF3 = iMA(_Symbol, TimeFrame3, FastMA_Period, 0, MA_Method, MA_Price); handleSlowMA_TF3 = iMA(_Symbol, TimeFrame3, SlowMA_Period, 0, MA_Method, MA_Price); } //--- Create market regime detection indicators (NEW in v4.0) if(UseMarketRegimeFilter) { handleRegimeFastSMA = iMA(_Symbol, RegimeTimeframe, Regime_FastSMA, 0, MODE_SMA, PRICE_CLOSE); handleRegimeSlowSMA = iMA(_Symbol, RegimeTimeframe, Regime_SlowSMA, 0, MODE_SMA, PRICE_CLOSE); handleRegimeADX = iADX(_Symbol, RegimeTimeframe, ADX_Period); handleRegimeATR = iATR(_Symbol, RegimeTimeframe, Regime_ATR_Period); if(handleRegimeFastSMA == INVALID_HANDLE || handleRegimeSlowSMA == INVALID_HANDLE || handleRegimeADX == INVALID_HANDLE || handleRegimeATR == INVALID_HANDLE) { Print("Error: Failed to create market regime indicators"); return INIT_FAILED; } ArraySetAsSeries(regimeFastSMA, true); ArraySetAsSeries(regimeSlowSMA, true); ArraySetAsSeries(regimeADX, true); ArraySetAsSeries(regimeATR, true); Print("Market Regime Detection: ENABLED (", EnumToString(RegimeTimeframe), ")"); } //--- Set arrays as series ArraySetAsSeries(fastMA, true); ArraySetAsSeries(slowMA, true); ArraySetAsSeries(adxMain, true); ArraySetAsSeries(atrBuffer, true); ArraySetAsSeries(rsiBuffer, true); ArraySetAsSeries(bbUpper, true); ArraySetAsSeries(bbMiddle, true); ArraySetAsSeries(bbLower, true); ArraySetAsSeries(macdMain, true); ArraySetAsSeries(macdSignal, true); //--- Initialize strategy stats InitializeStrategyStats(); //--- Initialize multi-symbol trading if(TradeMultipleSymbols) { if(!InitializeMultiSymbolTrading()) { Print("Error: Failed to initialize multi-symbol trading"); return INIT_FAILED; } } //--- Initialize daily tracking startOfDayBalance = accountInfo.Balance(); startOfDayEquity = accountInfo.Equity(); //--- Print initialization Print("========================================"); Print("ForexTrader v4.0 Enhanced - Initialized"); Print("Chart Symbol: ", _Symbol); if(TradeMultipleSymbols) { Print("Multi-Symbol Trading: ENABLED"); Print("Trading Symbols: ", totalSymbols); Print("Max Positions Per Symbol: ", MaxPositionsPerSymbol); Print("Max Total Positions: ", MaxTotalPositions); } else { Print("Single Symbol Trading: ", _Symbol); } Print("Active Strategies: ", CountActiveStrategies()); Print("Multi-Timeframe: ", UseMultiTimeframe ? "Yes" : "No"); Print("Market Regime Filter: ", UseMarketRegimeFilter ? "ENABLED" : "Disabled"); Print("Min Signal Score: ", MinSignalScore); Print("Dynamic Lot Sizing: ", UseATRSizing ? "ENABLED (ATR-based)" : "Fixed"); Print("Daily Drawdown Limit: ", DailyDrawdownPercent, "%"); Print("Max Floating Equity: ", MaxFloatingEquityPercent, "%"); Print("========================================"); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Expert Deinitialization | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Release all indicator handles for chart symbol if(handleFastMA != INVALID_HANDLE) IndicatorRelease(handleFastMA); if(handleSlowMA != INVALID_HANDLE) IndicatorRelease(handleSlowMA); if(handleADX != INVALID_HANDLE) IndicatorRelease(handleADX); if(handleATR != INVALID_HANDLE) IndicatorRelease(handleATR); if(handleRSI != INVALID_HANDLE) IndicatorRelease(handleRSI); if(handleBBUpper != INVALID_HANDLE) IndicatorRelease(handleBBUpper); if(handleMACD != INVALID_HANDLE) IndicatorRelease(handleMACD); //--- Release multi-timeframe handles if(handleFastMA_TF1 != INVALID_HANDLE) IndicatorRelease(handleFastMA_TF1); if(handleSlowMA_TF1 != INVALID_HANDLE) IndicatorRelease(handleSlowMA_TF1); if(handleFastMA_TF2 != INVALID_HANDLE) IndicatorRelease(handleFastMA_TF2); if(handleSlowMA_TF2 != INVALID_HANDLE) IndicatorRelease(handleSlowMA_TF2); if(handleFastMA_TF3 != INVALID_HANDLE) IndicatorRelease(handleFastMA_TF3); if(handleSlowMA_TF3 != INVALID_HANDLE) IndicatorRelease(handleSlowMA_TF3); //--- Release market regime handles (NEW in v4.0) if(handleRegimeFastSMA != INVALID_HANDLE) IndicatorRelease(handleRegimeFastSMA); if(handleRegimeSlowSMA != INVALID_HANDLE) IndicatorRelease(handleRegimeSlowSMA); if(handleRegimeADX != INVALID_HANDLE) IndicatorRelease(handleRegimeADX); if(handleRegimeATR != INVALID_HANDLE) IndicatorRelease(handleRegimeATR); //--- Release multi-symbol indicator handles if(TradeMultipleSymbols) { for(int i = 0; i < totalSymbols; i++) { if(symbolDataArray[i].handleFastMA != INVALID_HANDLE) IndicatorRelease(symbolDataArray[i].handleFastMA); if(symbolDataArray[i].handleSlowMA != INVALID_HANDLE) IndicatorRelease(symbolDataArray[i].handleSlowMA); if(symbolDataArray[i].handleADX != INVALID_HANDLE) IndicatorRelease(symbolDataArray[i].handleADX); if(symbolDataArray[i].handleATR != INVALID_HANDLE) IndicatorRelease(symbolDataArray[i].handleATR); if(symbolDataArray[i].handleRSI != INVALID_HANDLE) IndicatorRelease(symbolDataArray[i].handleRSI); if(symbolDataArray[i].handleBB != INVALID_HANDLE) IndicatorRelease(symbolDataArray[i].handleBB); if(symbolDataArray[i].handleMACD != INVALID_HANDLE) IndicatorRelease(symbolDataArray[i].handleMACD); } } //--- Print final stats PrintStrategyPerformance(); Print("ForexTrader v3.2 Multi-Strategy - Deinitialized"); } //+------------------------------------------------------------------+ //| Expert Tick Function | //+------------------------------------------------------------------+ void OnTick() { //--- Update market regime periodically (NEW in v4.0) if(UseMarketRegimeFilter) { if(TimeCurrent() - lastRegimeUpdate > regimeUpdateIntervalSeconds) { UpdateMarketRegime(); lastRegimeUpdate = TimeCurrent(); } } //--- Check for new bar on chart symbol static datetime lastBar = 0; datetime currentBar = iTime(_Symbol, PERIOD_CURRENT, 0); if(currentBar == lastBar) return; lastBar = currentBar; //--- Reset daily counter and check daily drawdown ResetDailyTradeCount(); //--- Check daily drawdown limit if(!CheckDailyDrawdownLimit()) { Print("Daily drawdown limit exceeded. Trading halted for today."); return; } //--- Check max drawdown limit if(!CheckDrawdownLimit()) { Print("Max drawdown exceeded. Trading halted."); return; } //--- Check floating equity limit if(!CheckFloatingEquityLimit()) { Print("Floating equity limit exceeded. No new trades."); return; } //--- Process trading for all symbols if(TradeMultipleSymbols) { for(int i = 0; i < totalSymbols; i++) { ProcessSymbolTrading(i); } } else { //--- Single symbol trading (legacy mode) if(!UpdateIndicators()) return; ManagePositions(); if(CanOpenNewTrade()) CheckEntrySignals(); } } //+------------------------------------------------------------------+ //| Trade Transaction Event | //+------------------------------------------------------------------+ void OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result) { if(trans.type == TRADE_TRANSACTION_DEAL_ADD) { ulong dealTicket = trans.deal; if(dealTicket > 0 && HistoryDealSelect(dealTicket)) { long dealMagic = HistoryDealGetInteger(dealTicket, DEAL_MAGIC); if(dealMagic == MagicNumber) { ENUM_DEAL_TYPE dealType = (ENUM_DEAL_TYPE)HistoryDealGetInteger(dealTicket, DEAL_TYPE); double dealProfit = HistoryDealGetDouble(dealTicket, DEAL_PROFIT); if(dealProfit != 0) // Trade closed { UpdateStrategyStats(trans.position, dealProfit); } } } } } //+------------------------------------------------------------------+ //| Validate Input Parameters | //+------------------------------------------------------------------+ bool ValidateInputs() { if(!UseMAStrategy && !UseRSIStrategy && !UseBBStrategy && !UseMACDStrategy) { Print("Error: At least one strategy must be enabled"); return false; } if(MinSignalScore < 0 || MinSignalScore > 100) { Print("Error: MinSignalScore must be between 0 and 100"); return false; } if(BaseRiskPercent <= 0 || BaseRiskPercent > 100) { Print("Error: Risk percent must be between 0 and 100"); return false; } if(MaxPortfolioRisk <= 0 || MaxPortfolioRisk > 100) { Print("Error: Max portfolio risk must be between 0 and 100"); return false; } return true; } //+------------------------------------------------------------------+ //| Update Indicator Values | //+------------------------------------------------------------------+ bool UpdateIndicators() { //--- Update MA indicators if(UseMAStrategy) { if(CopyBuffer(handleFastMA, 0, 0, 3, fastMA) < 3) return false; if(CopyBuffer(handleSlowMA, 0, 0, 3, slowMA) < 3) return false; } //--- Update RSI if(UseRSIStrategy) { if(CopyBuffer(handleRSI, 0, 0, 3, rsiBuffer) < 3) return false; } //--- Update BB if(UseBBStrategy) { if(CopyBuffer(handleBBUpper, 1, 0, 2, bbUpper) < 2) return false; if(CopyBuffer(handleBBMiddle, 0, 0, 2, bbMiddle) < 2) return false; if(CopyBuffer(handleBBLower, 2, 0, 2, bbLower) < 2) return false; } //--- Update MACD if(UseMACDStrategy) { if(CopyBuffer(handleMACD, 0, 0, 3, macdMain) < 3) return false; if(CopyBuffer(handleMACD, 1, 0, 3, macdSignal) < 3) return false; } //--- Update ADX if(UseADXFilter) { if(CopyBuffer(handleADX, 0, 0, 1, adxMain) < 1) return false; } //--- Update ATR if(UseATRFilter || UseATRSizing) { if(CopyBuffer(handleATR, 0, 0, 1, atrBuffer) < 1) return false; } return true; } //+------------------------------------------------------------------+ //| Check Drawdown Limit | //+------------------------------------------------------------------+ bool CheckDrawdownLimit() { double equity = accountInfo.Equity(); double balance = accountInfo.Balance(); if(balance <= 0) return false; double drawdownPercent = ((balance - equity) / balance) * 100.0; return (drawdownPercent <= MaxDrawdownPercent); } //+------------------------------------------------------------------+ //| Reset Daily Trade Count | //+------------------------------------------------------------------+ void ResetDailyTradeCount() { MqlDateTime currentTime, lastTime; TimeToStruct(TimeCurrent(), currentTime); TimeToStruct(lastTradeDate, lastTime); if(currentTime.day != lastTime.day || currentTime.mon != lastTime.mon || currentTime.year != lastTime.year) { dailyTradeCount = 0; lastTradeDate = TimeCurrent(); startOfDayBalance = accountInfo.Balance(); startOfDayEquity = accountInfo.Equity(); Print("New trading day started. Daily counters reset."); } } //+------------------------------------------------------------------+ //| Can Open New Trade | //+------------------------------------------------------------------+ bool CanOpenNewTrade() { //--- Check daily limit if(dailyTradeCount >= MaxDailyTrades) return false; //--- Check concurrent positions if(CountPositions() >= MaxConcurrentPositions) return false; //--- Check portfolio risk if(!CheckPortfolioRisk()) return false; //--- Check session filter if(UseSessionFilter && !IsWithinTradingSession()) return false; return true; } //+------------------------------------------------------------------+ //| Check Portfolio Risk | //+------------------------------------------------------------------+ bool CheckPortfolioRisk() { double totalRisk = 0; double balance = accountInfo.Balance(); for(int i = PositionsTotal() - 1; i >= 0; i--) { if(positionInfo.SelectByIndex(i)) { if(positionInfo.Magic() == MagicNumber) { double posRisk = CalculatePositionRisk(positionInfo.Ticket()); totalRisk += posRisk; } } } double riskPercent = (totalRisk / balance) * 100.0; return (riskPercent < MaxPortfolioRisk); } //+------------------------------------------------------------------+ //| Calculate Position Risk | //+------------------------------------------------------------------+ double CalculatePositionRisk(ulong ticket) { if(!positionInfo.SelectByTicket(ticket)) return 0; double openPrice = positionInfo.PriceOpen(); double sl = positionInfo.StopLoss(); double volume = positionInfo.Volume(); if(sl == 0) return 0; double slDistance = MathAbs(openPrice - sl); double ticksDistance = slDistance / tickSize; return ticksDistance * tickValue * volume; } //+------------------------------------------------------------------+ //| Check if Within Trading Session | //+------------------------------------------------------------------+ bool IsWithinTradingSession() { MqlDateTime tm; TimeToStruct(TimeCurrent(), tm); int hour = tm.hour; bool inAsian = (hour >= AsianStartHour && hour < AsianEndHour); bool inLondon = (hour >= LondonStartHour && hour < LondonEndHour); bool inNY = (hour >= NYStartHour && hour < NYEndHour); if(TradeAsianSession && inAsian) return true; if(TradeLondonSession && inLondon) return true; if(TradeNYSession && inNY) return true; return false; } //+------------------------------------------------------------------+ //| Check if Cooldown Elapsed | //+------------------------------------------------------------------+ bool IsCooldownElapsed(bool isBuySignal) { datetime relevantTime = SeparateCooldownByDirection ? (isBuySignal ? lastBuyTime : lastSellTime) : MathMax(lastBuyTime, lastSellTime); return (TimeCurrent() - relevantTime) >= (CooldownMinutes * 60); } //+------------------------------------------------------------------+ //| Check Entry Signals (ENHANCED in v4.0) | //+------------------------------------------------------------------+ void CheckEntrySignals() { //--- Check basic filters if(!IsSpreadAcceptable()) return; if(UseATRFilter && !IsVolatilityAcceptable()) return; if(UseADXFilter && !IsTrendStrong()) return; //--- Generate signals from each strategy (with regime filtering) int buySignalScore = 0; int sellSignalScore = 0; string buyReasons = ""; string sellReasons = ""; int strategiesUsed = 0; //--- MA Strategy (check regime) if(UseMAStrategy && IsStrategyEnabledForRegime(STRATEGY_MA)) { int maScore = AnalyzeMAStrategy(buyReasons, sellReasons); if(maScore > 0) buySignalScore += maScore; if(maScore < 0) sellSignalScore += MathAbs(maScore); if(maScore != 0) strategiesUsed++; } //--- RSI Strategy (check regime) if(UseRSIStrategy && IsStrategyEnabledForRegime(STRATEGY_RSI)) { int rsiScore = AnalyzeRSIStrategy(buyReasons, sellReasons); if(rsiScore > 0) buySignalScore += rsiScore; if(rsiScore < 0) sellSignalScore += MathAbs(rsiScore); if(rsiScore != 0) strategiesUsed++; } //--- BB Strategy (check regime) if(UseBBStrategy && IsStrategyEnabledForRegime(STRATEGY_BB)) { int bbScore = AnalyzeBBStrategy(buyReasons, sellReasons); if(bbScore > 0) buySignalScore += bbScore; if(bbScore < 0) sellSignalScore += MathAbs(bbScore); if(bbScore != 0) strategiesUsed++; } //--- MACD Strategy (check regime) if(UseMACDStrategy && IsStrategyEnabledForRegime(STRATEGY_MACD)) { int macdScore = AnalyzeMACDStrategy(buyReasons, sellReasons); if(macdScore > 0) buySignalScore += macdScore; if(macdScore < 0) sellSignalScore += MathAbs(macdScore); if(macdScore != 0) strategiesUsed++; } //--- Apply confluence bonus if multiple strategies agree (NEW in v4.0) if(strategiesUsed >= 2) { buySignalScore += (int)SignalConfluenceBonus; sellSignalScore += (int)SignalConfluenceBonus; if(buySignalScore > sellSignalScore) buyReasons += "Multi-Strategy Confluence | "; else sellReasons += "Multi-Strategy Confluence | "; } //--- Apply multi-timeframe confirmation if enabled if(UseMultiTimeframe && UseMAStrategy) { int mtfScore = AnalyzeMultiTimeframe(); if(mtfScore > 0) { buySignalScore += 20; buyReasons += "MTF Bullish | "; } else if(mtfScore < 0) { sellSignalScore += 20; sellReasons += "MTF Bearish | "; } } //--- Get regime-adjusted threshold (NEW in v4.0) int threshold = GetRegimeAdjustedThreshold(); //--- Process buy signal if(buySignalScore >= threshold && IsCooldownElapsed(true)) { string regimeNames[] = {"STRONG_UPTREND", "STRONG_DOWNTREND", "RANGING_LOW_VOL", "RANGING_HIGH_VOL", "NEUTRAL"}; Print("=== BUY SIGNAL | Score: ", buySignalScore, " | Threshold: ", threshold, " | Regime: ", regimeNames[currentMarketRegime], " ==="); Print("Reasons: ", buyReasons); double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); if(OpenPosition(ORDER_TYPE_BUY, ask, STRATEGY_MA)) { lastBuyTime = TimeCurrent(); dailyTradeCount++; } } //--- Process sell signal if(sellSignalScore >= threshold && IsCooldownElapsed(false)) { string regimeNames[] = {"STRONG_UPTREND", "STRONG_DOWNTREND", "RANGING_LOW_VOL", "RANGING_HIGH_VOL", "NEUTRAL"}; Print("=== SELL SIGNAL | Score: ", sellSignalScore, " | Threshold: ", threshold, " | Regime: ", regimeNames[currentMarketRegime], " ==="); Print("Reasons: ", sellReasons); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(OpenPosition(ORDER_TYPE_SELL, bid, STRATEGY_MA)) { lastSellTime = TimeCurrent(); dailyTradeCount++; } } } //+------------------------------------------------------------------+ //| Analyze MA Strategy (ENHANCED in v4.0) | //+------------------------------------------------------------------+ int AnalyzeMAStrategy(string &buyReasons, string &sellReasons) { //--- Check for crossover bool bullishCross = fastMA[1] > slowMA[1] && fastMA[2] <= slowMA[2]; bool bearishCross = fastMA[1] < slowMA[1] && fastMA[2] >= slowMA[2]; //--- Check MA distance (NEW in v4.0) double maDistance = MathAbs(fastMA[1] - slowMA[1]) / pipSize; if(maDistance < MA_DistanceMinimum) return 0; // MAs too close together //--- Check for crossover OR strong trend continuation int score = 0; bool isBullish = fastMA[1] > slowMA[1]; bool isBearish = fastMA[1] < slowMA[1]; //--- Crossover signals (strongest) if(bullishCross) { score = 35; // Increased from 30 buyReasons += "MA Bullish Cross | "; //--- Check MA slope for quality double maSlope = (fastMA[1] - fastMA[2]) / pipSize; if(maSlope >= MA_SlopeMinimum) { score += 10; buyReasons += "Strong Slope | "; } //--- Check momentum filter if enabled (NEW in v4.0) if(UseMomentumFilter && CheckMomentum(_Symbol, pipSize) > 0) { score += 10; buyReasons += "Bullish Momentum | "; } //--- Check breakout if enabled (NEW in v4.0) if(UseBreakoutDetection && CheckBreakout(_Symbol, pipSize) > 0) { score += 10; buyReasons += "Bullish Breakout | "; } return score; } else if(bearishCross) { score = -35; // Increased from -30 sellReasons += "MA Bearish Cross | "; //--- Check MA slope for quality double maSlope = (fastMA[2] - fastMA[1]) / pipSize; if(maSlope >= MA_SlopeMinimum) { score -= 10; sellReasons += "Strong Slope | "; } //--- Check momentum filter if enabled (NEW in v4.0) if(UseMomentumFilter && CheckMomentum(_Symbol, pipSize) < 0) { score -= 10; sellReasons += "Bearish Momentum | "; } //--- Check breakout if enabled (NEW in v4.0) if(UseBreakoutDetection && CheckBreakout(_Symbol, pipSize) < 0) { score -= 10; sellReasons += "Bearish Breakout | "; } return score; } //--- Trend continuation signals (weaker, only if regime allows) if(UseMarketRegimeFilter && currentMarketRegime != REGIME_NEUTRAL) { if(isBullish && fastMA[0] > fastMA[1] && fastMA[1] > fastMA[2]) { // Strong uptrend continuation score = 20; buyReasons += "MA Uptrend Continuation | "; return score; } else if(isBearish && fastMA[0] < fastMA[1] && fastMA[1] < fastMA[2]) { // Strong downtrend continuation score = -20; sellReasons += "MA Downtrend Continuation | "; return score; } } return 0; } //+------------------------------------------------------------------+ //| Analyze RSI Strategy | //+------------------------------------------------------------------+ int AnalyzeRSIStrategy(string &buyReasons, string &sellReasons) { double rsi = rsiBuffer[0]; double rsiPrev = rsiBuffer[1]; int score = 0; //--- Oversold bounce if(rsiPrev < RSI_Oversold && rsi > RSI_Oversold) { score = 25; buyReasons += "RSI Oversold Bounce | "; } //--- Overbought fall if(rsiPrev > RSI_Overbought && rsi < RSI_Overbought) { score = -25; sellReasons += "RSI Overbought Fall | "; } return score; } //+------------------------------------------------------------------+ //| Analyze Bollinger Bands Strategy | //+------------------------------------------------------------------+ int AnalyzeBBStrategy(string &buyReasons, string &sellReasons) { double close = iClose(_Symbol, PERIOD_CURRENT, 0); double closePrev = iClose(_Symbol, PERIOD_CURRENT, 1); int score = 0; //--- Bounce from lower band if(closePrev <= bbLower[1] && close > bbLower[0]) { score = 25; buyReasons += "BB Lower Bounce | "; } //--- Fall from upper band if(closePrev >= bbUpper[1] && close < bbUpper[0]) { score = -25; sellReasons += "BB Upper Fall | "; } return score; } //+------------------------------------------------------------------+ //| Analyze MACD Strategy | //+------------------------------------------------------------------+ int AnalyzeMACDStrategy(string &buyReasons, string &sellReasons) { int score = 0; //--- Bullish MACD crossover if(macdMain[1] > macdSignal[1] && macdMain[2] <= macdSignal[2]) { score = 20; buyReasons += "MACD Bullish Cross | "; } //--- Bearish MACD crossover if(macdMain[1] < macdSignal[1] && macdMain[2] >= macdSignal[2]) { score = -20; sellReasons += "MACD Bearish Cross | "; } return score; } //+------------------------------------------------------------------+ //| Analyze Multi-Timeframe | //+------------------------------------------------------------------+ int AnalyzeMultiTimeframe() { double fastMA_TF1[], slowMA_TF1[]; double fastMA_TF2[], slowMA_TF2[]; double fastMA_TF3[], slowMA_TF3[]; ArraySetAsSeries(fastMA_TF1, true); ArraySetAsSeries(slowMA_TF1, true); ArraySetAsSeries(fastMA_TF2, true); ArraySetAsSeries(slowMA_TF2, true); ArraySetAsSeries(fastMA_TF3, true); ArraySetAsSeries(slowMA_TF3, true); if(CopyBuffer(handleFastMA_TF1, 0, 0, 1, fastMA_TF1) < 1) return 0; if(CopyBuffer(handleSlowMA_TF1, 0, 0, 1, slowMA_TF1) < 1) return 0; if(CopyBuffer(handleFastMA_TF2, 0, 0, 1, fastMA_TF2) < 1) return 0; if(CopyBuffer(handleSlowMA_TF2, 0, 0, 1, slowMA_TF2) < 1) return 0; if(CopyBuffer(handleFastMA_TF3, 0, 0, 1, fastMA_TF3) < 1) return 0; if(CopyBuffer(handleSlowMA_TF3, 0, 0, 1, slowMA_TF3) < 1) return 0; int bullish = 0; int bearish = 0; if(fastMA_TF1[0] > slowMA_TF1[0]) bullish++; else bearish++; if(fastMA_TF2[0] > slowMA_TF2[0]) bullish++; else bearish++; if(fastMA_TF3[0] > slowMA_TF3[0]) bullish++; else bearish++; if(bullish >= MinTFConfirmation) return 1; if(bearish >= MinTFConfirmation) return -1; return 0; } //+------------------------------------------------------------------+ //| Update Market Regime (NEW in v4.0) | //+------------------------------------------------------------------+ void UpdateMarketRegime() { //--- Copy regime indicators if(CopyBuffer(handleRegimeFastSMA, 0, 0, 3, regimeFastSMA) < 3) return; if(CopyBuffer(handleRegimeSlowSMA, 0, 0, 3, regimeSlowSMA) < 3) return; if(CopyBuffer(handleRegimeADX, 0, 0, 3, regimeADX) < 3) return; if(CopyBuffer(handleRegimeATR, 0, 0, Regime_ATR_Period, regimeATR) < Regime_ATR_Period) return; double currentPrice = iClose(_Symbol, RegimeTimeframe, 0); //--- Calculate average ATR for volatility classification double avgATR = 0; for(int i = 0; i < Regime_ATR_Period; i++) avgATR += regimeATR[i]; avgATR /= Regime_ATR_Period; double currentATR = regimeATR[0]; bool isHighVolatility = (currentATR > avgATR * Regime_ATR_HighVol_Multiplier); //--- Determine trend direction bool isUptrend = (regimeFastSMA[0] > regimeSlowSMA[0] && currentPrice > regimeFastSMA[0]); bool isDowntrend = (regimeFastSMA[0] < regimeSlowSMA[0] && currentPrice < regimeFastSMA[0]); bool isTrending = (regimeADX[0] > Regime_ADX_Trending); bool isRanging = (regimeADX[0] < Regime_ADX_Ranging); //--- Classify market regime ENUM_MARKET_REGIME previousRegime = currentMarketRegime; if(isUptrend && isTrending) currentMarketRegime = REGIME_STRONG_UPTREND; else if(isDowntrend && isTrending) currentMarketRegime = REGIME_STRONG_DOWNTREND; else if(isRanging && !isHighVolatility) currentMarketRegime = REGIME_RANGING_LOW_VOL; else if(isRanging && isHighVolatility) currentMarketRegime = REGIME_RANGING_HIGH_VOL; else currentMarketRegime = REGIME_NEUTRAL; //--- Log regime changes if(currentMarketRegime != previousRegime) { string regimeNames[] = {"STRONG_UPTREND", "STRONG_DOWNTREND", "RANGING_LOW_VOL", "RANGING_HIGH_VOL", "NEUTRAL"}; Print("Market Regime Changed: ", regimeNames[previousRegime], " -> ", regimeNames[currentMarketRegime]); Print("ADX: ", DoubleToString(regimeADX[0], 1), " | ATR: ", DoubleToString(currentATR/pipSize, 1), " pips"); } } //+------------------------------------------------------------------+ //| Check if Strategy is Enabled for Current Regime (NEW in v4.0) | //+------------------------------------------------------------------+ bool IsStrategyEnabledForRegime(ENUM_STRATEGY_TYPE strategy) { if(!UseMarketRegimeFilter) return true; // All strategies enabled if regime filter disabled //--- Enable momentum strategies in trending markets if(currentMarketRegime == REGIME_STRONG_UPTREND || currentMarketRegime == REGIME_STRONG_DOWNTREND) { return (strategy == STRATEGY_MA || strategy == STRATEGY_MACD); } //--- Enable mean reversion strategies in ranging low-vol markets if(currentMarketRegime == REGIME_RANGING_LOW_VOL) { return (strategy == STRATEGY_RSI || strategy == STRATEGY_BB); } //--- Cautious in high-vol ranging (reduce activity) if(currentMarketRegime == REGIME_RANGING_HIGH_VOL) { return false; // Block all strategies in choppy high-vol } //--- Neutral: allow all but with higher thresholds return true; } //+------------------------------------------------------------------+ //| Get Regime-Adjusted Signal Threshold (NEW in v4.0) | //+------------------------------------------------------------------+ int GetRegimeAdjustedThreshold() { if(!UseAdaptiveScoring) return MinSignalScore; //--- Lower thresholds in strong trends (more opportunities) if(currentMarketRegime == REGIME_STRONG_UPTREND || currentMarketRegime == REGIME_STRONG_DOWNTREND) return (int)(MinSignalScore * 0.8); // 20% reduction //--- Keep normal threshold in ranging low-vol if(currentMarketRegime == REGIME_RANGING_LOW_VOL) return MinSignalScore; //--- Increase threshold in neutral/uncertain return (int)(MinSignalScore * 1.3); // 30% increase } //+------------------------------------------------------------------+ //| Check Momentum Filter (NEW in v4.0) | //+------------------------------------------------------------------+ int CheckMomentum(string symbol, double pipSz) { double closes[]; ArraySetAsSeries(closes, true); if(CopyClose(symbol, PERIOD_CURRENT, 0, MomentumBars + 1, closes) < MomentumBars + 1) return 0; //--- Calculate momentum: current price vs N bars ago double momentum = (closes[0] - closes[MomentumBars]) / pipSz; if(momentum > 3.0) // Bullish momentum (>3 pips in MomentumBars) return 1; else if(momentum < -3.0) // Bearish momentum return -1; return 0; } //+------------------------------------------------------------------+ //| Check Breakout Detection (NEW in v4.0) | //+------------------------------------------------------------------+ int CheckBreakout(string symbol, double pipSz) { double highs[], lows[]; ArraySetAsSeries(highs, true); ArraySetAsSeries(lows, true); if(CopyHigh(symbol, PERIOD_CURRENT, 1, BreakoutBars, highs) < BreakoutBars) return 0; if(CopyLow(symbol, PERIOD_CURRENT, 1, BreakoutBars, lows) < BreakoutBars) return 0; //--- Find range high/low double rangeHigh = highs[0]; double rangeLow = lows[0]; for(int i = 1; i < BreakoutBars; i++) { if(highs[i] > rangeHigh) rangeHigh = highs[i]; if(lows[i] < rangeLow) rangeLow = lows[i]; } double rangeSize = (rangeHigh - rangeLow) / pipSz; //--- Check if range is significant enough if(rangeSize < BreakoutThresholdPips) return 0; //--- Check current price vs range double currentPrice = iClose(symbol, PERIOD_CURRENT, 0); if(currentPrice > rangeHigh) // Bullish breakout return 1; else if(currentPrice < rangeLow) // Bearish breakout return -1; return 0; } //+------------------------------------------------------------------+ //| Check if Spread Acceptable | //+------------------------------------------------------------------+ bool IsSpreadAcceptable() { double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double spread = (ask - bid) / pipSize; if(spread > MaxSpreadPips) { return false; } return true; } //+------------------------------------------------------------------+ //| Check if Volatility Acceptable | //+------------------------------------------------------------------+ bool IsVolatilityAcceptable() { if(ArraySize(atrBuffer) == 0) return true; double atr = atrBuffer[0]; double atrPips = atr / pipSize; if(atrPips < ATR_MinimumPips || atrPips > ATR_MaximumPips) return false; return true; } //+------------------------------------------------------------------+ //| Check if Trend Strong | //+------------------------------------------------------------------+ bool IsTrendStrong() { if(ArraySize(adxMain) == 0) return true; return (adxMain[0] >= ADX_Minimum); } //+------------------------------------------------------------------+ //| Open Position (with all fixes) | //+------------------------------------------------------------------+ bool OpenPosition(ENUM_ORDER_TYPE orderType, double price, ENUM_STRATEGY_TYPE strategy) { //--- Calculate SL and TP double sl = CalculateStopLoss(orderType, price); double tp = CalculateTakeProfit(orderType, price); //--- Validate trade if(!ValidateTrade(orderType, price, sl, tp)) return false; //--- Calculate lot size with dynamic risk double riskPercent = CalculateDynamicRisk(); double lots = CalculateLotSize(price, sl, riskPercent); //--- Normalize sl = NormalizeDouble(sl, symbolDigits); tp = NormalizeDouble(tp, symbolDigits); lots = NormalizeLot(lots); if(lots < minLot || lots > maxLot) return false; //--- Open with retries bool success = false; int attempts = 0; while(attempts < MaxRetries && !success) { ResetLastError(); if(orderType == ORDER_TYPE_BUY) success = trade.Buy(lots, _Symbol, 0, sl, tp, TradeComment); else success = trade.Sell(lots, _Symbol, 0, sl, tp, TradeComment); if(success) { Print("Position opened: ", EnumToString(orderType), " | Lots: ", lots, " | SL: ", sl, " | TP: ", tp); //--- Track position for partial TP if(UsePartialTP) { trackedPositions[trackedPositionCount].ticket = trade.ResultOrder(); trackedPositions[trackedPositionCount].partialTPDone = false; trackedPositionCount++; } return true; } else { int error = GetLastError(); if(IsTransientError(error)) { Sleep(RetryDelayMs); attempts++; } else { break; } } } return false; } //+------------------------------------------------------------------+ //| Calculate Dynamic Risk Based on Win Rate | //+------------------------------------------------------------------+ double CalculateDynamicRisk() { if(!UseDynamicRisk) return BaseRiskPercent; //--- Calculate overall win rate int totalTrades = maStats.totalTrades + rsiStats.totalTrades + bbStats.totalTrades + macdStats.totalTrades; int totalWins = maStats.winningTrades + rsiStats.winningTrades + bbStats.winningTrades + macdStats.winningTrades; if(totalTrades < 10) return BaseRiskPercent; double winRate = (double)totalWins / totalTrades; //--- Adjust risk based on win rate double risk = BaseRiskPercent; if(winRate > 0.6) risk = BaseRiskPercent * 1.2; else if(winRate < 0.4) risk = BaseRiskPercent * 0.8; //--- Apply limits if(risk < MinRiskPercent) risk = MinRiskPercent; if(risk > MaxRiskPercent) risk = MaxRiskPercent; return risk; } //+------------------------------------------------------------------+ //| Calculate Stop Loss (ENHANCED in v4.0) | //+------------------------------------------------------------------+ double CalculateStopLoss(ENUM_ORDER_TYPE orderType, double price) { double slDistance; if(UseATRSizing && ArraySize(atrBuffer) > 0) { slDistance = atrBuffer[0] * ATR_SL_Multiplier; //--- Apply min/max bounds (NEW in v4.0) double slPips = slDistance / pipSize; if(slPips < MinSL_Pips) slDistance = MinSL_Pips * pipSize; if(slPips > MaxSL_Pips) slDistance = MaxSL_Pips * pipSize; } else { slDistance = StopLossPips * pipSize; } double sl = (orderType == ORDER_TYPE_BUY) ? price - slDistance : price + slDistance; return sl; } //+------------------------------------------------------------------+ //| Calculate Take Profit (ENHANCED in v4.0) | //+------------------------------------------------------------------+ double CalculateTakeProfit(ENUM_ORDER_TYPE orderType, double price) { double tpDistance; if(UseATRSizing && ArraySize(atrBuffer) > 0) { tpDistance = atrBuffer[0] * ATR_TP_Multiplier; //--- Apply minimum TP (NEW in v4.0) double tpPips = tpDistance / pipSize; if(tpPips < (MinSL_Pips * 1.5)) // TP should be at least 1.5x SL minimum tpDistance = (MinSL_Pips * 1.5) * pipSize; } else { tpDistance = TakeProfitPips * pipSize; } double tp = (orderType == ORDER_TYPE_BUY) ? price + tpDistance : price - tpDistance; return tp; } //+------------------------------------------------------------------+ //| Validate Trade | //+------------------------------------------------------------------+ bool ValidateTrade(ENUM_ORDER_TYPE orderType, double price, double sl, double tp) { long stopsLevelPoints = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL); double stopsLevel = stopsLevelPoints * point; if(MathAbs(price - sl) < stopsLevel) return false; if(MathAbs(price - tp) < stopsLevel) return false; return true; } //+------------------------------------------------------------------+ //| Calculate Lot Size | //+------------------------------------------------------------------+ double CalculateLotSize(double entryPrice, double stopLoss, double riskPercent) { if(UseFixedLot) return FixedLotSize; double balance = UseCompounding ? accountInfo.Equity() : accountInfo.Balance(); double riskAmount = balance * (riskPercent / 100.0); double slDistance = MathAbs(entryPrice - stopLoss); if(slDistance <= 0) return minLot; double ticksDistance = slDistance / tickSize; double riskPerLot = ticksDistance * tickValue; if(riskPerLot <= 0) return minLot; double lots = riskAmount / riskPerLot; if(lots > MaxLotSize) lots = MaxLotSize; if(lots < MinLotSize) lots = MinLotSize; return lots; } //+------------------------------------------------------------------+ //| Normalize Lot Size | //+------------------------------------------------------------------+ double NormalizeLot(double lots) { lots = MathRound(lots / lotStep) * lotStep; if(lots < minLot) lots = minLot; if(lots > maxLot) lots = maxLot; return NormalizeDouble(lots, 2); } //+------------------------------------------------------------------+ //| Count Positions | //+------------------------------------------------------------------+ int CountPositions() { int count = 0; for(int i = PositionsTotal() - 1; i >= 0; i--) { if(positionInfo.SelectByIndex(i)) { if(positionInfo.Symbol() == _Symbol && positionInfo.Magic() == MagicNumber) { count++; } } } return count; } //+------------------------------------------------------------------+ //| Manage Positions | //+------------------------------------------------------------------+ void ManagePositions() { for(int i = PositionsTotal() - 1; i >= 0; i--) { if(!positionInfo.SelectByIndex(i)) continue; if(positionInfo.Symbol() != _Symbol || positionInfo.Magic() != MagicNumber) continue; ulong ticket = positionInfo.Ticket(); double openPrice = positionInfo.PriceOpen(); double currentSL = positionInfo.StopLoss(); double currentTP = positionInfo.TakeProfit(); ENUM_POSITION_TYPE posType = positionInfo.PositionType(); double volume = positionInfo.Volume(); double currentPrice = (posType == POSITION_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_BID) : SymbolInfoDouble(_Symbol, SYMBOL_ASK); double profitPips = 0; if(posType == POSITION_TYPE_BUY) profitPips = (currentPrice - openPrice) / pipSize; else profitPips = (openPrice - currentPrice) / pipSize; //--- Partial TP if(UsePartialTP && profitPips >= PartialTP_Pips) { bool alreadyDone = false; for(int j = 0; j < trackedPositionCount; j++) { if(trackedPositions[j].ticket == ticket && trackedPositions[j].partialTPDone) { alreadyDone = true; break; } } if(!alreadyDone) { double closeVolume = NormalizeLot(volume * PartialTP_Percent / 100.0); if(closeVolume >= minLot && closeVolume < volume) { if(trade.PositionClosePartial(ticket, closeVolume)) { Print("Partial TP executed: Ticket ", ticket, " | Closed: ", closeVolume); for(int j = 0; j < trackedPositionCount; j++) { if(trackedPositions[j].ticket == ticket) { trackedPositions[j].partialTPDone = true; break; } } } } } } //--- Breakeven if(UseBreakeven && profitPips >= BreakevenTriggerPips) { double bePrice = openPrice + (BreakevenOffsetPips * pipSize * (posType == POSITION_TYPE_BUY ? 1 : -1)); bool needsUpdate = false; if(posType == POSITION_TYPE_BUY && (currentSL < bePrice || currentSL == 0)) needsUpdate = true; else if(posType == POSITION_TYPE_SELL && (currentSL > bePrice || currentSL == 0)) needsUpdate = true; if(needsUpdate) { bePrice = NormalizeDouble(bePrice, symbolDigits); if(trade.PositionModify(ticket, bePrice, currentTP)) { Print("Breakeven: Ticket ", ticket, " | SL: ", bePrice); } continue; } } //--- Trailing stop if(UseTrailingStop && profitPips >= TrailingActivationPips) { double trailDistance = TrailingStopPips * pipSize; double trailStep = TrailingStepPips * pipSize; double newSL = 0; if(posType == POSITION_TYPE_BUY) { newSL = currentPrice - trailDistance; if(newSL > currentSL + trailStep || currentSL == 0) { newSL = NormalizeDouble(newSL, symbolDigits); if(newSL > openPrice) { trade.PositionModify(ticket, newSL, currentTP); } } } else if(posType == POSITION_TYPE_SELL) { newSL = currentPrice + trailDistance; if(newSL < currentSL - trailStep || currentSL == 0) { newSL = NormalizeDouble(newSL, symbolDigits); if(newSL < openPrice) { trade.PositionModify(ticket, newSL, currentTP); } } } } } } //+------------------------------------------------------------------+ //| Check if Error is Transient | //+------------------------------------------------------------------+ bool IsTransientError(int error) { switch(error) { case 10004: case 10006: case 10007: case 10018: case 10021: case 10025: case 10027: return true; default: return false; } } //+------------------------------------------------------------------+ //| Initialize Strategy Stats | //+------------------------------------------------------------------+ void InitializeStrategyStats() { maStats.totalTrades = 0; maStats.winningTrades = 0; maStats.totalProfit = 0; maStats.winRate = 0; rsiStats = maStats; bbStats = maStats; macdStats = maStats; } //+------------------------------------------------------------------+ //| Update Strategy Stats | //+------------------------------------------------------------------+ void UpdateStrategyStats(ulong positionID, double profit) { //--- For simplicity, attribute to MA strategy //--- In a real implementation, you'd track which strategy opened each position maStats.totalTrades++; if(profit > 0) maStats.winningTrades++; maStats.totalProfit += profit; if(maStats.totalTrades > 0) maStats.winRate = (double)maStats.winningTrades / maStats.totalTrades * 100.0; } //+------------------------------------------------------------------+ //| Print Strategy Performance | //+------------------------------------------------------------------+ void PrintStrategyPerformance() { Print("========================================"); Print("Strategy Performance Summary"); Print("MA: Trades=", maStats.totalTrades, " WinRate=", maStats.winRate, "% Profit=", maStats.totalProfit); Print("========================================"); } //+------------------------------------------------------------------+ //| Count Active Strategies | //+------------------------------------------------------------------+ int CountActiveStrategies() { int count = 0; if(UseMAStrategy) count++; if(UseRSIStrategy) count++; if(UseBBStrategy) count++; if(UseMACDStrategy) count++; return count; } //+------------------------------------------------------------------+ //| Initialize Multi-Symbol Trading | //+------------------------------------------------------------------+ bool InitializeMultiSymbolTrading() { //--- Parse trading symbols string symbols[]; int count = StringSplit(TradingSymbols, ',', symbols); if(count <= 0) { Print("Error: No valid symbols found"); return false; } ArrayResize(symbolDataArray, count); totalSymbols = 0; //--- Initialize each symbol for(int i = 0; i < count; i++) { string symbol = symbols[i]; StringTrimLeft(symbol); StringTrimRight(symbol); //--- Check if symbol exists if(!SymbolSelect(symbol, true)) { Print("Warning: Symbol ", symbol, " not found or cannot be selected"); continue; } //--- Initialize symbol data SymbolData data; data.symbol = symbol; data.point = SymbolInfoDouble(symbol, SYMBOL_POINT); data.symbolDigits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); //--- Calculate pip size if(data.symbolDigits == 3 || data.symbolDigits == 5) data.pipSize = data.point * 10; else data.pipSize = data.point; //--- Get trading properties data.tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); data.tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE_PROFIT); if(data.tickValue == 0) { double contractSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE); data.tickValue = data.tickSize * contractSize; } data.lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP); data.minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); data.maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); //--- Initialize trading state data.lastBuyTime = 0; data.lastSellTime = 0; data.lastCloseTime = 0; data.positionCount = 0; //--- Create indicators for this symbol data.handleFastMA = INVALID_HANDLE; data.handleSlowMA = INVALID_HANDLE; data.handleADX = INVALID_HANDLE; data.handleATR = INVALID_HANDLE; data.handleRSI = INVALID_HANDLE; data.handleBB = INVALID_HANDLE; data.handleMACD = INVALID_HANDLE; if(UseMAStrategy) { data.handleFastMA = iMA(symbol, PERIOD_CURRENT, FastMA_Period, 0, MA_Method, MA_Price); data.handleSlowMA = iMA(symbol, PERIOD_CURRENT, SlowMA_Period, 0, MA_Method, MA_Price); } if(UseADXFilter) { data.handleADX = iADX(symbol, PERIOD_CURRENT, ADX_Period); } if(UseATRFilter) { data.handleATR = iATR(symbol, PERIOD_CURRENT, ATR_Period); } if(UseRSIStrategy) { data.handleRSI = iRSI(symbol, PERIOD_CURRENT, RSI_Period, RSI_Price); } if(UseBBStrategy) { data.handleBB = iBands(symbol, PERIOD_CURRENT, BB_Period, 0, BB_Deviation, BB_AppliedPrice); } if(UseMACDStrategy) { data.handleMACD = iMACD(symbol, PERIOD_CURRENT, MACD_FastEMA, MACD_SlowEMA, MACD_Signal, MACD_Price); } symbolDataArray[totalSymbols] = data; totalSymbols++; Print("Initialized symbol: ", symbol); } Print("Total symbols initialized: ", totalSymbols); return (totalSymbols > 0); } //+------------------------------------------------------------------+ //| Process Trading for a Symbol | //+------------------------------------------------------------------+ void ProcessSymbolTrading(int symbolIndex) { if(symbolIndex < 0 || symbolIndex >= totalSymbols) return; SymbolData data = symbolDataArray[symbolIndex]; string symbol = data.symbol; //--- Count positions for this symbol int symbolPositions = CountSymbolPositions(symbol); data.positionCount = symbolPositions; symbolDataArray[symbolIndex] = data; //--- Check symbol position limit if(symbolPositions >= MaxPositionsPerSymbol) return; //--- Check global position limit if(CountAllPositions() >= MaxTotalPositions) return; //--- Manage existing positions for this symbol ManageSymbolPositions(symbol); //--- Check if can open new trade if(!CanOpenNewTradeForSymbol(symbolIndex)) return; //--- Check for entry signals CheckSymbolEntrySignals(symbolIndex); } //+------------------------------------------------------------------+ //| Check Entry Signals for Symbol | //+------------------------------------------------------------------+ void CheckSymbolEntrySignals(int symbolIndex) { SymbolData data = symbolDataArray[symbolIndex]; string symbol = data.symbol; //--- Update indicator buffers double fastMA[], slowMA[], atrBuf[], adxBuf[], rsiBuf[]; double bbUpper[], bbMiddle[], bbLower[]; double macdMain[], macdSignal[]; ArraySetAsSeries(fastMA, true); ArraySetAsSeries(slowMA, true); ArraySetAsSeries(atrBuf, true); ArraySetAsSeries(adxBuf, true); ArraySetAsSeries(rsiBuf, true); ArraySetAsSeries(bbUpper, true); ArraySetAsSeries(bbMiddle, true); ArraySetAsSeries(bbLower, true); ArraySetAsSeries(macdMain, true); ArraySetAsSeries(macdSignal, true); //--- Copy indicator data if(UseMAStrategy) { if(CopyBuffer(data.handleFastMA, 0, 0, 3, fastMA) < 3) return; if(CopyBuffer(data.handleSlowMA, 0, 0, 3, slowMA) < 3) return; } if(UseATRFilter) { if(CopyBuffer(data.handleATR, 0, 0, 1, atrBuf) < 1) return; } if(UseADXFilter) { if(CopyBuffer(data.handleADX, 0, 0, 1, adxBuf) < 1) return; } if(UseRSIStrategy) { if(CopyBuffer(data.handleRSI, 0, 0, 2, rsiBuf) < 2) return; } if(UseBBStrategy) { if(CopyBuffer(data.handleBB, 0, 0, 2, bbUpper) < 2) return; if(CopyBuffer(data.handleBB, 1, 0, 2, bbMiddle) < 2) return; if(CopyBuffer(data.handleBB, 2, 0, 2, bbLower) < 2) return; } if(UseMACDStrategy) { if(CopyBuffer(data.handleMACD, 0, 0, 3, macdMain) < 3) return; if(CopyBuffer(data.handleMACD, 1, 0, 3, macdSignal) < 3) return; } //--- Check basic filters double ask = SymbolInfoDouble(symbol, SYMBOL_ASK); double bid = SymbolInfoDouble(symbol, SYMBOL_BID); double spread = (ask - bid) / data.pipSize; if(spread > MaxSpreadPips) return; if(UseATRFilter && ArraySize(atrBuf) > 0) { double atrPips = atrBuf[0] / data.pipSize; if(atrPips < ATR_MinimumPips || atrPips > ATR_MaximumPips) return; } if(UseADXFilter && ArraySize(adxBuf) > 0) { if(adxBuf[0] < ADX_Minimum) return; } //--- Generate signals (with regime filtering) int buySignalScore = 0; int sellSignalScore = 0; string buyReasons = ""; string sellReasons = ""; int strategiesUsed = 0; //--- Enhanced MA Strategy (check regime) if(UseMAStrategy && ArraySize(fastMA) >= 3 && IsStrategyEnabledForRegime(STRATEGY_MA)) { bool bullishCross = fastMA[1] > slowMA[1] && fastMA[2] <= slowMA[2]; bool bearishCross = fastMA[1] < slowMA[1] && fastMA[2] >= slowMA[2]; //--- Check MA distance double maDistance = MathAbs(fastMA[1] - slowMA[1]) / data.pipSize; if(maDistance < MA_DistanceMinimum) bullishCross = bearishCross = false; if(bullishCross) { int score = 35; // Enhanced base score buyReasons += "MA Bullish Cross | "; //--- Check slope double maSlope = (fastMA[1] - fastMA[2]) / data.pipSize; if(maSlope >= MA_SlopeMinimum) { score += 10; buyReasons += "Strong Slope | "; } //--- Check momentum if(UseMomentumFilter && CheckMomentum(symbol, data.pipSize) > 0) { score += 10; buyReasons += "Bullish Momentum | "; } //--- Check breakout if(UseBreakoutDetection && CheckBreakout(symbol, data.pipSize) > 0) { score += 10; buyReasons += "Bullish Breakout | "; } buySignalScore += score; strategiesUsed++; } else if(bearishCross) { int score = 35; // Enhanced base score sellReasons += "MA Bearish Cross | "; //--- Check slope double maSlope = (fastMA[2] - fastMA[1]) / data.pipSize; if(maSlope >= MA_SlopeMinimum) { score += 10; sellReasons += "Strong Slope | "; } //--- Check momentum if(UseMomentumFilter && CheckMomentum(symbol, data.pipSize) < 0) { score += 10; sellReasons += "Bearish Momentum | "; } //--- Check breakout if(UseBreakoutDetection && CheckBreakout(symbol, data.pipSize) < 0) { score += 10; sellReasons += "Bearish Breakout | "; } sellSignalScore += score; strategiesUsed++; } } //--- RSI Strategy (check regime) if(UseRSIStrategy && ArraySize(rsiBuf) >= 2 && IsStrategyEnabledForRegime(STRATEGY_RSI)) { if(rsiBuf[1] < RSI_Oversold && rsiBuf[0] > RSI_Oversold) { buySignalScore += 25; buyReasons += "RSI Oversold Bounce | "; strategiesUsed++; } if(rsiBuf[1] > RSI_Overbought && rsiBuf[0] < RSI_Overbought) { sellSignalScore += 25; sellReasons += "RSI Overbought Fall | "; strategiesUsed++; } } //--- BB Strategy (check regime) if(UseBBStrategy && ArraySize(bbLower) >= 2 && IsStrategyEnabledForRegime(STRATEGY_BB)) { double close = iClose(symbol, PERIOD_CURRENT, 0); double closePrev = iClose(symbol, PERIOD_CURRENT, 1); if(closePrev <= bbLower[1] && close > bbLower[0]) { buySignalScore += 25; buyReasons += "BB Lower Bounce | "; strategiesUsed++; } if(closePrev >= bbUpper[1] && close < bbUpper[0]) { sellSignalScore += 25; sellReasons += "BB Upper Fall | "; strategiesUsed++; } } //--- MACD Strategy (check regime) if(UseMACDStrategy && ArraySize(macdMain) >= 3 && IsStrategyEnabledForRegime(STRATEGY_MACD)) { if(macdMain[1] > macdSignal[1] && macdMain[2] <= macdSignal[2]) { buySignalScore += 20; buyReasons += "MACD Bullish | "; strategiesUsed++; } if(macdMain[1] < macdSignal[1] && macdMain[2] >= macdSignal[2]) { sellSignalScore += 20; sellReasons += "MACD Bearish | "; strategiesUsed++; } } //--- Apply confluence bonus if multiple strategies agree (NEW in v4.0) if(strategiesUsed >= 2) { buySignalScore += (int)SignalConfluenceBonus; sellSignalScore += (int)SignalConfluenceBonus; if(buySignalScore > sellSignalScore) buyReasons += "Multi-Strategy Confluence | "; else sellReasons += "Multi-Strategy Confluence | "; } //--- Get regime-adjusted threshold (NEW in v4.0) int threshold = GetRegimeAdjustedThreshold(); //--- Process buy signal if(buySignalScore >= threshold) { string regimeNames[] = {"STRONG_UPTREND", "STRONG_DOWNTREND", "RANGING_LOW_VOL", "RANGING_HIGH_VOL", "NEUTRAL"}; Print("=== BUY SIGNAL [", symbol, "] | Score: ", buySignalScore, " | Threshold: ", threshold, " | Regime: ", regimeNames[currentMarketRegime], " ==="); Print("Reasons: ", buyReasons); if(OpenSymbolPosition(symbolIndex, ORDER_TYPE_BUY)) { data.lastBuyTime = TimeCurrent(); symbolDataArray[symbolIndex] = data; dailyTradeCount++; } } //--- Process sell signal if(sellSignalScore >= threshold) { string regimeNames[] = {"STRONG_UPTREND", "STRONG_DOWNTREND", "RANGING_LOW_VOL", "RANGING_HIGH_VOL", "NEUTRAL"}; Print("=== SELL SIGNAL [", symbol, "] | Score: ", sellSignalScore, " | Threshold: ", threshold, " | Regime: ", regimeNames[currentMarketRegime], " ==="); Print("Reasons: ", sellReasons); if(OpenSymbolPosition(symbolIndex, ORDER_TYPE_SELL)) { data.lastSellTime = TimeCurrent(); symbolDataArray[symbolIndex] = data; dailyTradeCount++; } } } //+------------------------------------------------------------------+ //| Open Position for Symbol | //+------------------------------------------------------------------+ bool OpenSymbolPosition(int symbolIndex, ENUM_ORDER_TYPE orderType) { SymbolData data = symbolDataArray[symbolIndex]; string symbol = data.symbol; double price = (orderType == ORDER_TYPE_BUY) ? SymbolInfoDouble(symbol, SYMBOL_ASK) : SymbolInfoDouble(symbol, SYMBOL_BID); //--- Calculate SL and TP double sl = CalculateSymbolStopLoss(symbolIndex, orderType, price); double tp = CalculateSymbolTakeProfit(symbolIndex, orderType, price); //--- Validate trade if(!ValidateSymbolTrade(symbolIndex, orderType, price, sl, tp)) return false; //--- Calculate lot size double riskPercent = CalculateDynamicRisk(); double lots = CalculateSymbolLotSize(symbolIndex, price, sl, riskPercent); //--- Normalize sl = NormalizeDouble(sl, data.symbolDigits); tp = NormalizeDouble(tp, data.symbolDigits); lots = NormalizeSymbolLot(symbolIndex, lots); if(lots < data.minLot || lots > data.maxLot) return false; //--- Open with retries bool success = false; int attempts = 0; while(attempts < MaxRetries && !success) { ResetLastError(); if(orderType == ORDER_TYPE_BUY) success = trade.Buy(lots, symbol, 0, sl, tp, TradeComment); else success = trade.Sell(lots, symbol, 0, sl, tp, TradeComment); if(success) { Print("Position opened: ", symbol, " ", EnumToString(orderType), " | Lots: ", lots); //--- Track for partial TP if(UsePartialTP && trackedPositionCount < 100) { trackedPositions[trackedPositionCount].ticket = trade.ResultOrder(); trackedPositions[trackedPositionCount].partialTPDone = false; trackedPositionCount++; } return true; } else { int error = GetLastError(); if(IsTransientError(error)) { Sleep(RetryDelayMs); attempts++; } else { break; } } } return false; } //+------------------------------------------------------------------+ //| Calculate Stop Loss for Symbol | //+------------------------------------------------------------------+ double CalculateSymbolStopLoss(int symbolIndex, ENUM_ORDER_TYPE orderType, double price) { SymbolData data = symbolDataArray[symbolIndex]; double slDistance; if(UseATRSizing && data.handleATR != INVALID_HANDLE) { double atrBuf[]; ArraySetAsSeries(atrBuf, true); if(CopyBuffer(data.handleATR, 0, 0, 1, atrBuf) >= 1) { slDistance = atrBuf[0] * ATR_SL_Multiplier; //--- Apply min/max bounds (NEW in v4.0) double slPips = slDistance / data.pipSize; if(slPips < MinSL_Pips) slDistance = MinSL_Pips * data.pipSize; if(slPips > MaxSL_Pips) slDistance = MaxSL_Pips * data.pipSize; } else slDistance = StopLossPips * data.pipSize; } else { slDistance = StopLossPips * data.pipSize; } double sl = (orderType == ORDER_TYPE_BUY) ? price - slDistance : price + slDistance; return sl; } //+------------------------------------------------------------------+ //| Calculate Take Profit for Symbol | //+------------------------------------------------------------------+ double CalculateSymbolTakeProfit(int symbolIndex, ENUM_ORDER_TYPE orderType, double price) { SymbolData data = symbolDataArray[symbolIndex]; double tpDistance; if(UseATRSizing && data.handleATR != INVALID_HANDLE) { double atrBuf[]; ArraySetAsSeries(atrBuf, true); if(CopyBuffer(data.handleATR, 0, 0, 1, atrBuf) >= 1) { tpDistance = atrBuf[0] * ATR_TP_Multiplier; //--- Apply minimum TP (NEW in v4.0) double tpPips = tpDistance / data.pipSize; if(tpPips < (MinSL_Pips * 1.5)) // TP should be at least 1.5x SL minimum tpDistance = (MinSL_Pips * 1.5) * data.pipSize; } else tpDistance = TakeProfitPips * data.pipSize; } else { tpDistance = TakeProfitPips * data.pipSize; } double tp = (orderType == ORDER_TYPE_BUY) ? price + tpDistance : price - tpDistance; return tp; } //+------------------------------------------------------------------+ //| Validate Trade for Symbol | //+------------------------------------------------------------------+ bool ValidateSymbolTrade(int symbolIndex, ENUM_ORDER_TYPE orderType, double price, double sl, double tp) { SymbolData data = symbolDataArray[symbolIndex]; long stopsLevelPoints = SymbolInfoInteger(data.symbol, SYMBOL_TRADE_STOPS_LEVEL); double stopsLevel = stopsLevelPoints * data.point; if(MathAbs(price - sl) < stopsLevel) return false; if(MathAbs(price - tp) < stopsLevel) return false; return true; } //+------------------------------------------------------------------+ //| Calculate Lot Size for Symbol | //+------------------------------------------------------------------+ double CalculateSymbolLotSize(int symbolIndex, double entryPrice, double stopLoss, double riskPercent) { SymbolData data = symbolDataArray[symbolIndex]; if(UseFixedLot) return FixedLotSize; double balance = UseCompounding ? accountInfo.Equity() : accountInfo.Balance(); double riskAmount = balance * (riskPercent / 100.0); double slDistance = MathAbs(entryPrice - stopLoss); if(slDistance <= 0) return data.minLot; double ticksDistance = slDistance / data.tickSize; double riskPerLot = ticksDistance * data.tickValue; if(riskPerLot <= 0) return data.minLot; double lots = riskAmount / riskPerLot; if(lots > MaxLotSize) lots = MaxLotSize; if(lots < MinLotSize) lots = MinLotSize; return lots; } //+------------------------------------------------------------------+ //| Normalize Lot Size for Symbol | //+------------------------------------------------------------------+ double NormalizeSymbolLot(int symbolIndex, double lots) { SymbolData data = symbolDataArray[symbolIndex]; lots = MathRound(lots / data.lotStep) * data.lotStep; if(lots < data.minLot) lots = data.minLot; if(lots > data.maxLot) lots = data.maxLot; return NormalizeDouble(lots, 2); } //+------------------------------------------------------------------+ //| Count Positions for Symbol | //+------------------------------------------------------------------+ int CountSymbolPositions(string symbol) { int count = 0; for(int i = PositionsTotal() - 1; i >= 0; i--) { if(positionInfo.SelectByIndex(i)) { if(positionInfo.Symbol() == symbol && positionInfo.Magic() == MagicNumber) { count++; } } } return count; } //+------------------------------------------------------------------+ //| Count All Positions | //+------------------------------------------------------------------+ int CountAllPositions() { int count = 0; for(int i = PositionsTotal() - 1; i >= 0; i--) { if(positionInfo.SelectByIndex(i)) { if(positionInfo.Magic() == MagicNumber) { count++; } } } return count; } //+------------------------------------------------------------------+ //| Manage Positions for Symbol | //+------------------------------------------------------------------+ void ManageSymbolPositions(string symbol) { for(int i = PositionsTotal() - 1; i >= 0; i--) { if(!positionInfo.SelectByIndex(i)) continue; if(positionInfo.Symbol() != symbol || positionInfo.Magic() != MagicNumber) continue; ulong ticket = positionInfo.Ticket(); double openPrice = positionInfo.PriceOpen(); double currentSL = positionInfo.StopLoss(); double currentTP = positionInfo.TakeProfit(); ENUM_POSITION_TYPE posType = positionInfo.PositionType(); double volume = positionInfo.Volume(); double currentPrice = (posType == POSITION_TYPE_BUY) ? SymbolInfoDouble(symbol, SYMBOL_BID) : SymbolInfoDouble(symbol, SYMBOL_ASK); double pipSize = GetSymbolPipSize(symbol); double profitPips = 0; if(posType == POSITION_TYPE_BUY) profitPips = (currentPrice - openPrice) / pipSize; else profitPips = (openPrice - currentPrice) / pipSize; //--- Partial TP if(UsePartialTP && profitPips >= PartialTP_Pips) { bool alreadyDone = false; for(int j = 0; j < trackedPositionCount; j++) { if(trackedPositions[j].ticket == ticket && trackedPositions[j].partialTPDone) { alreadyDone = true; break; } } if(!alreadyDone) { double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); double closeVolume = MathRound((volume * PartialTP_Percent / 100.0) / minLot) * minLot; if(closeVolume >= minLot && closeVolume < volume) { if(trade.PositionClosePartial(ticket, closeVolume)) { Print("Partial TP: ", symbol, " Ticket ", ticket, " | Closed: ", closeVolume); for(int j = 0; j < trackedPositionCount; j++) { if(trackedPositions[j].ticket == ticket) { trackedPositions[j].partialTPDone = true; break; } } } } } } //--- Breakeven if(UseBreakeven && profitPips >= BreakevenTriggerPips) { double bePrice = openPrice + (BreakevenOffsetPips * pipSize * (posType == POSITION_TYPE_BUY ? 1 : -1)); bool needsUpdate = false; if(posType == POSITION_TYPE_BUY && (currentSL < bePrice || currentSL == 0)) needsUpdate = true; else if(posType == POSITION_TYPE_SELL && (currentSL > bePrice || currentSL == 0)) needsUpdate = true; if(needsUpdate) { int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); bePrice = NormalizeDouble(bePrice, digits); if(trade.PositionModify(ticket, bePrice, currentTP)) { Print("Breakeven: ", symbol, " Ticket ", ticket, " | SL: ", bePrice); } continue; } } //--- Trailing stop if(UseTrailingStop && profitPips >= TrailingActivationPips) { double trailDistance = TrailingStopPips * pipSize; double trailStep = TrailingStepPips * pipSize; double newSL = 0; if(posType == POSITION_TYPE_BUY) { newSL = currentPrice - trailDistance; if(newSL > currentSL + trailStep || currentSL == 0) { int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); newSL = NormalizeDouble(newSL, digits); if(newSL > openPrice) { trade.PositionModify(ticket, newSL, currentTP); } } } else if(posType == POSITION_TYPE_SELL) { newSL = currentPrice + trailDistance; if(newSL < currentSL - trailStep || currentSL == 0) { int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); newSL = NormalizeDouble(newSL, digits); if(newSL < openPrice) { trade.PositionModify(ticket, newSL, currentTP); } } } } } } //+------------------------------------------------------------------+ //| Get Symbol Pip Size | //+------------------------------------------------------------------+ double GetSymbolPipSize(string symbol) { double point = SymbolInfoDouble(symbol, SYMBOL_POINT); int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); if(digits == 3 || digits == 5) return point * 10; else return point; } //+------------------------------------------------------------------+ //| Can Open New Trade for Symbol | //+------------------------------------------------------------------+ bool CanOpenNewTradeForSymbol(int symbolIndex) { SymbolData data = symbolDataArray[symbolIndex]; //--- Check daily trade limit if(dailyTradeCount >= MaxDailyTrades) return false; //--- Check cooldown bool isBuySignal = true; // Will be determined by signal datetime relevantTime = SeparateCooldownByDirection ? (isBuySignal ? data.lastBuyTime : data.lastSellTime) : MathMax(data.lastBuyTime, data.lastSellTime); if((TimeCurrent() - relevantTime) < (CooldownMinutes * 60)) return false; //--- Check post-close cooldown if((TimeCurrent() - data.lastCloseTime) < (PostCloseCooldownMinutes * 60)) return false; //--- Check session filter if(UseSessionFilter && !IsWithinTradingSession()) return false; return true; } //+------------------------------------------------------------------+ //| Check Daily Drawdown Limit | //+------------------------------------------------------------------+ bool CheckDailyDrawdownLimit() { double currentEquity = accountInfo.Equity(); if(startOfDayBalance <= 0) return true; double dailyLoss = startOfDayBalance - currentEquity; double dailyLossPercent = (dailyLoss / startOfDayBalance) * 100.0; if(dailyLossPercent > DailyDrawdownPercent) { Print("Daily drawdown limit hit: ", dailyLossPercent, "% (limit: ", DailyDrawdownPercent, "%)"); return false; } return true; } //+------------------------------------------------------------------+ //| Check Floating Equity Limit | //+------------------------------------------------------------------+ bool CheckFloatingEquityLimit() { double balance = accountInfo.Balance(); double equity = accountInfo.Equity(); if(balance <= 0) return true; double floatingLoss = balance - equity; double floatingLossPercent = (floatingLoss / balance) * 100.0; if(floatingLossPercent > MaxFloatingEquityPercent) { Print("Floating equity limit hit: ", floatingLossPercent, "% (limit: ", MaxFloatingEquityPercent, "%)"); return false; } return true; } //+------------------------------------------------------------------+