//+------------------------------------------------------------------+
//| Simple SMA Crossover EA - ~100 lines |
//| Inputs: fast/slow SMA, lot, SL/TP (points), magic, timeout |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
input int FastPeriod = 9;
input int SlowPeriod = 21;
input double Lots = 0.01;
input int SlPoints = 200; // stop loss in points
input int TpPoints = 400; // take profit in points
input int Magic = 123456;
input int Slippage = 5;
input int MaxOrders = 1;
input int TimeFilterMinutes = 0; // 0 = disabled
CTrade trade;
int fastHandle, slowHandle;
double prevFast, prevSlow, curFast, curSlow;
ulong ticketLast=0;
//+------------------------------------------------------------------+
int OnInit()
{
fastHandle = iMA(_Symbol,PERIOD_CURRENT,FastPeriod,0,MODE_SMA,PRICE_CLOSE);
slowHandle = iMA(_Symbol,PERIOD_CURRENT,SlowPeriod,0,MODE_SMA,PRICE_CLOSE);
if(fastHandle==INVALID_HANDLE || slowHandle==INVALID_HANDLE)
{
Print("Failed to create indicators");
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(fastHandle!=INVALID_HANDLE) IndicatorRelease(fastHandle);
if(slowHandle!=INVALID_HANDLE) IndicatorRelease(slowHandle);
}
//+------------------------------------------------------------------+
void OnTick()
{
if(TimeFilterMinutes>0 && (TimeCurrent() % (TimeFilterMinutes*60)) != 0)
return; // simple time filter (fires only on boundary)
// read last two SMA values
if(CopyBuffer(fastHandle,0,0,2,&curFast) < 2) return;
if(CopyBuffer(slowHandle,0,0,2,&curSlow) < 2) return;
// curFast/curSlow are arrays when using CopyBuffer; handle accordingly
// but since we requested 2 values, curFast[0] is latest, curFast[1] previous
double fastArr[], slowArr[];
ArrayResize(fastArr,2); ArrayResize(slowArr,2);
if(CopyBuffer(fastHandle,0,0,2,fastArr) < 2) return;
if(CopyBuffer(slowHandle,0,0,2,slowArr) < 2) return;
double fast_now = fastArr[0], fast_prev = fastArr[1];
double slow_now = slowArr[0], slow_prev = slowArr[1];
int totalPos = CountOpenPositions(_Symbol,Magic);
// check for cross up
if(fast_prev <= slow_prev && fast_now > slow_now)
{
if(totalPos < MaxOrders)
TryOpen(ORDER_TYPE_BUY);
}
// check for cross down
if(fast_prev >= slow_prev && fast_now < slow_now)
{
if(totalPos < MaxOrders)
TryOpen(ORDER_TYPE_SELL);
}
// optional: simple reverse: if opposing signal and we have positions, close them
ManageExistingPositions();
}
//+------------------------------------------------------------------+
void TryOpen(ENUM_ORDER_TYPE type)
{
double price, sl, tp;
if(type==ORDER_TYPE_BUY)
{
price = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
sl = price - SlPoints*_Point;
tp = price + TpPoints*_Point;
trade.SetExpertMagicNumber(Magic);
trade.SetDeviationInPoints(Slippage);
if(!trade.Buy(Lots,_Symbol,price,NormalizeDouble(sl,_Digits),NormalizeDouble(tp,_Dig
its),NULL))
Print("Buy failed: ",GetLastError());
}
else if(type==ORDER_TYPE_SELL)
{
price = SymbolInfoDouble(_Symbol,SYMBOL_BID);
sl = price + SlPoints*_Point;
tp = price - TpPoints*_Point;
trade.SetExpertMagicNumber(Magic);
trade.SetDeviationInPoints(Slippage);
if(!trade.Sell(Lots,_Symbol,price,NormalizeDouble(sl,_Digits),NormalizeDouble(tp,_Di
gits),NULL))
Print("Sell failed: ",GetLastError());
}
}
//+------------------------------------------------------------------+
void ManageExistingPositions()
{
for(int i=PositionsTotal()-1;i>=0;i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
if(PositionGetInteger(POSITION_MAGIC) != Magic) continue;
string sym = PositionGetString(POSITION_SYMBOL);
if(sym != _Symbol) continue;
// very simple management: if opposite SMA direction, close
double fastArr[], slowArr[];
if(CopyBuffer(fastHandle,0,0,2,fastArr) < 2) return;
if(CopyBuffer(slowHandle,0,0,2,slowArr) < 2) return;
double fast_now = fastArr[0], slow_now = slowArr[0];
long type = PositionGetInteger(POSITION_TYPE);
if(type==POSITION_TYPE_BUY && fast_now < slow_now)
ClosePositionByTicket(ticket);
if(type==POSITION_TYPE_SELL && fast_now > slow_now)
ClosePositionByTicket(ticket);
}
}
}
//+------------------------------------------------------------------+
int CountOpenPositions(string symbol,int magic)
{
int cnt=0;
for(int i=0;i<PositionsTotal();i++)
{
if(PositionGetTicket(i) && PositionSelectByTicket(PositionGetTicket(i)))
{
if(PositionGetString(POSITION_SYMBOL)==symbol &&
PositionGetInteger(POSITION_MAGIC)==magic)
cnt++;
}
}
return cnt;
}
//+------------------------------------------------------------------+
void ClosePositionByTicket(ulong ticket)
{
if(!PositionSelectByTicket(ticket)) return;
string sym = PositionGetString(POSITION_SYMBOL);
double volume = PositionGetDouble(POSITION_VOLUME);
long type = PositionGetInteger(POSITION_TYPE);
trade.SetExpertMagicNumber(Magic);
trade.SetDeviationInPoints(Slippage);
bool ok=false;
if(type==POSITION_TYPE_BUY) ok = trade.PositionClose(ticket);
else if(type==POSITION_TYPE_SELL) ok = trade.PositionClose(ticket);
if(!ok) Print("Close failed for ",ticket," error:",GetLastError());
}
//+------------------------------------------------------------------+