//+------------------------------------------------------------------+
//| XAUUSD SMA Crossover EA with TP, SL, Trailing Stop, Volume |
//+------------------------------------------------------------------+
#property strict
#include <Trade\Trade.mqh>
CTrade trade;
input int fastPeriod = 2;
input int slowPeriod = 5;
input double lotSize = 0.01;
input double slippage = 0.03;
input double maxLossUSD = 10.0;
input double takeProfitUSD = 10.0;
input bool debugLogs = true;
int fastHandle, slowHandle;
double fastBuffer[], slowBuffer[];
long volume[];
double PointSize, TickValue;
int DigitsCount;
double SL_Points, TP_Points;
//+------------------------------------------------------------------+
int OnInit()
{
fastHandle = iMA(_Symbol, _Period, fastPeriod, 0, MODE_SMA, PRICE_CLOSE);
slowHandle = iMA(_Symbol, _Period, slowPeriod, 0, MODE_SMA, PRICE_OPEN);
if(fastHandle == INVALID_HANDLE || slowHandle == INVALID_HANDLE)
{
Print("Indicator creation failed.");
return INIT_FAILED;
}
ArraySetAsSeries(fastBuffer, true);
ArraySetAsSeries(slowBuffer, true);
ArraySetAsSeries(volume, true);
SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE, TickValue);
SymbolInfoDouble(_Symbol, SYMBOL_POINT, PointSize);
DigitsCount = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
SL_Points = NormalizeDouble((maxLossUSD / (TickValue * lotSize)) / PointSize, 0);
TP_Points = NormalizeDouble((takeProfitUSD / (TickValue * lotSize)) / PointSize, 0);
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
void OnTick()
{
if(Bars(_Symbol, _Period) < 25) return;
// Apply trailing stop if there's a position
if(PositionSelect(_Symbol))
ManageTrailingStop();
if(CopyBuffer(fastHandle, 0, 0, 3, fastBuffer) < 3 ||
CopyBuffer(slowHandle, 0, 0, 3, slowBuffer) < 3 ||
CopyTickVolume(_Symbol, 0, 0, 25, volume) < 25)
{
Print("Failed to copy data.");
return;
}
// Volume filter check
double avgVol = 0;
for(int i = 3; i < 23; i++) avgVol += volume[i];
avgVol /= 20;
if(volume[1] <= avgVol || volume[2] <= avgVol)
{
if(debugLogs)
Print("Low volume — no trade. V1:", volume[1], " V2:", volume[2], " AVG:", avgVol);
return;
}
// Crossover
bool bullish = fastBuffer[1] < slowBuffer[1] && fastBuffer[0] > slowBuffer[0];
bool bearish = fastBuffer[1] > slowBuffer[1] && fastBuffer[0] < slowBuffer[0];
bool hasPosition = PositionSelect(_Symbol);
long posType = hasPosition ? PositionGetInteger(POSITION_TYPE) : -1;
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
// Exit on reverse crossover
if(hasPosition)
{
if((posType == POSITION_TYPE_BUY && bearish) ||
(posType == POSITION_TYPE_SELL && bullish))
{
trade.PositionClose(_Symbol);
Print("Closed due to reverse crossover.");
return;
}
}
// Entry
if(!hasPosition)
{
if(bullish)
{
double sl = NormalizeDouble(bid - SL_Points * PointSize, DigitsCount);
double tp = NormalizeDouble(bid + TP_Points * PointSize, DigitsCount);
if(trade.Buy(lotSize, _Symbol, ask, slippage, sl, tp))
Print("BUY @ ", ask, " SL: ", sl, " TP: ", tp);
else
Print("BUY failed: ", trade.ResultRetcodeDescription());
}
else if(bearish)
{
double sl = NormalizeDouble(ask + SL_Points * PointSize, DigitsCount);
double tp = NormalizeDouble(ask - TP_Points * PointSize, DigitsCount);
if(trade.Sell(lotSize, _Symbol, bid, slippage, sl, tp))
Print("SELL @ ", bid, " SL: ", sl, " TP: ", tp);
else
Print("SELL failed: ", trade.ResultRetcodeDescription());
}
}
}
//+------------------------------------------------------------------+
//| Trailing Stop Management |
//+------------------------------------------------------------------+
void ManageTrailingStop()
{
double currentPrice = 0.0;
long type = PositionGetInteger(POSITION_TYPE);
double entry = PositionGetDouble(POSITION_PRICE_OPEN);
double sl = PositionGetDouble(POSITION_SL);
double tp = PositionGetDouble(POSITION_TP);
if(type == POSITION_TYPE_BUY)
{
currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double newSL = NormalizeDouble(currentPrice - SL_Points * PointSize, DigitsCount);
if(newSL > sl)
trade.PositionModify(_Symbol, newSL, tp);
}
else if(type == POSITION_TYPE_SELL)
{
currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double newSL = NormalizeDouble(currentPrice + SL_Points * PointSize, DigitsCount);
if(newSL < sl || sl == 0.0)
trade.PositionModify(_Symbol, newSL, tp);
}
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(fastHandle != INVALID_HANDLE) IndicatorRelease(fastHandle);
if(slowHandle != INVALID_HANDLE) IndicatorRelease(slowHandle);
}
//+------------------------------------------------------------------+