//+------------------------------------------------------------------+ //| ForexTrendBot.mq5 | //| Simple EMA 20/50 crossover EA - DEMO ACCOUNTS ONLY | //| Educational example; not a guarantee of profit. | //+------------------------------------------------------------------+ #property strict #property version "1.00" #property description "EMA 20/50 trend-following example. Demo accounts only." #include input double InpLots = 0.01; // Fixed lot size input int InpFastEMA = 20; // Fast EMA period input int InpSlowEMA = 50; // Slow EMA period input int InpStopLossPoints = 300; // Stop loss in points input int InpTakeProfitPoints = 600; // Take profit in points input int InpMaxSpreadPoints = 25; // Maximum spread in points input ulong InpMagicNumber = 205020; // EA identifier CTrade trade; int fastHandle = INVALID_HANDLE; int slowHandle = INVALID_HANDLE; datetime lastBarTime = 0; //+------------------------------------------------------------------+ int OnInit() { // This EA intentionally refuses to run on non-demo accounts. if((ENUM_ACCOUNT_TRADE_MODE)AccountInfoInteger(ACCOUNT_TRADE_MODE) != ACCOUNT_TRADE_MODE_DEMO) { Print("ForexTrendBot is DEMO-ONLY. Initialization blocked."); return(INIT_FAILED); } if(InpLots <= 0 || InpFastEMA <= 0 || InpSlowEMA <= 0 || InpFastEMA >= InpSlowEMA || InpStopLossPoints <= 0 || InpTakeProfitPoints <= 0 || InpMaxSpreadPoints < 0) { Print("Invalid input settings."); return(INIT_PARAMETERS_INCORRECT); } fastHandle = iMA(_Symbol, PERIOD_M15, InpFastEMA, 0, MODE_EMA, PRICE_CLOSE); slowHandle = iMA(_Symbol, PERIOD_M15, InpSlowEMA, 0, MODE_EMA, PRICE_CLOSE); if(fastHandle == INVALID_HANDLE || slowHandle == INVALID_HANDLE) { Print("Could not create EMA indicator handles. Error: ", GetLastError()); return(INIT_FAILED); } trade.SetExpertMagicNumber(InpMagicNumber); trade.SetTypeFillingBySymbol(_Symbol); Print("ForexTrendBot initialized on demo account. Signal timeframe: M15."); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(fastHandle != INVALID_HANDLE) IndicatorRelease(fastHandle); if(slowHandle != INVALID_HANDLE) IndicatorRelease(slowHandle); } //+------------------------------------------------------------------+ void OnTick() { if((ENUM_ACCOUNT_TRADE_MODE)AccountInfoInteger(ACCOUNT_TRADE_MODE) != ACCOUNT_TRADE_MODE_DEMO) return; if(!IsNewBar()) return; if(HasOurPosition()) return; MqlTick tick; if(!SymbolInfoTick(_Symbol, tick)) return; double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); if(point <= 0) return; double spreadPoints = (tick.ask - tick.bid) / point; if(spreadPoints > InpMaxSpreadPoints) { Print("Spread too high; skipping this bar. Spread points: ", spreadPoints); return; } // Dynamic series arrays: index 0=current bar, 1=last closed, 2=previous. double fast[], slow[]; ArrayResize(fast, 3); ArrayResize(slow, 3); ArraySetAsSeries(fast, true); ArraySetAsSeries(slow, true); if(CopyBuffer(fastHandle, 0, 0, 3, fast) < 3 || CopyBuffer(slowHandle, 0, 0, 3, slow) < 3) { Print("Not enough EMA data yet."); return; } bool bullishCross = (fast[2] <= slow[2] && fast[1] > slow[1]); bool bearishCross = (fast[2] >= slow[2] && fast[1] < slow[1]); int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); double sl = 0.0, tp = 0.0; if(bullishCross) { sl = NormalizeDouble(tick.ask - InpStopLossPoints * point, digits); tp = NormalizeDouble(tick.ask + InpTakeProfitPoints * point, digits); if(!trade.Buy(InpLots, _Symbol, 0.0, sl, tp, "EMA20/50 demo buy")) Print("Buy failed. Retcode: ", trade.ResultRetcode(), " - ", trade.ResultRetcodeDescription()); else Print("Demo BUY submitted. SL=", sl, " TP=", tp); } else if(bearishCross) { sl = NormalizeDouble(tick.bid + InpStopLossPoints * point, digits); tp = NormalizeDouble(tick.bid - InpTakeProfitPoints * point, digits); if(!trade.Sell(InpLots, _Symbol, 0.0, sl, tp, "EMA20/50 demo sell")) Print("Sell failed. Retcode: ", trade.ResultRetcode(), " - ", trade.ResultRetcodeDescription()); else Print("Demo SELL submitted. SL=", sl, " TP=", tp); } } //+------------------------------------------------------------------+ bool IsNewBar() { datetime currentBar = iTime(_Symbol, PERIOD_M15, 0); if(currentBar == 0 || currentBar == lastBarTime) return false; lastBarTime = currentBar; return true; } //+------------------------------------------------------------------+ bool HasOurPosition() { for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(ticket == 0) continue; if(PositionGetString(POSITION_SYMBOL) == _Symbol && (ulong)PositionGetInteger(POSITION_MAGIC) == InpMagicNumber) return true; } return false; } //+------------------------------------------------------------------+