#property copyright "Custom XAUUSD EA"
#property version "1.00"
#property strict
#property description "XAUUSD Aggressive Controlled Growth EA"
#include <Trade/Trade.mqh>
CTrade trade;
//==================================================
// USER SETTINGS
//==================================================
input group "=== GENERAL SETTINGS ==="
input string TradeSymbol = "XAUUSD";
input ENUM_TIMEFRAMES EntryTF = PERIOD_M15;
input ENUM_TIMEFRAMES TrendTF = PERIOD_H1;
input ulong MagicNumber = 20261114;
input int MaxDeviationPoints = 30;
input group "=== RISK MANAGEMENT ==="
input double RiskPercent = 1.5;
input double DailyLossLimit = 4.0;
input int MaxTradesPerDay = 3;
input int MaxOpenPositions = 1;
input group "=== STRATEGY SETTINGS ==="
input int FastEMA = 20;
input int SlowEMA = 50;
input int TrendEMA = 200;
input int RSIPeriod = 14;
input int ATRPeriod = 14;
input double ATR_Stop_Mult = 2.0;
input double RewardRatio = 2.0;
input double RSI_Buy_Level = 52.0;
input double RSI_Sell_Level = 48.0;
input group "=== TRADE PROTECTION ==="
input double MaxSpreadPrice = 0.60;
input double BreakEvenAtR = 1.0;
input double TrailAtR = 1.5;
input double TrailATRMult = 1.5;
//==================================================
// GLOBAL VARIABLES
//==================================================
int fastHandle;
int slowHandle;
int trendHandle;
int rsiHandle;
int atrHandle;
datetime lastBarTime = 0;
string dailyVariable;
//==================================================
// INITIALIZATION
//==================================================
int OnInit()
{
if(RiskPercent <= 0 || RiskPercent > 5 ||
DailyLossLimit <= 0 ||
MaxTradesPerDay < 1 ||
MaxOpenPositions < 1 ||
ATR_Stop_Mult <= 0 ||
RewardRatio <= 0)
{
Print("Invalid EA input settings.");
return INIT_PARAMETERS_INCORRECT;
}
string symbol = _Symbol;
StringToUpper(symbol);
if(StringFind(symbol, "XAU") < 0 &&
StringFind(symbol, "GOLD") < 0)
{
Print("Attach this EA to a Gold chart.");
return INIT_FAILED;
}
fastHandle = iMA(_Symbol, EntryTF,
FastEMA, 0, MODE_EMA, PRICE_CLOSE);
slowHandle = iMA(_Symbol, EntryTF,
SlowEMA, 0, MODE_EMA, PRICE_CLOSE);
trendHandle = iMA(_Symbol, TrendTF,
TrendEMA, 0, MODE_EMA, PRICE_CLOSE);
rsiHandle = iRSI(_Symbol, EntryTF,
RSIPeriod, PRICE_CLOSE);
atrHandle = iATR(_Symbol, EntryTF, ATRPeriod);
if(fastHandle == INVALID_HANDLE ||
slowHandle == INVALID_HANDLE ||
trendHandle == INVALID_HANDLE ||
rsiHandle == INVALID_HANDLE ||
atrHandle == INVALID_HANDLE)
{
Print("Indicator initialization failed.");
return INIT_FAILED;
}
trade.SetExpertMagicNumber(MagicNumber);
trade.SetDeviationInPoints(MaxDeviationPoints);
trade.SetTypeFillingBySymbol(_Symbol);
Print("XAUUSD EA successfully initialized.");
return INIT_SUCCEEDED;
}
//==================================================
// RELEASE INDICATORS
//==================================================
void OnDeinit(const int reason)
{
IndicatorRelease(fastHandle);
IndicatorRelease(slowHandle);
IndicatorRelease(trendHandle);
IndicatorRelease(rsiHandle);
IndicatorRelease(atrHandle);
}
//==================================================
// GET INDICATOR VALUE
//==================================================
double GetValue(int handle, int shift)
{
double buffer[];
ArraySetAsSeries(buffer, true);
if(CopyBuffer(handle, 0, shift, 1, buffer) != 1)
return EMPTY_VALUE;
return buffer[0];
}
//==================================================
// DAILY EQUITY TRACKING
//==================================================
string GetDailyKey()
{
MqlDateTime dt;
TimeToStruct(TimeCurrent(), dt);
return StringFormat("AGX_%I64d_%04d%02d%02d",
AccountInfoInteger(ACCOUNT_LOGIN),
dt.year, dt.mon, dt.day);
}
double GetDayStartEquity()
{
string key = GetDailyKey();
if(!GlobalVariableCheck(key))
{
GlobalVariableSet(key, AccountInfoDouble(ACCOUNT_EQUITY));
}
return GlobalVariableGet(key);
}
//==================================================
// DAILY LOSS PROTECTION
//==================================================
bool DailyLossAllowed()
{
double startingEquity = GetDayStartEquity();
if(startingEquity <= 0)
return false;
double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
double lossPercent =
((startingEquity - currentEquity) /
startingEquity) * 100.0;
if(lossPercent >= DailyLossLimit)
{
Print("Daily loss limit reached. Trading stopped.");
return false;
}
return true;
}
//==================================================
// COUNT TODAY'S ENTRIES
//==================================================
int TradesToday()
{
MqlDateTime dt;
TimeToStruct(TimeCurrent(), dt);
dt.hour = 0;
dt.min = 0;
dt.sec = 0;
datetime startTime = StructToTime(dt);
if(!HistorySelect(startTime, TimeCurrent()))
return 0;
int count = 0;
for(int i = 0; i < HistoryDealsTotal(); i++)
{
ulong ticket = HistoryDealGetTicket(i);
if(ticket == 0)
continue;
if(HistoryDealGetString(ticket, DEAL_SYMBOL) != _Symbol)
continue;
if(HistoryDealGetInteger(ticket, DEAL_MAGIC) !=
(long)MagicNumber)
continue;
ENUM_DEAL_ENTRY entry =
(ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket, DEAL_ENTRY);
if(entry == DEAL_ENTRY_IN || entry == DEAL_ENTRY_INOUT)
count++;
}
return count;
}
//==================================================
// COUNT OPEN EA POSITIONS
//==================================================
int OpenPositions()
{
int count = 0;
for(int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0)
continue;
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_MAGIC) ==
(long)MagicNumber)
{
count++;
}
}
return count;
}
//==================================================
// SPREAD PROTECTION
//==================================================
bool SpreadAllowed()
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(ask <= 0 || bid <= 0)
return false;
return (ask - bid) <= MaxSpreadPrice;
}
//==================================================
// CALCULATE LOT SIZE
//==================================================
double CalculateLotSize(ENUM_ORDER_TYPE orderType,
double entryPrice,
double stopPrice)
{
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
double riskMoney = equity * RiskPercent / 100.0;
double profitForOneLot = 0;
if(!OrderCalcProfit(orderType,
_Symbol,
1.0,
entryPrice,
stopPrice,
profitForOneLot))
{
Print("Could not calculate position risk.");
return 0;
}
double lossForOneLot = MathAbs(profitForOneLot);
if(lossForOneLot <= 0)
return 0;
double rawLots = riskMoney / lossForOneLot;
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
if(lotStep <= 0 || rawLots < minLot)
{
Print("Risk-based lot size is below broker minimum.");
return 0;
}
double lots = MathFloor(rawLots / lotStep) * lotStep;
lots = MathMin(lots, maxLot);
int digits = 0;
double step = lotStep;
while(step < 1.0 && digits < 8)
{
step *= 10.0;
digits++;
}
return NormalizeDouble(lots, digits);
}
//==================================================
// CHECK FOR NEW CANDLE
//==================================================
bool IsNewBar()
{
datetime currentBar = iTime(_Symbol, EntryTF, 0);
if(currentBar == 0)
return false;
if(currentBar != lastBarTime)
{
lastBarTime = currentBar;
return true;
}
return false;
}
//==================================================
// BUY SIGNAL
//==================================================
bool BuySignal()
{
double fast1 = GetValue(fastHandle, 1);
double fast2 = GetValue(fastHandle, 2);
double slow1 = GetValue(slowHandle, 1);
double trend = GetValue(trendHandle, 1);
double rsi = GetValue(rsiHandle, 1);
if(fast1 == EMPTY_VALUE ||
fast2 == EMPTY_VALUE ||
slow1 == EMPTY_VALUE ||
trend == EMPTY_VALUE ||
rsi == EMPTY_VALUE)
return false;
double close1 = iClose(_Symbol, EntryTF, 1);
double close2 = iClose(_Symbol, EntryTF, 2);
double trendClose = iClose(_Symbol, TrendTF, 1);
bool bullishTrend = trendClose > trend;
bool bullishMomentum = fast1 > slow1;
bool pullbackRecovery =
close2 <= fast2 && close1 > fast1;
bool rsiConfirmation = rsi >= RSI_Buy_Level;
return bullishTrend &&
bullishMomentum &&
pullbackRecovery &&
rsiConfirmation;
}
//==================================================
// SELL SIGNAL
//==================================================
bool SellSignal()
{
double fast1 = GetValue(fastHandle, 1);
double fast2 = GetValue(fastHandle, 2);
double slow1 = GetValue(slowHandle, 1);
double trend = GetValue(trendHandle, 1);
double rsi = GetValue(rsiHandle, 1);
if(fast1 == EMPTY_VALUE ||
fast2 == EMPTY_VALUE ||
slow1 == EMPTY_VALUE ||
trend == EMPTY_VALUE ||
rsi == EMPTY_VALUE)
return false;
double close1 = iClose(_Symbol, EntryTF, 1);
double close2 = iClose(_Symbol, EntryTF, 2);
double trendClose = iClose(_Symbol, TrendTF, 1);
bool bearishTrend = trendClose < trend;
bool bearishMomentum = fast1 < slow1;
bool pullbackRecovery =
close2 >= fast2 && close1 < fast1;
bool rsiConfirmation = rsi <= RSI_Sell_Level;
return bearishTrend &&
bearishMomentum &&
pullbackRecovery &&
rsiConfirmation;
}
//==================================================
// OPEN BUY TRADE
//==================================================
void OpenBuy()
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double atr = GetValue(atrHandle, 1);
if(atr == EMPTY_VALUE || atr <= 0)
return;
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
double sl = NormalizeDouble(
ask - atr * ATR_Stop_Mult, digits);
double tp = NormalizeDouble(
ask + (ask - sl) * RewardRatio, digits);
double lots = CalculateLotSize(ORDER_TYPE_BUY, ask, sl);
if(lots <= 0)
return;
if(!trade.Buy(lots, _Symbol, 0, sl, tp, "XAUUSD EA BUY"))
{
Print("BUY failed: ", trade.ResultRetcodeDescription());
}
else
{
Print("BUY request sent. Volume: ", lots);
}
}
//==================================================
// OPEN SELL TRADE
//==================================================
void OpenSell()
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double atr = GetValue(atrHandle, 1);
if(atr == EMPTY_VALUE || atr <= 0)
return;
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
double sl = NormalizeDouble(
bid + atr * ATR_Stop_Mult, digits);
double tp = NormalizeDouble(
bid - (sl - bid) * RewardRatio, digits);
double lots = CalculateLotSize(ORDER_TYPE_SELL, bid, sl);
if(lots <= 0)
return;
if(!trade.Sell(lots, _Symbol, 0, sl, tp, "XAUUSD EA SELL"))
{
Print("SELL failed: ", trade.ResultRetcodeDescription());
}
else
{
Print("SELL request sent. Volume: ", lots);
}
}
//==================================================
// BREAK-EVEN AND TRAILING STOP
//==================================================
void ManagePositions()
{
double atr = GetValue(atrHandle, 1);
if(atr == EMPTY_VALUE || atr <= 0)
return;
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0)
continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol ||
PositionGetInteger(POSITION_MAGIC) != (long)MagicNumber)
continue;
ENUM_POSITION_TYPE type =
(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double currentSL = PositionGetDouble(POSITION_SL);
double currentTP = PositionGetDouble(POSITION_TP);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
// Recover original risk distance from the 1:2 TP.
double initialRisk = MathAbs(currentTP - openPrice) /
RewardRatio;
if(initialRisk <= 0)
continue;
double profitDistance = 0;
double newSL = currentSL;
if(type == POSITION_TYPE_BUY)
{
profitDistance = bid - openPrice;
if(profitDistance >= initialRisk * BreakEvenAtR)
{
double be = openPrice;
if(currentSL == 0 || be > newSL)
newSL = be;
}
if(profitDistance >= initialRisk * TrailAtR)
{
double trailing = bid - atr * TrailATRMult;
if(trailing > newSL)
newSL = trailing;
}
if(newSL > currentSL && newSL < bid)
{
newSL = NormalizeDouble(newSL, digits);
if(!trade.PositionModify(ticket, newSL, currentTP))
Print("BUY stop modification failed: ",
trade.ResultRetcodeDescription());
}
}
else if(type == POSITION_TYPE_SELL)
{
profitDistance = openPrice - ask;
if(profitDistance >= initialRisk * BreakEvenAtR)
{
double be = openPrice;
if(currentSL == 0 || be < newSL)
newSL = be;
}
if(profitDistance >= initialRisk * TrailAtR)
{
double trailing = ask + atr * TrailATRMult;
if(newSL == 0 || trailing < newSL)
newSL = trailing;
}
if((currentSL == 0 || newSL < currentSL) && newSL > ask)
{
newSL = NormalizeDouble(newSL, digits);
if(!trade.PositionModify(ticket, newSL, currentTP))
Print("SELL stop modification failed: ",
trade.ResultRetcodeDescription());
}
}
}
}
//==================================================
// MAIN EA ENGINE
//==================================================
void OnTick()
{
// Manage existing trades on every tick.
ManagePositions();
// Only evaluate new entries at a new M15 candle.
if(!IsNewBar())
return;
if(!DailyLossAllowed())
return;
if(!SpreadAllowed())
return;
if(TradesToday() >= MaxTradesPerDay)
return;
if(OpenPositions() >= MaxOpenPositions)
return;
// Avoid entries when indicators are not ready.
if(BarsCalculated(fastHandle) < 250 ||
BarsCalculated(slowHandle) < 250 ||
BarsCalculated(trendHandle) < 250 ||
BarsCalculated(rsiHandle) < 50 ||
BarsCalculated(atrHandle) < 50)
return;
if(BuySignal())
{
OpenBuy();
}
else if(SellSignal())
{
OpenSell();
}
}