//+------------------------------------------------------------------+ //| UnitedEA.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" #property description "United EA - Runs multiple strategies on multiple instruments with instrument-specific parameters" #include #include "MagicNumberHelpers.mqh" //--- Strategy Selection input bool EnableRSIScalping = true; // Enable RSI Scalping Strategy input bool EnableMeanReversion = true; // Enable Mean Reversion Strategy input bool EnableDarvasBox = true; // Enable Darvas Box Strategy input bool EnableRSICrossOver = true; // Enable RSI Crossover Strategy input bool EnableRSIMidPoint = true; // Enable RSI Midpoint Strategy //--- Instrument Selection for RSI Scalping (each with its own parameters) input bool EnableRSI_XAUUSD = true; // Enable RSI Scalping on XAUUSD input bool EnableRSI_APPL = true; // Enable RSI Scalping on APPL input bool EnableRSI_BTCUSD = true; // Enable RSI Scalping on BTCUSD input bool EnableRSI_MSFT = true; // Enable RSI Scalping on MSFT input bool EnableRSI_NVDA = true; // Enable RSI Scalping on NVDA input bool EnableRSI_TSLA = true; // Enable RSI Scalping on TSLA //--- Magic Numbers for RSI Scalping (one per instrument) input int MagicNumber_RSI_XAUUSD = 129102315; // Magic Number for RSI Scalping XAUUSD input int MagicNumber_RSI_APPL = 123457; // Magic Number for RSI Scalping APPL input int MagicNumber_RSI_BTCUSD = 123459123; // Magic Number for RSI Scalping BTCUSD input int MagicNumber_RSI_MSFT = 123456; // Magic Number for RSI Scalping MSFT input int MagicNumber_RSI_NVDA = 12345; // Magic Number for RSI Scalping NVDA input int MagicNumber_RSI_TSLA = 125421321; // Magic Number for RSI Scalping TSLA //--- Magic Numbers for Other Strategies input int MagicNumber_MeanReversion = 12351; // Magic Number for Mean Reversion input int MagicNumber_DarvasBox = 135790; // Magic Number for Darvas Box input int MagicNumber_RSICrossOver = 123456; // Magic Number for RSI Crossover input int MagicNumber_RSIMidPoint = 123457; // Magic Number for RSI Midpoint //--- RSI Scalping Parameters: XAUUSD input ENUM_TIMEFRAMES RSI_XAUUSD_TimeFrame = PERIOD_H1; input int RSI_XAUUSD_Period = 14; input double RSI_XAUUSD_Overbought = 71; input double RSI_XAUUSD_Oversold = 57; input double RSI_XAUUSD_Target_Buy = 80; input double RSI_XAUUSD_Target_Sell = 57; input int RSI_XAUUSD_BarsToWait = 4; input double RSI_XAUUSD_LotSize = 0.1; //--- RSI Scalping Parameters: APPL input ENUM_TIMEFRAMES RSI_APPL_TimeFrame = PERIOD_M10; input int RSI_APPL_Period = 14; input double RSI_APPL_Overbought = 80; input double RSI_APPL_Oversold = 78; input double RSI_APPL_Target_Buy = 94; input double RSI_APPL_Target_Sell = 44; input int RSI_APPL_BarsToWait = 7; input double RSI_APPL_LotSize = 25; //--- RSI Scalping Parameters: BTCUSD input ENUM_TIMEFRAMES RSI_BTCUSD_TimeFrame = PERIOD_H1; input int RSI_BTCUSD_Period = 14; input double RSI_BTCUSD_Overbought = 90; input double RSI_BTCUSD_Oversold = 73; input double RSI_BTCUSD_Target_Buy = 88; input double RSI_BTCUSD_Target_Sell = 48; input int RSI_BTCUSD_BarsToWait = 6; input double RSI_BTCUSD_LotSize = 0.1; //--- RSI Scalping Parameters: MSFT input ENUM_TIMEFRAMES RSI_MSFT_TimeFrame = PERIOD_H3; input int RSI_MSFT_Period = 14; input double RSI_MSFT_Overbought = 19; input double RSI_MSFT_Oversold = 50; input double RSI_MSFT_Target_Buy = 71; input double RSI_MSFT_Target_Sell = 70; input int RSI_MSFT_BarsToWait = 1; input double RSI_MSFT_LotSize = 5; //--- RSI Scalping Parameters: NVDA input ENUM_TIMEFRAMES RSI_NVDA_TimeFrame = PERIOD_M15; input int RSI_NVDA_Period = 8; input double RSI_NVDA_Overbought = 36; input double RSI_NVDA_Oversold = 38; input double RSI_NVDA_Target_Buy = 90; input double RSI_NVDA_Target_Sell = 70; input int RSI_NVDA_BarsToWait = 5; input double RSI_NVDA_LotSize = 5; //--- RSI Scalping Parameters: TSLA input ENUM_TIMEFRAMES RSI_TSLA_TimeFrame = PERIOD_H1; input int RSI_TSLA_Period = 14; input double RSI_TSLA_Overbought = 54; input double RSI_TSLA_Oversold = 73; input double RSI_TSLA_Target_Buy = 87; input double RSI_TSLA_Target_Sell = 33; input int RSI_TSLA_BarsToWait = 1; input double RSI_TSLA_LotSize = 5; //--- Mean Reversion Parameters input int EMA_Periode = 46; input double PreisSchwelle = 600.0; input double SteigungSchwelle = 80.0; input int ÜberwachungTimeout = 800; input double TrailingStop = 260.0; input double MeanRev_LotSize = 0.03; input ENUM_TIMEFRAMES MeanRev_Timeframe = PERIOD_H1; //--- Structure for RSI Scalping Strategy Instance struct RSIScalpingStrategy { string symbol; int magic_number; ENUM_TIMEFRAMES timeframe; int period; double overbought; double oversold; double target_buy; double target_sell; int bars_to_wait; double lot_size; int rsi_handle; double rsi_buffer[]; ulong position_ticket; bool position_open; bool buy_position_open; bool sell_position_open; datetime last_bar_time; bool rsi_against_position; int bars_against_count; ENUM_POSITION_TYPE current_position_type; }; //--- Global variables CTrade trade; RSIScalpingStrategy rsi_strategies[6]; // Array for 6 instruments int rsi_strategy_count = 0; int ema_handle_meanrev = INVALID_HANDLE; double ema_array[]; ulong meanrev_ticket = 0; bool meanrev_position_open = false; datetime last_bar_time_meanrev = 0; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Initialize trade object trade.SetDeviationInPoints(10); trade.SetTypeFilling(ORDER_FILLING_FOK); // Initialize RSI Scalping strategies for each enabled instrument if(EnableRSIScalping) { if(EnableRSI_XAUUSD) { InitializeRSIStrategy("XAUUSD", MagicNumber_RSI_XAUUSD, RSI_XAUUSD_TimeFrame, RSI_XAUUSD_Period, RSI_XAUUSD_Overbought, RSI_XAUUSD_Oversold, RSI_XAUUSD_Target_Buy, RSI_XAUUSD_Target_Sell, RSI_XAUUSD_BarsToWait, RSI_XAUUSD_LotSize); } if(EnableRSI_APPL) { // Try different symbol variations for Apple (Pepperstone typically uses AAPL without suffix) // Try: AAPL, AAPL.US, APPL (in case of typo in broker) string appl_symbol = GetValidSymbol("AAPL", "AAPL.US"); if(appl_symbol != "") { InitializeRSIStrategy(appl_symbol, MagicNumber_RSI_APPL, RSI_APPL_TimeFrame, RSI_APPL_Period, RSI_APPL_Overbought, RSI_APPL_Oversold, RSI_APPL_Target_Buy, RSI_APPL_Target_Sell, RSI_APPL_BarsToWait, RSI_APPL_LotSize); } else { Print("Skipping AAPL strategy - symbol not available"); } } if(EnableRSI_BTCUSD) { InitializeRSIStrategy("BTCUSD", MagicNumber_RSI_BTCUSD, RSI_BTCUSD_TimeFrame, RSI_BTCUSD_Period, RSI_BTCUSD_Overbought, RSI_BTCUSD_Oversold, RSI_BTCUSD_Target_Buy, RSI_BTCUSD_Target_Sell, RSI_BTCUSD_BarsToWait, RSI_BTCUSD_LotSize); } if(EnableRSI_MSFT) { // Pepperstone typically uses MSFT without suffix string msft_symbol = GetValidSymbol("MSFT", "MSFT.US"); if(msft_symbol != "") { InitializeRSIStrategy(msft_symbol, MagicNumber_RSI_MSFT, RSI_MSFT_TimeFrame, RSI_MSFT_Period, RSI_MSFT_Overbought, RSI_MSFT_Oversold, RSI_MSFT_Target_Buy, RSI_MSFT_Target_Sell, RSI_MSFT_BarsToWait, RSI_MSFT_LotSize); } else { Print("Skipping MSFT strategy - symbol not available"); } } if(EnableRSI_NVDA) { // Pepperstone typically uses NVDA without suffix string nvda_symbol = GetValidSymbol("NVDA", "NVDA.US"); if(nvda_symbol != "") { InitializeRSIStrategy(nvda_symbol, MagicNumber_RSI_NVDA, RSI_NVDA_TimeFrame, RSI_NVDA_Period, RSI_NVDA_Overbought, RSI_NVDA_Oversold, RSI_NVDA_Target_Buy, RSI_NVDA_Target_Sell, RSI_NVDA_BarsToWait, RSI_NVDA_LotSize); } else { Print("Skipping NVDA strategy - symbol not available"); } } if(EnableRSI_TSLA) { // Pepperstone typically uses TSLA without suffix string tsla_symbol = GetValidSymbol("TSLA", "TSLA.US"); if(tsla_symbol != "") { InitializeRSIStrategy(tsla_symbol, MagicNumber_RSI_TSLA, RSI_TSLA_TimeFrame, RSI_TSLA_Period, RSI_TSLA_Overbought, RSI_TSLA_Oversold, RSI_TSLA_Target_Buy, RSI_TSLA_Target_Sell, RSI_TSLA_BarsToWait, RSI_TSLA_LotSize); } else { Print("Skipping TSLA strategy - symbol not available"); } } } // Initialize Mean Reversion indicator if(EnableMeanReversion) { ema_handle_meanrev = iMA(_Symbol, MeanRev_Timeframe, EMA_Periode, 0, MODE_EMA, PRICE_CLOSE); if(ema_handle_meanrev == INVALID_HANDLE) { Print("Error: Failed to create EMA indicator for Mean Reversion"); return(INIT_FAILED); } ArraySetAsSeries(ema_array, true); trade.SetExpertMagicNumber(MagicNumber_MeanReversion); Print("Mean Reversion Strategy initialized with Magic: ", MagicNumber_MeanReversion); } Print("United EA initialized successfully"); Print("Active RSI Scalping Strategies: ", rsi_strategy_count); for(int i = 0; i < rsi_strategy_count; i++) { Print(" - ", rsi_strategies[i].symbol, " (Magic: ", rsi_strategies[i].magic_number, ", TF: ", EnumToString(rsi_strategies[i].timeframe), ")"); } if(EnableMeanReversion) Print(" - Mean Reversion (Magic: ", MagicNumber_MeanReversion, ")"); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Get valid symbol name (try variations) | //+------------------------------------------------------------------+ string GetValidSymbol(string preferred, string fallback) { string symbols_to_try[]; ArrayResize(symbols_to_try, 0); // Build list of symbols to try ArrayResize(symbols_to_try, 1); symbols_to_try[0] = preferred; if(fallback != preferred) { ArrayResize(symbols_to_try, 2); symbols_to_try[1] = fallback; } // If preferred has .US, also try without it if(StringFind(preferred, ".US") >= 0) { string without_suffix = preferred; StringReplace(without_suffix, ".US", ""); if(without_suffix != fallback) { int size = ArraySize(symbols_to_try); ArrayResize(symbols_to_try, size + 1); symbols_to_try[size] = without_suffix; } } // Try each symbol variation for(int i = 0; i < ArraySize(symbols_to_try); i++) { string test_symbol = symbols_to_try[i]; // Try to select the symbol if(!SymbolSelect(test_symbol, true)) { // Symbol might already be selected, check if it exists if(!SymbolInfoInteger(test_symbol, SYMBOL_SELECT)) { continue; // Symbol doesn't exist, try next } } // Verify symbol is visible if(SymbolInfoInteger(test_symbol, SYMBOL_VISIBLE)) { // Check if we can get price data (symbol is really available) // During initialization, prices might be 0 if symbol is still synchronizing // So we'll be lenient and accept the symbol if it's visible double bid = SymbolInfoDouble(test_symbol, SYMBOL_BID); double ask = SymbolInfoDouble(test_symbol, SYMBOL_ASK); // Accept symbol if it has valid prices OR if it's visible (might be syncing) if((bid > 0 && ask > 0) || SymbolInfoInteger(test_symbol, SYMBOL_VISIBLE)) { if(bid > 0 && ask > 0) { Print("Using symbol: ", test_symbol, " (Bid: ", bid, ", Ask: ", ask, ")"); } else { Print("Using symbol: ", test_symbol, " (synchronizing, prices not yet available)"); } return test_symbol; } } } Print("Error: Could not find valid symbol for ", preferred, " or ", fallback); Print("Tried ", ArraySize(symbols_to_try), " symbol variations:"); for(int i = 0; i < ArraySize(symbols_to_try); i++) { Print(" ", (i+1), ". ", symbols_to_try[i]); } Print("These symbols may not be available in your broker's symbol list."); Print("Please add the symbol to Market Watch or disable this strategy."); return ""; // Return empty string to indicate failure } //+------------------------------------------------------------------+ //| Initialize RSI Scalping Strategy for an instrument | //+------------------------------------------------------------------+ void InitializeRSIStrategy(string symbol, int magic, ENUM_TIMEFRAMES tf, int period, double overbought, double oversold, double target_buy, double target_sell, int bars_wait, double lot_size) { if(rsi_strategy_count >= 6) { Print("Error: Maximum 6 RSI strategies allowed"); return; } // Work directly with array element (no reference) rsi_strategies[rsi_strategy_count].symbol = symbol; rsi_strategies[rsi_strategy_count].magic_number = magic; rsi_strategies[rsi_strategy_count].timeframe = tf; rsi_strategies[rsi_strategy_count].period = period; rsi_strategies[rsi_strategy_count].overbought = overbought; rsi_strategies[rsi_strategy_count].oversold = oversold; rsi_strategies[rsi_strategy_count].target_buy = target_buy; rsi_strategies[rsi_strategy_count].target_sell = target_sell; rsi_strategies[rsi_strategy_count].bars_to_wait = bars_wait; rsi_strategies[rsi_strategy_count].lot_size = lot_size; rsi_strategies[rsi_strategy_count].position_ticket = 0; rsi_strategies[rsi_strategy_count].position_open = false; rsi_strategies[rsi_strategy_count].buy_position_open = false; rsi_strategies[rsi_strategy_count].sell_position_open = false; rsi_strategies[rsi_strategy_count].last_bar_time = 0; rsi_strategies[rsi_strategy_count].rsi_against_position = false; rsi_strategies[rsi_strategy_count].bars_against_count = 0; rsi_strategies[rsi_strategy_count].current_position_type = WRONG_VALUE; // Ensure symbol is selected before creating indicator if(!SymbolSelect(symbol, true)) { // Symbol might already be selected, check if it exists if(!SymbolInfoInteger(symbol, SYMBOL_SELECT)) { Print("Error: Failed to select symbol ", symbol, " for RSI indicator"); Print("Please ensure the symbol exists in Market Watch or add it manually"); return; } } // Verify symbol is visible (prices might be 0 during synchronization) if(!SymbolInfoInteger(symbol, SYMBOL_VISIBLE)) { Print("Error: Symbol ", symbol, " is not visible"); Print("Please add the symbol to Market Watch"); return; } // Check prices (but don't fail if they're 0 - symbol might be syncing) double bid = SymbolInfoDouble(symbol, SYMBOL_BID); double ask = SymbolInfoDouble(symbol, SYMBOL_ASK); if(bid <= 0 || ask <= 0) { Print("Warning: Symbol ", symbol, " has no prices yet (Bid: ", bid, ", Ask: ", ask, ")"); Print("Symbol may be synchronizing. Will attempt to create indicator anyway..."); } // Create RSI indicator for this symbol rsi_strategies[rsi_strategy_count].rsi_handle = iRSI(symbol, tf, period, PRICE_CLOSE); if(rsi_strategies[rsi_strategy_count].rsi_handle == INVALID_HANDLE) { int error = GetLastError(); Print("Error: Failed to create RSI indicator for ", symbol, " (Error: ", error, ")"); Print("Symbol: ", symbol, ", Timeframe: ", EnumToString(tf), ", Period: ", period); Print("Please check if the symbol is available in your broker's symbol list"); return; } ArraySetAsSeries(rsi_strategies[rsi_strategy_count].rsi_buffer, true); rsi_strategy_count++; Print("RSI Scalping Strategy initialized for ", symbol, " (Magic: ", magic, ", TF: ", EnumToString(tf), ")"); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // Release all RSI indicators for(int i = 0; i < rsi_strategy_count; i++) { if(rsi_strategies[i].rsi_handle != INVALID_HANDLE) IndicatorRelease(rsi_strategies[i].rsi_handle); } if(ema_handle_meanrev != INVALID_HANDLE) IndicatorRelease(ema_handle_meanrev); Print("United EA deinitialized"); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Run RSI Scalping Strategies for all enabled instruments if(EnableRSIScalping) { for(int i = 0; i < rsi_strategy_count; i++) { RunRSIScalpingStrategy(i); } } // Run Mean Reversion Strategy if(EnableMeanReversion) { RunMeanReversionStrategy(); } } //+------------------------------------------------------------------+ //| RSI Scalping Strategy for a specific instrument (by index) | //+------------------------------------------------------------------+ void RunRSIScalpingStrategy(int strategy_index) { // Access strategy by index (no reference needed) // Check if we have enough bars if(Bars(rsi_strategies[strategy_index].symbol, rsi_strategies[strategy_index].timeframe) < rsi_strategies[strategy_index].period + 2) return; // Check if this is a new bar datetime current_bar_time = iTime(rsi_strategies[strategy_index].symbol, rsi_strategies[strategy_index].timeframe, 0); if(current_bar_time == rsi_strategies[strategy_index].last_bar_time) return; rsi_strategies[strategy_index].last_bar_time = current_bar_time; // Update RSI values if(CopyBuffer(rsi_strategies[strategy_index].rsi_handle, 0, 0, 3, rsi_strategies[strategy_index].rsi_buffer) < 3) return; double rsi_current = rsi_strategies[strategy_index].rsi_buffer[0]; double rsi_prev = rsi_strategies[strategy_index].rsi_buffer[1]; double rsi_two_bars_ago = rsi_strategies[strategy_index].rsi_buffer[2]; // Set magic number for this strategy trade.SetExpertMagicNumber(rsi_strategies[strategy_index].magic_number); // Check if position exists (regardless of flag state - handles EA restart) bool position_exists = PositionExistsByMagic(rsi_strategies[strategy_index].symbol, rsi_strategies[strategy_index].magic_number); if(position_exists) { // Get actual position type and ticket ulong ticket = GetPositionTicketByMagic(rsi_strategies[strategy_index].symbol, rsi_strategies[strategy_index].magic_number); ENUM_POSITION_TYPE pos_type = GetPositionTypeByMagic(rsi_strategies[strategy_index].symbol, rsi_strategies[strategy_index].magic_number); if(ticket == 0 || pos_type == WRONG_VALUE) { // Position doesn't exist or invalid rsi_strategies[strategy_index].position_open = false; rsi_strategies[strategy_index].buy_position_open = false; rsi_strategies[strategy_index].sell_position_open = false; rsi_strategies[strategy_index].position_ticket = 0; rsi_strategies[strategy_index].rsi_against_position = false; rsi_strategies[strategy_index].bars_against_count = 0; return; } // Update position tracking with fine-grained flags rsi_strategies[strategy_index].position_ticket = ticket; rsi_strategies[strategy_index].position_open = true; rsi_strategies[strategy_index].current_position_type = pos_type; if(pos_type == POSITION_TYPE_BUY) { rsi_strategies[strategy_index].buy_position_open = true; rsi_strategies[strategy_index].sell_position_open = false; } else if(pos_type == POSITION_TYPE_SELL) { rsi_strategies[strategy_index].buy_position_open = false; rsi_strategies[strategy_index].sell_position_open = true; } // Verify position still exists with correct ticket, symbol, and magic number if(!PositionSelectByTicketSymbolAndMagic(rsi_strategies[strategy_index].position_ticket, rsi_strategies[strategy_index].symbol, rsi_strategies[strategy_index].magic_number)) { // Position was closed externally or doesn't match this instrument, reset tracking rsi_strategies[strategy_index].position_open = false; rsi_strategies[strategy_index].buy_position_open = false; rsi_strategies[strategy_index].sell_position_open = false; rsi_strategies[strategy_index].position_ticket = 0; rsi_strategies[strategy_index].rsi_against_position = false; rsi_strategies[strategy_index].bars_against_count = 0; return; } // Double-check position type matches our tracking (instrument-specific verification) ENUM_POSITION_TYPE actual_pos_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); string actual_symbol = PositionGetString(POSITION_SYMBOL); if(actual_symbol != rsi_strategies[strategy_index].symbol) { Print("Warning: Position symbol mismatch for ", rsi_strategies[strategy_index].symbol, " - Found: ", actual_symbol, ". Resetting tracking."); rsi_strategies[strategy_index].position_open = false; rsi_strategies[strategy_index].buy_position_open = false; rsi_strategies[strategy_index].sell_position_open = false; rsi_strategies[strategy_index].position_ticket = 0; rsi_strategies[strategy_index].rsi_against_position = false; rsi_strategies[strategy_index].bars_against_count = 0; return; } // Update position type if it changed (shouldn't happen, but safety check) if(actual_pos_type != pos_type) { Print("Warning: Position type changed for ", rsi_strategies[strategy_index].symbol, " - Updating from ", EnumToString(pos_type), " to ", EnumToString(actual_pos_type)); pos_type = actual_pos_type; rsi_strategies[strategy_index].current_position_type = pos_type; if(pos_type == POSITION_TYPE_BUY) { rsi_strategies[strategy_index].buy_position_open = true; rsi_strategies[strategy_index].sell_position_open = false; } else if(pos_type == POSITION_TYPE_SELL) { rsi_strategies[strategy_index].buy_position_open = false; rsi_strategies[strategy_index].sell_position_open = true; } } if(pos_type == POSITION_TYPE_BUY) { // Check if RSI is against the position (below oversold) if(rsi_current < rsi_strategies[strategy_index].oversold) { if(!rsi_strategies[strategy_index].rsi_against_position) { rsi_strategies[strategy_index].rsi_against_position = true; rsi_strategies[strategy_index].bars_against_count = 1; } else { rsi_strategies[strategy_index].bars_against_count++; } // Close position if RSI has been against for Y bars if(rsi_strategies[strategy_index].bars_against_count >= rsi_strategies[strategy_index].bars_to_wait) { if(ClosePositionByMagic(trade, rsi_strategies[strategy_index].symbol, rsi_strategies[strategy_index].magic_number)) { rsi_strategies[strategy_index].position_open = false; rsi_strategies[strategy_index].buy_position_open = false; rsi_strategies[strategy_index].sell_position_open = false; rsi_strategies[strategy_index].position_ticket = 0; rsi_strategies[strategy_index].rsi_against_position = false; rsi_strategies[strategy_index].bars_against_count = 0; Print("Closed ", rsi_strategies[strategy_index].symbol, " BUY position - RSI against for ", rsi_strategies[strategy_index].bars_to_wait, " bars"); } else { Print("Failed to close ", rsi_strategies[strategy_index].symbol, " BUY position - will retry"); } return; } } else { // RSI is no longer against the position, reset counter if(rsi_strategies[strategy_index].rsi_against_position) { rsi_strategies[strategy_index].rsi_against_position = false; rsi_strategies[strategy_index].bars_against_count = 0; } // Exit long position when RSI reaches buy target if(rsi_current >= rsi_strategies[strategy_index].target_buy) { if(ClosePositionByMagic(trade, rsi_strategies[strategy_index].symbol, rsi_strategies[strategy_index].magic_number)) { rsi_strategies[strategy_index].position_open = false; rsi_strategies[strategy_index].buy_position_open = false; rsi_strategies[strategy_index].sell_position_open = false; rsi_strategies[strategy_index].position_ticket = 0; rsi_strategies[strategy_index].rsi_against_position = false; rsi_strategies[strategy_index].bars_against_count = 0; Print("Closed ", rsi_strategies[strategy_index].symbol, " BUY position - RSI reached target: ", rsi_strategies[strategy_index].target_buy); } else { Print("Failed to close ", rsi_strategies[strategy_index].symbol, " BUY position - will retry"); } } } } else if(pos_type == POSITION_TYPE_SELL) { // Check if RSI is against the position (above overbought) if(rsi_current > rsi_strategies[strategy_index].overbought) { if(!rsi_strategies[strategy_index].rsi_against_position) { rsi_strategies[strategy_index].rsi_against_position = true; rsi_strategies[strategy_index].bars_against_count = 1; } else { rsi_strategies[strategy_index].bars_against_count++; } // Close position if RSI has been against for Y bars if(rsi_strategies[strategy_index].bars_against_count >= rsi_strategies[strategy_index].bars_to_wait) { if(ClosePositionByMagic(trade, rsi_strategies[strategy_index].symbol, rsi_strategies[strategy_index].magic_number)) { rsi_strategies[strategy_index].position_open = false; rsi_strategies[strategy_index].buy_position_open = false; rsi_strategies[strategy_index].sell_position_open = false; rsi_strategies[strategy_index].position_ticket = 0; rsi_strategies[strategy_index].rsi_against_position = false; rsi_strategies[strategy_index].bars_against_count = 0; Print("Closed ", rsi_strategies[strategy_index].symbol, " SELL position - RSI against for ", rsi_strategies[strategy_index].bars_to_wait, " bars"); } else { Print("Failed to close ", rsi_strategies[strategy_index].symbol, " SELL position - will retry"); } return; } } else { // RSI is no longer against the position, reset counter if(rsi_strategies[strategy_index].rsi_against_position) { rsi_strategies[strategy_index].rsi_against_position = false; rsi_strategies[strategy_index].bars_against_count = 0; } // Exit short position when RSI reaches sell target if(rsi_current <= rsi_strategies[strategy_index].target_sell) { if(ClosePositionByMagic(trade, rsi_strategies[strategy_index].symbol, rsi_strategies[strategy_index].magic_number)) { rsi_strategies[strategy_index].position_open = false; rsi_strategies[strategy_index].buy_position_open = false; rsi_strategies[strategy_index].sell_position_open = false; rsi_strategies[strategy_index].position_ticket = 0; rsi_strategies[strategy_index].rsi_against_position = false; rsi_strategies[strategy_index].bars_against_count = 0; Print("Closed ", rsi_strategies[strategy_index].symbol, " SELL position - RSI reached target: ", rsi_strategies[strategy_index].target_sell); } else { Print("Failed to close ", rsi_strategies[strategy_index].symbol, " SELL position - will retry"); } } } } } else { // No position exists - reset all tracking flags rsi_strategies[strategy_index].position_open = false; rsi_strategies[strategy_index].buy_position_open = false; rsi_strategies[strategy_index].sell_position_open = false; rsi_strategies[strategy_index].position_ticket = 0; rsi_strategies[strategy_index].rsi_against_position = false; rsi_strategies[strategy_index].bars_against_count = 0; // Check for new entry signals (only if no position exists) if(!PositionExistsByMagic(rsi_strategies[strategy_index].symbol, rsi_strategies[strategy_index].magic_number)) { // Buy signal: RSI crosses from oversold to above oversold // Only enter if we don't already have a buy position for THIS EA (magic number) on THIS INSTRUMENT if(!rsi_strategies[strategy_index].buy_position_open) { if(rsi_two_bars_ago <= rsi_strategies[strategy_index].oversold && rsi_prev > rsi_strategies[strategy_index].oversold) { double ask = SymbolInfoDouble(rsi_strategies[strategy_index].symbol, SYMBOL_ASK); if(trade.Buy(rsi_strategies[strategy_index].lot_size, rsi_strategies[strategy_index].symbol, ask, 0, 0, "RSI Scalping Buy " + rsi_strategies[strategy_index].symbol)) { ulong new_ticket = trade.ResultOrder(); if(new_ticket > 0) { // Verify the position was actually opened for THIS SPECIFIC INSTRUMENT if(PositionSelectByTicketSymbolAndMagic(new_ticket, rsi_strategies[strategy_index].symbol, rsi_strategies[strategy_index].magic_number)) { rsi_strategies[strategy_index].position_ticket = new_ticket; rsi_strategies[strategy_index].position_open = true; rsi_strategies[strategy_index].buy_position_open = true; rsi_strategies[strategy_index].sell_position_open = false; rsi_strategies[strategy_index].current_position_type = POSITION_TYPE_BUY; Print("Opened BUY position for ", rsi_strategies[strategy_index].symbol, " (Ticket: ", rsi_strategies[strategy_index].position_ticket, ", Magic: ", rsi_strategies[strategy_index].magic_number, ")"); } else { Print("Error: Position opened but doesn't match instrument ", rsi_strategies[strategy_index].symbol, " - resetting tracking"); rsi_strategies[strategy_index].position_ticket = 0; rsi_strategies[strategy_index].position_open = false; rsi_strategies[strategy_index].buy_position_open = false; } } } } } // Sell signal: RSI crosses from overbought to below overbought // Only enter if we don't already have a sell position for THIS EA (magic number) on THIS INSTRUMENT if(!rsi_strategies[strategy_index].sell_position_open) { if(rsi_two_bars_ago >= rsi_strategies[strategy_index].overbought && rsi_prev < rsi_strategies[strategy_index].overbought) { double bid = SymbolInfoDouble(rsi_strategies[strategy_index].symbol, SYMBOL_BID); if(trade.Sell(rsi_strategies[strategy_index].lot_size, rsi_strategies[strategy_index].symbol, bid, 0, 0, "RSI Scalping Sell " + rsi_strategies[strategy_index].symbol)) { ulong new_ticket = trade.ResultOrder(); if(new_ticket > 0) { // Verify the position was actually opened for THIS SPECIFIC INSTRUMENT if(PositionSelectByTicketSymbolAndMagic(new_ticket, rsi_strategies[strategy_index].symbol, rsi_strategies[strategy_index].magic_number)) { rsi_strategies[strategy_index].position_ticket = new_ticket; rsi_strategies[strategy_index].position_open = true; rsi_strategies[strategy_index].buy_position_open = false; rsi_strategies[strategy_index].sell_position_open = true; rsi_strategies[strategy_index].current_position_type = POSITION_TYPE_SELL; Print("Opened SELL position for ", rsi_strategies[strategy_index].symbol, " (Ticket: ", rsi_strategies[strategy_index].position_ticket, ", Magic: ", rsi_strategies[strategy_index].magic_number, ")"); } else { Print("Error: Position opened but doesn't match instrument ", rsi_strategies[strategy_index].symbol, " - resetting tracking"); rsi_strategies[strategy_index].position_ticket = 0; rsi_strategies[strategy_index].position_open = false; rsi_strategies[strategy_index].sell_position_open = false; } } } } } } } } //+------------------------------------------------------------------+ //| Mean Reversion Strategy | //+------------------------------------------------------------------+ void RunMeanReversionStrategy() { // Check if this is a new bar datetime current_bar_time = iTime(_Symbol, MeanRev_Timeframe, 0); if(current_bar_time == last_bar_time_meanrev) return; last_bar_time_meanrev = current_bar_time; // Update EMA values if(CopyBuffer(ema_handle_meanrev, 0, 0, 3, ema_array) < 3) return; double ema_current = ema_array[0]; double ema_prev = ema_array[1]; double current_close = iClose(_Symbol, MeanRev_Timeframe, 0); // Set magic number for this strategy trade.SetExpertMagicNumber(MagicNumber_MeanReversion); // Check existing position if(PositionExistsByMagic(_Symbol, MagicNumber_MeanReversion)) { // Manage existing position (trailing stop, exit conditions, etc.) ManageMeanReversionPosition(ema_current, current_close); } else { // Check for new entry signals CheckMeanReversionEntry(ema_current, ema_prev, current_close); } } //+------------------------------------------------------------------+ //| Manage Mean Reversion Position | //+------------------------------------------------------------------+ void ManageMeanReversionPosition(double ema_current, double current_close) { if(!PositionSelectByMagic(_Symbol, MagicNumber_MeanReversion)) return; double position_profit = PositionGetDouble(POSITION_PROFIT); double current_price = PositionGetDouble(POSITION_PRICE_CURRENT); ENUM_POSITION_TYPE position_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); double pips_multiplier = (_Digits == 3 || _Digits == 5) ? 10.0 : 1.0; // Trailing stop if(position_profit > 0) { if(position_type == POSITION_TYPE_BUY) { double new_stop_loss = current_price - (TrailingStop * _Point * pips_multiplier); double current_stop_loss = PositionGetDouble(POSITION_SL); if(new_stop_loss > current_stop_loss) { ModifyPositionByMagic(trade, _Symbol, MagicNumber_MeanReversion, new_stop_loss, PositionGetDouble(POSITION_TP)); } } else if(position_type == POSITION_TYPE_SELL) { double new_stop_loss = current_price + (TrailingStop * _Point * pips_multiplier); double current_stop_loss = PositionGetDouble(POSITION_SL); if(new_stop_loss < current_stop_loss || current_stop_loss == 0) { ModifyPositionByMagic(trade, _Symbol, MagicNumber_MeanReversion, new_stop_loss, PositionGetDouble(POSITION_TP)); } } } // Exit when price crosses EMA bool exit_bullish = (position_type == POSITION_TYPE_SELL && current_close > ema_current); bool exit_bearish = (position_type == POSITION_TYPE_BUY && current_close < ema_current); if(exit_bullish || exit_bearish) { ClosePositionByMagic(trade, _Symbol, MagicNumber_MeanReversion); } } //+------------------------------------------------------------------+ //| Check Mean Reversion Entry Signals | //+------------------------------------------------------------------+ void CheckMeanReversionEntry(double ema_current, double ema_prev, double current_close) { // Simplified entry logic - can be expanded double pips_multiplier = (_Digits == 3 || _Digits == 5) ? 10.0 : 1.0; double preis_abstand = MathAbs(current_close - ema_current) / _Point / pips_multiplier; double steigung = (ema_current - ema_prev) / _Point / pips_multiplier; // Entry conditions bool bullish_signal = (current_close > ema_current && preis_abstand > PreisSchwelle && MathAbs(steigung) > SteigungSchwelle); bool bearish_signal = (current_close < ema_current && preis_abstand > PreisSchwelle && MathAbs(steigung) > SteigungSchwelle); if(bullish_signal) { if(trade.Buy(MeanRev_LotSize, _Symbol, 0, 0, 0, "Mean Reversion Buy")) { meanrev_ticket = trade.ResultOrder(); meanrev_position_open = true; } } else if(bearish_signal) { if(trade.Sell(MeanRev_LotSize, _Symbol, 0, 0, 0, "Mean Reversion Sell")) { meanrev_ticket = trade.ResultOrder(); meanrev_position_open = true; } } } //+------------------------------------------------------------------+