//+------------------------------------------------------------------+ //| Multi_Instrument_Trading_EA.mq5 | //| Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #include // Input parameters input double LotSize = 0.1; // Lot size for trading input int MagicNumber = 123456; // Magic number for orders input int MACD_Fast = 12; // MACD Fast EMA period input int MACD_Slow = 26; // MACD Slow EMA period input int MACD_Signal = 9; // MACD Signal period input double MaxSpread = 3.0; // Maximum allowed spread in points input double RiskPercent = 2.0; // Risk per trade as % of account input double MaxDailyLoss = 5.0; // Maximum daily loss % input bool EnableGBPUSD = true; // Enable GBP/USD trading input bool EnableUSDJPY = true; // Enable USD/JPY trading input bool EnableBuyScenario1 = true; // Enable Buy Scenario 1 input bool EnableBuyScenario2 = true; // Enable Buy Scenario 2 input bool EnableSellScenario1 = true; // Enable Sell Scenario 1 input bool EnableSellScenario2 = true; // Enable Sell Scenario 2 // Structure for instrument data struct InstrumentData { string symbol; double entryBuyLevel; double targetLevel; double supportLevel; double sellTarget; double expectedBuyPullback; double expectedSellRebound; int testCount_Support; int testCount_Entry; datetime lastTestTime_Support; datetime lastTestTime_Entry; bool inLongPosition; bool inShortPosition; int macdHandle; }; // Global variables CTrade trade; InstrumentData instruments[2]; double dailyStartBalance; datetime dailyStartTime; // Dynamic arrays for MACD data double macdMain_GBPUSD[], macdSignal_GBPUSD[]; double macdMain_USDJPY[], macdSignal_USDJPY[]; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Initialize instruments int index = 0; if(EnableGBPUSD) { instruments[index].symbol = "GBPUSD"; instruments[index].entryBuyLevel = 1.3600; instruments[index].targetLevel = 1.3641; instruments[index].supportLevel = 1.3566; instruments[index].sellTarget = 1.3521; instruments[index].expectedBuyPullback = 35; // pips instruments[index].expectedSellRebound = 25; // pips // Initialize MACD for GBP/USD instruments[index].macdHandle = iMACD("GBPUSD", PERIOD_CURRENT, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE); if(instruments[index].macdHandle == INVALID_HANDLE) { Print("Error creating MACD indicator for GBPUSD"); return INIT_FAILED; } ArraySetAsSeries(macdMain_GBPUSD, true); ArraySetAsSeries(macdSignal_GBPUSD, true); index++; } if(EnableUSDJPY) { instruments[index].symbol = "USDJPY"; instruments[index].entryBuyLevel = 143.77; instruments[index].targetLevel = 144.26; instruments[index].supportLevel = 143.36; instruments[index].sellTarget = 142.78; instruments[index].expectedBuyPullback = 35; // pips instruments[index].expectedSellRebound = 25; // pips // Initialize MACD for USD/JPY instruments[index].macdHandle = iMACD("USDJPY", PERIOD_CURRENT, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE); if(instruments[index].macdHandle == INVALID_HANDLE) { Print("Error creating MACD indicator for USDJPY"); return INIT_FAILED; } ArraySetAsSeries(macdMain_USDJPY, true); ArraySetAsSeries(macdSignal_USDJPY, true); } // Set trade parameters trade.SetExpertMagicNumber(MagicNumber); trade.SetDeviationInPoints(10); // Initialize daily tracking dailyStartBalance = AccountInfoDouble(ACCOUNT_BALANCE); dailyStartTime = TimeCurrent(); Print("Multi-Instrument Trading EA initialized successfully"); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { for(int i = 0; i < ArraySize(instruments); i++) { if(instruments[i].macdHandle != INVALID_HANDLE) IndicatorRelease(instruments[i].macdHandle); } } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Check daily risk management if(!CheckDailyRiskManagement()) return; // Process each enabled instrument for(int i = 0; i < ArraySize(instruments); i++) { if(instruments[i].symbol == "" || instruments[i].macdHandle == INVALID_HANDLE) continue; // Check spread for this instrument if(!CheckSpread(instruments[i].symbol)) continue; // Update MACD values for this instrument if(!UpdateMACDValues(i)) continue; // Update position status for this instrument UpdatePositionStatus(i); // Check trading scenarios for this instrument if(EnableBuyScenario1) CheckBuyScenario1(i); if(EnableBuyScenario2) CheckBuyScenario2(i); if(EnableSellScenario1) CheckSellScenario1(i); if(EnableSellScenario2) CheckSellScenario2(i); // Check exit conditions for this instrument CheckExitConditions(i); } } //+------------------------------------------------------------------+ //| Check daily risk management | //+------------------------------------------------------------------+ bool CheckDailyRiskManagement() { // Reset daily tracking at new day MqlDateTime timeStruct; TimeToStruct(TimeCurrent(), timeStruct); MqlDateTime startStruct; TimeToStruct(dailyStartTime, startStruct); if(timeStruct.day != startStruct.day) { dailyStartBalance = AccountInfoDouble(ACCOUNT_BALANCE); dailyStartTime = TimeCurrent(); Print("New trading day started. Daily balance reset."); } // Check if daily loss limit exceeded double currentBalance = AccountInfoDouble(ACCOUNT_BALANCE); double dailyLoss = (dailyStartBalance - currentBalance) / dailyStartBalance * 100; if(dailyLoss >= MaxDailyLoss) { Print("Daily loss limit exceeded: ", dailyLoss, "%. Trading stopped for today."); return false; } return true; } //+------------------------------------------------------------------+ //| Check spread for specific instrument | //+------------------------------------------------------------------+ bool CheckSpread(string symbol) { double ask = SymbolInfoDouble(symbol, SYMBOL_ASK); double bid = SymbolInfoDouble(symbol, SYMBOL_BID); double point = SymbolInfoDouble(symbol, SYMBOL_POINT); double spread = (ask - bid) / point; return spread <= MaxSpread; } //+------------------------------------------------------------------+ //| Calculate lot size based on risk management | //+------------------------------------------------------------------+ double CalculateLotSize(string symbol, double entryPrice, double stopLoss) { double balance = AccountInfoDouble(ACCOUNT_BALANCE); double riskAmount = balance * RiskPercent / 100; double point = SymbolInfoDouble(symbol, SYMBOL_POINT); double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP); double stopLossPoints = MathAbs(entryPrice - stopLoss) / point; double lotSize = riskAmount / (stopLossPoints * tickValue); // Round to nearest lot step lotSize = MathFloor(lotSize / lotStep) * lotStep; // Apply limits if(lotSize < minLot) lotSize = minLot; if(lotSize > maxLot) lotSize = maxLot; return lotSize; } //+------------------------------------------------------------------+ //| Update MACD indicator values for specific instrument | //+------------------------------------------------------------------+ bool UpdateMACDValues(int instrumentIndex) { if(instrumentIndex == 0 && instruments[0].symbol == "GBPUSD") // GBP/USD { if(CopyBuffer(instruments[instrumentIndex].macdHandle, 0, 0, 3, macdMain_GBPUSD) < 0 || CopyBuffer(instruments[instrumentIndex].macdHandle, 1, 0, 3, macdSignal_GBPUSD) < 0) { Print("Error copying MACD buffers for GBPUSD"); return false; } } else if(instrumentIndex == 1 && instruments[1].symbol == "USDJPY") // USD/JPY { if(CopyBuffer(instruments[instrumentIndex].macdHandle, 0, 0, 3, macdMain_USDJPY) < 0 || CopyBuffer(instruments[instrumentIndex].macdHandle, 1, 0, 3, macdSignal_USDJPY) < 0) { Print("Error copying MACD buffers for USDJPY"); return false; } } else if(instruments[instrumentIndex].symbol == "GBPUSD") { if(CopyBuffer(instruments[instrumentIndex].macdHandle, 0, 0, 3, macdMain_GBPUSD) < 0 || CopyBuffer(instruments[instrumentIndex].macdHandle, 1, 0, 3, macdSignal_GBPUSD) < 0) { Print("Error copying MACD buffers for GBPUSD"); return false; } } else if(instruments[instrumentIndex].symbol == "USDJPY") { if(CopyBuffer(instruments[instrumentIndex].macdHandle, 0, 0, 3, macdMain_USDJPY) < 0 || CopyBuffer(instruments[instrumentIndex].macdHandle, 1, 0, 3, macdSignal_USDJPY) < 0) { Print("Error copying MACD buffers for USDJPY"); return false; } } return true; } //+------------------------------------------------------------------+ //| Get MACD values for specific instrument | //+------------------------------------------------------------------+ double GetMACDMain(int instrumentIndex, int shift) { if(instruments[instrumentIndex].symbol == "GBPUSD") return macdMain_GBPUSD[shift]; else if(instruments[instrumentIndex].symbol == "USDJPY") return macdMain_USDJPY[shift]; return 0; } double GetMACDSignal(int instrumentIndex, int shift) { if(instruments[instrumentIndex].symbol == "GBPUSD") return macdSignal_GBPUSD[shift]; else if(instruments[instrumentIndex].symbol == "USDJPY") return macdSignal_USDJPY[shift]; return 0; } void UpdatePositionStatus(int instrumentIndex) { instruments[instrumentIndex].inLongPosition = false; instruments[instrumentIndex].inShortPosition = false; for(int i = PositionsTotal() - 1; i >= 0; i--) { if(PositionGetSymbol(i) == instruments[instrumentIndex].symbol && PositionGetInteger(POSITION_MAGIC) == MagicNumber) { if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) instruments[instrumentIndex].inLongPosition = true; else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) instruments[instrumentIndex].inShortPosition = true; } } } //+------------------------------------------------------------------+ //| Check Buy Scenario 1 for specific instrument | //+------------------------------------------------------------------+ void CheckBuyScenario1(int instrumentIndex) { if(instruments[instrumentIndex].inLongPosition) return; string symbol = instruments[instrumentIndex].symbol; double ask = SymbolInfoDouble(symbol, SYMBOL_ASK); double point = SymbolInfoDouble(symbol, SYMBOL_POINT); // Check if price is near entry level (within 5 pips) if(MathAbs(ask - instruments[instrumentIndex].entryBuyLevel) <= 5 * point) { // Check MACD conditions: above zero and rising if(GetMACDMain(instrumentIndex, 0) > 0 && GetMACDMain(instrumentIndex, 0) > GetMACDMain(instrumentIndex, 1)) { // Calculate lot size with risk management double stopLoss = instruments[instrumentIndex].supportLevel; double lotSize = CalculateLotSize(symbol, ask, stopLoss); // Execute buy order if(trade.Buy(lotSize, symbol, ask, stopLoss, instruments[instrumentIndex].targetLevel, "Buy Scenario 1 - " + symbol)) { Print("Buy Scenario 1 executed for ", symbol, " at ", ask, " Lot size: ", lotSize); } } } } //+------------------------------------------------------------------+ //| Check Buy Scenario 2 for specific instrument | //+------------------------------------------------------------------+ void CheckBuyScenario2(int instrumentIndex) { if(instruments[instrumentIndex].inLongPosition) return; string symbol = instruments[instrumentIndex].symbol; double bid = SymbolInfoDouble(symbol, SYMBOL_BID); double ask = SymbolInfoDouble(symbol, SYMBOL_ASK); double point = SymbolInfoDouble(symbol, SYMBOL_POINT); // Check if price is testing support level (within 3 pips) if(MathAbs(bid - instruments[instrumentIndex].supportLevel) <= 3 * point) { // Check if this is a new test (not within last 4 hours) if(TimeCurrent() - instruments[instrumentIndex].lastTestTime_Support > 4 * 3600) { instruments[instrumentIndex].testCount_Support++; instruments[instrumentIndex].lastTestTime_Support = TimeCurrent(); Print("Test #", instruments[instrumentIndex].testCount_Support, " of support level detected for ", symbol); // Determine oversold threshold based on instrument double oversoldThreshold = (symbol == "GBPUSD") ? -0.0005 : -0.0010; // If second test and MACD is oversold if(instruments[instrumentIndex].testCount_Support >= 2 && GetMACDMain(instrumentIndex, 0) < oversoldThreshold) { // Calculate lot size with risk management double stopLoss = instruments[instrumentIndex].supportLevel - 10 * point; double lotSize = CalculateLotSize(symbol, ask, stopLoss); // Execute buy order if(trade.Buy(lotSize, symbol, ask, stopLoss, instruments[instrumentIndex].targetLevel, "Buy Scenario 2 - " + symbol)) { Print("Buy Scenario 2 executed for ", symbol, " at ", ask, " Lot size: ", lotSize); instruments[instrumentIndex].testCount_Support = 0; // Reset counter } } } } // Reset counter if price moves significantly away from level if(MathAbs(bid - instruments[instrumentIndex].supportLevel) > 20 * point) { instruments[instrumentIndex].testCount_Support = 0; } } //+------------------------------------------------------------------+ //| Check Sell Scenario 1 for specific instrument | //+------------------------------------------------------------------+ void CheckSellScenario1(int instrumentIndex) { if(instruments[instrumentIndex].inShortPosition) return; string symbol = instruments[instrumentIndex].symbol; double bid = SymbolInfoDouble(symbol, SYMBOL_BID); double point = SymbolInfoDouble(symbol, SYMBOL_POINT); // Check if price breaks below support level if(bid < instruments[instrumentIndex].supportLevel - 2 * point) { // Check MACD conditions: below zero and declining if(GetMACDMain(instrumentIndex, 0) < 0 && GetMACDMain(instrumentIndex, 0) < GetMACDMain(instrumentIndex, 1)) { // Calculate lot size with risk management double stopLoss = instruments[instrumentIndex].entryBuyLevel; double lotSize = CalculateLotSize(symbol, bid, stopLoss); // Execute sell order if(trade.Sell(lotSize, symbol, bid, stopLoss, instruments[instrumentIndex].sellTarget, "Sell Scenario 1 - " + symbol)) { Print("Sell Scenario 1 executed for ", symbol, " at ", bid, " Lot size: ", lotSize); } } } } //+------------------------------------------------------------------+ //| Check Sell Scenario 2 for specific instrument | //+------------------------------------------------------------------+ void CheckSellScenario2(int instrumentIndex) { if(instruments[instrumentIndex].inShortPosition) return; string symbol = instruments[instrumentIndex].symbol; double ask = SymbolInfoDouble(symbol, SYMBOL_ASK); double bid = SymbolInfoDouble(symbol, SYMBOL_BID); double point = SymbolInfoDouble(symbol, SYMBOL_POINT); // Check if price is testing entry level (within 3 pips) if(MathAbs(ask - instruments[instrumentIndex].entryBuyLevel) <= 3 * point) { // Check if this is a new test (not within last 4 hours) if(TimeCurrent() - instruments[instrumentIndex].lastTestTime_Entry > 4 * 3600) { instruments[instrumentIndex].testCount_Entry++; instruments[instrumentIndex].lastTestTime_Entry = TimeCurrent(); Print("Test #", instruments[instrumentIndex].testCount_Entry, " of entry level detected for ", symbol); // Determine overbought threshold based on instrument double overboughtThreshold = (symbol == "GBPUSD") ? 0.0005 : 0.0010; // If second test and MACD is overbought if(instruments[instrumentIndex].testCount_Entry >= 2 && GetMACDMain(instrumentIndex, 0) > overboughtThreshold) { // Calculate lot size with risk management double stopLoss = instruments[instrumentIndex].entryBuyLevel + 10 * point; double lotSize = CalculateLotSize(symbol, bid, stopLoss); // Execute sell order if(trade.Sell(lotSize, symbol, bid, stopLoss, instruments[instrumentIndex].sellTarget, "Sell Scenario 2 - " + symbol)) { Print("Sell Scenario 2 executed for ", symbol, " at ", bid, " Lot size: ", lotSize); instruments[instrumentIndex].testCount_Entry = 0; // Reset counter } } } } // Reset counter if price moves significantly away from level if(MathAbs(ask - instruments[instrumentIndex].entryBuyLevel) > 20 * point) { instruments[instrumentIndex].testCount_Entry = 0; } } //+------------------------------------------------------------------+ //| Check exit conditions and automatic reversals | //+------------------------------------------------------------------+ void CheckExitConditions(int instrumentIndex) { string symbol = instruments[instrumentIndex].symbol; double bid = SymbolInfoDouble(symbol, SYMBOL_BID); double ask = SymbolInfoDouble(symbol, SYMBOL_ASK); double point = SymbolInfoDouble(symbol, SYMBOL_POINT); for(int i = PositionsTotal() - 1; i >= 0; i--) { if(PositionGetSymbol(i) == symbol && PositionGetInteger(POSITION_MAGIC) == MagicNumber) { ulong ticket = PositionGetInteger(POSITION_TICKET); double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); double currentPrice = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ? bid : ask; // Check long position exit at target if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { if(currentPrice >= instruments[instrumentIndex].targetLevel) { if(trade.PositionClose(ticket)) { Print("Long position closed at target for ", symbol, ": ", currentPrice); // Open automatic reversal short position for pullback double reversalTarget = instruments[instrumentIndex].targetLevel - instruments[instrumentIndex].expectedBuyPullback * point; double stopLoss = instruments[instrumentIndex].targetLevel + 15 * point; double lotSize = CalculateLotSize(symbol, bid, stopLoss); if(trade.Sell(lotSize, symbol, bid, stopLoss, reversalTarget, "Auto Reversal Short - " + symbol)) { Print("Automatic reversal short opened for ", symbol, " expecting ", instruments[instrumentIndex].expectedBuyPullback, " pip pullback"); } } } } // Check short position exit at target else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { if(currentPrice <= instruments[instrumentIndex].sellTarget) { if(trade.PositionClose(ticket)) { Print("Short position closed at target for ", symbol, ": ", currentPrice); // Open automatic reversal long position for rebound double reversalTarget = instruments[instrumentIndex].sellTarget + instruments[instrumentIndex].expectedSellRebound * point; double stopLoss = instruments[instrumentIndex].sellTarget - 15 * point; double lotSize = CalculateLotSize(symbol, ask, stopLoss); if(trade.Buy(lotSize, symbol, ask, stopLoss, reversalTarget, "Auto Reversal Long - " + symbol)) { Print("Automatic reversal long opened for ", symbol, " expecting ", instruments[instrumentIndex].expectedSellRebound, " pip rebound"); } } } } } } } //+------------------------------------------------------------------+ //| Trade transaction function | //+------------------------------------------------------------------+ void OnTradeTransaction(const MqlTradeTransaction& trans, const MqlTradeRequest& request, const MqlTradeResult& result) { // Handle trade events if(trans.type == TRADE_TRANSACTION_DEAL_ADD) { Print("Trade executed: ", trans.symbol, " Volume: ", trans.volume, " Price: ", trans.price, " Type: ", (trans.deal_type == DEAL_TYPE_BUY ? "BUY" : "SELL")); } }