//+------------------------------------------------------------------+ //| XAUUSD MTF MARKET HEALTH EA - MT5 | //| M5 Entry + M15 + H1 + H4 Confirmation | //+------------------------------------------------------------------+ #property strict #include CTrade trade; //==================== INPUTS ========================================// input ENUM_TIMEFRAMES EntryTF = PERIOD_M5; input int FastEMA = 9; input int SlowEMA = 15; input int TrendEMA = 100; input int RSIPeriod = 14; input int ATRPeriod = 14; input double MinHealthScore = 70.0; input double RiskPercent = 1.0; input double MaxDailyLossPercent = 3.0; input int MaxTradesPerDay = 5; input double SL_ATR_Multiplier = 1.5; input double TP_ATR_Multiplier = 2.5; input bool UseBreakEven = true; input double BreakEvenATR = 1.0; input bool UseTrailing = true; input double TrailingATR = 1.0; input int MaxSpreadPoints = 100; input ulong MagicNumber = 9051501; //==================== HANDLES ======================================// int fastM5, slowM5, trendM5, rsiM5, atrM5; int trendM15; int trendH1; int trendH4; datetime lastBar = 0; //==================== INIT ==========================================// int OnInit() { fastM5 = iMA(_Symbol, EntryTF, FastEMA, 0, MODE_EMA, PRICE_CLOSE); slowM5 = iMA(_Symbol, EntryTF, SlowEMA, 0, MODE_EMA, PRICE_CLOSE); trendM5 = iMA(_Symbol, EntryTF, TrendEMA, 0, MODE_EMA, PRICE_CLOSE); rsiM5 = iRSI(_Symbol, EntryTF, RSIPeriod, PRICE_CLOSE); atrM5 = iATR(_Symbol, EntryTF, ATRPeriod); trendM15 = iMA(_Symbol, PERIOD_M15, TrendEMA, 0, MODE_EMA, PRICE_CLOSE); trendH1 = iMA(_Symbol, PERIOD_H1, TrendEMA, 0, MODE_EMA, PRICE_CLOSE); trendH4 = iMA(_Symbol, PERIOD_H4, TrendEMA, 0, MODE_EMA, PRICE_CLOSE); if(fastM5 == INVALID_HANDLE || slowM5 == INVALID_HANDLE || trendM5 == INVALID_HANDLE || rsiM5 == INVALID_HANDLE || atrM5 == INVALID_HANDLE || trendM15 == INVALID_HANDLE || trendH1 == INVALID_HANDLE || trendH4 == INVALID_HANDLE) { Print("Indicator initialization failed."); return INIT_FAILED; } trade.SetExpertMagicNumber(MagicNumber); Print("MTF Market Health EA Started."); return INIT_SUCCEEDED; } //==================== DEINIT ========================================// void OnDeinit(const int reason) { IndicatorRelease(fastM5); IndicatorRelease(slowM5); IndicatorRelease(trendM5); IndicatorRelease(rsiM5); IndicatorRelease(atrM5); IndicatorRelease(trendM15); IndicatorRelease(trendH1); IndicatorRelease(trendH4); } //==================== NEW BAR =======================================// bool IsNewBar() { datetime t = iTime(_Symbol, EntryTF, 0); if(t != lastBar) { lastBar = t; return true; } return false; } //==================== GET VALUE =====================================// double GetMAValue(int handle, int shift) { double buffer[]; if(CopyBuffer(handle, 0, shift, 1, buffer) != 1) return 0; return buffer[0]; } //==================== RSI ===========================================// double GetRSI() { double buffer[]; if(CopyBuffer(rsiM5, 0, 1, 1, buffer) != 1) return 50; return buffer[0]; } //==================== ATR ===========================================// double GetATR() { double buffer[]; if(CopyBuffer(atrM5, 0, 1, 1, buffer) != 1) return 0; return buffer[0]; } //==================== TREND =========================================// int GetTrend(ENUM_TIMEFRAMES tf, int handle) { double ema = GetMAValue(handle, 1); double price = iClose(_Symbol, tf, 1); if(ema == 0 || price == 0) return 0; if(price > ema) return 1; if(price < ema) return -1; return 0; } //==================== VOLUME ========================================// bool VolumeBullish() { long currentVol = iVolume(_Symbol, EntryTF, 1); long previousVol = iVolume(_Symbol, EntryTF, 2); return currentVol >= previousVol; } //==================== SPREAD ========================================// bool SpreadOK() { double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double spread = (ask - bid) / _Point; return spread <= MaxSpreadPoints; } //==================== DAILY LOSS ====================================// double TodayProfit() { datetime start = StringToTime(TimeToString(TimeCurrent(), TIME_DATE)); if(!HistorySelect(start, TimeCurrent())) return 0; double profit = 0; int total = HistoryDealsTotal(); for(int i=0; i= 55) score += 10; if(direction == -1 && rsi <= 45) score += 10; // Volume = 10 if(VolumeBullish()) score += 10; return score; } //==================== LOT SIZE ======================================// double CalculateLot(double slDistance) { double balance = AccountInfoDouble(ACCOUNT_BALANCE); double riskMoney = balance * RiskPercent / 100.0; double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE); if(tickValue <= 0 || tickSize <= 0) return SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double lossPerLot = (slDistance / tickSize) * tickValue; if(lossPerLot <= 0) return SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double lot = riskMoney / lossPerLot; double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); lot = MathMax(lot, minLot); lot = MathMin(lot, maxLot); lot = MathFloor(lot / step) * step; return NormalizeDouble(lot, 2); } //==================== BUY SIGNAL ====================================// bool BuySignal() { double fast1 = GetMAValue(fastM5, 1); double fast2 = GetMAValue(fastM5, 2); double slow1 = GetMAValue(slowM5, 1); double slow2 = GetMAValue(slowM5, 2); if(fast1 == 0 || slow1 == 0) return false; bool crossover = fast2 <= slow2 && fast1 > slow1; return crossover; } //==================== SELL SIGNAL ===================================// bool SellSignal() { double fast1 = GetMAValue(fastM5, 1); double fast2 = GetMAValue(fastM5, 2); double slow1 = GetMAValue(slowM5, 1); double slow2 = GetMAValue(slowM5, 2); if(fast1 == 0 || slow1 == 0) return false; bool crossover = fast2 >= slow2 && fast1 < slow1; return crossover; } //==================== BUY ===========================================// void OpenBuy() { double atr = GetATR(); if(atr <= 0) return; double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double slDistance = atr * SL_ATR_Multiplier; double tpDistance = atr * TP_ATR_Multiplier; double lot = CalculateLot(slDistance); double sl = ask - slDistance; double tp = ask + tpDistance; trade.Buy( lot, _Symbol, ask, NormalizeDouble(sl, _Digits), NormalizeDouble(tp, _Digits), "MTF HEALTH BUY" ); } //==================== SELL ==========================================// void OpenSell() { double atr = GetATR(); if(atr <= 0) return; double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double slDistance = atr * SL_ATR_Multiplier; double tpDistance = atr * TP_ATR_Multiplier; double lot = CalculateLot(slDistance); double sl = bid + slDistance; double tp = bid - tpDistance; trade.Sell( lot, _Symbol, bid, NormalizeDouble(sl, _Digits), NormalizeDouble(tp, _Digits), "MTF HEALTH SELL" ); } //==================== POSITION MANAGEMENT ===========================// void ManagePosition() { if(!PositionSelect(_Symbol)) return; double atr = GetATR(); if(atr <= 0) return; long type = PositionGetInteger(POSITION_TYPE); double open = PositionGetDouble(POSITION_PRICE_OPEN); double sl = PositionGetDouble(POSITION_SL); double tp = PositionGetDouble(POSITION_TP); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // BUY if(type == POSITION_TYPE_BUY) { double profit = bid - open; // Break-even if(UseBreakEven && profit >= atr * BreakEvenATR) { double newSL = open; if(sl < newSL) { trade.PositionModify( _Symbol, NormalizeDouble(newSL, _Digits), tp ); } } // Trailing if(UseTrailing && profit >= atr * TrailingATR) { double newSL = bid - atr * TrailingATR; if(newSL > sl) { trade.PositionModify( _Symbol, NormalizeDouble(newSL, _Digits), tp ); } } } // SELL if(type == POSITION_TYPE_SELL) { double profit = open - ask; // Break-even if(UseBreakEven && profit >= atr * BreakEvenATR) { double newSL = open; if(sl == 0 || sl > newSL) { trade.PositionModify( _Symbol, NormalizeDouble(newSL, _Digits), tp ); } } // Trailing if(UseTrailing && profit >= atr * TrailingATR) { double newSL = ask + atr * TrailingATR; if(sl == 0 || newSL < sl) { trade.PositionModify( _Symbol, NormalizeDouble(newSL, _Digits), tp ); } } } } //==================== MAIN ==========================================// void OnTick() { // Position management runs continuously ManagePosition(); // New candle only for entries if(!IsNewBar()) return; // Spread protection if(!SpreadOK()) { Print("Spread too high - trade skipped."); return; } // Daily trade limit if(TradesToday() >= MaxTradesPerDay) { Print("Daily trade limit reached."); return; } // Daily loss protection double balance = AccountInfoDouble(ACCOUNT_BALANCE); double maxLoss = balance * MaxDailyLossPercent / 100.0; if(TodayProfit() <= -maxLoss) { Print("Daily loss limit reached."); return; } // One position at a time if(PositionSelect(_Symbol)) return; // BUY if(BuySignal()) { double score = GetHealthScore(1); Print("BUY Health Score = ", score); if(score >= MinHealthScore) { OpenBuy(); return; } } // SELL if(SellSignal()) { double score = GetHealthScore(-1); Print("SELL Health Score = ", score); if(score >= MinHealthScore) { OpenSell(); return; } } } //+------------------------------------------------------------------+