//+------------------------------------------------------------------+ //| MA + ATR Bands.mq5 | //| Copyright 2026, HectorandAlgos | //| https://www.mql5.com/en/users/hector001 | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, HectorandAlgos" #property link "https://www.mql5.com/en/users/hector001" #property version "1.00" #property indicator_chart_window #property indicator_buffers 4 #property indicator_plots 3 //--- Plot SMA #property indicator_label1 "SMA" #property indicator_type1 DRAW_LINE #property indicator_color1 clrDodgerBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- Plot Upper Band #property indicator_label2 "Upper Band" #property indicator_type2 DRAW_LINE #property indicator_color2 clrOrangeRed #property indicator_style2 STYLE_SOLID #property indicator_width2 1 //--- Plot Lower Band #property indicator_label3 "Lower Band" #property indicator_type3 DRAW_LINE #property indicator_color3 clrLimeGreen #property indicator_style3 STYLE_SOLID #property indicator_width3 1 enum ENUM_MODE { MODE_SYMMETRIC, MODE_ASYMMETRIC }; enum ENUM_REFERENCE_PRICE { PRICE_CURRENT_BAR, PRICE_PREVIOUS_BAR }; //--- Input parameters input int MAPeriod = 20; // MA Period input int ATRPeriod = 14; // ATR Period input double Multiplier = 2.0; // Mode 1 Multiplier input double BigMultiplier = 2.5; // Mode 2 Big Multiplier input double SmallMultiplier= 1.5; // Mode 2 Small Multiplier input ENUM_MODE Mode = MODE_SYMMETRIC; // Mode 1 - Symmetric OR Mode 2 - Asymmetric input ENUM_REFERENCE_PRICE RefPrice = PRICE_CURRENT_BAR; // Use Current Bar Close OR Use Previous Bar Close input bool UsePriceCenter = false; // Use Current Price as Center? input bool DebugPrint = true; // Enable Debug Printing //--- Indicator buffers double SMABuffer[]; double UpperBuffer[]; double LowerBuffer[]; double PriceCenterBuffer[]; //--- Handles int maHandle; int atrHandle; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Set buffers SetIndexBuffer(0, SMABuffer, INDICATOR_DATA); SetIndexBuffer(1, UpperBuffer, INDICATOR_DATA); SetIndexBuffer(2, LowerBuffer, INDICATOR_DATA); SetIndexBuffer(3, PriceCenterBuffer, INDICATOR_CALCULATIONS); //--- Set plot labels PlotIndexSetString(0, PLOT_LABEL, "SMA"); PlotIndexSetString(1, PLOT_LABEL, "Upper Band"); PlotIndexSetString(2, PLOT_LABEL, "Lower Band"); //--- Create handles maHandle = iMA(_Symbol, _Period, MAPeriod, 0, MODE_SMA, PRICE_CLOSE); atrHandle = iATR(_Symbol, _Period, ATRPeriod); if(maHandle == INVALID_HANDLE || atrHandle == INVALID_HANDLE) { Print("Error creating indicator handles"); return(INIT_FAILED); } if(DebugPrint) { Print("========================================"); Print("MA + ATR Bands Indicator Initialized"); Print("Symbol: ", _Symbol, " | Period: ", EnumToString(_Period)); Print("MA Period: ", MAPeriod, " | ATR Period: ", ATRPeriod); Print("Mode: ", Mode == MODE_SYMMETRIC ? "Symmetric" : "Asymmetric"); Print("Reference Price: ", RefPrice == PRICE_CURRENT_BAR ? "Current Bar" : "Previous Bar"); Print("Use Price Center: ", UsePriceCenter ? "YES" : "NO"); Print("Multiplier (Mode 1): ", Multiplier); Print("Big Multiplier (Mode 2): ", BigMultiplier); Print("Small Multiplier (Mode 2): ", SmallMultiplier); Print("Debug Print: ", DebugPrint ? "ENABLED" : "DISABLED"); Print("========================================"); } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(maHandle != INVALID_HANDLE) IndicatorRelease(maHandle); if(atrHandle != INVALID_HANDLE) IndicatorRelease(atrHandle); if(DebugPrint) { Print("========================================"); Print("MA + ATR Bands Indicator Deinitialized"); Print("Reason: ", reason); Print("========================================"); } } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { if(rates_total < MAPeriod || rates_total < ATRPeriod) { if(DebugPrint) Print("Not enough bars: rates_total=", rates_total, " MAPeriod=", MAPeriod, " ATRPeriod=", ATRPeriod); return(0); } //--- Determine start point int start = 0; if(prev_calculated == 0) { start = 0; if(DebugPrint) Print("First run: Starting from bar 0"); } else { start = prev_calculated - 1; if(start < 1) start = 1; if(DebugPrint) Print("Update run: Starting from bar ", start, " (prev_calculated=", prev_calculated, ")"); } //--- FIX: Copy data WITHOUT setting as series //--- We'll use normal array indexing (0 = oldest, rates_total-1 = newest) double maBuffer[]; double atrBuffer[]; //--- Copy ALL bars from the beginning int maCopied = CopyBuffer(maHandle, 0, 0, rates_total, maBuffer); int atrCopied = CopyBuffer(atrHandle, 0, 0, rates_total, atrBuffer); if(DebugPrint) { Print("Data Copy Status:"); Print(" maCopied: ", maCopied, " / ", rates_total, " bars"); Print(" atrCopied: ", atrCopied, " / ", rates_total, " bars"); //--- Check first few values to verify data is valid if(maCopied > 0 && atrCopied > 0) { Print(" Sample SMA[0]: ", DoubleToString(maBuffer[0], _Digits)); Print(" Sample SMA[", rates_total-1, "]: ", DoubleToString(maBuffer[rates_total-1], _Digits)); Print(" Sample ATR[0]: ", DoubleToString(atrBuffer[0], _Digits)); Print(" Sample ATR[", rates_total-1, "]: ", DoubleToString(atrBuffer[rates_total-1], _Digits)); } } if(maCopied <= 0 || atrCopied <= 0) { if(DebugPrint) { Print("ERROR: Failed to copy indicator data!"); Print(" maCopied=", maCopied, " atrCopied=", atrCopied); } return(0); } //--- Check for invalid data (DBL_MAX or DBL_MIN) bool validData = true; if(maCopied > 0) { double lastSMA = maBuffer[rates_total-1]; if(!MathIsValidNumber(lastSMA) || lastSMA > 1e308 || lastSMA < 1e-308) { if(DebugPrint) Print("ERROR: Invalid SMA data! lastSMA=", DoubleToString(lastSMA, _Digits)); validData = false; } } if(atrCopied > 0) { double lastATR = atrBuffer[rates_total-1]; if(!MathIsValidNumber(lastATR) || lastATR > 1e308 || lastATR < 1e-308) { if(DebugPrint) Print("ERROR: Invalid ATR data! lastATR=", DoubleToString(lastATR, _Digits)); validData = false; } } if(!validData) return(0); //--- Main calculation loop - process from start to end for(int i = start; i < rates_total; i++) { double sma = maBuffer[i]; double atr = atrBuffer[i]; double currentPrice = close[i]; //--- Determine which price to use for comparison double refPrice; if(RefPrice == PRICE_CURRENT_BAR) refPrice = close[i]; else // PRICE_PREVIOUS_BAR refPrice = (i > 0) ? close[i-1] : close[i]; //--- Center for bands double center = UsePriceCenter ? currentPrice : sma; PriceCenterBuffer[i] = center; //--- Calculate bands based on mode if(Mode == MODE_SYMMETRIC) { UpperBuffer[i] = center + (Multiplier * atr); LowerBuffer[i] = center - (Multiplier * atr); } else // MODE_ASYMMETRIC { if(refPrice > sma) { UpperBuffer[i] = center + (BigMultiplier * atr); LowerBuffer[i] = center - (SmallMultiplier * atr); } else if(refPrice < sma) { UpperBuffer[i] = center + (SmallMultiplier * atr); LowerBuffer[i] = center - (BigMultiplier * atr); } else // refPrice == sma { UpperBuffer[i] = center + (BigMultiplier * atr); LowerBuffer[i] = center - (BigMultiplier * atr); } } SMABuffer[i] = sma; } //--- DEBUG: Print last candle figures if(DebugPrint && rates_total > 0) { int lastIdx = rates_total - 1; Print("========================================"); Print("LAST CANDLE FIGURES (Index: ", lastIdx, ")"); Print("----------------------------------------"); Print("Time: ", TimeToString(time[lastIdx])); Print("Price Data:"); Print(" Open: ", DoubleToString(open[lastIdx], _Digits)); Print(" High: ", DoubleToString(high[lastIdx], _Digits)); Print(" Low: ", DoubleToString(low[lastIdx], _Digits)); Print(" Close: ", DoubleToString(close[lastIdx], _Digits)); Print("----------------------------------------"); Print("Indicator Values:"); Print(" SMA: ", DoubleToString(SMABuffer[lastIdx], _Digits)); Print(" ATR: ", DoubleToString(atrBuffer[lastIdx], _Digits)); Print(" Center: ", DoubleToString(PriceCenterBuffer[lastIdx], _Digits)); Print(" Upper Band: ", DoubleToString(UpperBuffer[lastIdx], _Digits)); Print(" Lower Band: ", DoubleToString(LowerBuffer[lastIdx], _Digits)); Print("----------------------------------------"); Print("Calculation Details:"); Print(" Ref Price: ", DoubleToString(refPriceFromClose(close, RefPrice, lastIdx), _Digits)); Print(" Center Source: ", UsePriceCenter ? "Current Close" : "SMA"); if(Mode == MODE_SYMMETRIC) { Print(" Mode: Symmetric"); Print(" Formula: Upper = Center + (", Multiplier, " × ATR)"); Print(" Lower = Center - (", Multiplier, " × ATR)"); } else { Print(" Mode: Asymmetric"); double refPriceVal = refPriceFromClose(close, RefPrice, lastIdx); string position = refPriceVal > SMABuffer[lastIdx] ? "ABOVE SMA" : (refPriceVal < SMABuffer[lastIdx] ? "BELOW SMA" : "EQUAL TO SMA"); Print(" Price Position: ", position); if(refPriceVal > SMABuffer[lastIdx]) { Print(" Formula: Upper = Center + (", BigMultiplier, " × ATR)"); Print(" Lower = Center - (", SmallMultiplier, " × ATR)"); } else if(refPriceVal < SMABuffer[lastIdx]) { Print(" Formula: Upper = Center + (", SmallMultiplier, " × ATR)"); Print(" Lower = Center - (", BigMultiplier, " × ATR)"); } else { Print(" Formula: Upper = Center + (", BigMultiplier, " × ATR)"); Print(" Lower = Center - (", BigMultiplier, " × ATR)"); } } Print(" Spread: ", spread[lastIdx]); Print(" Tick Volume: ", tick_volume[lastIdx]); Print("========================================"); } return(rates_total); } //+------------------------------------------------------------------+ //| Helper function to get reference price | //+------------------------------------------------------------------+ double refPriceFromClose(const double &close[], ENUM_REFERENCE_PRICE refType, int index) { if(refType == PRICE_CURRENT_BAR) return close[index]; else // PRICE_PREVIOUS_BAR return (index > 0) ? close[index-1] : close[index]; } //+------------------------------------------------------------------+