diff --git a/RSIDivergenceExtremaEURUSD/main.mq5 b/RSIDivergenceExtremaEURUSD/main.mq5 index 21d05bf..f6f6c4a 100644 --- a/RSIDivergenceExtremaEURUSD/main.mq5 +++ b/RSIDivergenceExtremaEURUSD/main.mq5 @@ -235,7 +235,7 @@ int OnInit() } // Initialize trade object - trade.SetExpertMagicNumber(123456); + trade.SetExpertMagicNumber(123457); Print("RSI Divergence Rebound Strategy Initialized"); Print("RSI Period: ", RSI_Period); diff --git a/RSIReverseFollowAUDUSD/main.mq5 b/RSIReverseFollowAUDUSD/main.mq5 new file mode 100644 index 0000000..084ae07 --- /dev/null +++ b/RSIReverseFollowAUDUSD/main.mq5 @@ -0,0 +1,477 @@ +//+------------------------------------------------------------------+ +//| RSIReverseFollow.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" + +#include + +// Input parameters +input group "Timeframe Settings" +input ENUM_TIMEFRAMES InpTimeframe = PERIOD_M3; // Trading Timeframe + +input group "RSI Settings" +input int InpRSIPeriod = 48; // RSI Period +input double InpRSIOverbought = 68; // RSI Overbought Level +input double InpRSIOversold = 12; // RSI Oversold Level +input double InpRSI50Distance = 4.0; // Distance from 50 to consider as near + +input group "Strategy 1 - RSI 50 Touch" +input bool InpEnableStrategy1 = true; // Enable Strategy 1 +input int InpMagicNumber1 = 123456; // Magic Number for Strategy 1 +input double InpLotSize1 = 0.01; // Lot Size for Strategy 1 +input bool InpEnableRSIExit1 = true; // Enable RSI-based exit for Strategy 1 +input bool InpUseSLTPWithRSI1 = false; // Use SL/TP alongside RSI exits +input int InpStopLoss1 = 188; // Stop Loss in pips +input int InpTakeProfit1 = 547; // Take Profit in pips +input double InpRSIExitBuy1 = 97.0; // RSI level to exit buy trades +input double InpRSIExitSell1 = 20.0; // RSI level to exit sell trades +input int InpTrailingStop1 = 125; // Trailing Stop in pips +input int InpTrailingStep1 = 400; // Trailing Step in pips +input int InpMaxTradeDuration1 = 22; // Maximum trade duration (hours) +input double InpLossThreshold1 = 7.1; // Minimum loss threshold to close trade + +input group "Strategy 2 - RSI Reversal" +input bool InpEnableStrategy2 = true; // Enable Strategy 2 +input int InpMagicNumber2 = 123457; // Magic Number for Strategy 2 +input double InpLotSize2 = 0.01; // Lot Size for Strategy 2 +input bool InpEnableRSIExit2 = false; // Enable RSI-based exit for Strategy 2 +input bool InpUseSLTPWithRSI2 = true; // Use SL/TP alongside RSI exits +input int InpStopLoss2 = 245; // Stop Loss in pips +input int InpTakeProfit2 = 410; // Take Profit in pips +input double InpRSIExitBuy2 = 70.0; // RSI level to exit buy trades +input double InpRSIExitSell2 = 5.0; // RSI level to exit sell trades +input int InpTrailingStop2 = 185; // Trailing Stop in pips +input int InpTrailingStep2 = 30; // Trailing Step in pips +input int InpMaxTradeDuration2 = 6; // Maximum trade duration (hours) +input double InpLossThreshold2 = 9.3; // Minimum loss threshold to close trade + +input group "Trading Hours" +input int InpStartHour = 16; // Trading Session Start Hour +input int InpEndHour = 19; // Trading Session End Hour +input bool InpCloseOutsideHours = true;// Close trades outside trading hours + +// Global variables +CTrade trade; +int rsiHandle; +double lastRSI[]; +bool wasOverbought = false; +bool wasOversold = false; +datetime lastBarTime = 0; +bool debugMode = true; // Enable detailed logging + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + // Initialize RSI indicator + rsiHandle = iRSI(_Symbol, InpTimeframe, InpRSIPeriod, PRICE_CLOSE); + if(rsiHandle == INVALID_HANDLE) + { + Print("Error creating RSI indicator"); + return INIT_FAILED; + } + + // Initialize trade settings + trade.SetExpertMagicNumber(InpMagicNumber1); + trade.SetMarginMode(); + trade.SetTypeFillingBySymbol(_Symbol); + trade.SetDeviationInPoints(10); + + // Initialize RSI array + ArraySetAsSeries(lastRSI, true); + ArrayResize(lastRSI, 3); + + return(INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) +{ + IndicatorRelease(rsiHandle); +} + +//+------------------------------------------------------------------+ +//| Check if new bar has formed | +//+------------------------------------------------------------------+ +bool IsNewBar() +{ + datetime time[]; + if(CopyTime(_Symbol, InpTimeframe, 0, 1, time) > 0) + { + if(time[0] != lastBarTime) + { + lastBarTime = time[0]; + return true; + } + } + return false; +} + +//+------------------------------------------------------------------+ +//| Check if within trading hours | +//+------------------------------------------------------------------+ +bool IsWithinTradingHours() +{ + datetime currentTime = TimeCurrent(); + MqlDateTime timeStruct; + TimeToStruct(currentTime, timeStruct); + + return (timeStruct.hour >= InpStartHour && timeStruct.hour < InpEndHour); +} + +//+------------------------------------------------------------------+ +//| Check for RSI signals | +//+------------------------------------------------------------------+ +void CheckRSISignals() +{ + // Get RSI values for current and previous bars + if(CopyBuffer(rsiHandle, 0, 0, 3, lastRSI) <= 0) + { + Print("Error getting RSI values"); + return; + } + + // Check for RSI extremes + if(lastRSI[0] >= InpRSIOverbought) + { + wasOverbought = true; + } + + if(lastRSI[0] <= InpRSIOversold) + { + wasOversold = true; + } +} + +//+------------------------------------------------------------------+ +//| Check for trailing stop | +//+------------------------------------------------------------------+ +void CheckTrailingStop(int magic, int trailingStop, int trailingStep) +{ + if(!PositionSelectByTicket(magic)) + return; + + double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT); + double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); + double stopLoss = PositionGetDouble(POSITION_SL); + ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); + + double newStopLoss = 0; + double trailingStopPoints = trailingStop * _Point; + double trailingStepPoints = trailingStep * _Point; + + if(posType == POSITION_TYPE_BUY) + { + if(currentPrice - openPrice > trailingStopPoints) + { + newStopLoss = currentPrice - trailingStopPoints; + if(newStopLoss > stopLoss + trailingStepPoints) + { + trade.PositionModify(magic, newStopLoss, PositionGetDouble(POSITION_TP)); + } + } + } + else if(posType == POSITION_TYPE_SELL) + { + if(openPrice - currentPrice > trailingStopPoints) + { + newStopLoss = currentPrice + trailingStopPoints; + if(newStopLoss < stopLoss - trailingStepPoints || stopLoss == 0) + { + trade.PositionModify(magic, newStopLoss, PositionGetDouble(POSITION_TP)); + } + } + } +} + +//+------------------------------------------------------------------+ +//| Check for time-based exits | +//+------------------------------------------------------------------+ +void CheckTimeBasedExits(int magic, int maxDuration, double lossThreshold) +{ + datetime currentTime = TimeCurrent(); + + if(PositionSelectByTicket(magic)) + { + datetime openTime = (datetime)PositionGetInteger(POSITION_TIME); + double profit = PositionGetDouble(POSITION_PROFIT); + double swap = PositionGetDouble(POSITION_SWAP); + double totalLoss = profit + swap; + + if(currentTime - openTime >= maxDuration * 3600) + { + if(totalLoss < -lossThreshold) + { + trade.PositionClose(magic); + } + } + } +} + +//+------------------------------------------------------------------+ +//| Check for trading hours exits | +//+------------------------------------------------------------------+ +void CheckTradingHoursExits() +{ + if(!InpCloseOutsideHours) + return; + + if(!IsWithinTradingHours()) + { + // Close Strategy 1 positions + if(PositionSelectByTicket(InpMagicNumber1)) + { + trade.PositionClose(InpMagicNumber1); + } + + // Close Strategy 2 positions + if(PositionSelectByTicket(InpMagicNumber2)) + { + trade.PositionClose(InpMagicNumber2); + } + } +} + +//+------------------------------------------------------------------+ +//| Check for RSI-based exits | +//+------------------------------------------------------------------+ +void CheckRSIExits(int magic, bool enableRSIExit, double exitBuyLevel, double exitSellLevel) +{ + if(!enableRSIExit) + return; + + // Try to find position by magic number + for(int i = PositionsTotal() - 1; i >= 0; i--) + { + if(PositionSelectByTicket(PositionGetTicket(i))) + { + if(PositionGetInteger(POSITION_MAGIC) == magic) + { + ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); + double currentRSI = lastRSI[0]; + + if(posType == POSITION_TYPE_BUY && currentRSI <= exitBuyLevel) + { + ulong ticket = PositionGetTicket(i); + if(trade.PositionClose(ticket)) + { + Print("Strategy ", magic == InpMagicNumber1 ? "1" : "2", " Buy position closed due to RSI exit level", + "\nTicket: ", ticket, + "\nRSI: ", DoubleToString(currentRSI, 2), + "\nExit Level: ", DoubleToString(exitBuyLevel, 2)); + } + else + { + Print("Failed to close Strategy ", magic == InpMagicNumber1 ? "1" : "2", " Buy position", + "\nTicket: ", ticket, + "\nRSI: ", DoubleToString(currentRSI, 2), + "\nExit Level: ", DoubleToString(exitBuyLevel, 2), + "\nError: ", GetLastError()); + } + } + else if(posType == POSITION_TYPE_SELL && currentRSI >= exitSellLevel) + { + ulong ticket = PositionGetTicket(i); + if(trade.PositionClose(ticket)) + { + Print("Strategy ", magic == InpMagicNumber1 ? "1" : "2", " Sell position closed due to RSI exit level", + "\nTicket: ", ticket, + "\nRSI: ", DoubleToString(currentRSI, 2), + "\nExit Level: ", DoubleToString(exitSellLevel, 2)); + } + else + { + Print("Failed to close Strategy ", magic == InpMagicNumber1 ? "1" : "2", " Sell position", + "\nTicket: ", ticket, + "\nRSI: ", DoubleToString(currentRSI, 2), + "\nExit Level: ", DoubleToString(exitSellLevel, 2), + "\nError: ", GetLastError()); + } + } + } + } + } +} + +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() +{ + // Check trading hours exits + CheckTradingHoursExits(); + + // Only process on new bar + if(!IsNewBar()) + { + // Check trailing stops and time-based exits every tick + if(InpEnableStrategy1) + { + CheckTrailingStop(InpMagicNumber1, InpTrailingStop1, InpTrailingStep1); + CheckTimeBasedExits(InpMagicNumber1, InpMaxTradeDuration1, InpLossThreshold1); + } + + if(InpEnableStrategy2) + { + CheckTrailingStop(InpMagicNumber2, InpTrailingStop2, InpTrailingStep2); + CheckTimeBasedExits(InpMagicNumber2, InpMaxTradeDuration2, InpLossThreshold2); + } + return; + } + + // Check for RSI signals + CheckRSISignals(); + + // Get current price + double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK); + double stopLoss = 0; + double takeProfit = 0; + + // Strategy 1: Enter on RSI 50 touch after oversold/overbought + if(InpEnableStrategy1) + { + if(!IsWithinTradingHours()) + { + MqlDateTime timeStruct; + TimeToStruct(TimeCurrent(), timeStruct); + Print("Strategy 1: Outside trading hours", + "\nCurrent Hour: ", timeStruct.hour, + "\nTrading Hours: ", InpStartHour, ":00 - ", InpEndHour, ":00"); + return; + } + + // Check for RSI-based exits for Strategy 1 + if(InpEnableRSIExit1) + { + CheckRSIExits(InpMagicNumber1, true, InpRSIExitBuy1, InpRSIExitSell1); + } + + // Log current RSI state + Print("Strategy 1 Current State:", + "\nRSI: ", DoubleToString(lastRSI[0], 2), + "\nDistance from 50: ", DoubleToString(MathAbs(lastRSI[0] - 50), 2), + "\nWas Oversold: ", wasOversold ? "Yes" : "No", + "\nWas Overbought: ", wasOverbought ? "Yes" : "No", + "\nPosition Exists: ", PositionSelectByTicket(InpMagicNumber1) ? "Yes" : "No"); + + // Buy signal: RSI was oversold and now is near 50 + if(wasOversold && MathAbs(lastRSI[0] - 50) <= InpRSI50Distance) + { + if(!PositionSelectByTicket(InpMagicNumber1)) + { + stopLoss = InpEnableRSIExit1 && !InpUseSLTPWithRSI1 ? 0 : currentPrice - InpStopLoss1 * _Point; + takeProfit = InpEnableRSIExit1 && !InpUseSLTPWithRSI1 ? 0 : currentPrice + InpTakeProfit1 * _Point; + + trade.SetExpertMagicNumber(InpMagicNumber1); + if(trade.Buy(InpLotSize1, _Symbol, 0, stopLoss, takeProfit, "RSI 50 Touch Buy")) + { + Print("Strategy 1 Buy trade executed: RSI was oversold and now near 50", + "\nRSI: ", DoubleToString(lastRSI[0], 2), + "\nDistance from 50: ", DoubleToString(MathAbs(lastRSI[0] - 50), 2), + "\nEntry Price: ", DoubleToString(currentPrice, _Digits), + "\nStop Loss: ", stopLoss == 0 ? "None" : DoubleToString(stopLoss, _Digits), + "\nTake Profit: ", takeProfit == 0 ? "None" : DoubleToString(takeProfit, _Digits)); + wasOversold = false; + } + else + { + Print("Failed to execute Strategy 1 Buy trade", + "\nRSI: ", DoubleToString(lastRSI[0], 2), + "\nDistance from 50: ", DoubleToString(MathAbs(lastRSI[0] - 50), 2), + "\nError: ", GetLastError()); + } + } + else + { + Print("Strategy 1 Buy signal detected but position already exists", + "\nRSI: ", DoubleToString(lastRSI[0], 2), + "\nDistance from 50: ", DoubleToString(MathAbs(lastRSI[0] - 50), 2)); + } + } + + // Sell signal: RSI was overbought and now is near 50 + if(wasOverbought && MathAbs(lastRSI[0] - 50) <= InpRSI50Distance) + { + if(!PositionSelectByTicket(InpMagicNumber1)) + { + stopLoss = InpEnableRSIExit1 && !InpUseSLTPWithRSI1 ? 0 : currentPrice + InpStopLoss1 * _Point; + takeProfit = InpEnableRSIExit1 && !InpUseSLTPWithRSI1 ? 0 : currentPrice - InpTakeProfit1 * _Point; + + trade.SetExpertMagicNumber(InpMagicNumber1); + if(trade.Sell(InpLotSize1, _Symbol, 0, stopLoss, takeProfit, "RSI 50 Touch Sell")) + { + Print("Strategy 1 Sell trade executed: RSI was overbought and now near 50", + "\nRSI: ", DoubleToString(lastRSI[0], 2), + "\nDistance from 50: ", DoubleToString(MathAbs(lastRSI[0] - 50), 2), + "\nEntry Price: ", DoubleToString(currentPrice, _Digits), + "\nStop Loss: ", stopLoss == 0 ? "None" : DoubleToString(stopLoss, _Digits), + "\nTake Profit: ", takeProfit == 0 ? "None" : DoubleToString(takeProfit, _Digits)); + wasOverbought = false; + } + else + { + Print("Failed to execute Strategy 1 Sell trade", + "\nRSI: ", DoubleToString(lastRSI[0], 2), + "\nDistance from 50: ", DoubleToString(MathAbs(lastRSI[0] - 50), 2), + "\nError: ", GetLastError()); + } + } + else + { + Print("Strategy 1 Sell signal detected but position already exists", + "\nRSI: ", DoubleToString(lastRSI[0], 2), + "\nDistance from 50: ", DoubleToString(MathAbs(lastRSI[0] - 50), 2)); + } + } + } + + // Strategy 2: Enter on RSI reversal from extremes + if(InpEnableStrategy2 && IsWithinTradingHours()) + { + // Check for RSI-based exits for Strategy 2 + if(InpEnableRSIExit2) + { + CheckRSIExits(InpMagicNumber2, true, InpRSIExitBuy2, InpRSIExitSell2); + } + + // Sell signal: RSI was overbought and now is moving down + if(wasOverbought && lastRSI[0] < lastRSI[1] && !PositionSelectByTicket(InpMagicNumber2)) + { + stopLoss = InpEnableRSIExit2 && !InpUseSLTPWithRSI2 ? 0 : currentPrice + InpStopLoss2 * _Point; + takeProfit = InpEnableRSIExit2 && !InpUseSLTPWithRSI2 ? 0 : currentPrice - InpTakeProfit2 * _Point; + + trade.SetExpertMagicNumber(InpMagicNumber2); + trade.Sell(InpLotSize2, _Symbol, 0, stopLoss, takeProfit, "RSI Reversal Sell"); + } + + // Buy signal: RSI was oversold and now is moving up + if(wasOversold && lastRSI[0] > lastRSI[1] && !PositionSelectByTicket(InpMagicNumber2)) + { + stopLoss = InpEnableRSIExit2 && !InpUseSLTPWithRSI2 ? 0 : currentPrice - InpStopLoss2 * _Point; + takeProfit = InpEnableRSIExit2 && !InpUseSLTPWithRSI2 ? 0 : currentPrice + InpTakeProfit2 * _Point; + + trade.SetExpertMagicNumber(InpMagicNumber2); + trade.Buy(InpLotSize2, _Symbol, 0, stopLoss, takeProfit, "RSI Reversal Buy"); + } + } + + // Check trailing stops and time-based exits + if(InpEnableStrategy1) + { + CheckTrailingStop(InpMagicNumber1, InpTrailingStop1, InpTrailingStep1); + CheckTimeBasedExits(InpMagicNumber1, InpMaxTradeDuration1, InpLossThreshold1); + } + + if(InpEnableStrategy2) + { + CheckTrailingStop(InpMagicNumber2, InpTrailingStop2, InpTrailingStep2); + CheckTimeBasedExits(InpMagicNumber2, InpMaxTradeDuration2, InpLossThreshold2); + } +} diff --git a/RSIReverseFollowAUDUSD/test-balance.jpg b/RSIReverseFollowAUDUSD/test-balance.jpg new file mode 100644 index 0000000..abdd824 Binary files /dev/null and b/RSIReverseFollowAUDUSD/test-balance.jpg differ diff --git a/SmartRSIAUDUSD/main.mq5 b/SmartRSIAUDUSD/main.mq5 new file mode 100644 index 0000000..dc3e87a --- /dev/null +++ b/SmartRSIAUDUSD/main.mq5 @@ -0,0 +1,352 @@ +//+------------------------------------------------------------------+ +//| SmartRSI.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" + +#include + +// Input parameters for RSI +input group "RSI Settings" +input int RSI_Period = 125; // RSI Period +input ENUM_APPLIED_PRICE RSI_Price = PRICE_MEDIAN; // RSI Applied Price + +// Strategy Selection +input group "Strategy Selection" +input bool UseTrendFollowing = false; // Use Trend Following Strategy +input bool UseReversal = true; // Use Reversal Strategy + +// Time Frames +input group "Time Frames" +input ENUM_TIMEFRAMES Trend_TimeFrame = PERIOD_H12; // Trend Following Time Frame +input ENUM_TIMEFRAMES Rev_TimeFrame = PERIOD_M6; // Reversal Time Frame + +// Enum for RSI conditions +enum ENUM_RSI_CONDITION +{ + RSI_BELOW_OVERSOLD, // RSI below oversold level + RSI_ABOVE_OVERBOUGHT, // RSI above overbought level + RSI_BELOW_MIDPOINT, // RSI below midpoint + RSI_ABOVE_MIDPOINT, // RSI above midpoint + RSI_CROSS_OVERSOLD, // RSI crosses below oversold + RSI_CROSS_OVERBOUGHT // RSI crosses above overbought +}; + +// Entry/Exit Conditions +input group "Entry/Exit Conditions" +input ENUM_RSI_CONDITION Trend_Entry_Condition = RSI_BELOW_OVERSOLD; // Trend Entry Condition +input ENUM_RSI_CONDITION Trend_Exit_Condition = RSI_BELOW_MIDPOINT; // Trend Exit Condition +input ENUM_RSI_CONDITION Rev_Entry_Condition = RSI_CROSS_OVERSOLD; // Reversal Entry Condition +input ENUM_RSI_CONDITION Rev_Exit_Condition = RSI_BELOW_MIDPOINT; // Reversal Exit Condition + +// Trend Following Strategy Parameters +input group "Trend Following Strategy" +input double Trend_Overbought = 11; // Overbought level for trend following +input double Trend_Oversold = 26; // Oversold level for trend following +input double Trend_Exit_Long = 50; // Exit level for long positions +input double Trend_Exit_Short = 50; // Exit level for short positions +input double Trend_LotSize = 0.09; // Lot size for trend following +input int Trend_Magic = 12345; // Magic number for trend following +input bool Trend_CloseOpposite = false; // Close opposite trades on profit +input double Trend_ProfitToClose = 180; // Profit in points to close opposite trades +input int Trend_TimeToClose = 1; // Bars to wait before closing opposite trades + +// Reversal Strategy Parameters +input group "Reversal Strategy" +input double Rev_Overbought = 60; // Overbought level for reversal +input double Rev_Oversold = 226; // Oversold level for reversal +input double Rev_Exit_Long = 50; // Exit level for long positions +input double Rev_Exit_Short = 50; // Exit level for short positions +input double Rev_LotSize = 0.06; // Lot size for reversal +input int Rev_Magic = 54321; // Magic number for reversal +input bool Rev_CloseOpposite = true; // Close opposite trades on profit +input double Rev_ProfitToClose = 105; // Profit in points to close opposite trades +input int Rev_TimeToClose = 5; // Bars to wait before closing opposite trades + +// Indicator buffers +double trend_rsi_buffer[]; +double rev_rsi_buffer[]; +int trend_rsi_handle; +int rev_rsi_handle; +CTrade trade; +datetime last_trend_bar_time; +datetime last_rev_bar_time; +datetime trend_long_entry_time = 0; +datetime trend_short_entry_time = 0; +datetime rev_long_entry_time = 0; +datetime rev_short_entry_time = 0; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + // Initialize RSI indicators + trend_rsi_handle = iRSI(_Symbol, Trend_TimeFrame, RSI_Period, RSI_Price); + rev_rsi_handle = iRSI(_Symbol, Rev_TimeFrame, RSI_Period, RSI_Price); + + if(trend_rsi_handle == INVALID_HANDLE || rev_rsi_handle == INVALID_HANDLE) + { + Print("Failed to create RSI indicators"); + return INIT_FAILED; + } + + // Set buffer size and series + ArraySetAsSeries(trend_rsi_buffer, true); + ArraySetAsSeries(rev_rsi_buffer, true); + + // Initialize trade object + trade.SetExpertMagicNumber(Trend_Magic); + trade.SetMarginMode(); + trade.SetTypeFillingBySymbol(_Symbol); + trade.SetDeviationInPoints(10); + + // Initialize last bar times + last_trend_bar_time = 0; + last_rev_bar_time = 0; + + return(INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) +{ + if(trend_rsi_handle != INVALID_HANDLE) + IndicatorRelease(trend_rsi_handle); + if(rev_rsi_handle != INVALID_HANDLE) + IndicatorRelease(rev_rsi_handle); +} + +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() +{ + datetime current_trend_time = iTime(_Symbol, Trend_TimeFrame, 0); + datetime current_rev_time = iTime(_Symbol, Rev_TimeFrame, 0); + + // Check if new bar has formed for trend following + if(current_trend_time != last_trend_bar_time) + { + last_trend_bar_time = current_trend_time; + + // Update RSI values for trend following + if(CopyBuffer(trend_rsi_handle, 0, 0, 2, trend_rsi_buffer) <= 0) + { + Print("Failed to copy trend RSI buffer"); + return; + } + + // Run trend following strategy if enabled + if(UseTrendFollowing) + CheckTrendFollowing(); + } + + // Check if new bar has formed for reversal + if(current_rev_time != last_rev_bar_time) + { + last_rev_bar_time = current_rev_time; + + // Update RSI values for reversal + if(CopyBuffer(rev_rsi_handle, 0, 0, 2, rev_rsi_buffer) <= 0) + { + Print("Failed to copy reversal RSI buffer"); + return; + } + + // Run reversal strategy if enabled + if(UseReversal) + CheckReversal(); + } +} + +//+------------------------------------------------------------------+ +//| Check RSI Condition | +//+------------------------------------------------------------------+ +bool CheckRSICondition(ENUM_RSI_CONDITION condition, double level, double &buffer[]) +{ + switch(condition) + { + case RSI_BELOW_OVERSOLD: + return buffer[0] < level; + case RSI_ABOVE_OVERBOUGHT: + return buffer[0] > level; + case RSI_BELOW_MIDPOINT: + return buffer[0] < 50; + case RSI_ABOVE_MIDPOINT: + return buffer[0] > 50; + case RSI_CROSS_OVERSOLD: + return buffer[0] < level && buffer[1] >= level; + case RSI_CROSS_OVERBOUGHT: + return buffer[0] > level && buffer[1] <= level; + } + return false; +} + +//+------------------------------------------------------------------+ +//| Check Trend Following Strategy | +//+------------------------------------------------------------------+ +void CheckTrendFollowing() +{ + // Check for existing positions + bool hasLong = PositionSelectByMagic(Trend_Magic, POSITION_TYPE_BUY); + bool hasShort = PositionSelectByMagic(Trend_Magic, POSITION_TYPE_SELL); + + // Entry logic + if(!hasLong && !hasShort) + { + if(CheckRSICondition(Trend_Entry_Condition, Trend_Oversold, trend_rsi_buffer)) + { + // Open short position + trade.SetExpertMagicNumber(Trend_Magic); + trade.Sell(Trend_LotSize, _Symbol, 0, 0, 0, "SmartRSI Trend"); + trend_short_entry_time = TimeCurrent(); + } + else if(CheckRSICondition(Trend_Entry_Condition, Trend_Overbought, trend_rsi_buffer)) + { + // Open long position + trade.SetExpertMagicNumber(Trend_Magic); + trade.Buy(Trend_LotSize, _Symbol, 0, 0, 0, "SmartRSI Trend"); + trend_long_entry_time = TimeCurrent(); + } + } + + // Exit logic + if(hasLong && CheckRSICondition(Trend_Exit_Condition, Trend_Exit_Long, trend_rsi_buffer)) + { + trade.SetExpertMagicNumber(Trend_Magic); + trade.PositionClose(_Symbol); + } + else if(hasShort && CheckRSICondition(Trend_Exit_Condition, Trend_Exit_Short, trend_rsi_buffer)) + { + trade.SetExpertMagicNumber(Trend_Magic); + trade.PositionClose(_Symbol); + } + + // Check for opposite trade closing + if(Trend_CloseOpposite) + { + if(hasLong && (TimeCurrent() - trend_long_entry_time) >= Trend_TimeToClose * PeriodSeconds(Trend_TimeFrame)) + { + double profit = PositionGetDouble(POSITION_PROFIT); + if(profit >= Trend_ProfitToClose * _Point) + { + // Close short position if exists + if(PositionSelectByMagic(Trend_Magic, POSITION_TYPE_SELL)) + { + trade.SetExpertMagicNumber(Trend_Magic); + trade.PositionClose(_Symbol); + } + } + } + else if(hasShort && (TimeCurrent() - trend_short_entry_time) >= Trend_TimeToClose * PeriodSeconds(Trend_TimeFrame)) + { + double profit = PositionGetDouble(POSITION_PROFIT); + if(profit >= Trend_ProfitToClose * _Point) + { + // Close long position if exists + if(PositionSelectByMagic(Trend_Magic, POSITION_TYPE_BUY)) + { + trade.SetExpertMagicNumber(Trend_Magic); + trade.PositionClose(_Symbol); + } + } + } + } +} + +//+------------------------------------------------------------------+ +//| Check Reversal Strategy | +//+------------------------------------------------------------------+ +void CheckReversal() +{ + // Check for existing positions + bool hasLong = PositionSelectByMagic(Rev_Magic, POSITION_TYPE_BUY); + bool hasShort = PositionSelectByMagic(Rev_Magic, POSITION_TYPE_SELL); + + // Entry logic + if(!hasLong && !hasShort) + { + if(CheckRSICondition(Rev_Entry_Condition, Rev_Oversold, rev_rsi_buffer)) + { + // Open long position + trade.SetExpertMagicNumber(Rev_Magic); + trade.Buy(Rev_LotSize, _Symbol, 0, 0, 0, "SmartRSI Reversal"); + rev_long_entry_time = TimeCurrent(); + } + else if(CheckRSICondition(Rev_Entry_Condition, Rev_Overbought, rev_rsi_buffer)) + { + // Open short position + trade.SetExpertMagicNumber(Rev_Magic); + trade.Sell(Rev_LotSize, _Symbol, 0, 0, 0, "SmartRSI Reversal"); + rev_short_entry_time = TimeCurrent(); + } + } + + // Exit logic + if(hasLong && CheckRSICondition(Rev_Exit_Condition, Rev_Exit_Long, rev_rsi_buffer)) + { + trade.SetExpertMagicNumber(Rev_Magic); + trade.PositionClose(_Symbol); + } + else if(hasShort && CheckRSICondition(Rev_Exit_Condition, Rev_Exit_Short, rev_rsi_buffer)) + { + trade.SetExpertMagicNumber(Rev_Magic); + trade.PositionClose(_Symbol); + } + + // Check for opposite trade closing + if(Rev_CloseOpposite) + { + if(hasLong && (TimeCurrent() - rev_long_entry_time) >= Rev_TimeToClose * PeriodSeconds(Rev_TimeFrame)) + { + double profit = PositionGetDouble(POSITION_PROFIT); + if(profit >= Rev_ProfitToClose * _Point) + { + // Close short position if exists + if(PositionSelectByMagic(Rev_Magic, POSITION_TYPE_SELL)) + { + trade.SetExpertMagicNumber(Rev_Magic); + trade.PositionClose(_Symbol); + } + } + } + else if(hasShort && (TimeCurrent() - rev_short_entry_time) >= Rev_TimeToClose * PeriodSeconds(Rev_TimeFrame)) + { + double profit = PositionGetDouble(POSITION_PROFIT); + if(profit >= Rev_ProfitToClose * _Point) + { + // Close long position if exists + if(PositionSelectByMagic(Rev_Magic, POSITION_TYPE_BUY)) + { + trade.SetExpertMagicNumber(Rev_Magic); + trade.PositionClose(_Symbol); + } + } + } + } +} + +//+------------------------------------------------------------------+ +//| Position Select By Magic | +//+------------------------------------------------------------------+ +bool PositionSelectByMagic(int magic, ENUM_POSITION_TYPE posType) +{ + for(int i = PositionsTotal() - 1; i >= 0; i--) + { + if(PositionGetTicket(i)) + { + if(PositionGetInteger(POSITION_MAGIC) == magic && + PositionGetInteger(POSITION_TYPE) == posType) + { + return true; + } + } + } + return false; +} diff --git a/SmartRSIAUDUSD/test-balance.jpg b/SmartRSIAUDUSD/test-balance.jpg new file mode 100644 index 0000000..181e8e1 Binary files /dev/null and b/SmartRSIAUDUSD/test-balance.jpg differ