/*
 ____| _ \   _ \  ____|\ \  /    ___|__ __|  \ __ __|_ _|  _ \   \  | 
 |    |   | |   | __|   \  /   \___ \   |   _ \   |    |  |   |   \ | 
 __|  |   | __ <  |        \_____|   |  |  ___ \  |    |  |   | |\  | 
_|   \___/ _| \_\_____| _/\_\  _____/  _|_/    _\_|  ___|\___/ _| \_| 
                                                                      
*/
//+------------------------------------------------------------------+
//|                                               Accidental SMA.mq4 |
//+------------------------------------------------------------------+
#property copyright "c. 2025, Forex-Station"
#property link      "http://www.Forex-Station.com/"
#property description "SMA (20) - Simple Moving Average"
#property strict

#property indicator_chart_window
#property indicator_buffers 8
#property indicator_plots   8

// Fill upper
#property indicator_color1  clrHotPink
#property indicator_width1  3
#property indicator_style1  STYLE_SOLID
#property indicator_label1  "Fill Upper"

// Fill lower
#property indicator_color2  clrSpringGreen
#property indicator_width2  3
#property indicator_style2  STYLE_SOLID
#property indicator_label2  "Fill Lower"

// Upper Cloud Fill (FillUpper to EMA1) - Ichimoku-style
#property indicator_color3  clrHotPink
#property indicator_width3  1
#property indicator_style3  STYLE_DOT
#property indicator_label3  "Upper Cloud Top"

#property indicator_color4  clrHotPink
#property indicator_width4  1
#property indicator_style4  STYLE_DOT
#property indicator_label4  "Upper Cloud Bottom"

// Lower Cloud Fill (FillLower to EMA1) - Ichimoku-style
#property indicator_color5  clrSpringGreen
#property indicator_width5  1
#property indicator_style5  STYLE_DOT
#property indicator_label5  "Lower Cloud Top"

#property indicator_color6  clrSpringGreen
#property indicator_width6  1
#property indicator_style6  STYLE_DOT
#property indicator_label6  "Lower Cloud Bottom"

// SMA Green (when PMA above SMA)
#property indicator_color7  clrCrimson
#property indicator_width7  5
#property indicator_style7  STYLE_SOLID
#property indicator_label7  "SMA Down"

// SMA Red (when PMA below SMA)
#property indicator_color8  clrDarkGreen
#property indicator_width8  5
#property indicator_style8  STYLE_SOLID
#property indicator_label8  "SMA Up"

//--- Input parameters
input ENUM_APPLIED_PRICE InpPrice  = PRICE_CLOSE;  // Source
input int                InpLength = 20;           // Length

//--- Button 1 (SMA) parameters
input string             button_note1          = "--- SMA Button Settings ---"; // ------------------------------
input int                btn_Subwindow         = 0;                 // What window to put the button on
input ENUM_BASE_CORNER   btn_corner            = CORNER_LEFT_UPPER; // chart corner for anchoring
input string             btn_text              = "SMA";             // Display text
input string             btn_Font              = "Arial";           // button font name
input int                btn_FontSize          = 9;                 // font size
input color              btn_text_ON_color     = clrLime;           // ON color when the button is turned on
input color              btn_text_OFF_color    = clrRed;            // OFF color when the button is turned off
input color              btn_background_color  = clrDimGray;        // background color of the button
input color              btn_border_color      = clrBlack;          // border color the button
input int                button_x              = 20;                // Horizontal location
input int                button_y              = 195;               // Vertical location
input int                btn_Width             = 40;                // width
input int                btn_Height            = 20;                // height
input string             UniqueButtonID        = "SMA20";           // Unique ID for SMA button

//--- Button 2 (Cloud) parameters
input string             button_note2          = "--- Cloud Button Settings ---"; // ------------------------------
input string             btn2_text             = "Cloud";           // Display text
input color              btn2_text_ON_color    = clrLime;           // ON color when the button is turned on
input color              btn2_text_OFF_color   = clrRed;            // OFF color when the button is turned off
input color              btn2_background_color = clrDimGray;        // background color of the button
input color              btn2_border_color     = clrBlack;          // border color the button
input int                button2_x             = 60;                // Horizontal location
input int                button2_y             = 195;               // Vertical location
input int                btn2_Width            = 40;                // width
input int                btn2_Height           = 20;                // height
input string             UniqueButton2ID       = "Cloud20";         // Unique ID for Cloud button
input string             button_note3          = "------------------------------"; // ------------------------------

bool show_sma = true, show_cloud = true;
string IndicatorObjPrefix, buttonId, buttonId2;

//--- Indicator buffers
double PMABuffer[], PredictBuffer[], SMAGreenBuffer[], SMARedBuffer[], FillUpperBuffer[], FillLowerBuffer[], UpperCloudTop[], UpperCloudBottom[], LowerCloudTop[], LowerCloudBottom[];

//+------------------------------------------------------------------+
int OnInit()
{
   IndicatorDigits(Digits);
   IndicatorBuffers(10);
   
   IndicatorObjPrefix = "__" + btn_text + "__";
   
   // Create Button 1 (SMA)
   buttonId = "_" + UniqueButtonID + IndicatorObjPrefix + "_BT_";
   if (ObjectFind(buttonId) < 0) 
      createButton(buttonId, btn_text, btn_Width, btn_Height, btn_Font, btn_FontSize, 
                   btn_background_color, btn_border_color, btn_text_ON_color);
   ObjectSetInteger(0, buttonId, OBJPROP_YDISTANCE, button_y);
   ObjectSetInteger(0, buttonId, OBJPROP_XDISTANCE, button_x);
   
   // Create Button 2 (Cloud)
   buttonId2 = "_" + UniqueButton2ID + IndicatorObjPrefix + "_BT2_";
   if (ObjectFind(buttonId2) < 0) 
      createButton(buttonId2, btn2_text, btn2_Width, btn2_Height, btn_Font, btn_FontSize, 
                   btn2_background_color, btn2_border_color, btn2_text_ON_color);
   ObjectSetInteger(0, buttonId2, OBJPROP_YDISTANCE, button2_y);
   ObjectSetInteger(0, buttonId2, OBJPROP_XDISTANCE, button2_x);

   init2();
   
   // Set initial states
   show_sma = (GetButtonState(buttonId) != "off");
   show_cloud = (GetButtonState(buttonId2) != "off");
   
   UpdateDisplay();
   
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
void createButton(string buttonID, string buttonText, int width2, int height, 
                  string font, int fontSize, color bgColor, color borderColor, color txtColor)
{
   ObjectDelete(0, buttonID);
   ObjectCreate(0, buttonID, OBJ_BUTTON, btn_Subwindow, 0, 0);
   ObjectSetInteger(0, buttonID, OBJPROP_COLOR, txtColor);
   ObjectSetInteger(0, buttonID, OBJPROP_BGCOLOR, bgColor);
   ObjectSetInteger(0, buttonID, OBJPROP_BORDER_COLOR, borderColor);
   ObjectSetInteger(0, buttonID, OBJPROP_BORDER_TYPE, BORDER_RAISED);
   ObjectSetInteger(0, buttonID, OBJPROP_XSIZE, width2);
   ObjectSetInteger(0, buttonID, OBJPROP_YSIZE, height);
   ObjectSetString(0, buttonID, OBJPROP_FONT, font);
   ObjectSetString(0, buttonID, OBJPROP_TEXT, buttonText);
   ObjectSetInteger(0, buttonID, OBJPROP_FONTSIZE, fontSize);
   ObjectSetInteger(0, buttonID, OBJPROP_SELECTABLE, false);
   ObjectSetInteger(0, buttonID, OBJPROP_CORNER, btn_corner);
   ObjectSetInteger(0, buttonID, OBJPROP_HIDDEN, true);
   ObjectSetInteger(0, buttonID, OBJPROP_XDISTANCE, 9999);
   ObjectSetInteger(0, buttonID, OBJPROP_YDISTANCE, 9999);
   ObjectSetInteger(0, buttonID, OBJPROP_STATE, true);
}

//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{ 
   switch(reason)
   {
      case REASON_PARAMETERS:
      case REASON_CHARTCHANGE:
      case REASON_RECOMPILE:
      case REASON_CLOSE: break;
      default:
         ObjectDelete(buttonId);
         ObjectDelete(buttonId2);
   }
}

//+------------------------------------------------------------------+
string GetButtonState(string whichbutton)
{
   bool selected = ObjectGetInteger(ChartID(), whichbutton, OBJPROP_STATE);
   if (selected)
      return ("on");
   else
      return ("off");
}

//+------------------------------------------------------------------+
void UpdateDisplay()
{
   // Update SMA display (buffers 6, 7)
   if (show_sma)
   {
      SetIndexStyle(6, DRAW_LINE);
      SetIndexStyle(7, DRAW_LINE);
   }
   else
   {
      SetIndexStyle(6, DRAW_NONE);
      SetIndexStyle(7, DRAW_NONE);
   }
   
   // Update Cloud display (buffers 0, 1, 2, 3, 4, 5)
   if (show_cloud)
   {
      SetIndexStyle(0, DRAW_LINE);
      SetIndexStyle(1, DRAW_LINE);
      SetIndexStyle(2, DRAW_HISTOGRAM);
      SetIndexStyle(3, DRAW_HISTOGRAM);
      SetIndexStyle(4, DRAW_HISTOGRAM);
      SetIndexStyle(5, DRAW_HISTOGRAM);
   }
   else
   {
      SetIndexStyle(0, DRAW_NONE);
      SetIndexStyle(1, DRAW_NONE);
      SetIndexStyle(2, DRAW_NONE);
      SetIndexStyle(3, DRAW_NONE);
      SetIndexStyle(4, DRAW_NONE);
      SetIndexStyle(5, DRAW_NONE);
   }
   
   ChartRedraw();
}

//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
{
   if(id == CHARTEVENT_OBJECT_CREATE || id == CHARTEVENT_OBJECT_DELETE) return;
   if(id == CHARTEVENT_MOUSE_MOVE || id == CHARTEVENT_MOUSE_WHEEL) return;

   static string prevState1 = "";
   static string prevState2 = "";
   
   // Handle Button 1 (SMA) click
   if (id == CHARTEVENT_OBJECT_CLICK && sparam == buttonId)
   {
      string newState = GetButtonState(buttonId);
      if (newState != prevState1)
      {
         if (newState == "off")
         {
            ObjectSetInteger(0, buttonId, OBJPROP_COLOR, btn_text_OFF_color);
            show_sma = false;
         }
         else
         {
            ObjectSetInteger(0, buttonId, OBJPROP_COLOR, btn_text_ON_color);
            show_sma = true;
         }
         ObjectSetString(ChartID(), buttonId, OBJPROP_TEXT, btn_text);
         prevState1 = newState;
         UpdateDisplay();
      }
   }
   
   // Handle Button 2 (Cloud) click
   if (id == CHARTEVENT_OBJECT_CLICK && sparam == buttonId2)
   {
      string newState = GetButtonState(buttonId2);
      if (newState != prevState2)
      {
         if (newState == "off")
         {
            ObjectSetInteger(0, buttonId2, OBJPROP_COLOR, btn2_text_OFF_color);
            show_cloud = false;
         }
         else
         {
            ObjectSetInteger(0, buttonId2, OBJPROP_COLOR, btn2_text_ON_color);
            show_cloud = true;
         }
         ObjectSetString(ChartID(), buttonId2, OBJPROP_TEXT, btn2_text);
         prevState2 = newState;
         UpdateDisplay();
      }
   }
}

//+------------------------------------------------------------------+
int init2()
{
   if(InpLength < 2)
   {
      Print("Length must be >= 2");
      return(INIT_PARAMETERS_INCORRECT);
   }
   
   // Set buffer mapping
   SetIndexBuffer(0, FillUpperBuffer);
   SetIndexBuffer(1, FillLowerBuffer);
   SetIndexBuffer(2, UpperCloudTop);
   SetIndexBuffer(3, UpperCloudBottom);
   SetIndexBuffer(4, LowerCloudTop);
   SetIndexBuffer(5, LowerCloudBottom);
   SetIndexBuffer(6, SMAGreenBuffer);
   SetIndexBuffer(7, SMARedBuffer);
   SetIndexBuffer(8, PMABuffer);
   SetIndexBuffer(9, PredictBuffer);
   
   // Set drawing styles
   SetIndexStyle(0, DRAW_LINE);
   SetIndexStyle(1, DRAW_LINE);
   SetIndexStyle(2, DRAW_HISTOGRAM);
   SetIndexStyle(3, DRAW_HISTOGRAM);
   SetIndexStyle(4, DRAW_HISTOGRAM);
   SetIndexStyle(5, DRAW_HISTOGRAM);
   SetIndexStyle(6, DRAW_LINE);
   SetIndexStyle(7, DRAW_LINE);
   SetIndexStyle(8, DRAW_LINE);
   SetIndexStyle(9, DRAW_LINE);
   
   // Set labels
   SetIndexLabel(0, "Fill Upper");
   SetIndexLabel(1, "Fill Lower");
   SetIndexLabel(2, "Upper Cloud Top");
   SetIndexLabel(3, "Upper Cloud Bottom");
   SetIndexLabel(4, "Lower Cloud Top");
   SetIndexLabel(5, "Lower Cloud Bottom");
   SetIndexLabel(6, "SMA Up");
   SetIndexLabel(7, "SMA Down");
   SetIndexLabel(8, "PMA");
   SetIndexLabel(9, "Predict");
   
   // Set starting bar
   SetIndexDrawBegin(0, InpLength);
   SetIndexDrawBegin(1, InpLength);
   SetIndexDrawBegin(2, InpLength);
   SetIndexDrawBegin(3, InpLength);
   SetIndexDrawBegin(4, InpLength);
   SetIndexDrawBegin(5, InpLength);
   SetIndexDrawBegin(6, InpLength);
   SetIndexDrawBegin(7, InpLength);
   SetIndexDrawBegin(8, InpLength);
   SetIndexDrawBegin(9, InpLength + 2);
   
   // Set empty values
   for(int i = 0; i < 10; i++)
      SetIndexEmptyValue(i, EMPTY_VALUE);
   
   IndicatorShortName("Accidental MA(" + IntegerToString(InpLength) + ")");
   IndicatorDigits(Digits);
   
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
double LinearRegression(const double &price[], int period, int shift, int offset)
{
   if(period < 2 || shift + period > ArraySize(price))
      return(0.0);
      
   double sumX = 0.0, sumY = 0.0, sumXY = 0.0, sumX2 = 0.0;
   
   for(int i = 0; i < period; i++)
   {
      double x = i;
      double y = price[shift + i];
      sumX += x;
      sumY += y;
      sumXY += x * y;
      sumX2 += x * x;
   }
   
   double n = period;
   double slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
   double intercept = (sumY - slope * sumX) / n;
   
   double x = period - 1 - offset;
   return(intercept + slope * x);
}

//+------------------------------------------------------------------+
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 < InpLength + 4)
      return(0);
   
   int limit;
   if(prev_calculated == 0)
   {
      limit = rates_total - InpLength - 4;
      ArrayInitialize(PMABuffer, EMPTY_VALUE);
      ArrayInitialize(PredictBuffer, EMPTY_VALUE);
      ArrayInitialize(SMAGreenBuffer, EMPTY_VALUE);
      ArrayInitialize(SMARedBuffer, EMPTY_VALUE);
      ArrayInitialize(FillUpperBuffer, EMPTY_VALUE);
      ArrayInitialize(FillLowerBuffer, EMPTY_VALUE);
      ArrayInitialize(UpperCloudTop, EMPTY_VALUE);
      ArrayInitialize(UpperCloudBottom, EMPTY_VALUE);
      ArrayInitialize(LowerCloudTop, EMPTY_VALUE);
      ArrayInitialize(LowerCloudBottom, EMPTY_VALUE);
   }
   else
   {
      limit = rates_total - prev_calculated;
   }
   
   double price[];
   ArrayResize(price, rates_total);
   ArraySetAsSeries(price, true);
   
   switch(InpPrice)
   {
      case PRICE_CLOSE:    ArrayCopy(price, close); break;
      case PRICE_OPEN:     ArrayCopy(price, open); break;
      case PRICE_HIGH:     ArrayCopy(price, high); break;
      case PRICE_LOW:      ArrayCopy(price, low); break;
      case PRICE_MEDIAN:   
         for(int i = 0; i < rates_total; i++)
            price[i] = (high[i] + low[i]) / 2.0;
         break;
      case PRICE_TYPICAL:
         for(int i = 0; i < rates_total; i++)
            price[i] = (high[i] + low[i] + close[i]) / 3.0;
         break;
      case PRICE_WEIGHTED:
         for(int i = 0; i < rates_total; i++)
            price[i] = (high[i] + low[i] + close[i] * 2.0) / 4.0;
         break;
   }
   
   ArraySetAsSeries(high, true);
   ArraySetAsSeries(low, true);
   ArraySetAsSeries(PMABuffer, true);
   ArraySetAsSeries(PredictBuffer, true);
   ArraySetAsSeries(SMAGreenBuffer, true);
   ArraySetAsSeries(SMARedBuffer, true);
   ArraySetAsSeries(FillUpperBuffer, true);
   ArraySetAsSeries(FillLowerBuffer, true);
   ArraySetAsSeries(UpperCloudTop, true);
   ArraySetAsSeries(UpperCloudBottom, true);
   ArraySetAsSeries(LowerCloudTop, true);
   ArraySetAsSeries(LowerCloudBottom, true);
   
   double cumRange = 0.0;
   for(int i = rates_total - 1; i >= 0; i--)
      cumRange += high[i] - low[i];
   double aRng = cumRange / (rates_total + 1);
   
   for(int i = limit; i >= 0; i--)
   {
      if(i > rates_total - InpLength - 1)
         continue;
         
      double sum = 0.0;
      for(int j = 0; j < InpLength; j++)
         sum += price[i + j];
      double sma = sum / InpLength;
      
      double lr0 = LinearRegression(price, InpLength, i, 0);
      double lr1 = LinearRegression(price, InpLength, i, 1);
      double slope = lr0 - lr1;
      
      double pma = sma + slope * InpLength * 0.5;
      PMABuffer[i] = pma;
      
      if(pma > sma) {
         SMAGreenBuffer[i] = sma;
         SMARedBuffer[i] = EMPTY_VALUE;
      } else {
         SMAGreenBuffer[i] = EMPTY_VALUE;
         SMARedBuffer[i] = sma;
      }
      
      if(i < rates_total - 1) {
         double nextPma = PMABuffer[i + 1];
         if(nextPma != EMPTY_VALUE) {
            bool currentBullish = (pma > sma);
            bool nextBullish = (nextPma > SMAGreenBuffer[i + 1] || (SMAGreenBuffer[i + 1] != EMPTY_VALUE && SMARedBuffer[i + 1] == EMPTY_VALUE));
            
            if(currentBullish != nextBullish) {
               SMAGreenBuffer[i] = sma;
               SMARedBuffer[i] = sma;
            }
         }
      }
      
      if(i <= rates_total - InpLength - 3)
      {
         double lr0_2 = LinearRegression(price, InpLength, i + 2, 0);
         double lr1_2 = LinearRegression(price, InpLength, i + 2, 1);
         double slope2 = lr0_2 - lr1_2;
         
         double predictPMA = pma + 0.5 * (slope - slope2) * InpLength;
         PredictBuffer[i] = predictPMA;
      }
      
      bool above = pma > sma;
      if(above)
      {
         FillUpperBuffer[i] = sma + aRng * 5;
         FillLowerBuffer[i] = sma;
      }
      else
      {
         FillUpperBuffer[i] = sma;
         FillLowerBuffer[i] = sma - aRng * 5;
      }
      
      double ema1 = iMA(NULL, 0, 1, 0, MODE_EMA, PRICE_CLOSE, i);
      
      if(above && FillUpperBuffer[i] != EMPTY_VALUE)
      {
         UpperCloudTop[i] = MathMax(FillUpperBuffer[i], ema1);
         UpperCloudBottom[i] = MathMin(FillUpperBuffer[i], ema1);
         LowerCloudTop[i] = EMPTY_VALUE;
         LowerCloudBottom[i] = EMPTY_VALUE;
      }
      else if(!above && FillLowerBuffer[i] != EMPTY_VALUE)
      {
         UpperCloudTop[i] = EMPTY_VALUE;
         UpperCloudBottom[i] = EMPTY_VALUE;
         LowerCloudTop[i] = MathMax(FillLowerBuffer[i], ema1);
         LowerCloudBottom[i] = MathMin(FillLowerBuffer[i], ema1);
      }
      else
      {
         UpperCloudTop[i] = EMPTY_VALUE;
         UpperCloudBottom[i] = EMPTY_VALUE;
         LowerCloudTop[i] = EMPTY_VALUE;
         LowerCloudBottom[i] = EMPTY_VALUE;
      }
   }
   
   return(rates_total);
}
//+------------------------------------------------------------------+