//+------------------------------------------------------------------+ //| OrdersEA_Smart_Grid.mq5 | //| Copyright 2024, Garfield Heron | //| https://fetcherpay.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, Garfield Heron" #property link "https://fetcherpay.com" #property version "3.0" #property strict #include #include #define VERSION "Version 3.0 Smart Grid MT5" #define MAX_TRADES 600 #define MAX_LOG_TRADES 1200 //--- Input Parameters input string Email= "garfield@fetcherpay.com"; input int MagicNum= 333; //--- Smart Grid Settings input string GridSettings = "=== Smart Grid Settings ==="; input bool UseAutoPivots = true; input double HIGH= 0; input double LOW= 0; input double Entry= 10; input double TP= 15; input double Lots=0.01; input int MaxLevels = 10; //--- Range Filter Settings input string FilterSettings = "=== Range Filters ==="; input bool UseRSIFilter = true; input int RSIPeriod = 14; input int RSILower = 35; input int RSIUpper = 65; input bool UseADXFilter = true; input int ADXPeriod = 14; input double ADXMax = 25; input bool UseATRFilter = true; input int ATRPeriod = 14; input double ATRMultiplier = 1.5; //--- Risk Management input string RiskSettings = "=== Risk Management ==="; input int StopLoss=0; input int TRADE_RANGE= 50; input double LongLimit= 0; input double ShortLimit= 0; input string GetOut= "N"; input string OpenNewTrades="Y"; input bool Opposite= false; input int TakeProfitLevelPercent= 50; input int TakeProfitLevelDollarAmount= 2000; input int BaseEquity= 10000; input bool Master= false; input bool DiagnosticModeOn= false; //--- Trade Object CTrade trade; CPositionInfo positionInfo; //--- Indicator Handles int RSIHandle = INVALID_HANDLE; int ADXHandle = INVALID_HANDLE; int ATRHandle = INVALID_HANDLE; //--- Pivot Point Variables double PivotP = 0; double PivotR1 = 0; double PivotR2 = 0; double PivotS1 = 0; double PivotS2 = 0; //--- Original OrdersEA Variables int initialCycleEquity= 0; int longs, shorts; ulong longsTicket[MAX_TRADES]; ulong shortsTicket[MAX_TRADES]; ulong logTickets[MAX_LOG_TRADES]; datetime logTicketsTime[MAX_LOG_TRADES]; int logTicketsCounter; int Levels; double price[MAX_TRADES]; int stoplevel; bool bFirstTick= false; int logId; bool bEnableLongs; bool bEnableShorts; double tickValue; int MaximalLoss; ulong lastTicketSentOpen= 0, lastTicketSentClose= 0; double longAvgPrice= 0, longAvgLots= 0; double shortAvgPrice= 0, shortAvgLots= 0; double longProfit= 0; double shortProfit= 0; bool bInit= false; int TakeProfitVal=0; bool AboveHigh; bool BelowLow; int tradeLogId; double closeOnProfit; bool bGetOutOK, bOpenNewTradesOK; int initEquity; int lotDigits; bool bWithdrawMailSent= false; bool bGetOutHandled; int PingTimeMinutes= 240; bool bValidSettings; string errMsg; datetime PivotCalculationTime = 0; bool TradeExecutedToday = false; bool R1HitToday = false; bool S1HitToday = false; //+------------------------------------------------------------------+ //| Calculate Pivot Points | //+------------------------------------------------------------------+ void CalculatePivotPoints() { MqlRates rates[1]; int copied = CopyRates(_Symbol, PERIOD_D1, 1, 1, rates); if(copied < 1) { Print("Failed to get daily rates for pivot calculation"); return; } double prevHigh = rates[0].high; double prevLow = rates[0].low; double prevClose = rates[0].close; PivotP = (prevHigh + prevLow + prevClose) / 3.0; PivotR1 = (2.0 * PivotP) - prevLow; PivotS1 = (2.0 * PivotP) - prevHigh; PivotR2 = PivotP + (prevHigh - prevLow); PivotS2 = PivotP - (prevHigh - prevLow); if(UseAutoPivots) { double atr = 0; if(ATRHandle != INVALID_HANDLE) { double atrBuf[1]; if(CopyBuffer(ATRHandle, 0, 0, 1, atrBuf) > 0) atr = atrBuf[0]; } if(UseATRFilter && atr > 0) { PivotR1 = NormalizeDouble(PivotP + (atr * ATRMultiplier), _Digits); PivotS1 = NormalizeDouble(PivotP - (atr * ATRMultiplier), _Digits); } // Use the calculated values // Note: In actual usage, you would set HIGH/LOW from inputs } Print("Pivot Calculated: P=", PivotP, " R1=", PivotR1, " S1=", PivotS1); } //+------------------------------------------------------------------+ //| Check if Market is Ranging | //+------------------------------------------------------------------+ bool IsRangingMarket() { bool isRanging = true; double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(UseRSIFilter && RSIHandle != INVALID_HANDLE) { double rsiBuf[1]; if(CopyBuffer(RSIHandle, 0, 0, 1, rsiBuf) > 0) { double rsi = rsiBuf[0]; if(rsi < RSILower || rsi > RSIUpper) { Print("RSI Filter: Market at extremes (RSI=", rsi, ")"); isRanging = false; } } } if(UseADXFilter && ADXHandle != INVALID_HANDLE && isRanging) { double adxBuf[1]; if(CopyBuffer(ADXHandle, 0, 0, 1, adxBuf) > 0) { double adx = adxBuf[0]; if(adx > ADXMax) { Print("ADX Filter: Market trending (ADX=", adx, ")"); isRanging = false; } } } double actualHigh = (HIGH > 0) ? HIGH : PivotR1; double actualLow = (LOW > 0) ? LOW : PivotS1; if(currentPrice > actualHigh || currentPrice < actualLow) { Print("Price outside grid range"); isRanging = false; } return isRanging; } //+------------------------------------------------------------------+ //| Calculate Lot Size | //+------------------------------------------------------------------+ double CalcLots() { double tmp = (AccountInfoDouble(ACCOUNT_EQUITY) - initEquity); double a = EquityFactorPercent; double b = LotsFactorPercent; double lots; if(0 == EquityFactorPercent || 0 == LotsFactorPercent) lots = Lots; else { a = initEquity * a / 100.0; b = b / 100.0; if(tmp > 0) tmp = MathPow(1 + b, (tmp / a)); else if(tmp < 0) tmp = MathPow(1 - b, MathAbs(tmp / a)); else tmp = 1; lots = NormalizeDouble(Lots * tmp, lotDigits); double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); if(lots < minLot) lots = minLot; } return lots; } //+------------------------------------------------------------------+ //| Add Trade to Log | //+------------------------------------------------------------------+ void AddTradeToLog(ulong ticket) { bool rc = false; int i = 0; for(i = 0; i < logTicketsCounter; i++) { if(logTickets[i] == ticket) { rc = true; break; } } if(!rc && i < MAX_LOG_TRADES) { logTickets[logTicketsCounter] = ticket; logTicketsTime[logTicketsCounter] = TimeCurrent(); logTicketsCounter++; } } //+------------------------------------------------------------------+ //| Send Notification | //+------------------------------------------------------------------+ void SendNotificationEx(string title, string subject) { if(!MQLInfoInteger(MQL_OPTIMIZATION)) { double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); string msg = title + ": " + subject; msg = msg + " | Price: " + DoubleToString(bid, _Digits); msg = msg + " | Longs: " + IntegerToString(longs) + " @ " + DoubleToString(longAvgPrice, _Digits); msg = msg + " | Shorts: " + IntegerToString(shorts) + " @ " + DoubleToString(shortAvgPrice, _Digits); msg = msg + " | Equity: " + DoubleToString(AccountInfoDouble(ACCOUNT_EQUITY), 2); SendNotification(msg); Print(msg); } } //+------------------------------------------------------------------+ //| Log function | //+------------------------------------------------------------------+ void Log(string st) { if(DiagnosticModeOn) { Print(TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS) + ": " + st); } } //+------------------------------------------------------------------+ //| Expert initialization | //+------------------------------------------------------------------+ int OnInit() { trade.SetExpertMagicNumber(MagicNum); trade.SetDeviationInPoints(10); trade.SetTypeFilling(ORDER_FILLING_IOC); initEquity = BaseEquity; lotDigits = 2; double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE); double tickValueCurr = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); tickValue = (tickSize > 0) ? tickValueCurr / tickSize : 0; stoplevel = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL); if(stoplevel <= 0) stoplevel = 0; // Initialize indicators if(UseRSIFilter) RSIHandle = iRSI(_Symbol, PERIOD_CURRENT, RSIPeriod, PRICE_CLOSE); if(UseADXFilter) ADXHandle = iADX(_Symbol, PERIOD_CURRENT, ADXPeriod); if(UseATRFilter) ATRHandle = iATR(_Symbol, PERIOD_CURRENT, ATRPeriod); CalculatePivotPoints(); Print("Smart Grid EA MT5 Initialized"); Print("Magic: ", MagicNum); Print("AutoPivots: ", UseAutoPivots); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(RSIHandle != INVALID_HANDLE) IndicatorRelease(RSIHandle); if(ADXHandle != INVALID_HANDLE) IndicatorRelease(ADXHandle); if(ATRHandle != INVALID_HANDLE) IndicatorRelease(ATRHandle); Print("Smart Grid EA MT5 Deinitialized"); } //+------------------------------------------------------------------+ //| Place Buy Stop Order | //+------------------------------------------------------------------+ bool PlaceBuyStop(double priceLevel, int level) { if(level >= MaxLevels) return false; double lots = CalcLots(); double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); double sl = (StopLoss > 0) ? priceLevel - (StopLoss * point) : 0; double tp = priceLevel + (TP * point); MqlTradeRequest request = {}; MqlTradeResult result = {}; request.action = TRADE_ACTION_PENDING; request.symbol = _Symbol; request.volume = lots; request.price = priceLevel; request.sl = sl; request.tp = tp; request.deviation = 10; request.magic = MagicNum; request.comment = "Smart Grid Buy " + IntegerToString(level); request.type = ORDER_TYPE_BUY_STOP; request.type_filling = ORDER_FILLING_IOC; if(trade.OrderSend(request, result)) { if(result.retcode == TRADE_RETCODE_DONE || result.retcode == TRADE_RETCODE_PLACED) { Print("Buy Stop Level ", level, " placed at ", priceLevel, " Ticket: ", result.order); return true; } } Print("Error placing buy stop: ", trade.ResultRetcodeDescription()); return false; } //+------------------------------------------------------------------+ //| Place Sell Stop Order | //+------------------------------------------------------------------+ bool PlaceSellStop(double priceLevel, int level) { if(level >= MaxLevels) return false; double lots = CalcLots(); double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); double sl = (StopLoss > 0) ? priceLevel + (StopLoss * point) : 0; double tp = priceLevel - (TP * point); MqlTradeRequest request = {}; MqlTradeResult result = {}; request.action = TRADE_ACTION_PENDING; request.symbol = _Symbol; request.volume = lots; request.price = priceLevel; request.sl = sl; request.tp = tp; request.deviation = 10; request.magic = MagicNum; request.comment = "Smart Grid Sell " + IntegerToString(level); request.type = ORDER_TYPE_SELL_STOP; request.type_filling = ORDER_FILLING_IOC; if(trade.OrderSend(request, result)) { if(result.retcode == TRADE_RETCODE_DONE || result.retcode == TRADE_RETCODE_PLACED) { Print("Sell Stop Level ", level, " placed at ", priceLevel, " Ticket: ", result.order); return true; } } Print("Error placing sell stop: ", trade.ResultRetcodeDescription()); return false; } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { static datetime lastBarTime = 0; datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0); MqlDateTime dt; TimeToStruct(TimeCurrent(), dt); // Recalculate pivots at new day (hour 0, first 5 minutes) if(dt.hour == 0 && dt.min < 5 && currentBarTime != lastBarTime) { CalculatePivotPoints(); } if(currentBarTime != lastBarTime) { lastBarTime = currentBarTime; // Check if we should trade if(!IsRangingMarket()) { Print("Market not suitable for grid trading"); return; } // Get grid boundaries double actualHigh = (HIGH > 0) ? HIGH : PivotR1; double actualLow = (LOW > 0) ? LOW : PivotS1; double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID); double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); double entryPips = Entry * point; // Log status Print("Smart Grid: Price=", currentPrice, " Range: ", actualLow, " - ", actualHigh); Print("RSI/ADX filters passed - Grid active"); // Example: Place grid orders (simplified) // In full implementation, check existing orders first for(int i = 0; i < MaxLevels; i++) { double buyLevel = actualLow + (i * entryPips); double sellLevel = actualHigh - (i * entryPips); if(buyLevel < currentPrice) PlaceBuyStop(buyLevel, i); if(sellLevel > currentPrice) PlaceSellStop(sellLevel, i); } } }