//+------------------------------------------------------------------+
//|                                       BB_Williams_Indicator.mq4  |
//|                  Bollinger Band Crossover with Williams %R Filter |
//|                              Arrow Signal Indicator               |
//+------------------------------------------------------------------+
#property copyright "BB Williams Strategy Indicator"
#property link      ""
#property version   "1.00"
#property strict

#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 Lime
#property indicator_color2 Red
#property indicator_width1 2
#property indicator_width2 2

//+------------------------------------------------------------------+
//| Input Parameters                                                  |
//+------------------------------------------------------------------+
// Bollinger Bands Settings (20 SMA = Middle BB line)
input int      BB_Period = 20;              // BB Period (SMA Period)
input double   BB_Deviation = 2.0;          // BB Deviation
input int      BB_Shift = 0;                // BB Shift

// Williams %R Settings
input int      WPR_Period = 14;             // Williams %R Period
input double   WPR_LongUpper = -40.0;       // Williams %R Long Upper Level (-40)
input double   WPR_LongLower = 0.0;         // Williams %R Long Lower Level (0)
input double   WPR_ShortUpper = -60.0;      // Williams %R Short Upper Level (-60)
input double   WPR_ShortLower = -100.0;     // Williams %R Short Lower Level (-100)

// Alert Settings
input bool     EnableAlerts = true;         // Enable Alerts
input bool     EnableSound = true;          // Enable Sound Alerts

//+------------------------------------------------------------------+
//| Buffers                                                           |
//+------------------------------------------------------------------+
double CrossUp[];
double CrossDown[];
datetime alertTag;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                          |
//+------------------------------------------------------------------+
int OnInit()
{
   // Arrow UP (Buy signal)
   SetIndexStyle(0, DRAW_ARROW, 0, 2);
   SetIndexArrow(0, 233);  // Up arrow
   SetIndexBuffer(0, CrossUp);
   SetIndexLabel(0, "Buy Signal");
   
   // Arrow DOWN (Sell signal)
   SetIndexStyle(1, DRAW_ARROW, 0, 2);
   SetIndexArrow(1, 234);  // Down arrow
   SetIndexBuffer(1, CrossDown);
   SetIndexLabel(1, "Sell Signal");
   
   IndicatorShortName("BB Williams Signal (" + IntegerToString(BB_Period) + ")");
   
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| 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[])
{
   int limit;
   int counted_bars = prev_calculated;
   
   if(counted_bars < 0) return(-1);
   if(counted_bars > 0) counted_bars--;
   
   limit = rates_total - counted_bars;
   
   // Calculate average range for arrow positioning
   for(int i = limit - 1; i >= 0; i--)
   {
      // Skip if not enough bars
      if(i + 2 >= rates_total) continue;
      
      // Calculate range for arrow offset
      double Range = 0;
      double AvgRange = 0;
      int counter;
      for(counter = i; counter <= i + 9 && counter < rates_total; counter++)
      {
         AvgRange += MathAbs(high[counter] - low[counter]);
      }
      Range = AvgRange / 10;
      
      // Get Bollinger Bands values
      double bbMiddle_i = iBands(NULL, 0, BB_Period, BB_Deviation, BB_Shift, PRICE_CLOSE, MODE_MAIN, i);
      double bbMiddle_i1 = iBands(NULL, 0, BB_Period, BB_Deviation, BB_Shift, PRICE_CLOSE, MODE_MAIN, i + 1);
      double bbUpper_i = iBands(NULL, 0, BB_Period, BB_Deviation, BB_Shift, PRICE_CLOSE, MODE_UPPER, i);
      double bbLower_i = iBands(NULL, 0, BB_Period, BB_Deviation, BB_Shift, PRICE_CLOSE, MODE_LOWER, i);
      
      // Get Williams %R value
      double wpr_i = iWPR(NULL, 0, WPR_Period, i);
      
      // Initialize buffers
      CrossUp[i] = EMPTY_VALUE;
      CrossDown[i] = EMPTY_VALUE;
      
      // BUY SIGNAL CONDITIONS:
      // 1. Price starts below MA of BB then crosses and closes above the MA
      // 2. Williams %R between -40% and 0
      // 3. High of candle should NOT be above upper BB (additional rule)
      bool longCrossover = (open[i + 1] < bbMiddle_i1 || close[i + 1] < bbMiddle_i1) && 
                           (close[i] > bbMiddle_i);
      bool wprLongOK = (wpr_i >= WPR_LongUpper && wpr_i <= WPR_LongLower);
      bool highNotAboveUpperBB = (high[i] <= bbUpper_i);
      
      if(longCrossover && wprLongOK && highNotAboveUpperBB)
      {
         CrossUp[i] = low[i] - Range * 0.5;
         
         // Alert on new signal (bar 0 only)
         if(i == 0 && alertTag != time[0])
         {
            if(EnableAlerts)
            {
               Alert(Symbol(), " M", Period(), " - BB Williams BUY Signal!");
            }
            if(EnableSound)
            {
               PlaySound("alert.wav");
            }
            alertTag = time[0];
         }
      }
      
      // SELL SIGNAL CONDITIONS:
      // 1. Price starts above MA of BB then crosses and closes below the MA
      // 2. Williams %R between -60% and -100%
      // 3. Low of candle should NOT be below lower BB (additional rule)
      bool shortCrossover = (open[i + 1] > bbMiddle_i1 || close[i + 1] > bbMiddle_i1) && 
                            (close[i] < bbMiddle_i);
      bool wprShortOK = (wpr_i >= WPR_ShortLower && wpr_i <= WPR_ShortUpper);
      bool lowNotBelowLowerBB = (low[i] >= bbLower_i);
      
      if(shortCrossover && wprShortOK && lowNotBelowLowerBB)
      {
         CrossDown[i] = high[i] + Range * 0.5;
         
         // Alert on new signal (bar 0 only)
         if(i == 0 && alertTag != time[0])
         {
            if(EnableAlerts)
            {
               Alert(Symbol(), " M", Period(), " - BB Williams SELL Signal!");
            }
            if(EnableSound)
            {
               PlaySound("alert.wav");
            }
            alertTag = time[0];
         }
      }
   }
   
   return(rates_total);
}
//+------------------------------------------------------------------+
