diff --git a/RSIMidPointHijackXAUUSD/main.mq5 b/RSIMidPointHijackXAUUSD/main.mq5 index f9ebcd8..66677fe 100644 --- a/RSIMidPointHijackXAUUSD/main.mq5 +++ b/RSIMidPointHijackXAUUSD/main.mq5 @@ -27,13 +27,13 @@ input double InpLockProfitThreshold = 0.0; // Lock Profit Threshold (pips) input bool InpCloseOppositeTrades = false; // Close Opposite Trades When Profiting input group "RSI Follow Strategy" -input int InpRSIPeriod = 87; // RSI Period -input int InpRSIOverbought = 72; // RSI Overbought Level -input int InpRSIOversold = 50; // RSI Oversold Level -input int InpRSIExitLevel = 40; // RSI Exit Level -input int InpRSIFollowStartHour = 0; // RSI Follow Start Hour (0-23) -input int InpRSIFollowEndHour = 7; // RSI Follow End Hour (0-23) -input bool InpRSIFollowCloseOutsideHours = true; // Close trades outside trading hours +input int InpRSIPeriod = 32; // RSI Period +input int InpRSIOverbought = 78; // RSI Overbought Level +input int InpRSIOversold = 46; // RSI Oversold Level +input int InpRSIExitLevel = 44; // RSI Exit Level +input int InpRSIFollowStartHour = 23; // RSI Follow Start Hour (0-23) +input int InpRSIFollowEndHour = 8; // RSI Follow End Hour (0-23) +input bool InpRSIFollowCloseOutsideHours = false; // Close trades outside trading hours input group "RSI Reverse Strategy" input int InpRSIReversePeriod = 59; // RSI Period @@ -72,6 +72,12 @@ int emaCrossSignalBar = 0; datetime lastBarTime = 0; datetime rsiReverseLastCloseTime = 0; bool rsiReverseInCooldown = false; +double lastBarRSI = 0; // Store last bar's RSI value +double lastBarRSIReverse = 0; // Store last bar's RSI Reverse value +double lastBarEMA = 0; // Store last bar's EMA value +double lastBarClose = 0; // Store last bar's close value +double lastBarEMAPrev = 0; // Store previous bar's EMA value +double lastBarClosePrev = 0; // Store previous bar's close value //+------------------------------------------------------------------+ //| Expert initialization function | @@ -224,20 +230,14 @@ void CheckRSIFollowStrategy() if(InpEnableStrategyLock && HasProfitablePosition(InpMagicNumberRSIFollow)) return; - double rsi[]; - ArraySetAsSeries(rsi, true); - CopyBuffer(rsiHandle, 0, 0, 3, rsi); - - if(ArraySize(rsi) < 3) return; - - // Check for overbought condition - if(rsi[1] > InpRSIOverbought) + // Use lastBarRSI instead of copying buffer + if(lastBarRSI > InpRSIOverbought) rsiOverbought = true; - else if(rsi[1] < InpRSIOversold) + else if(lastBarRSI < InpRSIOversold) rsiOversold = true; // Check for entry signals - if(rsiOverbought && rsi[1] < rsi[0] && rsi[1] < InpRSIExitLevel) + if(rsiOverbought && lastBarRSI < InpRSIExitLevel) { // Sell signal if(!HasPosition(InpMagicNumberRSIFollow)) @@ -247,7 +247,7 @@ void CheckRSIFollowStrategy() } rsiOverbought = false; } - else if(rsiOversold && rsi[1] > rsi[0] && rsi[1] > InpRSIExitLevel) + else if(rsiOversold && lastBarRSI > InpRSIExitLevel) { // Buy signal if(!HasPosition(InpMagicNumberRSIFollow)) @@ -312,20 +312,14 @@ void CheckRSIReverseStrategy() if(IsRSIReverseInCooldown()) return; - double rsi[]; - ArraySetAsSeries(rsi, true); - CopyBuffer(rsiReverseHandle, 0, 0, 3, rsi); - - if(ArraySize(rsi) < 3) return; - - // Check for overbought/oversold conditions - if(rsi[1] > InpRSIReverseOverbought) + // Use lastBarRSIReverse instead of copying buffer + if(lastBarRSIReverse > InpRSIReverseOverbought) rsiReverseOverbought = true; - else if(rsi[1] < InpRSIReverseOversold) + else if(lastBarRSIReverse < InpRSIReverseOversold) rsiReverseOversold = true; // Check for entry signals - if(rsiReverseOverbought && rsi[1] < InpRSIReverseCrossLevel) + if(rsiReverseOverbought && lastBarRSIReverse < InpRSIReverseCrossLevel) { // Sell signal if(!HasPosition(InpMagicNumberRSIReverse)) @@ -335,7 +329,7 @@ void CheckRSIReverseStrategy() } rsiReverseOverbought = false; } - else if(rsiReverseOversold && rsi[1] > InpRSIReverseCrossLevel) + else if(rsiReverseOversold && lastBarRSIReverse > InpRSIReverseCrossLevel) { // Buy signal if(!HasPosition(InpMagicNumberRSIReverse)) @@ -369,24 +363,15 @@ void CheckEMACrossStrategy() if(InpEnableStrategyLock && HasProfitablePosition(InpMagicNumberEMACross)) return; - double ema[], close[]; - ArraySetAsSeries(ema, true); - ArraySetAsSeries(close, true); - - CopyBuffer(emaHandle, 0, 0, InpEMADistancePeriod + 2, ema); - CopyClose(_Symbol, InpTimeframe, 0, InpEMADistancePeriod + 2, close); - - if(ArraySize(ema) < InpEMADistancePeriod + 2 || ArraySize(close) < InpEMADistancePeriod + 2) return; - - // Check for cross signals - if(ema[1] < close[1] && ema[0] > close[0]) + // Check for cross signals using stored values + if(lastBarEMAPrev < lastBarClosePrev && lastBarEMA > lastBarClose) { // Buy cross signal emaCrossBuySignal = true; emaCrossSellSignal = false; emaCrossSignalBar = 0; } - else if(ema[1] > close[1] && ema[0] < close[0]) + else if(lastBarEMAPrev > lastBarClosePrev && lastBarEMA < lastBarClose) { // Sell cross signal emaCrossSellSignal = true; @@ -401,49 +386,65 @@ void CheckEMACrossStrategy() { // Check if price has moved above EMA by the required distance for the required period bool distanceConditionMet = true; - for(int i = 0; i < InpEMADistancePeriod; i++) - { - double distance = (close[i] - ema[i]) / _Point; - if(distance < InpEMADistancePips) - { - distanceConditionMet = false; - break; - } - } + double emaHistory[], closeHistory[]; + ArraySetAsSeries(emaHistory, true); + ArraySetAsSeries(closeHistory, true); - if(distanceConditionMet && !HasPosition(InpMagicNumberEMACross)) + if(CopyBuffer(emaHandle, 0, 0, InpEMADistancePeriod, emaHistory) > 0 && + CopyClose(_Symbol, InpTimeframe, 0, InpEMADistancePeriod, closeHistory) > 0) { - trade.SetExpertMagicNumber(InpMagicNumberEMACross); - trade.Buy(InpLotSize, _Symbol, 0, 0, 0, "EMA Cross Distance"); - emaCrossBuySignal = false; + for(int i = 0; i < InpEMADistancePeriod; i++) + { + double distance = (closeHistory[i] - emaHistory[i]) / _Point; + if(distance < InpEMADistancePips) + { + distanceConditionMet = false; + break; + } + } + + if(distanceConditionMet && !HasPosition(InpMagicNumberEMACross)) + { + trade.SetExpertMagicNumber(InpMagicNumberEMACross); + trade.Buy(InpLotSize, _Symbol, 0, 0, 0, "EMA Cross Distance"); + emaCrossBuySignal = false; + } } } else if(emaCrossSellSignal) { // Check if price has moved below EMA by the required distance for the required period bool distanceConditionMet = true; - for(int i = 0; i < InpEMADistancePeriod; i++) - { - double distance = (ema[i] - close[i]) / _Point; - if(distance < InpEMADistancePips) - { - distanceConditionMet = false; - break; - } - } + double emaHistory[], closeHistory[]; + ArraySetAsSeries(emaHistory, true); + ArraySetAsSeries(closeHistory, true); - if(distanceConditionMet && !HasPosition(InpMagicNumberEMACross)) + if(CopyBuffer(emaHandle, 0, 0, InpEMADistancePeriod, emaHistory) > 0 && + CopyClose(_Symbol, InpTimeframe, 0, InpEMADistancePeriod, closeHistory) > 0) { - trade.SetExpertMagicNumber(InpMagicNumberEMACross); - trade.Sell(InpLotSize, _Symbol, 0, 0, 0, "EMA Cross Distance"); - emaCrossSellSignal = false; + for(int i = 0; i < InpEMADistancePeriod; i++) + { + double distance = (emaHistory[i] - closeHistory[i]) / _Point; + if(distance < InpEMADistancePips) + { + distanceConditionMet = false; + break; + } + } + + if(distanceConditionMet && !HasPosition(InpMagicNumberEMACross)) + { + trade.SetExpertMagicNumber(InpMagicNumberEMACross); + trade.Sell(InpLotSize, _Symbol, 0, 0, 0, "EMA Cross Distance"); + emaCrossSellSignal = false; + } } } } else { - // Original cross entry logic - if(ema[1] < close[1] && ema[0] > close[0]) + // Original cross entry logic using stored values + if(lastBarEMAPrev < lastBarClosePrev && lastBarEMA > lastBarClose) { // Buy signal if(!HasPosition(InpMagicNumberEMACross)) @@ -452,7 +453,7 @@ void CheckEMACrossStrategy() trade.Buy(InpLotSize, _Symbol, 0, 0, 0, "EMA Cross"); } } - else if(ema[1] > close[1] && ema[0] < close[0]) + else if(lastBarEMAPrev > lastBarClosePrev && lastBarEMA < lastBarClose) { // Sell signal if(!HasPosition(InpMagicNumberEMACross)) @@ -485,6 +486,30 @@ void OnTick() if(!IsNewBar()) return; + // Get indicator values for the new bar + double rsi[], rsiReverse[], ema[], close[]; + ArraySetAsSeries(rsi, true); + ArraySetAsSeries(rsiReverse, true); + ArraySetAsSeries(ema, true); + ArraySetAsSeries(close, true); + + // Store previous values + lastBarEMAPrev = lastBarEMA; + lastBarClosePrev = lastBarClose; + + // Get new values + if(CopyBuffer(rsiHandle, 0, 0, 1, rsi) > 0) + lastBarRSI = rsi[0]; + + if(CopyBuffer(rsiReverseHandle, 0, 0, 1, rsiReverse) > 0) + lastBarRSIReverse = rsiReverse[0]; + + if(CopyBuffer(emaHandle, 0, 0, 1, ema) > 0) + lastBarEMA = ema[0]; + + if(CopyClose(_Symbol, InpTimeframe, 0, 1, close) > 0) + lastBarClose = close[0]; + // Check for new signals if(InpEnableRSIFollow) CheckRSIFollowStrategy(); @@ -502,20 +527,13 @@ void OnTick() //+------------------------------------------------------------------+ void CheckExitConditions() { - double rsi[], rsiReverse[], ema[], close[]; - ArraySetAsSeries(rsi, true); - ArraySetAsSeries(rsiReverse, true); - ArraySetAsSeries(ema, true); - ArraySetAsSeries(close, true); - if(InpEnableRSIFollow) { - CopyBuffer(rsiHandle, 0, 0, 1, rsi); // Check RSI Follow exit conditions if(HasPosition(InpMagicNumberRSIFollow)) { - if((positionInfo.PositionType() == POSITION_TYPE_BUY && rsi[0] < InpRSIExitLevel) || - (positionInfo.PositionType() == POSITION_TYPE_SELL && rsi[0] > InpRSIExitLevel)) + if((positionInfo.PositionType() == POSITION_TYPE_BUY && lastBarRSI < InpRSIExitLevel) || + (positionInfo.PositionType() == POSITION_TYPE_SELL && lastBarRSI > InpRSIExitLevel)) { ClosePosition(InpMagicNumberRSIFollow); } @@ -524,12 +542,11 @@ void CheckExitConditions() if(InpEnableRSIReverse) { - CopyBuffer(rsiReverseHandle, 0, 0, 1, rsiReverse); // Check RSI Reverse exit conditions if(HasPosition(InpMagicNumberRSIReverse)) { - if((positionInfo.PositionType() == POSITION_TYPE_BUY && rsiReverse[0] < InpRSIReverseExitLevel) || - (positionInfo.PositionType() == POSITION_TYPE_SELL && rsiReverse[0] > InpRSIReverseExitLevel)) + if((positionInfo.PositionType() == POSITION_TYPE_BUY && lastBarRSIReverse < InpRSIReverseExitLevel) || + (positionInfo.PositionType() == POSITION_TYPE_SELL && lastBarRSIReverse > InpRSIReverseExitLevel)) { ClosePosition(InpMagicNumberRSIReverse); } @@ -538,13 +555,11 @@ void CheckExitConditions() if(InpEnableEMACross) { - CopyBuffer(emaHandle, 0, 0, 2, ema); - CopyClose(_Symbol, InpTimeframe, 0, 2, close); - // Check EMA Cross exit conditions + // Check EMA Cross exit conditions using stored values if(HasPosition(InpMagicNumberEMACross)) { - if((positionInfo.PositionType() == POSITION_TYPE_BUY && ema[0] > close[0]) || - (positionInfo.PositionType() == POSITION_TYPE_SELL && ema[0] < close[0])) + if((positionInfo.PositionType() == POSITION_TYPE_BUY && lastBarEMA > lastBarClose) || + (positionInfo.PositionType() == POSITION_TYPE_SELL && lastBarEMA < lastBarClose)) { ClosePosition(InpMagicNumberEMACross); } diff --git a/RSIScalpingEURUSD/main.mq5 b/RSIScalpingEURUSD/main.mq5 new file mode 100644 index 0000000..afdcc91 --- /dev/null +++ b/RSIScalpingEURUSD/main.mq5 @@ -0,0 +1,363 @@ +//+------------------------------------------------------------------+ +//| RSIScalping.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 ENUM_TIMEFRAMES TimeFrame = PERIOD_M30; // Timeframe for Analysis +input int RSI_Period = 14; // RSI Period +input ENUM_APPLIED_PRICE RSI_Applied_Price = PRICE_CLOSE; // RSI Applied Price +input double RSI_Overbought = 77; // RSI Overbought Level +input double RSI_Oversold = 10; // RSI Oversold Level +input double RSI_Target_Buy = 27; // RSI Target for Buy Exit +input double RSI_Target_Sell = 43; // RSI Target for Sell Exit +input int BarsToWait = 14; // Bars to wait when RSI goes against position +input double LotSize = 0.1; // Lot Size +input int MagicNumber = 12345; // Magic Number +input int Slippage = 3; // Slippage in points + +//--- Global variables +CTrade trade; +int rsi_handle; +double rsi_buffer[]; +double rsi_prev, rsi_current, rsi_two_bars_ago; +bool position_open = false; +int position_ticket = 0; +ENUM_POSITION_TYPE current_position_type = POSITION_TYPE_BUY; +datetime last_bar_time = 0; +bool rsi_against_position = false; +int bars_against_count = 0; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + // Initialize RSI indicator + rsi_handle = iRSI(_Symbol, TimeFrame, RSI_Period, RSI_Applied_Price); + if(rsi_handle == INVALID_HANDLE) + { + Print("Error creating RSI indicator"); + return(INIT_FAILED); + } + + // Initialize trade object + trade.SetExpertMagicNumber(MagicNumber); + trade.SetDeviationInPoints(Slippage); + trade.SetTypeFilling(ORDER_FILLING_FOK); + + // Allocate arrays + ArraySetAsSeries(rsi_buffer, true); + + Print("RSI Scalping EA initialized successfully on timeframe: ", EnumToString(TimeFrame)); + return(INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) +{ + if(rsi_handle != INVALID_HANDLE) + IndicatorRelease(rsi_handle); +} + +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() +{ + // Check if we have enough bars + if(Bars(_Symbol, TimeFrame) < RSI_Period + 2) + { + Print("TRACE: Not enough bars. Bars=", Bars(_Symbol, TimeFrame), " RSI_Period+2=", RSI_Period+2); + return; + } + + // Check if this is a new bar + datetime current_bar_time = iTime(_Symbol, TimeFrame, 0); + if(current_bar_time == last_bar_time) + { + Print("TRACE: Same bar, skipping. current_bar_time=", current_bar_time, " last_bar_time=", last_bar_time); + return; // Still the same bar, don't process + } + + Print("TRACE: New bar detected. current_bar_time=", current_bar_time, " last_bar_time=", last_bar_time); + last_bar_time = current_bar_time; + + // Update RSI values + if(!UpdateRSI()) + { + Print("TRACE: Failed to update RSI values"); + return; + } + + Print("TRACE: RSI values - Current=", rsi_current, " Previous=", rsi_prev); + + // Check for existing position + CheckExistingPosition(); + + // Check for new entry signals + if(!position_open) + { + Print("TRACE: No position open, checking entry signals"); + CheckEntrySignals(); + } + else + { + Print("TRACE: Position already open, skipping entry signals"); + } +} + +//+------------------------------------------------------------------+ +//| Update RSI values | +//+------------------------------------------------------------------+ +bool UpdateRSI() +{ + Print("TRACE: Updating RSI values..."); + + if(CopyBuffer(rsi_handle, 0, 0, 3, rsi_buffer) < 3) + { + Print("TRACE: Error copying RSI data. Copied=", CopyBuffer(rsi_handle, 0, 0, 3, rsi_buffer)); + return false; + } + + rsi_current = rsi_buffer[0]; // Current bar + rsi_prev = rsi_buffer[1]; // Previous bar + rsi_two_bars_ago = rsi_buffer[2]; // Two bars ago + + Print("TRACE: RSI buffer values - [0]=", rsi_buffer[0], " [1]=", rsi_buffer[1], " [2]=", rsi_buffer[2]); + + return true; +} + +//+------------------------------------------------------------------+ +//| Check existing position for exit conditions | +//+------------------------------------------------------------------+ +void CheckExistingPosition() +{ + if(!position_open) + { + Print("TRACE: No position open, skipping position check"); + return; + } + + Print("TRACE: Checking existing position. Ticket=", position_ticket, " Type=", (current_position_type == POSITION_TYPE_BUY ? "BUY" : "SELL")); + + // Check if position still exists + if(!PositionSelectByTicket(position_ticket)) + { + Print("TRACE: Position no longer exists, resetting state"); + position_open = false; + position_ticket = 0; + rsi_against_position = false; + bars_against_count = 0; + return; + } + + // Exit conditions based on RSI target + if(current_position_type == POSITION_TYPE_BUY) + { + Print("TRACE: Checking BUY position exit - rsi_current=", rsi_current, " RSI_Target_Buy=", RSI_Target_Buy, " RSI_Oversold=", RSI_Oversold); + + // Check if RSI is against the position (below oversold) + if(rsi_current < RSI_Oversold) + { + if(!rsi_against_position) + { + Print("TRACE: RSI went against BUY position (below oversold), starting counter"); + rsi_against_position = true; + bars_against_count = 1; + } + else + { + bars_against_count++; + Print("TRACE: RSI still against BUY position. Bars against: ", bars_against_count, "/", BarsToWait); + } + + // Close position if RSI has been against for Y bars + if(bars_against_count >= BarsToWait) + { + Print("TRACE: RSI against BUY position for ", BarsToWait, " bars, closing position!"); + ClosePosition(); + return; + } + } + else + { + // RSI is no longer against the position, reset counter + if(rsi_against_position) + { + Print("TRACE: RSI no longer against BUY position, resetting counter"); + rsi_against_position = false; + bars_against_count = 0; + } + + // Exit long position when RSI reaches buy target + if(rsi_current >= RSI_Target_Buy) + { + Print("TRACE: BUY position target reached!"); + ClosePosition(); + } + else + { + Print("TRACE: BUY position exit condition not met"); + } + } + } + else if(current_position_type == POSITION_TYPE_SELL) + { + Print("TRACE: Checking SELL position exit - rsi_current=", rsi_current, " RSI_Target_Sell=", RSI_Target_Sell, " RSI_Overbought=", RSI_Overbought); + + // Check if RSI is against the position (above overbought) + if(rsi_current > RSI_Overbought) + { + if(!rsi_against_position) + { + Print("TRACE: RSI went against SELL position (above overbought), starting counter"); + rsi_against_position = true; + bars_against_count = 1; + } + else + { + bars_against_count++; + Print("TRACE: RSI still against SELL position. Bars against: ", bars_against_count, "/", BarsToWait); + } + + // Close position if RSI has been against for Y bars + if(bars_against_count >= BarsToWait) + { + Print("TRACE: RSI against SELL position for ", BarsToWait, " bars, closing position!"); + ClosePosition(); + return; + } + } + else + { + // RSI is no longer against the position, reset counter + if(rsi_against_position) + { + Print("TRACE: RSI no longer against SELL position, resetting counter"); + rsi_against_position = false; + bars_against_count = 0; + } + + // Exit short position when RSI reaches sell target + if(rsi_current <= RSI_Target_Sell) + { + Print("TRACE: SELL position target reached!"); + ClosePosition(); + } + else + { + Print("TRACE: SELL position exit condition not met"); + } + } + } +} + +//+------------------------------------------------------------------+ +//| Check for entry signals | +//+------------------------------------------------------------------+ +void CheckEntrySignals() +{ + Print("TRACE: Checking entry signals..."); + Print("TRACE: Buy condition - rsi_two_bars_ago <= RSI_Oversold && rsi_prev > RSI_Oversold"); + Print("TRACE: Buy condition values - rsi_two_bars_ago=", rsi_two_bars_ago, " <= ", RSI_Oversold, " && rsi_prev=", rsi_prev, " > ", RSI_Oversold); + + // Buy signal: RSI crosses from oversold to above oversold (checking the actual crossover) + if(rsi_two_bars_ago <= RSI_Oversold && rsi_prev > RSI_Oversold) + { + Print("TRACE: Buy signal detected!"); + OpenBuyPosition(); + } + else + { + Print("TRACE: Buy signal condition not met"); + } + + Print("TRACE: Sell condition - rsi_two_bars_ago >= RSI_Overbought && rsi_prev < RSI_Overbought"); + Print("TRACE: Sell condition values - rsi_two_bars_ago=", rsi_two_bars_ago, " >= ", RSI_Overbought, " && rsi_prev=", rsi_prev, " < ", RSI_Overbought); + + // Sell signal: RSI crosses from overbought to below overbought (checking the actual crossover) + if(rsi_two_bars_ago >= RSI_Overbought && rsi_prev < RSI_Overbought) + { + Print("TRACE: Sell signal detected!"); + OpenSellPosition(); + } + else + { + Print("TRACE: Sell signal condition not met"); + } +} + +//+------------------------------------------------------------------+ +//| Open buy position | +//+------------------------------------------------------------------+ +void OpenBuyPosition() +{ + Print("TRACE: Attempting to open buy position..."); + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); + Print("TRACE: Current ask price=", ask, " LotSize=", LotSize); + + if(trade.Buy(LotSize, _Symbol, ask, 0, 0, "RSI Scalping Buy")) + { + position_ticket = trade.ResultOrder(); + position_open = true; + current_position_type = POSITION_TYPE_BUY; + Print("TRACE: Buy position opened successfully! Ticket=", position_ticket, " Price=", ask); + } + else + { + Print("TRACE: Error opening buy position. Retcode=", trade.ResultRetcode(), " Description=", trade.ResultRetcodeDescription()); + } +} + +//+------------------------------------------------------------------+ +//| Open sell position | +//+------------------------------------------------------------------+ +void OpenSellPosition() +{ + Print("TRACE: Attempting to open sell position..."); + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); + Print("TRACE: Current bid price=", bid, " LotSize=", LotSize); + + if(trade.Sell(LotSize, _Symbol, bid, 0, 0, "RSI Scalping Sell")) + { + position_ticket = trade.ResultOrder(); + position_open = true; + current_position_type = POSITION_TYPE_SELL; + Print("TRACE: Sell position opened successfully! Ticket=", position_ticket, " Price=", bid); + } + else + { + Print("TRACE: Error opening sell position. Retcode=", trade.ResultRetcode(), " Description=", trade.ResultRetcodeDescription()); + } +} + +//+------------------------------------------------------------------+ +//| Close current position | +//+------------------------------------------------------------------+ +void ClosePosition() +{ + Print("TRACE: Attempting to close position. Ticket=", position_ticket); + + if(trade.PositionClose(position_ticket)) + { + Print("TRACE: Position closed successfully! Ticket=", position_ticket); + position_open = false; + position_ticket = 0; + rsi_against_position = false; + bars_against_count = 0; + } + else + { + Print("TRACE: Error closing position. Retcode=", trade.ResultRetcode(), " Description=", trade.ResultRetcodeDescription()); + } +} diff --git a/RSIScalpingEURUSD/test-balance.png b/RSIScalpingEURUSD/test-balance.png new file mode 100644 index 0000000..8a5e8d9 Binary files /dev/null and b/RSIScalpingEURUSD/test-balance.png differ diff --git a/RSIScalpingXAUUSD/main.mq5 b/RSIScalpingXAUUSD/main.mq5 new file mode 100644 index 0000000..3c231df --- /dev/null +++ b/RSIScalpingXAUUSD/main.mq5 @@ -0,0 +1,281 @@ +//+------------------------------------------------------------------+ +//| RSIScalping.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 ENUM_TIMEFRAMES TimeFrame = PERIOD_H1; // Timeframe for Analysis +input int RSI_Period = 14; // RSI Period +input ENUM_APPLIED_PRICE RSI_Applied_Price = PRICE_CLOSE; // RSI Applied Price +input double RSI_Overbought = 71; // RSI Overbought Level +input double RSI_Oversold = 57; // RSI Oversold Level +input double RSI_Target_Buy = 80; // RSI Target for Buy Exit +input double RSI_Target_Sell = 57; // RSI Target for Sell Exit +input int BarsToWait = 4; // Bars to wait when RSI goes against position +input double LotSize = 0.1; // Lot Size +input int MagicNumber = 12345; // Magic Number +input int Slippage = 3; // Slippage in points + +//--- Global variables +CTrade trade; +int rsi_handle; +double rsi_buffer[]; +double rsi_prev, rsi_current, rsi_two_bars_ago; +bool position_open = false; +int position_ticket = 0; +ENUM_POSITION_TYPE current_position_type = POSITION_TYPE_BUY; +datetime last_bar_time = 0; +bool rsi_against_position = false; +int bars_against_count = 0; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + // Initialize RSI indicator + rsi_handle = iRSI(_Symbol, TimeFrame, RSI_Period, RSI_Applied_Price); + if(rsi_handle == INVALID_HANDLE) + { + return(INIT_FAILED); + } + + // Initialize trade object + trade.SetExpertMagicNumber(MagicNumber); + trade.SetDeviationInPoints(Slippage); + trade.SetTypeFilling(ORDER_FILLING_FOK); + + // Allocate arrays + ArraySetAsSeries(rsi_buffer, true); + + return(INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) +{ + if(rsi_handle != INVALID_HANDLE) + IndicatorRelease(rsi_handle); +} + +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() +{ + // Check if we have enough bars + if(Bars(_Symbol, TimeFrame) < RSI_Period + 2) + { + return; + } + + // Check if this is a new bar + datetime current_bar_time = iTime(_Symbol, TimeFrame, 0); + if(current_bar_time == last_bar_time) + { + return; // Still the same bar, don't process + } + + last_bar_time = current_bar_time; + + // Update RSI values + if(!UpdateRSI()) + { + return; + } + + // Check for existing position + CheckExistingPosition(); + + // Check for new entry signals + if(!position_open) + { + CheckEntrySignals(); + } +} + +//+------------------------------------------------------------------+ +//| Update RSI values | +//+------------------------------------------------------------------+ +bool UpdateRSI() +{ + if(CopyBuffer(rsi_handle, 0, 0, 3, rsi_buffer) < 3) + { + return false; + } + + rsi_current = rsi_buffer[0]; // Current bar + rsi_prev = rsi_buffer[1]; // Previous bar + rsi_two_bars_ago = rsi_buffer[2]; // Two bars ago + + return true; +} + +//+------------------------------------------------------------------+ +//| Check existing position for exit conditions | +//+------------------------------------------------------------------+ +void CheckExistingPosition() +{ + if(!position_open) + { + return; + } + + // Check if position still exists + if(!PositionSelectByTicket(position_ticket)) + { + position_open = false; + position_ticket = 0; + rsi_against_position = false; + bars_against_count = 0; + return; + } + + // Exit conditions based on RSI target + if(current_position_type == POSITION_TYPE_BUY) + { + // Check if RSI is against the position (below oversold) + if(rsi_current < RSI_Oversold) + { + if(!rsi_against_position) + { + rsi_against_position = true; + bars_against_count = 1; + } + else + { + bars_against_count++; + } + + // Close position if RSI has been against for Y bars + if(bars_against_count >= BarsToWait) + { + ClosePosition(); + return; + } + } + else + { + // RSI is no longer against the position, reset counter + if(rsi_against_position) + { + rsi_against_position = false; + bars_against_count = 0; + } + + // Exit long position when RSI reaches buy target + if(rsi_current >= RSI_Target_Buy) + { + ClosePosition(); + } + } + } + else if(current_position_type == POSITION_TYPE_SELL) + { + // Check if RSI is against the position (above overbought) + if(rsi_current > RSI_Overbought) + { + if(!rsi_against_position) + { + rsi_against_position = true; + bars_against_count = 1; + } + else + { + bars_against_count++; + } + + // Close position if RSI has been against for Y bars + if(bars_against_count >= BarsToWait) + { + ClosePosition(); + return; + } + } + else + { + // RSI is no longer against the position, reset counter + if(rsi_against_position) + { + rsi_against_position = false; + bars_against_count = 0; + } + + // Exit short position when RSI reaches sell target + if(rsi_current <= RSI_Target_Sell) + { + ClosePosition(); + } + } + } +} + +//+------------------------------------------------------------------+ +//| Check for entry signals | +//+------------------------------------------------------------------+ +void CheckEntrySignals() +{ + // Buy signal: RSI crosses from oversold to above oversold (checking the actual crossover) + if(rsi_two_bars_ago <= RSI_Oversold && rsi_prev > RSI_Oversold) + { + OpenBuyPosition(); + } + + // Sell signal: RSI crosses from overbought to below overbought (checking the actual crossover) + if(rsi_two_bars_ago >= RSI_Overbought && rsi_prev < RSI_Overbought) + { + OpenSellPosition(); + } +} + +//+------------------------------------------------------------------+ +//| Open buy position | +//+------------------------------------------------------------------+ +void OpenBuyPosition() +{ + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); + + if(trade.Buy(LotSize, _Symbol, ask, 0, 0, "RSI Scalping Buy")) + { + position_ticket = trade.ResultOrder(); + position_open = true; + current_position_type = POSITION_TYPE_BUY; + } +} + +//+------------------------------------------------------------------+ +//| Open sell position | +//+------------------------------------------------------------------+ +void OpenSellPosition() +{ + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); + + if(trade.Sell(LotSize, _Symbol, bid, 0, 0, "RSI Scalping Sell")) + { + position_ticket = trade.ResultOrder(); + position_open = true; + current_position_type = POSITION_TYPE_SELL; + } +} + +//+------------------------------------------------------------------+ +//| Close current position | +//+------------------------------------------------------------------+ +void ClosePosition() +{ + if(trade.PositionClose(position_ticket)) + { + position_open = false; + position_ticket = 0; + rsi_against_position = false; + bars_against_count = 0; + } +} diff --git a/RSIScalpingXAUUSD/test-balance.png b/RSIScalpingXAUUSD/test-balance.png new file mode 100644 index 0000000..06f553b Binary files /dev/null and b/RSIScalpingXAUUSD/test-balance.png differ