315 lines
10 KiB
Plaintext
315 lines
10 KiB
Plaintext
// Input Parameters
|
|
#include <Trade\Trade.mqh>
|
|
|
|
input group "Trade Management"
|
|
input int MagicNumber = 7;
|
|
input int rsiPeriod = 19; // RSI period
|
|
input int overboughtLevel = 93; // Overbought level (RSI > 70 for sell)
|
|
input int oversoldLevel = 22; // Oversold level (RSI < 30 for buy)
|
|
input double entryRSIBuySpread = 0;
|
|
input double entryRSISellSpread = 0;
|
|
input double lotSize = 0.01; // Trade lot size
|
|
input int slippage = 3; // Slippage for orders
|
|
input int cooldownSeconds = 209; // Cooldown period in seconds
|
|
input ENUM_TIMEFRAMES TimeFrame1 = PERIOD_M1; // RSI Timeframe
|
|
input ENUM_TIMEFRAMES TimeFrame2 = PERIOD_M1; // EMA Timeframe
|
|
input ENUM_TIMEFRAMES BarTimeFrame = PERIOD_M12; // EMA Timeframe
|
|
input int emaPeriod = 140; // EMA period
|
|
input double emaSlopeThreshold = 105; // EMA slope threshold for trend strength
|
|
input double exitBuyRSI = 86;
|
|
input double exitSellRSI = 10;
|
|
input double TrailingStop = 295;
|
|
input double emaDistanceThreshold = 165;
|
|
input int tradingHourOneBegin = 24;
|
|
input int tradingHourOneEnd = 22;
|
|
input int tradingHourTwoBegin = 6;
|
|
input int tradingHourTwoEnd = 19;
|
|
datetime bartime;
|
|
// RSI Handle
|
|
int rsiHandle;
|
|
|
|
input bool Sunday =false; // Sunday
|
|
input bool Monday =false; // Monday
|
|
input bool Tuesday =true; // Tuesday
|
|
input bool Wednesday=true; // Wednesday
|
|
input bool Thursday =true; // Thursday
|
|
input bool Friday =false; // Friday
|
|
input bool Saturday =false; // Saturday
|
|
|
|
bool WeekDays[7];
|
|
|
|
void WeekDays_Init()
|
|
{
|
|
WeekDays[0]=Sunday;
|
|
WeekDays[1]=Monday;
|
|
WeekDays[2]=Tuesday;
|
|
WeekDays[3]=Wednesday;
|
|
WeekDays[4]=Thursday;
|
|
WeekDays[5]=Friday;
|
|
WeekDays[6]=Saturday;
|
|
}
|
|
|
|
bool WeekDays_Check(datetime aTime)
|
|
{
|
|
MqlDateTime stm;
|
|
TimeToStruct(aTime,stm);
|
|
return(WeekDays[stm.day_of_week]);
|
|
}
|
|
|
|
|
|
// EMA Handle
|
|
int emaHandle;
|
|
double previousRSIDef = 0;
|
|
// Create CTrade object for executing trades
|
|
CTrade trade;
|
|
|
|
// Track the last trade time
|
|
datetime lastTradeTime = 0;
|
|
|
|
void OnInit() {
|
|
WeekDays_Init();
|
|
|
|
// Create RSI handle
|
|
rsiHandle = iRSI(_Symbol, TimeFrame1, rsiPeriod, PRICE_CLOSE);
|
|
if (rsiHandle == INVALID_HANDLE) {
|
|
Print("Error creating RSI handle: ", GetLastError());
|
|
return;
|
|
}
|
|
|
|
// Create EMA handle
|
|
emaHandle = iMA(_Symbol, TimeFrame2, emaPeriod, 0, MODE_EMA, PRICE_CLOSE);
|
|
if (emaHandle == INVALID_HANDLE) {
|
|
Print("Error creating EMA handle: ", GetLastError());
|
|
return;
|
|
}
|
|
|
|
// Initialization successful
|
|
Print("RSI and EMA Reversal Strategy Initialized.");
|
|
}
|
|
|
|
void OnTick() {
|
|
if(bartime==iTime(_Symbol,BarTimeFrame,0))return;
|
|
bartime=iTime(_Symbol,BarTimeFrame,0);
|
|
|
|
// Check if RSI data is available
|
|
double rsi[];
|
|
if (CopyBuffer(rsiHandle, 0, 0, 2, rsi) <= 0) {
|
|
Print("Error copying RSI data: ", GetLastError());
|
|
return;
|
|
}
|
|
|
|
// Check if EMA data is available
|
|
double ema[];
|
|
if (CopyBuffer(emaHandle, 0, 0, 2, ema) <= 0) {
|
|
Print("Error copying EMA data: ", GetLastError());
|
|
return;
|
|
}
|
|
|
|
// Get the current time
|
|
datetime currentTime = TimeCurrent();
|
|
|
|
|
|
int currentHour = TimeHour(TimeCurrent());
|
|
|
|
if(!WeekDays_Check(TimeTradeServer())) {
|
|
Close_Position_MN(MagicNumber);
|
|
return;
|
|
}
|
|
|
|
if (!(currentHour < tradingHourOneEnd && currentHour > tradingHourOneBegin || currentHour < tradingHourTwoEnd && currentHour > tradingHourTwoBegin))
|
|
{
|
|
|
|
Close_Position_MN(MagicNumber);
|
|
return; // Prevent further trading during this time
|
|
}
|
|
|
|
|
|
// Ensure there is at least one position
|
|
bool hasPosition = (PositionsTotal() > 0);
|
|
|
|
|
|
|
|
// Get the current and previous RSI values
|
|
double currentRSI = rsi[0];
|
|
double previousRSI = rsi[1];
|
|
|
|
if(previousRSIDef == 0) {
|
|
previousRSIDef = currentRSI;
|
|
return;
|
|
}
|
|
|
|
// Get the current and previous EMA values
|
|
double currentEMA = ema[0];
|
|
double previousEMA = ema[1];
|
|
|
|
// Calculate the EMA slope (difference between current and previous EMA values)
|
|
double emaSlope = (currentEMA - previousEMA) * 100;
|
|
Print(emaSlope);
|
|
|
|
double closeCurr = iClose(Symbol(), Period(), 0); // Close of current bar
|
|
// ** NEW CODE: Calculate distance to EMA and adjust score **
|
|
double priceToEmaDistance = (closeCurr - currentEMA) * 10; // Distance between the current price and the EMA
|
|
Print("priceToEmaDistance");
|
|
Print(priceToEmaDistance);
|
|
|
|
|
|
// Determine if there are existing buy or sell positions
|
|
bool isBuyPosition = false;
|
|
bool isSellPosition = false;
|
|
if (hasPosition) {
|
|
if (PositionSelect(_Symbol)) {
|
|
int positionType = PositionGetInteger(POSITION_TYPE);
|
|
if (positionType == POSITION_TYPE_BUY) {
|
|
isBuyPosition = true;
|
|
} else if (positionType == POSITION_TYPE_SELL) {
|
|
isSellPosition = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
ApplyTrailingStop();
|
|
|
|
// Check if the cooldown period has elapsed since the last trade
|
|
bool cooldownPassed = (currentTime - lastTradeTime) >= cooldownSeconds;
|
|
|
|
// Check if EMA slope is above the threshold (indicating strong trend)
|
|
bool isTrendStrong = MathAbs(emaSlope) > emaSlopeThreshold || MathAbs(priceToEmaDistance) > emaDistanceThreshold;
|
|
|
|
// Close trade logic when RSI crosses 50
|
|
if (isBuyPosition && currentRSI > exitBuyRSI) {
|
|
// Close buy position
|
|
Close_Position_MN(MagicNumber);
|
|
lastTradeTime = currentTime; // Update last trade time
|
|
}
|
|
|
|
if (isSellPosition && currentRSI < exitSellRSI) {
|
|
Close_Position_MN(MagicNumber);
|
|
lastTradeTime = currentTime; // Update last trade time
|
|
|
|
}
|
|
|
|
|
|
// If the EMA slope is strong, do not place new trades
|
|
if (isTrendStrong) {
|
|
Close_Position_MN(MagicNumber);
|
|
lastTradeTime = currentTime; // Update last trade time
|
|
Print("Strong trend detected (EMA slope), skipping new trade.");
|
|
return;
|
|
}
|
|
|
|
// SELL logic (RSI crosses over the overbought level)
|
|
if (currentRSI < overboughtLevel - entryRSISellSpread && previousRSIDef >= overboughtLevel && !isSellPosition && !hasPosition && cooldownPassed) {
|
|
trade.SetExpertMagicNumber(MagicNumber);
|
|
if (trade.Sell(lotSize, _Symbol, 0, 0, "Sell Order")) {
|
|
Print("Sell order placed.");
|
|
lastTradeTime = currentTime; // Update last trade time
|
|
} else {
|
|
Print("Error placing sell order: ", GetLastError());
|
|
}
|
|
}
|
|
|
|
// BUY logic (RSI crosses below the oversold level)
|
|
if (currentRSI > oversoldLevel + entryRSIBuySpread && previousRSIDef <= oversoldLevel && !isBuyPosition && !hasPosition && cooldownPassed) {
|
|
trade.SetExpertMagicNumber(MagicNumber);
|
|
if (trade.Buy(lotSize, _Symbol, 0, 0, "Buy Order")) {
|
|
Print("Buy order placed.");
|
|
lastTradeTime = currentTime; // Update last trade time
|
|
} else {
|
|
Print("Error placing buy order: ", GetLastError());
|
|
}
|
|
}
|
|
|
|
previousRSIDef = currentRSI;
|
|
}
|
|
|
|
void OnDeinit(const int reason) {
|
|
// Release RSI and EMA handles on deinitialization
|
|
if (rsiHandle != INVALID_HANDLE) {
|
|
IndicatorRelease(rsiHandle);
|
|
Print("RSI handle released.");
|
|
}
|
|
if (emaHandle != INVALID_HANDLE) {
|
|
IndicatorRelease(emaHandle);
|
|
Print("EMA handle released.");
|
|
}
|
|
}
|
|
|
|
|
|
void Close_Position_MN(ulong magicNumber)
|
|
{
|
|
int total = PositionsTotal();
|
|
for(int i = total - 1; i >= 0; i--)
|
|
{
|
|
ulong ticket = PositionGetTicket(i);
|
|
|
|
// Use PositionSelect by symbol instead of ticket
|
|
string symbol = PositionGetSymbol(i);
|
|
if(PositionSelect(symbol))
|
|
{
|
|
if (PositionGetInteger(POSITION_MAGIC) == magicNumber && PositionGetInteger(POSITION_TICKET) == ticket)
|
|
{
|
|
if(symbol == _Symbol) // Verify the symbol
|
|
{
|
|
Print("MN " + magicNumber);
|
|
trade.PositionClose(ticket);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int errorCode = GetLastError();
|
|
Print("aaaa PositionSelect failed with error code: ", errorCode);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ApplyTrailingStop()
|
|
{
|
|
Print("Scanning for trailing stop");
|
|
for(int i=PositionsTotal()-1; i>=0; i--)
|
|
{
|
|
string symbol = PositionGetSymbol(i);
|
|
ulong PositionTicket = PositionGetTicket(i);
|
|
long trade_type = PositionGetInteger(POSITION_TYPE);
|
|
|
|
if(!PositionGetInteger(POSITION_MAGIC) == MagicNumber) {
|
|
return;
|
|
}
|
|
|
|
double POINT = SymbolInfoDouble( symbol, SYMBOL_POINT );
|
|
int DIGIT = (int) SymbolInfoInteger( symbol, SYMBOL_DIGITS );
|
|
|
|
|
|
if(trade_type == 0)
|
|
{
|
|
double Bid = NormalizeDouble(SymbolInfoDouble(symbol,SYMBOL_BID),DIGIT);
|
|
|
|
if(Bid-PositionGetDouble(POSITION_PRICE_OPEN) > NormalizeDouble(POINT * TrailingStop,DIGIT))
|
|
{
|
|
if(PositionGetDouble(POSITION_SL) < NormalizeDouble(Bid - POINT * TrailingStop,DIGIT))
|
|
{
|
|
trade.PositionModify(PositionTicket,NormalizeDouble(Bid - POINT * TrailingStop,DIGIT),PositionGetDouble(POSITION_TP));
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if(trade_type == 1)
|
|
{
|
|
double Ask = NormalizeDouble(SymbolInfoDouble(symbol,SYMBOL_ASK),DIGIT);
|
|
|
|
if((PositionGetDouble(POSITION_PRICE_OPEN) - Ask) > NormalizeDouble( POINT * TrailingStop,DIGIT))
|
|
{
|
|
if((PositionGetDouble(POSITION_SL) > NormalizeDouble(Ask + POINT * TrailingStop,DIGIT)) || (PositionGetDouble(POSITION_SL)==0))
|
|
{
|
|
trade.PositionModify(PositionTicket,NormalizeDouble(Ask + POINT * TrailingStop,DIGIT),PositionGetDouble(POSITION_TP));
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
int TimeHour(datetime when=0){ if(when == 0) when = TimeCurrent();
|
|
return when / 3600 % 24;
|
|
} |