﻿//+------------------------------------------------------------------+
//|                                                  YearlyPivot.mq5 |
//|                         Converted from MonthlyPivot.mq4 to MQL5  |
//|                         with yearly pivot logic                   |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 7
#property indicator_plots   7

#property indicator_label1  "Yearly Pivot"
#property indicator_type1   DRAW_LINE
#property indicator_color1  Magenta
#property indicator_width1  2

#property indicator_label2  "Y_S1"
#property indicator_type2   DRAW_LINE
#property indicator_color2  RoyalBlue
#property indicator_width2  2

#property indicator_label3  "Y_R1"
#property indicator_type3   DRAW_LINE
#property indicator_color3  Crimson
#property indicator_width3  2

#property indicator_label4  "Y_S2"
#property indicator_type4   DRAW_LINE
#property indicator_color4  RoyalBlue
#property indicator_width4  2

#property indicator_label5  "Y_R2"
#property indicator_type5   DRAW_LINE
#property indicator_color5  Crimson
#property indicator_width5  2

#property indicator_label6  "Y_S3"
#property indicator_type6   DRAW_LINE
#property indicator_color6  SeaGreen
#property indicator_width6  2

#property indicator_label7  "Y_R3"
#property indicator_type7   DRAW_LINE
#property indicator_color7  SeaGreen
#property indicator_width7  2

//---- indicator buffers
double PBuffer[];
double S1Buffer[];
double R1Buffer[];
double S2Buffer[];
double R2Buffer[];
double S3Buffer[];
double R3Buffer[];

int    fontsize = 10;

// Current pivot levels (held across bars until next year boundary)
double P  = 0, S1 = 0, R1 = 0;
double S2 = 0, R2 = 0, S3 = 0, R3 = 0;

// Accumulators for the year currently being built
double yearly_high, yearly_low, yearly_close;

//+------------------------------------------------------------------+
int OnInit()
  {
   SetIndexBuffer(0, PBuffer,  INDICATOR_DATA);
   SetIndexBuffer(1, S1Buffer, INDICATOR_DATA);
   SetIndexBuffer(2, R1Buffer, INDICATOR_DATA);
   SetIndexBuffer(3, S2Buffer, INDICATOR_DATA);
   SetIndexBuffer(4, R2Buffer, INDICATOR_DATA);
   SetIndexBuffer(5, S3Buffer, INDICATOR_DATA);
   SetIndexBuffer(6, R3Buffer, INDICATOR_DATA);

   ArrayInitialize(PBuffer,  EMPTY_VALUE);
   ArrayInitialize(S1Buffer, EMPTY_VALUE);
   ArrayInitialize(R1Buffer, EMPTY_VALUE);
   ArrayInitialize(S2Buffer, EMPTY_VALUE);
   ArrayInitialize(R2Buffer, EMPTY_VALUE);
   ArrayInitialize(S3Buffer, EMPTY_VALUE);
   ArrayInitialize(R3Buffer, EMPTY_VALUE);

   for(int p = 0; p < 7; p++)
      PlotIndexSetDouble(p, PLOT_EMPTY_VALUE, EMPTY_VALUE);

   IndicatorSetString(INDICATOR_SHORTNAME, "YearlyPivotPoint");

   // --- text label objects ---
   string names[] = {"YearlyPivot","YSup1","YRes1","YSup2","YRes2","YSup3","YRes3"};
   string texts[] = {
      "                            Yearly Pivot Point",
      "        yS 1","        yR 1",
      "        yS 2","        yR 2",
      "        yS 3","        yR 3"
   };
   for(int k = 0; k < 7; k++)
     {
      if(ObjectFind(0, names[k]) < 0)
         ObjectCreate(0, names[k], OBJ_TEXT, 0, 0, 0);
      ObjectSetString(0,  names[k], OBJPROP_TEXT,     texts[k]);
      ObjectSetString(0,  names[k], OBJPROP_FONT,     "Arial");
      ObjectSetInteger(0, names[k], OBJPROP_FONTSIZE, fontsize);
      ObjectSetInteger(0, names[k], OBJPROP_COLOR,    clrRed);
     }

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   string names[] = {"YearlyPivot","YSup1","YRes1","YSup2","YRes2","YSup3","YRes3"};
   for(int k = 0; k < 7; k++)
      ObjectDelete(0, names[k]);
  }

//+------------------------------------------------------------------+
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 < 2) return(0);

   // In OnCalculate, index 0 = oldest bar, index rates_total-1 = newest bar
   // (ArraySetAsSeries is NOT called, so this is the default time-ascending order)

   int limit;
   if(prev_calculated <= 1)
     {
      // Full recalculation — reset everything and walk from the oldest bar
      limit = 0;
      P = S1 = R1 = S2 = R2 = S3 = R3 = 0.0;
      yearly_high  = high[0];
      yearly_low   = low[0];
      yearly_close = close[0];
     }
   else
     {
      // Incremental update — only process new bars
      limit = prev_calculated - 1;
     }

   for(int i = limit; i < rates_total - 1; i++)
     {
      MqlDateTime dt_cur, dt_prev;
      TimeToStruct(time[i],   dt_cur);
      TimeToStruct(time[i-1 >= 0 ? i-1 : 0], dt_prev);

      // Detect year boundary
      bool new_year = (i > 0) && (dt_cur.year != dt_prev.year);

      if(new_year)
        {
         // Previous bar was the last bar of the old year
         double prev_close = close[i-1];
         double prev_open  = open[i];           // first open of new year

         // Compute pivots from the completed year's H / L / C (+ new year open)
         P  = (yearly_high + yearly_low + prev_open + prev_close) / 4.0;
         R1 = (2.0 * P) - yearly_low;
         S1 = (2.0 * P) - yearly_high;
         R2 = P + (yearly_high - yearly_low);
         S2 = P - (yearly_high - yearly_low);
         R3 = (2.0 * P) + (yearly_high - (2.0 * yearly_low));
         S3 = (2.0 * P) - ((2.0 * yearly_high) - yearly_low);

         // Reset accumulators for the new year
         yearly_high  = high[i];
         yearly_low   = low[i];
         yearly_close = close[i];

         // Reposition text labels at the year boundary
         string names[]  = {"YearlyPivot","YSup1","YRes1","YSup2","YRes2","YSup3","YRes3"};
         double levels[] = {P, S1, R1, S2, R2, S3, R3};
         for(int k = 0; k < 7; k++)
            ObjectMove(0, names[k], 0, time[i], levels[k]);
        }
      else
        {
         // Still inside the same year — update rolling H/L/C
         if(high[i]  > yearly_high)  yearly_high  = high[i];
         if(low[i]   < yearly_low)   yearly_low   = low[i];
         yearly_close = close[i];
        }

      // Paint buffers (leave EMPTY_VALUE until the first pivot is calculated)
      if(P != 0.0)
        {
         PBuffer[i]  = P;
         S1Buffer[i] = S1;
         R1Buffer[i] = R1;
         S2Buffer[i] = S2;
         R2Buffer[i] = R2;
         S3Buffer[i] = S3;
         R3Buffer[i] = R3;
        }
     }

   // Paint the last (current, incomplete) bar with the running pivot
   int last = rates_total - 1;
   if(P != 0.0)
     {
      PBuffer[last]  = P;
      S1Buffer[last] = S1;
      R1Buffer[last] = R1;
      S2Buffer[last] = S2;
      R2Buffer[last] = R2;
      S3Buffer[last] = S3;
      R3Buffer[last] = R3;
     }

   return(rates_total);
  }
//+------------------------------------------------------------------+