Update
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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 <Trade\Trade.mqh>
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 282 KiB |
@@ -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 <Trade\Trade.mqh>
|
||||
|
||||
// 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;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 290 KiB |
Reference in New Issue
Block a user