//+------------------------------------------------------------------+ //| ProfitMaker.mq5 | //| Haridoss Kumarasamy | //| https://www.mql5.com | //+------------------------------------------------------------------+ //| EMA_OB_FVG_EA.mq5 | //| Complete Strategy with Dashboard, OB Entry, FVG Exit | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ #property strict #include #include CTrade trade; //--- Inputs input int FastEMA = 20; input int SlowEMA = 50; input ENUM_TIMEFRAMES EMATF = PERIOD_M1; input double TrailingStop = 50; input int StartHour = 9; input int EndHour = 17; input double LotSize = 0.1; input double LossThreshold = 200; // Loss threshold in pips //--- Global Variables double emaFastPrev, emaSlowPrev; double emaFastCurr, emaSlowCurr; MqlRates priceData[]; //+------------------------------------------------------------------+ //| Expert initialization | //+------------------------------------------------------------------+ int OnInit() { Print("EMA_OB_FVG_EA initialized."); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Time Filter datetime currentTime = TimeCurrent(); MqlDateTime dt; TimeToStruct(currentTime, dt); int currentHour = dt.hour; if(currentHour < StartHour || currentHour >= EndHour) return; //--- Get EMAs int fastHandle = iMA(_Symbol, EMATF, FastEMA, 0, MODE_EMA, PRICE_CLOSE); int slowHandle = iMA(_Symbol, EMATF, SlowEMA, 0, MODE_EMA, PRICE_CLOSE); double fastBuffer[2], slowBuffer[2]; if(CopyBuffer(fastHandle, 0, 0, 2, fastBuffer) < 0 || CopyBuffer(slowHandle, 0, 0, 2, slowBuffer) < 0) return; emaFastCurr = fastBuffer[0]; emaFastPrev = fastBuffer[1]; emaSlowCurr = slowBuffer[0]; emaSlowPrev = slowBuffer[1]; //--- Trend Detection bool uptrend = emaFastCurr > emaSlowCurr && emaFastPrev > emaSlowPrev; bool downtrend = emaFastCurr < emaSlowCurr && emaFastPrev < emaSlowPrev; //--- OB Entry Logic if(uptrend && isBullishRejectionCandle()) { if(!PositionSelect(_Symbol)) trade.Buy(LotSize, _Symbol, SymbolInfoDouble(_Symbol, SYMBOL_ASK), 0, 0, "Buy OB"); } if(downtrend && isBearishRejectionCandle()) { if(!PositionSelect(_Symbol)) trade.Sell(LotSize, _Symbol, SymbolInfoDouble(_Symbol, SYMBOL_BID), 0, 0, "Sell OB"); } //--- Apply Trailing Stop applyTrailingStop(); //--- Reverse Order Logic if trade is in loss and threshold is exceeded if(PositionSelect(_Symbol)) { double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); double currentPrice = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_BID) : SymbolInfoDouble(_Symbol, SYMBOL_ASK); // Calculate the loss in pips double lossInPips = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ? (openPrice - currentPrice) / _Point : (currentPrice - openPrice) / _Point; // Check if loss exceeds threshold if(lossInPips >= LossThreshold) { // Close losing position trade.PositionClose(_Symbol); // Open opposite trade if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) trade.Sell(LotSize, _Symbol, SymbolInfoDouble(_Symbol, SYMBOL_BID), 0, 0, "Reverse Sell"); else trade.Buy(LotSize, _Symbol, SymbolInfoDouble(_Symbol, SYMBOL_ASK), 0, 0, "Reverse Buy"); } } //--- Draw Dashboard drawDashboard(uptrend, downtrend); } //+------------------------------------------------------------------+ //| Check for Bullish OB candle | //+------------------------------------------------------------------+ bool isBullishRejectionCandle() { double open = iOpen(_Symbol, PERIOD_CURRENT, 1); double close = iClose(_Symbol, PERIOD_CURRENT, 1); double high = iHigh(_Symbol, PERIOD_CURRENT, 1); double low = iLow(_Symbol, PERIOD_CURRENT, 1); return (close > open && (high - close) < (close - low)); } //+------------------------------------------------------------------+ //| Check for Bearish OB candle | //+------------------------------------------------------------------+ bool isBearishRejectionCandle() { double open = iOpen(_Symbol, PERIOD_CURRENT, 1); double close = iClose(_Symbol, PERIOD_CURRENT, 1); double high = iHigh(_Symbol, PERIOD_CURRENT, 1); double low = iLow(_Symbol, PERIOD_CURRENT, 1); return (open > close && (open - low) < (high - close)); } //+------------------------------------------------------------------+ //| Apply trailing stop logic | //+------------------------------------------------------------------+ void applyTrailingStop() { if(PositionSelect(_Symbol)) { double price = SymbolInfoDouble(_Symbol, SYMBOL_BID); double trailing = TrailingStop * _Point; double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); double sl = PositionGetDouble(POSITION_SL); double newSL; if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { newSL = price - trailing; if((sl == 0 || newSL > sl) && (price - openPrice) > trailing) trade.PositionModify(_Symbol, newSL, 0); } else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { price = SymbolInfoDouble(_Symbol, SYMBOL_ASK); newSL = price + trailing; if((sl == 0 || newSL < sl) && (openPrice - price) > trailing) trade.PositionModify(_Symbol, newSL, 0); } } } //+------------------------------------------------------------------+ //| Draw Dashboard | //+------------------------------------------------------------------+ void drawDashboard(bool uptrend, bool downtrend) { string objName = "Dashboard"; int x = 10, y = 10; double balance = AccountInfoDouble(ACCOUNT_BALANCE); double spread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD); string currentTrade = "No Position"; if(PositionSelect(_Symbol)) { currentTrade = PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY ? "Buy" : "Sell"; } string msg = "EMA_OB_FVG_EA\nTrend: "; msg += uptrend ? "UPTREND" : downtrend ? "DOWNTREND" : "RANGING"; msg += "\nBalance: " + DoubleToString(balance, 2); msg += "\nSpread: " + IntegerToString(spread) + " pips"; msg += "\nCurrent Trade: " + currentTrade; if(!ObjectFind(0, objName)) ObjectCreate(0, objName, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, x); ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, y); ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, 12); ObjectSetInteger(0, objName, OBJPROP_COLOR, clrBlanchedAlmond); ObjectSetString(0, objName, OBJPROP_TEXT, msg); } //+------------------------------------------------------------------+ //| Chart Event for FVG drawing | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(id == CHARTEVENT_CLICK) { ArraySetAsSeries(priceData, true); CopyRates(_Symbol, PERIOD_CURRENT, 0, 100, priceData); drawFVGs(); } } //+------------------------------------------------------------------+ //| Scan and draw FVGs | //+------------------------------------------------------------------+ void drawFVGs() { ObjectsDeleteAll(0, "FVG_"); int bars = ArraySize(priceData); for(int i = 3; i < bars; i++) { double high2 = priceData[i - 2].high; double low0 = priceData[i].low; double high0 = priceData[i].high; double low2 = priceData[i - 2].low; datetime time1 = priceData[i - 2].time; datetime time2 = priceData[i].time; if(low0 > high2) // Bullish FVG { string name = "FVG_" + IntegerToString(i); DrawRect(name, time1, time2, high2, low0, clrGreen); } else if(high0 < low2) // Bearish FVG { string name = "FVG_" + IntegerToString(i); DrawRect(name, time1, time2, high0, low2, clrRed); } } } //+------------------------------------------------------------------+ //| Helper to draw rectangle | //+------------------------------------------------------------------+ void DrawRect(string name, datetime time1, datetime time2, double price1, double price2, color clr) { if(!ObjectCreate(0, name, OBJ_RECTANGLE, 0, time1, price1, time2, price2)) return; ObjectSetInteger(0, name, OBJPROP_COLOR, clr); ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID); ObjectSetInteger(0, name, OBJPROP_WIDTH, 1); }