/*
███████╗ ██████╗ ██████╗ ███████╗██╗  ██╗     ███████╗████████╗ █████╗ ████████╗██╗ ██████╗ ███╗   ██╗
██╔════╝██╔═══██╗██╔══██╗██╔════╝╚██╗██╔╝     ██╔════╝╚══██╔══╝██╔══██╗╚══██╔══╝██║██╔═══██╗████╗  ██║
█████╗  ██║   ██║██████╔╝█████╗   ╚███╔╝█████╗███████╗   ██║   ███████║   ██║   ██║██║   ██║██╔██╗ ██║
██╔══╝  ██║   ██║██╔══██╗██╔══╝   ██╔██╗╚════╝╚════██║   ██║   ██╔══██║   ██║   ██║██║   ██║██║╚██╗██║
██║     ╚██████╔╝██║  ██║███████╗██╔╝ ██╗     ███████║   ██║   ██║  ██║   ██║   ██║╚██████╔╝██║ ╚████║
╚═╝      ╚═════╝ ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝     ╚══════╝   ╚═╝   ╚═╝  ╚═╝   ╚═╝   ╚═╝ ╚═════╝ ╚═╝  ╚═══╝
*/
//+------------------------------------------------------------------+
//|                                                       TMA+CG.mq4 |
//|                                                           mladen |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2025, Forex-Station"
#property link      "https://forex-station.com/post1295578535.html#p1295578535"
#property version   "1.01"

#property description "Centered TMA does not [REPAINT]. Repainting is a coding error"
#property description "Centered TMA recalculates - as any extrapolation using code does"
#property description "This indicator recalculates"
#property description "not for sale, auction, rent, nor lease"

#property indicator_chart_window
#property indicator_buffers 14

// TMA1 Upper/Lower bands (buffers 0-1)
#property indicator_color1  clrMaroon
#property indicator_color2  clrDarkBlue
#property indicator_width1  2
#property indicator_width2  2

// TMA2 Upper/Lower bands (buffers 2-3)
#property indicator_color3  clrMaroon
#property indicator_color4  clrDarkBlue
#property indicator_style3  STYLE_DOT
#property indicator_style4  STYLE_DOT

// TMA3 Upper/Lower bands (buffers 4-5)
#property indicator_color5  clrMaroon
#property indicator_color6  clrDarkBlue
#property indicator_style5  STYLE_DOT
#property indicator_style6  STYLE_DOT

// TMA4 Upper/Lower bands (buffers 6-7)
#property indicator_color7  clrMaroon
#property indicator_color8  clrDarkBlue
#property indicator_style7  STYLE_DOT
#property indicator_style8  STYLE_DOT

// TMA5 Upper/Lower bands (buffers 8-9)
#property indicator_color9  clrMaroon
#property indicator_color10 clrDarkBlue
#property indicator_style9  STYLE_DOT
#property indicator_style10 STYLE_DOT

// TMA6 Upper/Lower bands (buffers 10-11)
#property indicator_color11 clrCrimson
#property indicator_color12 clrDeepSkyBlue
#property indicator_width11 2
#property indicator_width12 2

// TMA7 Upper/Lower bands (buffers 12-13)
#property indicator_color13 clrBrown
#property indicator_color14 clrNavy
#property indicator_width13 5
#property indicator_width14 5

//+------------------------------------------------------------------+
//| Timeframe Enumeration for Dropdown Menu (with AHTF)              |
//+------------------------------------------------------------------+
enum enTimeFrames
{
   tf_cu  = PERIOD_CURRENT, // Current timeframe
   tf_m1  = PERIOD_M1,      // M1
   tf_m5  = PERIOD_M5,      // M5
   tf_m15 = PERIOD_M15,     // M15
   tf_m30 = PERIOD_M30,     // M30
   tf_h1  = PERIOD_H1,      // H1
   tf_h4  = PERIOD_H4,      // H4
   tf_d1  = PERIOD_D1,      // D1
   tf_w1  = PERIOD_W1,      // W1
   tf_mn1 = PERIOD_MN1,     // MN
   tf_n1  = -1,             // First higher TF
   tf_n2  = -2,             // Second higher TF
   tf_n3  = -3              // Third higher TF
};

extern enTimeFrames          TimeFrame                    = tf_m30;  // Timeframe
extern int                   HalfLength                   = 34;
extern ENUM_APPLIED_PRICE    Price                        = PRICE_WEIGHTED;
extern double                BandsDeviations              = 2.0;
extern int                   Skipping_Every_Other_TMA     = 4;

//Forex-Station button template start41
extern string             button_note1_         = "------------------------------";
extern int                btn_Subwindow         = 0;
extern ENUM_BASE_CORNER   btn_corner            = CORNER_LEFT_UPPER;
extern string             btn_text              = "TMA";
extern string             btn_Font              = "Arial";
extern int                btn_FontSize          = 9;
extern color              btn_text_ON_color     = clrLime;
extern color              btn_text_OFF_color    = clrRed;
extern color              btn_background_color  = clrDimGray;
extern color              btn_border_color      = clrBlack;
extern int                button_x              = 20;
extern int                button_y              = 195;
extern int                btn_Width             = 80;
extern int                btn_Height            = 20;
extern string             UniqueButtonID        = "TMAM30";
extern string             button_note2          = "------------------------------";
extern bool               Interpolate           = true;

bool show_data, recalc=false;
string IndicatorObjPrefix, buttonId;

// Main display buffers (21 total)
double tmBuffer1[], upBuffer1[], dnBuffer1[];
double tmBuffer2[], upBuffer2[], dnBuffer2[];
double tmBuffer3[], upBuffer3[], dnBuffer3[];
double tmBuffer4[], upBuffer4[], dnBuffer4[];
double tmBuffer5[], upBuffer5[], dnBuffer5[];
double tmBuffer6[], upBuffer6[], dnBuffer6[];
double tmBuffer7[], upBuffer7[], dnBuffer7[];

// Working buffers for bands calculation (14 total)
double wuBuffer1[], wdBuffer1[];
double wuBuffer2[], wdBuffer2[];
double wuBuffer3[], wdBuffer3[];
double wuBuffer4[], wdBuffer4[];
double wuBuffer5[], wdBuffer5[];
double wuBuffer6[], wdBuffer6[];
double wuBuffer7[], wdBuffer7[];

int timeFrame;
//+------------------------------------------------------------------------------------------------------------------+
int OnInit()
{
   IndicatorDigits(Digits);
   IndicatorObjPrefix = "__" + btn_text + "__";
   
   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);

   // Initialize timeframe using AHTF resolution
   timeFrame = timeFrameValue((int)TimeFrame);
   
   HalfLength = MathMax(HalfLength, 1);
   
   IndicatorBuffers(37);
   
   // ========== VISIBLE BUFFERS (0-15) ==========
   
   // TMA1 Upper/Lower bands (buffers 0-1)
   SetIndexBuffer(0, upBuffer1);  SetIndexDrawBegin(0, HalfLength);
   SetIndexLabel(0, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength) + ") upper band");
   
   SetIndexBuffer(1, dnBuffer1);  SetIndexDrawBegin(1, HalfLength);
   SetIndexLabel(1, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength) + ") lower band");
   
   // TMA2 Upper/Lower bands (buffers 2-3)
   SetIndexBuffer(2, upBuffer2);  SetIndexDrawBegin(2, HalfLength + Skipping_Every_Other_TMA);
   SetIndexLabel(2, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength + Skipping_Every_Other_TMA) + ") upper band");
   
   SetIndexBuffer(3, dnBuffer2);  SetIndexDrawBegin(3, HalfLength + Skipping_Every_Other_TMA);
   SetIndexLabel(3, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength + Skipping_Every_Other_TMA) + ") lower band");
   
   // TMA3 Upper/Lower bands (buffers 4-5)
   SetIndexBuffer(4, upBuffer3);  SetIndexDrawBegin(4, HalfLength + Skipping_Every_Other_TMA*2);
   SetIndexLabel(4, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength + Skipping_Every_Other_TMA*2) + ") upper band");
   
   SetIndexBuffer(5, dnBuffer3);  SetIndexDrawBegin(5, HalfLength + Skipping_Every_Other_TMA*2);
   SetIndexLabel(5, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength + Skipping_Every_Other_TMA*2) + ") lower band");
   
   // TMA4 Upper/Lower bands (buffers 6-7)
   SetIndexBuffer(6, upBuffer4);  SetIndexDrawBegin(6, HalfLength + Skipping_Every_Other_TMA*3);
   SetIndexLabel(6, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength + Skipping_Every_Other_TMA*3) + ") upper band");
   
   SetIndexBuffer(7, dnBuffer4);  SetIndexDrawBegin(7, HalfLength + Skipping_Every_Other_TMA*3);
   SetIndexLabel(7, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength + Skipping_Every_Other_TMA*3) + ") lower band");
   
   // TMA5 Upper/Lower bands (buffers 8-9)
   SetIndexBuffer(8, upBuffer5);  SetIndexDrawBegin(8, HalfLength + Skipping_Every_Other_TMA*4);
   SetIndexLabel(8, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength + Skipping_Every_Other_TMA*4) + ") upper band");
   
   SetIndexBuffer(9, dnBuffer5);  SetIndexDrawBegin(9, HalfLength + Skipping_Every_Other_TMA*4);
   SetIndexLabel(9, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength + Skipping_Every_Other_TMA*4) + ") lower band");
   
   // TMA6 Upper/Lower bands (buffers 10-11)
   SetIndexBuffer(10, upBuffer6); SetIndexDrawBegin(10, HalfLength + Skipping_Every_Other_TMA*5);
   SetIndexLabel(10, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength + Skipping_Every_Other_TMA*5) + ") upper band");
   
   SetIndexBuffer(11, dnBuffer6); SetIndexDrawBegin(11, HalfLength + Skipping_Every_Other_TMA*5);
   SetIndexLabel(11, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength + Skipping_Every_Other_TMA*5) + ") lower band");
   
   // TMA7 Upper/Lower bands (buffers 12-13)
   SetIndexBuffer(12, upBuffer7); SetIndexDrawBegin(12, HalfLength + Skipping_Every_Other_TMA*6);
   SetIndexLabel(12, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength + Skipping_Every_Other_TMA*6) + ") upper band");
   
   SetIndexBuffer(13, dnBuffer7); SetIndexDrawBegin(13, HalfLength + Skipping_Every_Other_TMA*6);
   SetIndexLabel(13, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength + Skipping_Every_Other_TMA*6) + ") lower band");
   
   // ========== HIDDEN TMA CENTER LINES (16-22) ==========
   
   SetIndexBuffer(16, tmBuffer1); SetIndexDrawBegin(16, HalfLength);
   SetIndexLabel(16, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength) + ")");
   
   SetIndexBuffer(17, tmBuffer2); SetIndexDrawBegin(17, HalfLength + Skipping_Every_Other_TMA);
   SetIndexLabel(17, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength + Skipping_Every_Other_TMA) + ")");
   
   SetIndexBuffer(18, tmBuffer3); SetIndexDrawBegin(18, HalfLength + Skipping_Every_Other_TMA*2);
   SetIndexLabel(18, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength + Skipping_Every_Other_TMA*2) + ")");
   
   SetIndexBuffer(19, tmBuffer4); SetIndexDrawBegin(19, HalfLength + Skipping_Every_Other_TMA*3);
   SetIndexLabel(19, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength + Skipping_Every_Other_TMA*3) + ")");
   
   SetIndexBuffer(20, tmBuffer5); SetIndexDrawBegin(20, HalfLength + Skipping_Every_Other_TMA*4);
   SetIndexLabel(20, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength + Skipping_Every_Other_TMA*4) + ")");
   
   SetIndexBuffer(21, tmBuffer6); SetIndexDrawBegin(21, HalfLength + Skipping_Every_Other_TMA*5);
   SetIndexLabel(21, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength + Skipping_Every_Other_TMA*5) + ")");
   
   SetIndexBuffer(22, tmBuffer7); SetIndexDrawBegin(22, HalfLength + Skipping_Every_Other_TMA*6);
   SetIndexLabel(22, timeFrameToString(timeFrame) + " TMA (" + IntegerToString(HalfLength + Skipping_Every_Other_TMA*6) + ")");
   
   // ========== WORKING BUFFERS (23-36, not displayed) ==========
   SetIndexBuffer(23, wuBuffer1);
   SetIndexBuffer(24, wdBuffer1);
   SetIndexBuffer(25, wuBuffer2);
   SetIndexBuffer(26, wdBuffer2);
   SetIndexBuffer(27, wuBuffer3);
   SetIndexBuffer(28, wdBuffer3);
   SetIndexBuffer(29, wuBuffer4);
   SetIndexBuffer(30, wdBuffer4);
   SetIndexBuffer(31, wuBuffer5);
   SetIndexBuffer(32, wdBuffer5);
   SetIndexBuffer(33, wuBuffer6);
   SetIndexBuffer(34, wdBuffer6);
   SetIndexBuffer(35, wuBuffer7);
   SetIndexBuffer(36, wdBuffer7);

   show_data = ObjectGetInteger(0, buttonId, OBJPROP_STATE);
   
   if (show_data) ObjectSetInteger(0, buttonId, OBJPROP_COLOR, btn_text_ON_color); 
   else ObjectSetInteger(0, buttonId, OBJPROP_COLOR, btn_text_OFF_color);
   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, 0);
   ObjectSetInteger(0, buttonID, OBJPROP_CORNER, btn_corner);
   ObjectSetInteger(0, buttonID, OBJPROP_HIDDEN, 1);
   ObjectSetInteger(0, buttonID, OBJPROP_XDISTANCE, 9999);
   ObjectSetInteger(0, buttonID, OBJPROP_YDISTANCE, 9999);
   ObjectSetInteger(0, buttonId, OBJPROP_STATE, true);
}
//+------------------------------------------------------------------------------------------------------------------+
void OnDeinit(const int reason) 
{
   if(reason != REASON_CHARTCHANGE) ObjectDelete(buttonId);
}
//+------------------------------------------------------------------------------------------------------------------+
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;

   if (id == CHARTEVENT_OBJECT_CLICK && sparam == buttonId)
   {
      show_data = ObjectGetInteger(0, buttonId, OBJPROP_STATE);
      int idx;
      
      if (show_data)
      {
         ObjectSetInteger(0, buttonId, OBJPROP_COLOR, btn_text_ON_color); 
         for (idx = 0; idx < indicator_buffers; idx++)
            SetIndexStyle(idx, DRAW_LINE);
         recalc = true;
         start();
      }
      else
      {
         ObjectSetInteger(0, buttonId, OBJPROP_COLOR, btn_text_OFF_color);
         for (idx = 0; idx < indicator_buffers; idx++)
            SetIndexStyle(idx, DRAW_NONE);
      }
   }
}
//+------------------------------------------------------------------------------------------------------------------+
// Global cache for HTF price data
double htfPriceCache[];
int    htfPriceCacheSize = 0;

//+------------------------------------------------------------------------------------------------------------------+
int start()
{
   if (!show_data) return(0);
   
   int counted_bars = IndicatorCounted();
   if (recalc) 
   {
      counted_bars = 0;
      recalc = false;
   }
   
   if (counted_bars < 0) return(-1);
   if (counted_bars > 0) counted_bars--;
   
   // Get HTF bar count
   int htfBars = iBars(NULL, timeFrame);
   if (htfBars <= 0) return(0);
   
   // Limit calculation for efficiency
   int maxHalfLen = HalfLength + Skipping_Every_Other_TMA * 6;
   int limit = MathMin(Bars - 1, Bars - counted_bars + maxHalfLen + 10);
   
   // For efficiency, only recalculate recent bars after initial calculation
   if (counted_bars > 0 && limit < Bars - 50) 
      limit = maxHalfLen + 20;
   
   // Pre-cache HTF price data to avoid repeated iHigh/iLow/iClose/iOpen calls
   int cacheNeeded = MathMin(htfBars, limit / MathMax(1, timeFrame / Period()) + maxHalfLen + 50);
   if (cacheNeeded > htfPriceCacheSize)
   {
      ArrayResize(htfPriceCache, cacheNeeded);
      htfPriceCacheSize = cacheNeeded;
   }
   
   // Fill the cache with HTF price data
   for (int c = 0; c < cacheNeeded && c < htfBars; c++)
   {
      double h = iHigh(NULL, timeFrame, c);
      double l = iLow(NULL, timeFrame, c);
      double cc = iClose(NULL, timeFrame, c);
      
      // Calculate weighted price (most common)
      if (Price == PRICE_WEIGHTED)
         htfPriceCache[c] = (h + l + cc + cc) / 4.0;
      else if (Price == PRICE_TYPICAL)
         htfPriceCache[c] = (h + l + cc) / 3.0;
      else if (Price == PRICE_MEDIAN)
         htfPriceCache[c] = (h + l) / 2.0;
      else if (Price == PRICE_CLOSE)
         htfPriceCache[c] = cc;
      else if (Price == PRICE_HIGH)
         htfPriceCache[c] = h;
      else if (Price == PRICE_LOW)
         htfPriceCache[c] = l;
      else if (Price == PRICE_OPEN)
         htfPriceCache[c] = iOpen(NULL, timeFrame, c);
      else
         htfPriceCache[c] = cc;
   }
   
   // Calculate all 7 TMAs
   int halfLen1 = HalfLength;
   int halfLen2 = HalfLength + Skipping_Every_Other_TMA;
   int halfLen3 = HalfLength + Skipping_Every_Other_TMA * 2;
   int halfLen4 = HalfLength + Skipping_Every_Other_TMA * 3;
   int halfLen5 = HalfLength + Skipping_Every_Other_TMA * 4;
   int halfLen6 = HalfLength + Skipping_Every_Other_TMA * 5;
   int halfLen7 = HalfLength + Skipping_Every_Other_TMA * 5; // Same as 6
   
   double fullLen1 = 2.0 * halfLen1 + 1.0;
   double fullLen2 = 2.0 * halfLen2 + 1.0;
   double fullLen3 = 2.0 * halfLen3 + 1.0;
   double fullLen4 = 2.0 * halfLen4 + 1.0;
   double fullLen5 = 2.0 * halfLen5 + 1.0;
   double fullLen6 = 2.0 * halfLen6 + 1.0;
   double fullLen7 = 2.0 * halfLen7 + 1.0;
   
   double bandsDev7 = BandsDeviations + 1.0; // TMA7 uses different deviation
   
   int i, n, k;
   
   for (i = limit; i >= 0; i--)
   {
      // Map chart bar to HTF bar
      int y = (timeFrame == Period()) ? i : iBarShift(NULL, timeFrame, Time[i]);
      if (y < 0 || y >= cacheNeeded) continue;
      
      // Calculate TMA1
      if (y < cacheNeeded - halfLen1)
         calculateTmaBarCached(i, y, halfLen1, fullLen1, BandsDeviations,
                         tmBuffer1, upBuffer1, dnBuffer1, wuBuffer1, wdBuffer1, cacheNeeded);
      
      // Calculate TMA2
      if (y < cacheNeeded - halfLen2)
         calculateTmaBarCached(i, y, halfLen2, fullLen2, BandsDeviations,
                         tmBuffer2, upBuffer2, dnBuffer2, wuBuffer2, wdBuffer2, cacheNeeded);
      
      // Calculate TMA3
      if (y < cacheNeeded - halfLen3)
         calculateTmaBarCached(i, y, halfLen3, fullLen3, BandsDeviations,
                         tmBuffer3, upBuffer3, dnBuffer3, wuBuffer3, wdBuffer3, cacheNeeded);
      
      // Calculate TMA4
      if (y < cacheNeeded - halfLen4)
         calculateTmaBarCached(i, y, halfLen4, fullLen4, BandsDeviations,
                         tmBuffer4, upBuffer4, dnBuffer4, wuBuffer4, wdBuffer4, cacheNeeded);
      
      // Calculate TMA5
      if (y < cacheNeeded - halfLen5)
         calculateTmaBarCached(i, y, halfLen5, fullLen5, BandsDeviations,
                         tmBuffer5, upBuffer5, dnBuffer5, wuBuffer5, wdBuffer5, cacheNeeded);
      
      // Calculate TMA6
      if (y < cacheNeeded - halfLen6)
         calculateTmaBarCached(i, y, halfLen6, fullLen6, BandsDeviations,
                         tmBuffer6, upBuffer6, dnBuffer6, wuBuffer6, wdBuffer6, cacheNeeded);
      
      // Calculate TMA7 (with different deviation)
      if (y < cacheNeeded - halfLen7)
         calculateTmaBarCached(i, y, halfLen7, fullLen7, bandsDev7,
                         tmBuffer7, upBuffer7, dnBuffer7, wuBuffer7, wdBuffer7, cacheNeeded);
   }
   
   // Interpolation for MTF display
   if (Interpolate && timeFrame > Period())
   {
      for (i = limit; i >= 0; i--)
      {
         int shift1 = iBarShift(NULL, timeFrame, Time[i]);
         datetime time1 = iTime(NULL, timeFrame, shift1);
         
         if (i > 0 && shift1 == iBarShift(NULL, timeFrame, Time[i-1])) continue;
         
         for (n = 1; i + n < Bars && Time[i + n] >= time1; n++) continue;
         
         if (n <= 1) continue;
         
         double factor = 1.0 / n;
         for (k = 1; k < n; k++)
         {
            double kf = k * factor;
            double kf1 = 1.0 - kf;
            
            tmBuffer1[i+k] = kf * tmBuffer1[i+n] + kf1 * tmBuffer1[i];
            upBuffer1[i+k] = kf * upBuffer1[i+n] + kf1 * upBuffer1[i];
            dnBuffer1[i+k] = kf * dnBuffer1[i+n] + kf1 * dnBuffer1[i];
            
            tmBuffer2[i+k] = kf * tmBuffer2[i+n] + kf1 * tmBuffer2[i];
            upBuffer2[i+k] = kf * upBuffer2[i+n] + kf1 * upBuffer2[i];
            dnBuffer2[i+k] = kf * dnBuffer2[i+n] + kf1 * dnBuffer2[i];
            
            tmBuffer3[i+k] = kf * tmBuffer3[i+n] + kf1 * tmBuffer3[i];
            upBuffer3[i+k] = kf * upBuffer3[i+n] + kf1 * upBuffer3[i];
            dnBuffer3[i+k] = kf * dnBuffer3[i+n] + kf1 * dnBuffer3[i];
            
            tmBuffer4[i+k] = kf * tmBuffer4[i+n] + kf1 * tmBuffer4[i];
            upBuffer4[i+k] = kf * upBuffer4[i+n] + kf1 * upBuffer4[i];
            dnBuffer4[i+k] = kf * dnBuffer4[i+n] + kf1 * dnBuffer4[i];
            
            tmBuffer5[i+k] = kf * tmBuffer5[i+n] + kf1 * tmBuffer5[i];
            upBuffer5[i+k] = kf * upBuffer5[i+n] + kf1 * upBuffer5[i];
            dnBuffer5[i+k] = kf * dnBuffer5[i+n] + kf1 * dnBuffer5[i];
            
            tmBuffer6[i+k] = kf * tmBuffer6[i+n] + kf1 * tmBuffer6[i];
            upBuffer6[i+k] = kf * upBuffer6[i+n] + kf1 * upBuffer6[i];
            dnBuffer6[i+k] = kf * dnBuffer6[i+n] + kf1 * dnBuffer6[i];
            
            tmBuffer7[i+k] = kf * tmBuffer7[i+n] + kf1 * tmBuffer7[i];
            upBuffer7[i+k] = kf * upBuffer7[i+n] + kf1 * upBuffer7[i];
            dnBuffer7[i+k] = kf * dnBuffer7[i+n] + kf1 * dnBuffer7[i];
         }
      }
   }
   
   return(0);
}
//+------------------------------------------------------------------------------------------------------------------+
// Unified TMA calculation for a single bar - uses cached HTF price data
// i = chart bar index, y = HTF bar index
void calculateTmaBarCached(int i, int y, int halfLen, double fullLen, double bandsDev,
                     double &tmBuf[], double &upBuf[], double &dnBuf[], double &wuBuf[], double &wdBuf[], int cacheSize)
{
   // Calculate TMA value using triangular weighted average from cached data
   double sum = (halfLen + 1) * htfPriceCache[y];
   double sumw = halfLen + 1;
   
   for (int j = 1, kk = halfLen; j <= halfLen; j++, kk--)
   {
      // Look forward in time (older bars) - always valid if y + j < cacheSize
      if (y + j < cacheSize)
      {
         sum += kk * htfPriceCache[y + j];
         sumw += kk;
      }
      
      // Look backward in time (newer bars) - only if y - j >= 0
      if (y - j >= 0)
      {
         sum += kk * htfPriceCache[y - j];
         sumw += kk;
      }
   }
   
   tmBuf[i] = sum / sumw;
   
   // Calculate bands
   double diff = htfPriceCache[y] - tmBuf[i];
   
   if (y >= cacheSize - halfLen - 1) return;
   
   if (y == cacheSize - halfLen - 1 || i >= Bars - 1)
   {
      upBuf[i] = tmBuf[i];
      dnBuf[i] = tmBuf[i];
      if (diff >= 0)
      {
         wuBuf[i] = MathPow(diff, 2);
         wdBuf[i] = 0;
      }
      else
      {
         wdBuf[i] = MathPow(diff, 2);
         wuBuf[i] = 0;
      }
      return;
   }
   
   // For bands, we need to check if previous buffer value exists
   if (i + 1 >= Bars || wuBuf[i+1] == 0)
   {
      upBuf[i] = tmBuf[i];
      dnBuf[i] = tmBuf[i];
      wuBuf[i] = (diff >= 0) ? MathPow(diff, 2) : 0;
      wdBuf[i] = (diff < 0) ? MathPow(diff, 2) : 0;
      return;
   }
   
   // EMA-style running calculation for bands
   if (diff >= 0)
   {
      wuBuf[i] = (wuBuf[i+1] * (fullLen - 1) + MathPow(diff, 2)) / fullLen;
      wdBuf[i] = wdBuf[i+1] * (fullLen - 1) / fullLen;
   }
   else
   {
      wdBuf[i] = (wdBuf[i+1] * (fullLen - 1) + MathPow(diff, 2)) / fullLen;
      wuBuf[i] = wuBuf[i+1] * (fullLen - 1) / fullLen;
   }
   
   upBuf[i] = tmBuf[i] + bandsDev * MathSqrt(wuBuf[i]);
   dnBuf[i] = tmBuf[i] - bandsDev * MathSqrt(wdBuf[i]);
}
//+------------------------------------------------------------------------------------------------------------------+
string sTfTable[] = {"M1", "M5", "M15", "M30", "H1", "H4", "D1", "W1", "MN"};
int iTfTable[] = {1, 5, 15, 30, 60, 240, 1440, 10080, 43200};

string timeFrameToString(int tf)
{
   for (int i = ArraySize(iTfTable) - 1; i >= 0; i--) 
      if (tf == iTfTable[i]) return(sTfTable[i]);
   return("");
}
//+------------------------------------------------------------------------------------------------------------------+
// AHTF: Resolve timeframe including negative values for "next higher TF"
int timeFrameValue(int _tf)
{
   // Handle negative values (AHTF: -1 = 1st higher, -2 = 2nd higher, etc.)
   int add = (_tf >= 0) ? 0 : MathAbs(_tf);
   if (add != 0) _tf = Period();  // Start from current chart period
   
   // Find current TF index in table
   int size = ArraySize(iTfTable);
   int i = 0;
   for (; i < size; i++)
      if (iTfTable[i] == _tf) break;
   
   // If not found, use current period
   if (i == size)
   {
      _tf = Period();
      for (i = 0; i < size; i++)
         if (iTfTable[i] == _tf) break;
   }
   
   // Add offset for AHTF and clamp to max
   int resultIdx = MathMin(i + add, size - 1);
   int result = iTfTable[resultIdx];
   
   // Don't allow lower TF than chart
   if (result < Period()) result = Period();
   
   return result;
}
//+------------------------------------------------------------------------------------------------------------------+
