191 lines
7.2 KiB
MQL5
191 lines
7.2 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| EA1.mq5 |
|
|
//| SMA 12/26 Crossover Strategy |
|
|
//| Timeframe: M15 |
|
|
//| TP: 1000 pips | SL: 500 pips |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "EA1"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
#include <Trade\Trade.mqh>
|
|
|
|
//--- Input Parameters
|
|
input int FastPeriod = 12; // Fast SMA Period
|
|
input int SlowPeriod = 26; // Slow SMA Period
|
|
input double LotSize = 0.1; // Trade Lot Size
|
|
input int TakeProfitPips = 1000; // Take Profit in Pips
|
|
input int StopLossPips = 500; // Stop Loss in Pips
|
|
input double PipSize = 0.0001; // Pip Size (0.0001 for FX, 0.01 for JPY pairs)
|
|
input int MagicNumber = 112600; // Magic Number
|
|
|
|
//--- Global Variables
|
|
CTrade trade;
|
|
int fastHandle;
|
|
int slowHandle;
|
|
datetime lastBarTime = 0;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
// Validate inputs
|
|
if(FastPeriod >= SlowPeriod)
|
|
{
|
|
Print("ERROR: FastPeriod must be less than SlowPeriod.");
|
|
return INIT_PARAMETERS_INCORRECT;
|
|
}
|
|
|
|
// Create SMA indicator handles on M15 timeframe
|
|
fastHandle = iMA(_Symbol, PERIOD_M15, FastPeriod, 0, MODE_SMA, PRICE_CLOSE);
|
|
slowHandle = iMA(_Symbol, PERIOD_M15, SlowPeriod, 0, MODE_SMA, PRICE_CLOSE);
|
|
|
|
if(fastHandle == INVALID_HANDLE || slowHandle == INVALID_HANDLE)
|
|
{
|
|
Print("ERROR: Failed to create MA indicator handles.");
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
trade.SetExpertMagicNumber(MagicNumber);
|
|
trade.SetDeviationInPoints(10);
|
|
|
|
Print("EA1 initialized | Symbol: ", _Symbol,
|
|
" | FastSMA: ", FastPeriod,
|
|
" | SlowSMA: ", SlowPeriod,
|
|
" | TP: ", TakeProfitPips, " pips",
|
|
" | SL: ", StopLossPips, " pips");
|
|
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert deinitialization function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
if(fastHandle != INVALID_HANDLE) IndicatorRelease(fastHandle);
|
|
if(slowHandle != INVALID_HANDLE) IndicatorRelease(slowHandle);
|
|
Print("EA1 deinitialized.");
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert tick function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
// Only process logic on a new M15 bar
|
|
datetime currentBarTime = iTime(_Symbol, PERIOD_M15, 0);
|
|
if(currentBarTime == lastBarTime)
|
|
return;
|
|
lastBarTime = currentBarTime;
|
|
|
|
// Get crossover signal from closed bars [1] and [2]
|
|
int signal = CheckCrossover();
|
|
if(signal == 0)
|
|
return;
|
|
|
|
// Close any opposite open position before opening a new trade
|
|
CloseOppositePosition(signal);
|
|
|
|
// Avoid opening a duplicate position in the same direction
|
|
if(HasOpenPosition(signal))
|
|
return;
|
|
|
|
// Calculate SL and TP in price
|
|
double tpDistance = TakeProfitPips * PipSize;
|
|
double slDistance = StopLossPips * PipSize;
|
|
|
|
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
|
|
if(signal == 1) // BUY signal — SMA12 crossed above SMA26
|
|
{
|
|
double sl = NormalizeDouble(ask - slDistance, _Digits);
|
|
double tp = NormalizeDouble(ask + tpDistance, _Digits);
|
|
if(trade.Buy(LotSize, _Symbol, ask, sl, tp, "SMA CrossUp"))
|
|
Print("BUY opened | Ask: ", ask, " | SL: ", sl, " | TP: ", tp);
|
|
else
|
|
Print("BUY failed | Error: ", GetLastError());
|
|
}
|
|
else if(signal == -1) // SELL signal — SMA12 crossed below SMA26
|
|
{
|
|
double sl = NormalizeDouble(bid + slDistance, _Digits);
|
|
double tp = NormalizeDouble(bid - tpDistance, _Digits);
|
|
if(trade.Sell(LotSize, _Symbol, bid, sl, tp, "SMA CrossDown"))
|
|
Print("SELL opened | Bid: ", bid, " | SL: ", sl, " | TP: ", tp);
|
|
else
|
|
Print("SELL failed | Error: ", GetLastError());
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check for SMA crossover on the last two closed bars |
|
|
//| Returns: 1 = Bullish cross (SMA12 crosses ABOVE SMA26) |
|
|
//| -1 = Bearish cross (SMA12 crosses BELOW SMA26) |
|
|
//| 0 = No crossover |
|
|
//+------------------------------------------------------------------+
|
|
int CheckCrossover()
|
|
{
|
|
double fastCurrent[1], fastPrev[1];
|
|
double slowCurrent[1], slowPrev[1];
|
|
|
|
// Copy values for bar [1] (last closed bar) and bar [2] (bar before that)
|
|
if(CopyBuffer(fastHandle, 0, 1, 1, fastCurrent) < 1) return 0;
|
|
if(CopyBuffer(fastHandle, 0, 2, 1, fastPrev) < 1) return 0;
|
|
if(CopyBuffer(slowHandle, 0, 1, 1, slowCurrent) < 1) return 0;
|
|
if(CopyBuffer(slowHandle, 0, 2, 1, slowPrev) < 1) return 0;
|
|
|
|
bool bullishCross = (fastPrev[0] <= slowPrev[0]) && (fastCurrent[0] > slowCurrent[0]);
|
|
bool bearishCross = (fastPrev[0] >= slowPrev[0]) && (fastCurrent[0] < slowCurrent[0]);
|
|
|
|
if(bullishCross) return 1;
|
|
if(bearishCross) return -1;
|
|
return 0;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Close any open position opposite to the new signal |
|
|
//+------------------------------------------------------------------+
|
|
void CloseOppositePosition(int signal)
|
|
{
|
|
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
|
{
|
|
ulong ticket = PositionGetTicket(i);
|
|
if(ticket == 0) continue;
|
|
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
|
|
if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
|
|
|
|
long posType = PositionGetInteger(POSITION_TYPE);
|
|
|
|
// Close BUY position on a SELL signal, or SELL position on a BUY signal
|
|
if((signal == -1 && posType == POSITION_TYPE_BUY) ||
|
|
(signal == 1 && posType == POSITION_TYPE_SELL))
|
|
{
|
|
if(trade.PositionClose(ticket))
|
|
Print("Position closed | Ticket: ", ticket);
|
|
else
|
|
Print("Close failed | Ticket: ", ticket, " | Error: ", GetLastError());
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Check if there is already an open position in the signal direction|
|
|
//+------------------------------------------------------------------+
|
|
bool HasOpenPosition(int signal)
|
|
{
|
|
for(int i = 0; i < PositionsTotal(); i++)
|
|
{
|
|
ulong ticket = PositionGetTicket(i);
|
|
if(ticket == 0) continue;
|
|
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
|
|
if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
|
|
|
|
long posType = PositionGetInteger(POSITION_TYPE);
|
|
if(signal == 1 && posType == POSITION_TYPE_BUY) return true;
|
|
if(signal == -1 && posType == POSITION_TYPE_SELL) return true;
|
|
}
|
|
return false;
|
|
}
|
|
//+------------------------------------------------------------------+
|