//+------------------------------------------------------------------+ //| SimpleRSIReversalAUDUSD.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property strict // Include trade class #include // Input parameters input int RSIPeriod = 28; // RSI period input double OverboughtLevel = 68; // Overbought level input double OversoldLevel = 30; // Oversold level input int TakeProfitPips = 175; // Take profit in pips input int StopLossPips = 5; // Stop loss in pips input double MaxLotSize = 0.2; // Maximum lot size input int MaxSpread = 1000; // Maximum allowed spread in pips input int MaxDuration = 340; // Maximum trade duration in hours input bool UseStopLoss = false; // Use stop loss input bool UseTakeProfit = false; // Use take profit input bool UseRSIExit = true; // Use RSI for exit input double RSIExitLevel = 48; // RSI level to exit (50 = neutral) input bool CloseOutsideSession = true; // Close trades outside Asian session input color PanelBackground = clrBlack; // Panel background color input color PanelText = clrWhite; // Panel text color input int PanelX = 10; // Panel X position input int PanelY = 20; // Panel Y position // Global variables CTrade trade; int rsiHandle; bool isPositionOpen = false; double positionOpenPrice = 0; datetime positionOpenTime = 0; ENUM_POSITION_TYPE lastPositionType = POSITION_TYPE_BUY; bool sessionCloseAttempted = false; // Track if we've attempted to close positions for current session // RSI crossover variables double rsiCurrent = 0; double rsiPrevious = 0; double rsiPrevious2 = 0; bool rsiCrossedOverbought = false; bool rsiCrossedOversold = false; bool rsiCrossedExitLevel = false; // Panel objects string panelName = "RSIPanel"; int panelWidth = 200; int panelHeight = 200; int labelHeight = 20; int labelSpacing = 5; // Session times (UTC) const int AsianSessionStart = 0; // 00:00 UTC const int AsianSessionEnd = 8; // 08:00 UTC //+------------------------------------------------------------------+ //| Create panel | //+------------------------------------------------------------------+ void CreatePanel() { // Create panel background ObjectCreate(0, panelName, OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, panelName, OBJPROP_XDISTANCE, PanelX); ObjectSetInteger(0, panelName, OBJPROP_YDISTANCE, PanelY); ObjectSetInteger(0, panelName, OBJPROP_XSIZE, panelWidth); ObjectSetInteger(0, panelName, OBJPROP_YSIZE, panelHeight); ObjectSetInteger(0, panelName, OBJPROP_BGCOLOR, PanelBackground); ObjectSetInteger(0, panelName, OBJPROP_BORDER_TYPE, BORDER_FLAT); ObjectSetInteger(0, panelName, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, panelName, OBJPROP_COLOR, PanelText); ObjectSetInteger(0, panelName, OBJPROP_STYLE, STYLE_SOLID); ObjectSetInteger(0, panelName, OBJPROP_WIDTH, 1); ObjectSetInteger(0, panelName, OBJPROP_BACK, false); ObjectSetInteger(0, panelName, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, panelName, OBJPROP_SELECTED, false); ObjectSetInteger(0, panelName, OBJPROP_HIDDEN, true); ObjectSetInteger(0, panelName, OBJPROP_ZORDER, 0); // Create title label ObjectCreate(0, panelName + "Title", OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, panelName + "Title", OBJPROP_XDISTANCE, PanelX + 5); ObjectSetInteger(0, panelName + "Title", OBJPROP_YDISTANCE, PanelY + 5); ObjectSetInteger(0, panelName + "Title", OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetString(0, panelName + "Title", OBJPROP_TEXT, "RSI Reversal"); ObjectSetInteger(0, panelName + "Title", OBJPROP_COLOR, PanelText); ObjectSetInteger(0, panelName + "Title", OBJPROP_FONTSIZE, 10); // Create score labels CreateScoreLabel("RSI", "RSI: ", 0); CreateScoreLabel("Position", "Position: ", 1); CreateScoreLabel("Spread", "Spread: ", 2); CreateScoreLabel("Session", "Session: ", 3); CreateScoreLabel("SL", "Stop Loss: ", 4); CreateScoreLabel("TP", "Take Profit: ", 5); CreateScoreLabel("Cross", "Cross: ", 6); } //+------------------------------------------------------------------+ //| Create score label | //+------------------------------------------------------------------+ void CreateScoreLabel(string name, string text, int index) { ObjectCreate(0, panelName + name, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, panelName + name, OBJPROP_XDISTANCE, PanelX + 5); ObjectSetInteger(0, panelName + name, OBJPROP_YDISTANCE, PanelY + 30 + index * (labelHeight + labelSpacing)); ObjectSetInteger(0, panelName + name, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetString(0, panelName + name, OBJPROP_TEXT, text); ObjectSetInteger(0, panelName + name, OBJPROP_COLOR, PanelText); ObjectSetInteger(0, panelName + name, OBJPROP_FONTSIZE, 8); } //+------------------------------------------------------------------+ //| Update panel values | //+------------------------------------------------------------------+ void UpdatePanel(double rsi, string position, int spread, string session, double sl, double tp, string crossInfo) { ObjectSetString(0, panelName + "RSI", OBJPROP_TEXT, "RSI: " + DoubleToString(rsi, 2)); ObjectSetString(0, panelName + "Position", OBJPROP_TEXT, "Position: " + position); ObjectSetString(0, panelName + "Spread", OBJPROP_TEXT, "Spread: " + IntegerToString(spread) + " pips"); ObjectSetString(0, panelName + "Session", OBJPROP_TEXT, "Session: " + session); ObjectSetString(0, panelName + "SL", OBJPROP_TEXT, "Stop Loss: " + IntegerToString(StopLossPips) + " pips"); ObjectSetString(0, panelName + "TP", OBJPROP_TEXT, "Take Profit: " + IntegerToString(TakeProfitPips) + " pips"); ObjectSetString(0, panelName + "Cross", OBJPROP_TEXT, "Cross: " + crossInfo); } //+------------------------------------------------------------------+ //| Check if current time is in Asian session | //+------------------------------------------------------------------+ bool IsAsianSession() { datetime currentTime = TimeCurrent(); MqlDateTime timeStruct; TimeToStruct(currentTime, timeStruct); return (timeStruct.hour >= AsianSessionStart && timeStruct.hour < AsianSessionEnd); } //+------------------------------------------------------------------+ //| Get current session name | //+------------------------------------------------------------------+ string GetCurrentSession() { datetime currentTime = TimeCurrent(); MqlDateTime timeStruct; TimeToStruct(currentTime, timeStruct); if(timeStruct.hour >= AsianSessionStart && timeStruct.hour < AsianSessionEnd) return "Asian"; else if(timeStruct.hour >= 8 && timeStruct.hour < 16) return "London"; else if(timeStruct.hour >= 13 && timeStruct.hour < 21) return "New York"; else return "Other"; } //+------------------------------------------------------------------+ //| Check if trading is allowed | //+------------------------------------------------------------------+ bool IsTradingAllowed() { // Check if market is open if(!SymbolInfoInteger(_Symbol, SYMBOL_TRADE_MODE) == SYMBOL_TRADE_MODE_FULL) { return false; } // Check if we have enough money if(AccountInfoDouble(ACCOUNT_MARGIN_FREE) <= 0) { return false; } return true; } //+------------------------------------------------------------------+ //| Check RSI crossover conditions | //+------------------------------------------------------------------+ void CheckRSICrossover() { // Reset crossover flags rsiCrossedOverbought = false; rsiCrossedOversold = false; rsiCrossedExitLevel = false; // Check for overbought crossover (RSI crosses above overbought level) if(rsiPrevious < OverboughtLevel && rsiCurrent >= OverboughtLevel) { rsiCrossedOverbought = true; } // Check for oversold crossover (RSI crosses below oversold level) if(rsiPrevious > OversoldLevel && rsiCurrent <= OversoldLevel) { rsiCrossedOversold = true; } // Check for exit level crossover if(rsiPrevious < RSIExitLevel && rsiCurrent >= RSIExitLevel) { rsiCrossedExitLevel = true; } else if(rsiPrevious > RSIExitLevel && rsiCurrent <= RSIExitLevel) { rsiCrossedExitLevel = true; } } //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Initialize RSI indicator rsiHandle = iRSI(_Symbol, PERIOD_M15, RSIPeriod, PRICE_CLOSE); if(rsiHandle == INVALID_HANDLE) { return(INIT_FAILED); } // Wait a bit for the indicator to be ready Sleep(100); // Initialize RSI values with retry logic double rsi[]; ArraySetAsSeries(rsi, true); int retryCount = 0; bool rsiInitialized = false; while(retryCount < 10 && !rsiInitialized) { int copied = CopyBuffer(rsiHandle, 0, 0, 3, rsi); if(copied >= 3) { rsiCurrent = rsi[0]; rsiPrevious = rsi[1]; rsiPrevious2 = rsi[2]; rsiInitialized = true; } else { retryCount++; Sleep(100); } } if(!rsiInitialized) { // Don't fail initialization, just set default values rsiCurrent = 50.0; rsiPrevious = 50.0; rsiPrevious2 = 50.0; } // Create panel CreatePanel(); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // Release indicator handles IndicatorRelease(rsiHandle); // Remove panel objects ObjectsDeleteAll(0, panelName); } //+------------------------------------------------------------------+ //| Close all trades for the current symbol | //+------------------------------------------------------------------+ bool CloseAllTrades(string reason = "") { bool allClosed = true; int totalPositions = PositionsTotal(); if(totalPositions == 0) return true; // Check if there are any positions with our magic number bool hasOurPositions = false; for(int i = 0; i < totalPositions; i++) { if(PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_MAGIC) == 123456) { hasOurPositions = true; break; } } for(int i = totalPositions - 1; i >= 0; i--) { if(PositionGetSymbol(i) == _Symbol) { // Try to close position with retry logic int retryCount = 0; bool positionClosed = false; while(retryCount < 3 && !positionClosed) { if(trade.PositionClose(_Symbol)) { isPositionOpen = false; positionClosed = true; } else { int error = GetLastError(); // If error is 4756 (Trade disabled), wait longer before retry if(error == 4756) { Sleep(5000); // Wait 5 seconds before retry retryCount++; } else { // For other errors, break the loop break; } } } if(!positionClosed) { allClosed = false; } } } return allClosed; } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Check if trading is allowed if(!IsTradingAllowed()) { return; } // Check if we're in Asian session if(!IsAsianSession()) { // Close all positions if outside Asian session and CloseOutsideSession is true if(CloseOutsideSession && !sessionCloseAttempted) { CloseAllTrades("Outside Asian session"); sessionCloseAttempted = true; } return; } else { // Reset the session close attempt flag when we enter Asian session sessionCloseAttempted = false; } // Get current spread double spread = SymbolInfoDouble(_Symbol, SYMBOL_ASK) - SymbolInfoDouble(_Symbol, SYMBOL_BID); int spreadInPips = (int)(spread / _Point); // Check if spread is too high if(spreadInPips > MaxSpread) { return; } // Get RSI values from bar data double rsi[]; ArraySetAsSeries(rsi, true); int copied = CopyBuffer(rsiHandle, 0, 0, 3, rsi); if(copied < 3) { return; } // Update RSI values rsiPrevious2 = rsiPrevious; rsiPrevious = rsiCurrent; rsiCurrent = rsi[0]; // Validate RSI values if(rsiCurrent == 0 || rsiPrevious == 0) { return; } // Check for RSI crossovers CheckRSICrossover(); // Get current prices double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // Get position status string positionStatus = "None"; for(int i = 0; i < PositionsTotal(); i++) { if(PositionGetSymbol(i) == _Symbol) { ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); positionStatus = (posType == POSITION_TYPE_BUY) ? "Long" : "Short"; break; } } // Calculate stop loss and take profit levels double sl = 0; double tp = 0; // Prepare crossover info for panel string crossInfo = "None"; if(rsiCrossedOverbought) crossInfo = "Overbought"; else if(rsiCrossedOversold) crossInfo = "Oversold"; else if(rsiCrossedExitLevel) crossInfo = "Exit"; // Update panel UpdatePanel(rsiCurrent, positionStatus, spreadInPips, GetCurrentSession(), sl, tp, crossInfo); // Check for open position bool hasOpenPosition = false; for(int i = 0; i < PositionsTotal(); i++) { if(PositionGetSymbol(i) == _Symbol) { hasOpenPosition = true; // Get position details double positionProfit = PositionGetDouble(POSITION_PROFIT); double positionVolume = PositionGetDouble(POSITION_VOLUME); double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // Check for RSI exit if enabled if(UseRSIExit && rsiCrossedExitLevel) { bool shouldExit = false; // For long positions, exit when RSI crosses above exit level if(posType == POSITION_TYPE_BUY && rsiCurrent >= RSIExitLevel && rsiPrevious < RSIExitLevel) { shouldExit = true; } // For short positions, exit when RSI crosses below exit level else if(posType == POSITION_TYPE_SELL && rsiCurrent <= RSIExitLevel && rsiPrevious > RSIExitLevel) { shouldExit = true; } if(shouldExit) { CloseAllTrades("RSI Exit Crossover"); return; } } // Check for timeout if(TimeCurrent() - positionOpenTime > MaxDuration * 3600) { CloseAllTrades("Timeout"); return; } break; } } // If no position is open, look for entry signals based on RSI crossover if(!hasOpenPosition) { // Place buy order if RSI crosses below oversold level (oversold crossover) if(rsiCrossedOversold) { double sl = UseStopLoss ? currentBid - StopLossPips * _Point : 0; double tp = UseTakeProfit ? currentBid + TakeProfitPips * _Point : 0; if(UseStopLoss && sl >= currentBid) return; if(UseTakeProfit && tp <= currentBid) return; // Set trade parameters trade.SetDeviationInPoints(3); trade.SetTypeFilling(ORDER_FILLING_IOC); trade.SetExpertMagicNumber(123456); // Place buy order using CTrade if(trade.Buy(MaxLotSize, _Symbol, currentAsk, sl, tp, "RSI Oversold Crossover Buy")) { isPositionOpen = true; positionOpenPrice = currentAsk; positionOpenTime = TimeCurrent(); lastPositionType = POSITION_TYPE_BUY; } } // Place sell order if RSI crosses above overbought level (overbought crossover) else if(rsiCrossedOverbought) { double sl = UseStopLoss ? currentAsk + StopLossPips * _Point : 0; double tp = UseTakeProfit ? currentAsk - TakeProfitPips * _Point : 0; if(UseStopLoss && sl <= currentAsk) return; if(UseTakeProfit && tp >= currentAsk) return; // Set trade parameters trade.SetDeviationInPoints(3); trade.SetTypeFilling(ORDER_FILLING_IOC); trade.SetExpertMagicNumber(123456); // Place sell order using CTrade if(trade.Sell(MaxLotSize, _Symbol, currentBid, sl, tp, "RSI Overbought Crossover Sell")) { isPositionOpen = true; positionOpenPrice = currentBid; positionOpenTime = TimeCurrent(); lastPositionType = POSITION_TYPE_SELL; } } } }