//+------------------------------------------------------------------+
//|                  Gold Momentum Arrows Subwindow                  |
//+------------------------------------------------------------------+

#property indicator_separate_window
#property indicator_buffers 3
#property indicator_color1 clrGold
#property indicator_width1 1
#property indicator_color2 clrAqua     // Color for up arrows
#property indicator_color3 clrYellow    // Color for down arrows

#property indicator_maximum 1.5
#property indicator_minimum -1.5

#property indicator_level1 1
#property indicator_level2 -1

#property indicator_levelcolor clrLightGray
#property indicator_levelstyle STYLE_DOT

//--- input parameters
 int   MomentumPeriod   = 1;   // Lookback period for momentum
 int   VolatilityPeriod = 1;   // Lookback period for volatility (ATR)
 double WeightFactor    = 21.0; // Weighting factor for sensitivity

//--- indicator buffers
double XAU_Momentum_Buffer[];
double UpArrowBuffer[];
double DownArrowBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   // Indicator will be drawn in a separate window
   IndicatorBuffers(3);

   // Set up buffer 0 for XAU Momentum
   SetIndexStyle(0, DRAW_LINE);
   SetIndexBuffer(0, XAU_Momentum_Buffer);
   SetIndexLabel(0, "XAU Momentum");

   // Set up buffer 1 for Up Arrows (when price crosses below -1)
   SetIndexStyle(1, DRAW_ARROW);
   SetIndexArrow(1, 233);  // Up arrow
   SetIndexBuffer(1, UpArrowBuffer);
   SetIndexEmptyValue(1, EMPTY_VALUE);
   
   // Set up buffer 2 for Down Arrows (when price crosses above +1)
   SetIndexStyle(2, DRAW_ARROW);
   SetIndexArrow(2, 234);  // Down arrow
   SetIndexBuffer(2, DownArrowBuffer);
   SetIndexEmptyValue(2, EMPTY_VALUE);

   // Name and short description of indicator
   IndicatorShortName("xau");

   // Set timer to auto-refresh every 30 seconds
   EventSetTimer(30);

   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   // Kill the timer when the indicator is removed
   EventKillTimer();
}

//+------------------------------------------------------------------+
//| Timer event function                                             |
//+------------------------------------------------------------------+
void OnTimer()
{
   // Redraw the chart to force the indicator to refresh every 30 seconds
   ChartRedraw();
}

//+------------------------------------------------------------------+
//| 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[])
{
   // Ensure there are enough bars to calculate momentum and volatility
   if(rates_total < MomentumPeriod + VolatilityPeriod)
      return(0);

   int start;
   // If this is not the first call, re-calculate the last closed bar
   if(prev_calculated > 0)
      start = prev_calculated - 1;
   else
      start = MomentumPeriod;

   // Process closed bars (all bars except the current forming one)
   for(int i = start; i < rates_total - 1; i++)
   {
      // Calculate raw momentum as a percentage change over the MomentumPeriod.
      double rawMomentum = (close[i] - close[i - MomentumPeriod]) / close[i - MomentumPeriod] * 100.0;

      // Get volatility using ATR; if ATR is zero, use 1.0 to avoid division by zero.
      double volatility = iATR(NULL, 0, VolatilityPeriod, i);
      if(volatility == 0)
         volatility = 1.0;

      // Calculate the weighted momentum
      double weightedMomentum = (rawMomentum / volatility) * WeightFactor;

      // Assign the weighted momentum to the buffer
      XAU_Momentum_Buffer[i] = weightedMomentum;
      
      // Reset arrow buffers
      UpArrowBuffer[i] = EMPTY_VALUE;
      DownArrowBuffer[i] = EMPTY_VALUE;
      
      // Check for arrow conditions only on closed bars
      if(i > 0)
      {
         // Up arrow when crossing below -1 (from above)
         if (XAU_Momentum_Buffer[i-1] > -1 && XAU_Momentum_Buffer[i] <= -1)
         {
            UpArrowBuffer[i] = -1; // Position the arrow at -1 level
         }
         // Down arrow when crossing above +1 (from below)
         else if (XAU_Momentum_Buffer[i-1] < 1 && XAU_Momentum_Buffer[i] >= 1)
         {
            DownArrowBuffer[i] = 1; // Position the arrow at +1 level
         }
      }
   }

   // Process the current forming bar so that it updates live.
   // Use different variable names to avoid redeclaration errors.
   int currentBar = rates_total - 1;
   {
      double rawMomentum_curr = (close[currentBar] - close[currentBar - MomentumPeriod]) / close[currentBar - MomentumPeriod] * 100.0;
      double volatility_curr = iATR(NULL, 0, VolatilityPeriod, currentBar);
      if(volatility_curr == 0)
         volatility_curr = 1.0;
      double weightedMomentum_curr = (rawMomentum_curr / volatility_curr) * WeightFactor;
      XAU_Momentum_Buffer[currentBar] = weightedMomentum_curr;

      // For the forming bar, do not show arrows until it closes.
      UpArrowBuffer[currentBar]   = EMPTY_VALUE;
      DownArrowBuffer[currentBar] = EMPTY_VALUE;
   }

   // Return rates_total so the forming bar continues to update each tick
   return(rates_total);
}
