Need help creating custom deviation indicator

 

Hello everybody,

After some time learning how to code EAs, I am giving a first try at indicators : I'd like to create a custom indicator that shows :

New deviation = Standard deviation + Highest standard deviation - Lowest standard deviation

(Highest deviation and Lowest deviation should be calulated on the same number of bars as the standard deviation).


I tried to modify the default StdDev indicator, added 3 buffers for ExtNewDevBuffer, ExtHHBuffer, andExtLLBuffer,

but I have trouble calculating the Highest and Lowest values of the standard deviation, and including them in the indicator formula.

Any help would be highly appreciated. Indicators architecture is giving me a hard time.

Here's what I have so far :


#include <MovingAverages.mqh>

#property indicator_separate_window
#property indicator_buffers 5 
#property indicator_plots   1
#property indicator_type1   DRAW_LINE
#property indicator_color1  MediumSeaGreen
#property indicator_style1  STYLE_SOLID

//--- input parameters
input int            InpPeriod=20;   // Period
input int            InpShift=0;     // Shift

//--- indicator buffers
double ExtNewDevBuffer[];
double ExtMABuffer[];
double ExtStdDevBuffer[];
double ExtHHBuffer[];
double ExtLLBuffer[];

int    ExtPeriod,ExtShift;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit()
  {
//--- check for input values
   if(InpPeriod<=1)
     {
      ExtPeriod=20;
      PrintFormat("Incorrect value for input variable InpPeriod=%d. Indicator will use value %d for calculations.",
                   InpPeriod,ExtPeriod);
     }
   else
      ExtPeriod=InpPeriod;
   if(InpShift<0)
     {
      ExtShift=0;
      PrintFormat("Incorrect value for input variable InpShift=%d. Indicator will use value %d for calculations.",
                  InpShift,ExtShift);
     }
   else
      ExtShift=InpShift;
//--- define indicator buffers as indexes
   SetIndexBuffer(0,ExtNewDevBuffer);
   SetIndexBuffer(1,ExtMABuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,ExtStdDevBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(3,ExtHHBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,ExtLLBuffer,INDICATOR_CALCULATIONS);
//--- set indicator short name
   string short_name=StringFormat("NewDev(%d)",ExtPeriod);
   IndicatorSetString(INDICATOR_SHORTNAME,short_name);
   PlotIndexSetString(0,PLOT_LABEL,short_name);
//--- set index shift
   PlotIndexSetInteger(0,PLOT_SHIFT,ExtShift);
  }
  
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,const int prev_calculated,const int begin,const double &price[])
  {
   if(rates_total<ExtPeriod)
      return(0);
//--- starting work
   int start=prev_calculated-1;
//--- correct position for first iteration
   if(start<ExtPeriod)
     {
      start=ExtPeriod-1;
      ArrayInitialize(ExtNewDevBuffer,0.0);
      ArrayInitialize(ExtMABuffer,0.0);
      ArrayInitialize(ExtStdDevBuffer,0.0);
      ArrayInitialize(ExtHHBuffer,0.0);
      ArrayInitialize(ExtLLBuffer,0.0);
      PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtPeriod-1+begin);
     }
     
//--- main cycle
   for(int i=start; i<rates_total && !IsStopped(); i++)
     {
      //--- Calculate StdDev
      ExtMABuffer[i]=SimpleMA(i,ExtPeriod,price);
      ExtStdDevBuffer[i]=StdDevFunc(price,ExtMABuffer,i);
        
      //--- Calculate HH and LL on ExtStdDevBuffer
      ExtHHBuffer[i]=ExtStdDevBuffer[ArrayMaximum(ExtStdDevBuffer,0,ExtPeriod)];
      ExtLLBuffer[i]=ExtStdDevBuffer[ArrayMinimum(ExtStdDevBuffer,0,ExtPeriod)];
  
     //--- Calculate NewDev
      ExtNewDevBuffer[i]=ExtStdDevBuffer[i]+ExtHHBuffer[i]-ExtLLBuffer[i];
     }
     
//--- OnCalculate done. Return new prev_calculated.
   return(rates_total);
  }
  
//+------------------------------------------------------------------+
//| Calculate Standard Deviation                                     |
//+------------------------------------------------------------------+
double StdDevFunc(const double &price[],const double &ma_price[],const int position)
  {
   double dev=0.0;
   for(int i=0; i<ExtPeriod; i++)
      dev+=MathPow(price[position-i]-ma_price[position],2.0);
   dev=MathSqrt(dev/ExtPeriod);
   return(dev);
  }
 
Question.

Do you know why standard deviation is multiplied by 2.0 or sometimes by 3.0??

Do you realize what standard deviation is telling you?

Curious...

ExtStdDev needs, if I see this right, to be set as series array. Else you would need to adjust your search parameters you give to ArrMax/ArrMin.

 

Dominik Egert:


Thanks for your answer Dominik. If I'm not mistaken, standard deviation shows the "distance" of an individual to the mean of the population. 2 or 3 StdDev added/substracted to the mean (Bollinger) defines bands in which a value has a probability to be found (95%,99% for a standard distribution). Please correct me if I'm wrong.

The formula that I wrote in the first post has no signification to me... (New deviation = Standard deviation + Highest standard deviation - Lowest standard deviation) It is just an example, but I would like to use StdDev, Highest StdDev, and Lowest StdDev in the final calculation.

I coded an EA that gives me the correct values (function below), but I can't get it to work inside an indicator.

double CheckNewDev()
  {   
   MqlRates StdDevInformation[];
   ArraySetAsSeries(StdDevInformation,true);
   int StdDevData = CopyRates(Symbol(),Period(),0,20,StdDevInformation); 
   double StdDevArray[];
   ArraySetAsSeries(StdDevArray,true);
   int StdDevDefinition = iStdDev(_Symbol,_Period,20,0,MODE_SMA,PRICE_CLOSE);
   CopyBuffer(StdDevDefinition,0,0,20,StdDevArray);
   
   double StdDev =  StdDevArray[0];                          // Standard deviation (20)
   double HH = StdDevArray[ArrayMaximum(StdDevArray,0,20)];  // Highest standard deviation value over the last 20 bars
   double LL = StdDevArray[ArrayMinimum(StdDevArray,0,20)];  // Lowest standard deviation value over the last 20 bars
   
   double NewDev = StdDev+HH-LL; // Just an example formula with no signification
   
   return NewDev;
  }



 

Things get better. I drew StdDev, HH, and LL to have a better look at what is going on.

All values seems correct at the current bar only (screenshot https://i.postimg.cc/GptssBsL/Screen1.png)

Though I cannot get it to work on past data. Any hint about this please ?


New code :

#include <MovingAverages.mqh>

#property indicator_separate_window
#property indicator_buffers 5 
#property indicator_plots   5

#property indicator_label2  "StdDev"
#property indicator_type2   DRAW_LINE
#property indicator_color2  MediumSeaGreen
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

#property indicator_label3  "HH"
#property indicator_type3   DRAW_LINE
#property indicator_color3  Green
#property indicator_style3  STYLE_SOLID
#property indicator_width3  2

#property indicator_label4  "LL"
#property indicator_type4   DRAW_LINE
#property indicator_color4  Red
#property indicator_style4  STYLE_SOLID
#property indicator_width4  2


//--- input parameters
input int            InpPeriod=20;   // Period
input int            InpShift=0;     // Shift

//--- indicator buffers
double ExtNewDevBuffer[];
double ExtMABuffer[];
double ExtStdDevBuffer[];
double ExtHHBuffer[];
double ExtLLBuffer[];

int    ExtPeriod,ExtShift;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit()
  {
//--- check for input values
   if(InpPeriod<=1)
     {
      ExtPeriod=20;
      PrintFormat("Incorrect value for input variable InpPeriod=%d. Indicator will use value %d for calculations.",
                   InpPeriod,ExtPeriod);
     }
   else
      ExtPeriod=InpPeriod;
   if(InpShift<0)
     {
      ExtShift=0;
      PrintFormat("Incorrect value for input variable InpShift=%d. Indicator will use value %d for calculations.",
                  InpShift,ExtShift);
     }
   else
      ExtShift=InpShift;
//--- define indicator buffers as indexes
   SetIndexBuffer(0,ExtMABuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(1,ExtStdDevBuffer);
   SetIndexBuffer(2,ExtHHBuffer);
   SetIndexBuffer(3,ExtLLBuffer);
   SetIndexBuffer(4,ExtNewDevBuffer);
  }
  
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,const int prev_calculated,const int begin,const double &price[])
  {
   if(rates_total<ExtPeriod)
      return(0);
//--- starting work
   int start=prev_calculated-1;
//--- correct position for first iteration
   if(start<ExtPeriod)
     {
      start=ExtPeriod-1;
      ArrayInitialize(ExtMABuffer,0.0);
      ArrayInitialize(ExtStdDevBuffer,0.0);
      ArrayInitialize(ExtHHBuffer,0.0);
      ArrayInitialize(ExtLLBuffer,0.0);
      ArrayInitialize(ExtNewDevBuffer,0.0);
     }
     
//--- main cycle  
   for(int i=start; i<rates_total && !IsStopped(); i++)
     {
      //--- Calculate StdDev
      ExtMABuffer[i]=SimpleMA(i,ExtPeriod,price);
      ExtStdDevBuffer[i]=StdDevFunc(price,ExtMABuffer,i);
        
      //--- Calculate HH and LL on ExtStdDevBuffer
      ArraySetAsSeries(ExtStdDevBuffer,true);
      ExtHHBuffer[i]=ExtStdDevBuffer[ArrayMaximum(ExtStdDevBuffer,0,ExtPeriod)];
      ExtLLBuffer[i]=ExtStdDevBuffer[ArrayMinimum(ExtStdDevBuffer,0,ExtPeriod)];
      ArraySetAsSeries(ExtStdDevBuffer,false);
      
      //--- Calculate NewDev
      ExtNewDevBuffer[i]=ExtStdDevBuffer[i]+ExtHHBuffer[i]-ExtLLBuffer[i];
      
     }
     
//--- OnCalculate done. Return new prev_calculated.
   return(rates_total);
  }
  
//+------------------------------------------------------------------+
//| Calculate Standard Deviation                                     |
//+------------------------------------------------------------------+
double StdDevFunc(const double &price[],const double &ma_price[],const int position)
  {
   double dev=0.0;
   for(int i=0; i<ExtPeriod; i++)
      dev+=MathPow(price[position-i]-ma_price[position],2.0);
   dev=MathSqrt(dev/ExtPeriod);
   return(dev);
  }
 
Stddev * 2.0 = about 68% of data points within this range.

Studded * 3.0 = about 98% of data points within this range.

When using low and high to be added you would be around a value of ie 2.8ish...


 
Dominik Egert:
Stddev * 2.0 = about 68% of data points within this range.

Studded * 3.0 = about 98% of data points within this range.

When using low and high to be added you would be around a value of ie 2.8ish...


My point is to create an indicator that include StdDev, Highest StdDev and Lowest StdDev in the final calculation. So I gave this meaningless calculation exemple of NewDev (New deviation = Standard deviation + Highest standard deviation - Lowest standard deviation).

This is not about the signification of Standard deviation, it could have been any other value...

 
I did not mean to criticize your approach, I was thinking loud.
And as I am doing so, I notice an increase in volatility when going your approach. On average my assumption might be correct, but that's not your aim....



 
Dominik Egert:
I notice an increase in volatility when going your approach. On average my assumption might be correct, but that's not your aim....

I have no idea what you mean, no offence.

 

I added loops in the main cycle and it seems to work.

But I still can't make it calculate on past data. 

//--- main cycle  
   for(int i=start; i<rates_total && !IsStopped(); i++)
     {
      //--- Calculate StdDev
      ExtMABuffer[i]=SimpleMA(i,ExtPeriod,price);
      ExtStdDevBuffer[i]=StdDevFunc(price,ExtMABuffer,i);
     }  
 
   for(int i=start; i<rates_total && !IsStopped(); i++)
     {
      //--- Calculate HH and LL on ExtStdDevBuffer
      ArraySetAsSeries(ExtStdDevBuffer,true);
      ExtHHBuffer[i]=ExtStdDevBuffer[ArrayMaximum(ExtStdDevBuffer,0,ExtPeriod)];
      ExtLLBuffer[i]=ExtStdDevBuffer[ArrayMinimum(ExtStdDevBuffer,0,ExtPeriod)];
      ArraySetAsSeries(ExtStdDevBuffer,false);
     }  
      
   for(int i=start; i<rates_total && !IsStopped(); i++)
     {
      //--- Calculate NewDev
      ExtNewDevBuffer[i]=ExtStdDevBuffer[i]+ExtHHBuffer[i]-ExtLLBuffer[i];
     }        
 
Your issue seems to be related to the second parameter of ArrayMax/Min...

Check the docs...

I suspect it should be "i".
 

I needed to modify the starting position of ArrayMax() and ArrayMin() to calculate HH and LL values on past bars as well.

Here is where I am :

//--- main cycle  
   for(int i=start; i<rates_total && !IsStopped(); i++)
     {
      //--- Calculate StdDev
      ExtMABuffer[i]=SimpleMA(i,ExtPeriod,price);
      ExtStdDevBuffer[i]=StdDevFunc(price,ExtMABuffer,i);
     }  
   
   for(int i=start; i<rates_total && !IsStopped(); i++)
     {
      //--- Calculate HH and LL on ExtStdDevBuffer
      ExtHHBuffer[i]=ExtStdDevBuffer[ArrayMaximum(ExtStdDevBuffer,i,ExtPeriod)];
      ExtLLBuffer[i]=ExtStdDevBuffer[ArrayMinimum(ExtStdDevBuffer,i,ExtPeriod)];
     }   
   
   for(int i=start; i<rates_total && !IsStopped(); i++)
     {
      //--- Calculate NewDev
      ExtNewDevBuffer[i]=ExtStdDevBuffer[i]+ExtHHBuffer[i]-ExtLLBuffer[i];
     }              

ArrayMax() and ArrayMin() are now being calculated on the future bars instead of the previous bars. I looked at timeseries, but I can't make it work right now. Some help would be appreciated.

Reason: