//+------------------------------------------------------------------+
//|                                        dynamic zone smoothed rsi |
//|                                                           mladen |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

//Modified, 6/sep/2025, by jeanlouie, www.forexfactory.com/jeanlouie
// - optional chart arrows on main line crossing bands

//Modified to add arrow buffers in sub-window

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

#property indicator_separate_window
#property indicator_buffers 6
#property indicator_color1  DeepSkyBlue
#property indicator_color2  LimeGreen
#property indicator_color3  Red
#property indicator_color4  DimGray
#property indicator_color5  clrLime
#property indicator_color6  clrRed
#property indicator_width1  2
#property indicator_width5  2
#property indicator_width6  2
#property indicator_style4  STYLE_DOT

//
//
//
//
//

extern int    CciLength              = 50;
extern ENUM_APPLIED_PRICE CciPrice   = PRICE_TYPICAL;
extern int    CciSmooth              = 3;
extern int    DzLookBackBars         = 70;
extern double DzStartBuyProbability  = 0.16;
extern double DzStartSellProbability = 0.16;
extern bool   ShowArrows             = true;
extern int    ArrowSize              = 3;
extern double ArrowGap               = 0.5;
extern color  arrowsUpColor          = clrLime;
extern color  arrowsDnColor          = clrRed;
extern bool   ShowSubWindowArrows    = true;
extern int    SubWindowArrowUpCode   = 233;  // Arrow symbol code for buy signals
extern int    SubWindowArrowDnCode   = 234;  // Arrow symbol code for sell signals
extern int    SubWindowArrowSize     = 2;

//
//
//
//
//

double cci[];
double ccs[];
double ccw[];
double cen[];
double bli[];
double sli[];
double arrowUp[];
double arrowDn[];
double alpha;
string ind_name;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int init()
{
   IndicatorBuffers(8);
   SetIndexBuffer(0,ccs);
   SetIndexBuffer(1,bli);
   SetIndexBuffer(2,sli);
   SetIndexBuffer(3,cen);
   SetIndexBuffer(4,arrowUp);
   SetIndexBuffer(5,arrowDn);
   SetIndexBuffer(6,cci);
   SetIndexBuffer(7,ccw);

   //
   // Set arrow buffer properties
   //
   
   SetIndexStyle(4,DRAW_ARROW,EMPTY,SubWindowArrowSize);
   SetIndexArrow(4,SubWindowArrowUpCode);
   SetIndexLabel(4,"Buy Signal");
   
   SetIndexStyle(5,DRAW_ARROW,EMPTY,SubWindowArrowSize);
   SetIndexArrow(5,SubWindowArrowDnCode);
   SetIndexLabel(5,"Sell Signal");

   //
   //
   //
   //
   //
   
   string PriceType;
      switch(CciPrice)
      {
         case PRICE_CLOSE:    PriceType = "Close";    break;  // 0
         case PRICE_OPEN:     PriceType = "Open";     break;  // 1
         case PRICE_HIGH:     PriceType = "High";     break;  // 2
         case PRICE_LOW:      PriceType = "Low";      break;  // 3
         case PRICE_MEDIAN:   PriceType = "Median";   break;  // 4
         case PRICE_TYPICAL:  PriceType = "Typical";  break;  // 5
         case PRICE_WEIGHTED: PriceType = "Weighted"; break;  // 6
      }      

   //
   //
   //
   //
   //

   CciLength = MathMax(CciLength ,1);
       alpha = 2.0 /(1.0+MathSqrt(CciSmooth));
   
   ind_name = "Dynamic zone CCI ("+CciLength+","+PriceType+","+DzLookBackBars+","+DoubleToStr(DzStartBuyProbability,3)+","+DoubleToStr(DzStartSellProbability,3)+")";
   IndicatorShortName (ind_name);
   
   return(0);
}
int deinit()
{
   ObjectsDeleteAll(0,ind_name,0,OBJ_ARROW);
   return(0);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int start()
{
   int counted_bars=IndicatorCounted();
   int i,limit;

   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
         limit = MathMin(Bars-counted_bars,Bars-1);

   //
   //
   //
   //
   //
   //

   for(i=limit; i >= 0; i--)
   {
      cci[i] = iCCI(NULL,0,CciLength,CciPrice,i);
         if (i==Bars-1)
         {
            ccw[i] = cci[i];
            ccs[i] = cci[i];
            arrowUp[i] = EMPTY_VALUE;
            arrowDn[i] = EMPTY_VALUE;
            continue;
         }
      
      //
      //
      //
      //
      //
      
      if (CciSmooth>1)
      {
            ccw[i] = ccw[i+1]+alpha*(cci[i]-ccw[i+1]);
            ccs[i] = ccs[i+1]+alpha*(ccw[i]-ccs[i+1]);
      }
      else  ccs[i] = cci[i];         
      bli[i] = dzBuy (i, ccs, DzStartBuyProbability,  DzLookBackBars);
      sli[i] = dzSell(i, ccs, DzStartSellProbability, DzLookBackBars);
      cen[i] = dzSell(i, ccs, 0.5,                    DzLookBackBars);
      
      //
      // Initialize arrow buffers
      //
      
      arrowUp[i] = EMPTY_VALUE;
      arrowDn[i] = EMPTY_VALUE;
      
      //
      // Check for signal crossings
      //
      
      if(i<Bars-1){
         long t = Time[i];
         double gap = iATR(_Symbol,_Period,14,i)*ArrowGap;
         string name = "";
         bool buySignal = false;
         bool sellSignal = false;
         
         // Buy signal: CCI crosses above buy line
         if(bli[i+1]>ccs[i+1] && ccs[i]>bli[i]){
            buySignal = true;
            
            // Chart arrows
            if(ShowArrows){
               name = ind_name+"_buy_"+string(datetime(t));
               obj_arrow(name,t,Low[i]-gap,ANCHOR_TOP,233,arrowsUpColor);
            }
            
            // Sub-window arrows
            if(ShowSubWindowArrows){
               arrowUp[i] = bli[i];
            }
         }
         else if(ShowArrows){
            name = ind_name+"_buy_"+string(datetime(t));
            if(ObjectFind(0,name)==0)ObjectDelete(0,name);
         }
         
         // Sell signal: CCI crosses below sell line
         if(sli[i+1]<ccs[i+1] && ccs[i]<sli[i]){
            sellSignal = true;
            
            // Chart arrows
            if(ShowArrows){
               name = ind_name+"_sel_"+string(datetime(t));
               obj_arrow(name,t,High[i]+gap,ANCHOR_BOTTOM,234,arrowsDnColor);
            }
            
            // Sub-window arrows
            if(ShowSubWindowArrows){
               arrowDn[i] = sli[i];
            }
         }
         else if(ShowArrows){
            name = ind_name+"_sel_"+string(datetime(t));
            if(ObjectFind(0,name)==0)ObjectDelete(0,name);
         }
      }
      
   }
   return(0);
}



//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

double dzBuy(int i, double& array[], double initValue, int lookBackBars)
{
   double left  = -10000;
   double right =  10000;
   
   if ((Bars-i)<lookBackBars) return(EMPTY_VALUE);
   
   //
   //
   //
   //
   //

   double eps      = 0.001;
   double yval     = (left+right)/2.0;
	double delta    = yval-left;
	int    maxSteps = 0;
	
		while (delta>0.005 && maxSteps<50)
		{
			maxSteps++;
   	      double count = 0;
			   for (int k=0; k<lookBackBars;k++) if (array[i+k]<yval) count++;
	
				double prob = count/lookBackBars;
               if (prob<(initValue-eps))
               {
                  left = yval;
                  yval = (yval+right)/2.0;
               }
               else
               {
                  right = yval;
                  yval  = (yval+left)/2.0;
               }
               delta=yval-left;
      }               
      return(yval);   
}

//
//
//
//
//

double dzSell(int i, double& array[], double initValue, int lookBackBars)
{
   double left  = -10000;
   double right =  10000;
   
   if ((Bars-i)<lookBackBars) return(EMPTY_VALUE);
   
   //
   //
   //
   //
   //

   double eps      = 0.001;
   double yval     = (left+right)/2.0;
	double delta    = yval-left;
	int    maxSteps = 0;
	
		while (delta>0.005 && maxSteps<50)
		{
			maxSteps++;
   	      double count = 0;
			   for (int k=0; k<lookBackBars;k++) if (array[i+k]>yval) count++;
	
				double prob = count/lookBackBars;
               if (prob<(initValue-eps))
               {
                  right = yval;
                  yval  = (yval+left)/2.0;
               }
               else
               {
                  left = yval;
                  yval = (yval+right)/2.0;
               }
               delta=yval-left;
      }               
      return(yval);   
}

//
//
//
//
//

void obj_arrow(string name, long t, double p, ENUM_ARROW_ANCHOR anc, uchar code, color clr)
{
   if(ObjectFind(0,name)!=0)ObjectCreate(name,OBJ_ARROW,0,t,p);
   ObjectSetInteger(0,name,OBJPROP_ANCHOR,anc);
   ObjectSetInteger(0,name,OBJPROP_ARROWCODE,code);
   ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
   ObjectSetInteger(0,name,OBJPROP_WIDTH,ArrowSize);
}