//+------------------------------------------------------------------+ //| ForexTrader_v3.2_Scalper_Production.mq5 | //| High-Frequency Scalping Multi-Symbol EA | //| Optimized for M1/M5 with Tight Stops & Quick Targets | //+------------------------------------------------------------------+ #property copyright "ForexTrader EA v3.2 Scalper - High-Frequency Production" #property link "https://github.com/simonokwundue-ops/Experienced-FX-Trader" #property version "3.21" #property description "High-frequency scalper with momentum and breakout detection" #property description "Designed for M1/M5 timeframes with 5-15 pip stops" #property description "Multiple small positions for frequent profits" #property description "Advanced micro-trend and momentum analysis" #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 }; //+------------------------------------------------------------------+ //| Input Parameters - Multi-Symbol Trading | //+------------------------------------------------------------------+ input group "=== Multi-Symbol Scalping (v3.2) ===" input bool TradeMultipleSymbols = true; // Enable Multi-Symbol Trading input string TradingSymbols = "EURUSD,GBPUSD,USDJPY,AUDUSD"; // High-Liquidity Symbols Only input int MaxPositionsPerSymbol = 3; // Max Positions Per Symbol (Scalping) input bool AllowHedging = true; // Allow Opposite Directions Per Symbol input int MaxTotalPositions = 8; // Max Total Positions (Higher for scalping) input double MaxFloatingEquityPercent = 5.0; // Max Floating Equity Risk (%) //+------------------------------------------------------------------+ //| Input Parameters - Strategy Selection | //+------------------------------------------------------------------+ input group "=== Scalping Strategy Selection ===" input bool UseMAStrategy = true; // Use Fast MA Crossover input bool UseRSIStrategy = true; // Use RSI Momentum input bool UseBBStrategy = true; // Use BB Squeeze/Breakout input bool UseMACDStrategy = true; // Use MACD Momentum input bool UseMomentumFilter = true; // Use Price Momentum Filter input bool UseBreakoutDetection = true; // Use Breakout Detection input int MinSignalScore = 20; // Minimum Signal Score (Lower for scalping) //+------------------------------------------------------------------+ //| Input Parameters - Multi-Timeframe | //+------------------------------------------------------------------+ input group "=== Multi-Timeframe Analysis ===" input bool UseMultiTimeframe = false; // Disable for scalping (faster) input ENUM_TIMEFRAMES TimeFrame1 = PERIOD_M1; // Fast Timeframe (M1) input ENUM_TIMEFRAMES TimeFrame2 = PERIOD_M5; // Medium Timeframe (M5) input ENUM_TIMEFRAMES TimeFrame3 = PERIOD_M15; // Slow Timeframe (M15) input int MinTFConfirmation = 2; // Min Timeframes for Signal (1-3) //+------------------------------------------------------------------+ //| Input Parameters - MA Strategy (Scalping Optimized) | //+------------------------------------------------------------------+ input group "=== Fast Moving Average Scalping ===" input int FastMA_Period = 5; // Fast MA Period (Very fast for scalping) input int SlowMA_Period = 20; // Slow MA Period (Quick reference) input ENUM_MA_METHOD MA_Method = MODE_EMA; // MA Method (EMA recommended) input ENUM_APPLIED_PRICE MA_Price = PRICE_CLOSE; // MA Applied Price input double MA_SlopeMinimum = 2.0; // Min MA Slope (Pips) - Lower for scalping //+------------------------------------------------------------------+ //| 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 - Scalping Filters | //+------------------------------------------------------------------+ input group "=== Scalping Signal Filters ===" input bool UseADXFilter = false; // Disable ADX for scalping (too slow) input int ADX_Period = 14; // ADX Period input double ADX_Minimum = 15.0; // Minimum ADX Level (Lower) input bool UseATRFilter = true; // Use ATR Volatility Filter input int ATR_Period = 14; // ATR Period input double ATR_MinimumPips = 3.0; // Minimum ATR (Pips) - Lower for scalping input double ATR_MaximumPips = 50.0; // Maximum ATR (Pips) - Avoid high volatility //+------------------------------------------------------------------+ //| Input Parameters - Momentum & Breakout | //+------------------------------------------------------------------+ input group "=== Momentum & Breakout Detection ===" input int MomentumBars = 3; // Bars for Momentum Calculation input double MinMomentumPips = 3.0; // Minimum Momentum (Pips) input int BreakoutBars = 5; // Bars for Breakout Detection input double BreakoutMinPips = 5.0; // Minimum Breakout Size (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 Parameters - Position Sizing (Scalping) | //+------------------------------------------------------------------+ input group "=== Scalping Position Sizing ===" input double StopLossPips = 10.0; // Stop Loss (Pips) - Tight for scalping input double TakeProfitPips = 15.0; // Take Profit (Pips) - Quick target input bool UseATRSizing = false; // Disable ATR sizing for consistent scalping input double ATR_SL_Multiplier = 1.0; // ATR Multiplier for SL input double ATR_TP_Multiplier = 1.5; // ATR Multiplier for TP input double MaxSpreadPips = 2.0; // Max Spread (Pips) - Very tight for scalping //+------------------------------------------------------------------+ //| Input Parameters - Position Management (Scalping) | //+------------------------------------------------------------------+ input group "=== Scalping Position Management ===" input bool UseBreakeven = true; // Move to Breakeven input double BreakevenTriggerPips = 5.0; // Breakeven Trigger (Pips) - Quick input double BreakevenOffsetPips = 1.0; // Breakeven Offset (Pips) input bool UsePartialTP = false; // Disable Partial TP for scalping input double PartialTP_Pips = 8.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 = 8.0; // Trailing Distance (Pips) - Tight input double TrailingStepPips = 2.0; // Trailing Step (Pips) - Small steps input double TrailingActivationPips = 6.0; // Trailing Activation (Pips) - Early //+------------------------------------------------------------------+ //| Input Parameters - Trading Controls (Scalping) | //+------------------------------------------------------------------+ input group "=== Scalping Trading Controls ===" input int MaxDailyTrades = 200; // Max Trades Per Day (High for scalping) input int MaxConcurrentPositions = 8; // Max Concurrent Positions input int CooldownMinutes = 0; // Cooldown Between Trades (0 for scalping) input bool SeparateCooldownByDirection = true; // Separate Buy/Sell Cooldown input int PostCloseCooldownMinutes = 0; // Cooldown After Position Close (0 for scalping) //+------------------------------------------------------------------+ //| 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 = 234568; // Magic Number (Different from v3.2) input string TradeComment = "ForexTrader_v3.2_Scalper"; // Trade Comment input int Slippage = 50; // Max Slippage (Points) - Higher for scalping input int MaxRetries = 3; // Max Order Retries input int RetryDelayMs = 500; // Retry Delay (Ms) - Faster //+------------------------------------------------------------------+ //| 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; // Trading state for single-symbol mode (legacy) 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; //+------------------------------------------------------------------+ //| 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); } //--- 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 v3.2 SCALPER - Initialized"); Print("Chart Symbol: ", _Symbol); Print("Scalping Mode: HIGH FREQUENCY"); if(TradeMultipleSymbols) { Print("Multi-Symbol Scalping: ENABLED"); Print("Trading Symbols: ", totalSymbols); Print("Max Positions Per Symbol: ", MaxPositionsPerSymbol); Print("Max Total Positions: ", MaxTotalPositions); } else { Print("Single Symbol Scalping: ", _Symbol); } Print("Active Strategies: ", CountActiveStrategies()); Print("Momentum Filter: ", UseMomentumFilter ? "ON" : "OFF"); Print("Breakout Detection: ", UseBreakoutDetection ? "ON" : "OFF"); Print("Min Signal Score: ", MinSignalScore, " (Scalping optimized)"); Print("Stop Loss: ", StopLossPips, " pips | Take Profit: ", TakeProfitPips, " pips"); Print("Daily Drawdown Limit: ", DailyDrawdownPercent, "%"); Print("Max Floating Equity: ", MaxFloatingEquityPercent, "%"); Print("Max Daily Trades: ", MaxDailyTrades); 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 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() { //--- 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 | //+------------------------------------------------------------------+ void CheckEntrySignals() { //--- Check basic filters if(!IsSpreadAcceptable()) return; if(UseATRFilter && !IsVolatilityAcceptable()) return; if(UseADXFilter && !IsTrendStrong()) return; //--- Generate signals from each strategy int buySignalScore = 0; int sellSignalScore = 0; string buyReasons = ""; string sellReasons = ""; //--- MA Strategy if(UseMAStrategy) { int maScore = AnalyzeMAStrategy(buyReasons, sellReasons); if(maScore > 0) buySignalScore += maScore; if(maScore < 0) sellSignalScore += MathAbs(maScore); } //--- RSI Strategy if(UseRSIStrategy) { int rsiScore = AnalyzeRSIStrategy(buyReasons, sellReasons); if(rsiScore > 0) buySignalScore += rsiScore; if(rsiScore < 0) sellSignalScore += MathAbs(rsiScore); } //--- BB Strategy if(UseBBStrategy) { int bbScore = AnalyzeBBStrategy(buyReasons, sellReasons); if(bbScore > 0) buySignalScore += bbScore; if(bbScore < 0) sellSignalScore += MathAbs(bbScore); } //--- MACD Strategy if(UseMACDStrategy) { int macdScore = AnalyzeMACDStrategy(buyReasons, sellReasons); if(macdScore > 0) buySignalScore += macdScore; if(macdScore < 0) sellSignalScore += MathAbs(macdScore); } //--- 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 | "; } } //--- Process buy signal if(buySignalScore >= MinSignalScore && IsCooldownElapsed(true)) { Print("=== BUY SIGNAL | Score: ", buySignalScore, " ==="); 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 >= MinSignalScore && IsCooldownElapsed(false)) { Print("=== SELL SIGNAL | Score: ", sellSignalScore, " ==="); Print("Reasons: ", sellReasons); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(OpenPosition(ORDER_TYPE_SELL, bid, STRATEGY_MA)) { lastSellTime = TimeCurrent(); dailyTradeCount++; } } } //+------------------------------------------------------------------+ //| Analyze MA Strategy | //+------------------------------------------------------------------+ 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]; if(!bullishCross && !bearishCross) return 0; //--- Check MA slope double maSlope = MathAbs(fastMA[1] - fastMA[2]) / pipSize; if(maSlope < MA_SlopeMinimum) return 0; //--- Calculate score int score = 30; // Base score if(bullishCross) { buyReasons += "MA Bullish Cross | "; return score; } else if(bearishCross) { sellReasons += "MA Bearish Cross | "; 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; } //+------------------------------------------------------------------+ //| 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 | //+------------------------------------------------------------------+ double CalculateStopLoss(ENUM_ORDER_TYPE orderType, double price) { double slDistance; if(UseATRSizing && ArraySize(atrBuffer) > 0) { slDistance = atrBuffer[0] * ATR_SL_Multiplier; } else { slDistance = StopLossPips * pipSize; } double sl = (orderType == ORDER_TYPE_BUY) ? price - slDistance : price + slDistance; return sl; } //+------------------------------------------------------------------+ //| Calculate Take Profit | //+------------------------------------------------------------------+ double CalculateTakeProfit(ENUM_ORDER_TYPE orderType, double price) { double tpDistance; if(UseATRSizing && ArraySize(atrBuffer) > 0) { tpDistance = atrBuffer[0] * ATR_TP_Multiplier; } 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 (local variables with distinct names) double symFastMA[], symSlowMA[], symAtrBuf[], symAdxBuf[], symRsiBuf[]; double symBbUpper[], symBbMiddle[], symBbLower[]; double symMacdMain[], symMacdSignal[]; ArraySetAsSeries(symFastMA, true); ArraySetAsSeries(symSlowMA, true); ArraySetAsSeries(symAtrBuf, true); ArraySetAsSeries(symAdxBuf, true); ArraySetAsSeries(symRsiBuf, true); ArraySetAsSeries(symBbUpper, true); ArraySetAsSeries(symBbMiddle, true); ArraySetAsSeries(symBbLower, true); ArraySetAsSeries(symMacdMain, true); ArraySetAsSeries(symMacdSignal, true); //--- Copy indicator data if(UseMAStrategy) { if(CopyBuffer(data.handleFastMA, 0, 0, 3, symFastMA) < 3) return; if(CopyBuffer(data.handleSlowMA, 0, 0, 3, symSlowMA) < 3) return; } if(UseATRFilter) { if(CopyBuffer(data.handleATR, 0, 0, 1, symAtrBuf) < 1) return; } if(UseADXFilter) { if(CopyBuffer(data.handleADX, 0, 0, 1, symAdxBuf) < 1) return; } if(UseRSIStrategy) { if(CopyBuffer(data.handleRSI, 0, 0, 2, symRsiBuf) < 2) return; } if(UseBBStrategy) { if(CopyBuffer(data.handleBB, 0, 0, 2, symBbUpper) < 2) return; if(CopyBuffer(data.handleBB, 1, 0, 2, symBbMiddle) < 2) return; if(CopyBuffer(data.handleBB, 2, 0, 2, symBbLower) < 2) return; } if(UseMACDStrategy) { if(CopyBuffer(data.handleMACD, 0, 0, 3, symMacdMain) < 3) return; if(CopyBuffer(data.handleMACD, 1, 0, 3, symMacdSignal) < 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(symAtrBuf) > 0) { double atrPips = symAtrBuf[0] / data.pipSize; if(atrPips < ATR_MinimumPips || atrPips > ATR_MaximumPips) return; } if(UseADXFilter && ArraySize(symAdxBuf) > 0) { if(symAdxBuf[0] < ADX_Minimum) return; } //--- Generate signals int buySignalScore = 0; int sellSignalScore = 0; string buyReasons = ""; string sellReasons = ""; //--- Momentum Filter (Scalping specific) if(UseMomentumFilter) { int momentum = CheckMomentum(symbol, data.pipSize); if(momentum > 0) { buySignalScore += 15; buyReasons += "Bullish Momentum | "; } else if(momentum < 0) { sellSignalScore += 15; sellReasons += "Bearish Momentum | "; } } //--- Breakout Detection (Scalping specific) if(UseBreakoutDetection) { int breakout = CheckBreakout(symbol, data.pipSize); if(breakout > 0) { buySignalScore += 20; buyReasons += "Bullish Breakout | "; } else if(breakout < 0) { sellSignalScore += 20; sellReasons += "Bearish Breakout | "; } } //--- MA Strategy if(UseMAStrategy && ArraySize(symFastMA) >= 3) { bool bullishCross = symFastMA[1] > symSlowMA[1] && symFastMA[2] <= symSlowMA[2]; bool bearishCross = symFastMA[1] < symSlowMA[1] && symFastMA[2] >= symSlowMA[2]; if(bullishCross) { double maSlope = MathAbs(symFastMA[1] - symFastMA[2]) / data.pipSize; if(maSlope >= MA_SlopeMinimum) { buySignalScore += 30; buyReasons += "MA Bullish | "; } } else if(bearishCross) { double maSlope = MathAbs(symFastMA[1] - symFastMA[2]) / data.pipSize; if(maSlope >= MA_SlopeMinimum) { sellSignalScore += 30; sellReasons += "MA Bearish | "; } } } //--- RSI Strategy if(UseRSIStrategy && ArraySize(symRsiBuf) >= 2) { if(symRsiBuf[1] < RSI_Oversold && symRsiBuf[0] > RSI_Oversold) { buySignalScore += 25; buyReasons += "RSI Oversold Bounce | "; } if(symRsiBuf[1] > RSI_Overbought && symRsiBuf[0] < RSI_Overbought) { sellSignalScore += 25; sellReasons += "RSI Overbought Fall | "; } } //--- BB Strategy if(UseBBStrategy && ArraySize(symBbLower) >= 2) { double close = iClose(symbol, PERIOD_CURRENT, 0); double closePrev = iClose(symbol, PERIOD_CURRENT, 1); if(closePrev <= symBbLower[1] && close > symBbLower[0]) { buySignalScore += 25; buyReasons += "BB Lower Bounce | "; } if(closePrev >= symBbUpper[1] && close < symBbUpper[0]) { sellSignalScore += 25; sellReasons += "BB Upper Fall | "; } } //--- MACD Strategy if(UseMACDStrategy && ArraySize(symMacdMain) >= 3) { if(symMacdMain[1] > symMacdSignal[1] && symMacdMain[2] <= symMacdSignal[2]) { buySignalScore += 20; buyReasons += "MACD Bullish | "; } if(symMacdMain[1] < symMacdSignal[1] && symMacdMain[2] >= symMacdSignal[2]) { sellSignalScore += 20; sellReasons += "MACD Bearish | "; } } //--- Process buy signal if(buySignalScore >= MinSignalScore) { Print("=== BUY SIGNAL [", symbol, "] | Score: ", buySignalScore, " ==="); Print("Reasons: ", buyReasons); if(OpenSymbolPosition(symbolIndex, ORDER_TYPE_BUY)) { data.lastBuyTime = TimeCurrent(); symbolDataArray[symbolIndex] = data; dailyTradeCount++; } } //--- Process sell signal if(sellSignalScore >= MinSignalScore) { Print("=== SELL SIGNAL [", symbol, "] | Score: ", sellSignalScore, " ==="); 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; 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; 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 symPipSize = GetSymbolPipSize(symbol); double profitPips = 0; if(posType == POSITION_TYPE_BUY) profitPips = (currentPrice - openPrice) / symPipSize; else profitPips = (openPrice - currentPrice) / symPipSize; //--- 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 symMinLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); double closeVolume = MathRound((volume * PartialTP_Percent / 100.0) / symMinLot) * symMinLot; if(closeVolume >= symMinLot && 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 symPoint = SymbolInfoDouble(symbol, SYMBOL_POINT); int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); if(digits == 3 || digits == 5) return symPoint * 10; else return symPoint; } //+------------------------------------------------------------------+ //| Check Price Momentum (Scalping) | //+------------------------------------------------------------------+ int CheckMomentum(string symbol, double symbolPipSize) { double closePrices[]; ArraySetAsSeries(closePrices, true); int bars = MomentumBars + 1; if(CopyClose(symbol, PERIOD_CURRENT, 0, bars, closePrices) < bars) return 0; //--- Calculate momentum (price change over MomentumBars) double momentum = (closePrices[0] - closePrices[MomentumBars]) / symbolPipSize; //--- Strong bullish momentum if(momentum >= MinMomentumPips) return 1; //--- Strong bearish momentum if(momentum <= -MinMomentumPips) return -1; return 0; } //+------------------------------------------------------------------+ //| Check Breakout (Scalping) | //+------------------------------------------------------------------+ int CheckBreakout(string symbol, double symbolPipSize) { double highPrices[], lowPrices[]; double closePrices[]; ArraySetAsSeries(highPrices, true); ArraySetAsSeries(lowPrices, true); ArraySetAsSeries(closePrices, true); int bars = BreakoutBars + 1; if(CopyHigh(symbol, PERIOD_CURRENT, 0, bars, highPrices) < bars) return 0; if(CopyLow(symbol, PERIOD_CURRENT, 0, bars, lowPrices) < bars) return 0; if(CopyClose(symbol, PERIOD_CURRENT, 0, 2, closePrices) < 2) return 0; //--- Find recent high/low (excluding current bar) double recentHigh = highPrices[1]; double recentLow = lowPrices[1]; for(int i = 2; i <= BreakoutBars; i++) { if(highPrices[i] > recentHigh) recentHigh = highPrices[i]; if(lowPrices[i] < recentLow) recentLow = lowPrices[i]; } //--- Check for bullish breakout double breakoutSize = (closePrices[0] - recentHigh) / symbolPipSize; if(breakoutSize >= BreakoutMinPips) return 1; //--- Check for bearish breakout breakoutSize = (recentLow - closePrices[0]) / symbolPipSize; if(breakoutSize >= BreakoutMinPips) return -1; return 0; } //+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+