Option levels indicator. Please help to debug.

 

I'd like to make option levels indicator for MT4. My Russian version of topic is at https://www.mql5.com/ru/forum/224805

Here it is my idea. According to one theory (Ildar Nurgaliev, Russian  https://www.youtube.com/channel/UClZo081odiV1tVTnXPLY13w?app=desktop) price moves from volume to volume. The nearest sources of volume correspond to option levels which are at-the-money. These levels are located at the strike nearest to current price (open session or close of preivous session for example). The author of the trading system suggests to use every day the nearest to current price strike and breakeven points of its call and put options. He builds such call and put levels using pricing sheets from CME monthly or 3-week to expiration option (foreign exchange, oil, gold) taken from QuikStrike http://cmegroup.quikstrike.net  .

These levels do not correspond to any volume. The levels are calculated with Black-Showels formula.

(https://en.wikipedia.org/wiki/Black–Scholes_model)

So I've decided to make an indicator looking like Bollinger Bands but with breakeven points of call and put options.

I've made a version but it doesn't draw anything even simple moving average. It includes probability.dll (in archive). Please anyone help to find errors.

Индикатор опционных уровней
Индикатор опционных уровней
  • 2018.01.15
  • www.mql5.com
В последнее время у меня возникла идея создания индикатора опционных уровней, основанного на системе Ильдара Нургалиева...
 

Here it is code with comments.

//+------------------------------------------------------------------+

//|                                                        Bands.mq4 |

//|                   Copyright 2005-2014, MetaQuotes Software Corp. |

//|                                              http://www.mql4.com |

//+------------------------------------------------------------------+

#property copyright   "2005-2014, MetaQuotes Software Corp."

#property link        "http://www.mql4.com"

#property description "Bollinger Bands"

#property strict



#include <MovingAverages.mqh>

#include <Probability.mqh>



#property indicator_chart_window

#property indicator_buffers 9

#property indicator_color1 LightSeaGreen

#property indicator_color2 LightSeaGreen

#property indicator_color3 LightSeaGreen

//--- indicator parameters

input int    InpBandsPeriod=20;      // Bands Period

input int    InpBandsShift=0;        // Bands Shift

input double InpBandsDeviations=2.0; // Bands Deviations

//+------------------------------------------------------------------+

//| Custom indicator initialization function                         |

//+----------------------------------------------------------------

extern string ExpDate = "2018.02.10"; //Date of expiration of option http://cmegroup.quikstrike.net

extern double DaysInYear=365;  //Quantity of working days in the year

extern double DaysInMonth=30;  // ... in the month

extern double RFreeRate = 1.15;

/*Risk free rate 

https://www.treasury.gov/resource-c...interest-rates/Pages/TextView.aspx?data=yield

*/

extern string CurrencySymbol = ""; //

//--- buffers

double ExtUpperBuffer[];    //Upper band

double ExtLowerBuffer[];    //Lower band

double ExtStdDevBuffer[];   //Volatility for every bar

double ExtCallBuffer[];     //Calls counted for every bar

double ExtPutBuffer[];      //Puts counted for every bar

double ExtDeFirstBuffer[];  //D1 for Black-Showels formula for every bar 

double ExtStrikeBuffer[];   //The nearest strike to current price

double ExtMovingBuffer[];   //Middle line

double DTEBuffer[];         //DTE - days to expiration for every bar



int OnInit(void)

  {

//--- 1 additional buffer used for counting.

   IndicatorBuffers(9);

   IndicatorDigits(Digits);

//--- middle line

   SetIndexStyle(0,DRAW_LINE);

   SetIndexBuffer(0,ExtMovingBuffer);

   SetIndexShift(0,InpBandsShift);

   SetIndexLabel(0,"Bands SMA");

//--- upper band

   SetIndexStyle(1,DRAW_LINE);

   SetIndexBuffer(1,ExtUpperBuffer);

   SetIndexShift(1,InpBandsShift);

   SetIndexLabel(1,"Bands Upper");

//--- lower band

   SetIndexStyle(2,DRAW_LINE);

   SetIndexBuffer(2,ExtLowerBuffer);

   SetIndexShift(2,InpBandsShift);

   SetIndexLabel(2,"Bands Lower");

//--- work buffer --  (not drawn on the chart)

   SetIndexBuffer(3,ExtStdDevBuffer);

   SetIndexBuffer(4,ExtCallBuffer);

   SetIndexBuffer(5,ExtPutBuffer);

   SetIndexBuffer(6,ExtDeFirstBuffer);

   SetIndexBuffer(7,ExtStrikeBuffer);

   SetIndexBuffer(8,DTEBuffer);

//--- check for input parameter

   if(InpBandsPeriod<=0)

     {

      Print("Wrong input parameter Bands Period=",InpBandsPeriod);

      return(INIT_FAILED);

     }

//---

   SetIndexDrawBegin(0,InpBandsPeriod+InpBandsShift);

   SetIndexDrawBegin(1,InpBandsPeriod+InpBandsShift);

   SetIndexDrawBegin(2,InpBandsPeriod+InpBandsShift);

//--- initialization done

   return(INIT_SUCCEEDED);

  }

//+------------------------------------------------------------------+

//| Bollinger Bands                                                  |

//+------------------------------------------------------------------+

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 i,pos;

   double TFCoeff;

//---

   if(rates_total<=InpBandsPeriod || InpBandsPeriod<=0)

      return(0);

//--- counting from 0 to rates_total --- Bars are counted from earler to newer ones

   ArraySetAsSeries(ExtMovingBuffer,false);

   ArraySetAsSeries(ExtUpperBuffer,false);

   ArraySetAsSeries(ExtLowerBuffer,false);

   ArraySetAsSeries(ExtStdDevBuffer,false);

   ArraySetAsSeries(ExtCallBuffer,false);

   ArraySetAsSeries(ExtPutBuffer,false);

   ArraySetAsSeries(ExtDeFirstBuffer,false);

   ArraySetAsSeries(ExtStrikeBuffer,false);

   ArraySetAsSeries(DTEBuffer,false);

   ArraySetAsSeries(close,false);

   ArraySetAsSeries(open,false);

   ArraySetAsSeries(high,false);

   ArraySetAsSeries(low,false);

//--- initial zero

   TFCoeff=PERIOD_D1/Period(); //Difference of the current TF and D1, needed for daily volatility calculations

   if(prev_calculated<1)

     {

      for(i=0; i<InpBandsPeriod; i++)

        {

         ExtMovingBuffer[i]=EMPTY_VALUE;

         ExtUpperBuffer[i]=EMPTY_VALUE;

         ExtLowerBuffer[i]=EMPTY_VALUE;

        }

     }

//--- starting calculation

   if(prev_calculated>1)

      pos=prev_calculated-1;

   else

      pos=0;

//--- main cycle

   for(i=pos; i<rates_total && !IsStopped(); i++)

     {

      //--- middle line

      ExtMovingBuffer[i]=SimpleMA(i,InpBandsPeriod,close);     

      //--- calculate and write down StdDev

      //ExtStdDevBuffer[i]=StdDev_Func(i,close,ExtMovingBuffer,TFCoeff*InpBandsPeriod);  - initial formula from the stanadard indicator with my multiplier * TFCoeff

      //Two formulae for volatitilty. Try either

      //ExtStdDevBuffer[i]=StdDev_Func(i,open,close,high,low,TFCoeff*InpBandsPeriod)/ExtMovingBuffer[i]*sqrt(DaysInYear*TFCoeff);//Rogers-Satchell Volatility 

      //https://www.rdocumentation.org/packages/TTR/versions/0.23-2/topics/volatility

      //https://www.quantshare.com/item-192-rogers-satchell-volatility-estimator

      ExtStdDevBuffer[i]=iATR(NULL,PERIOD_D1,InpBandsPeriod,round(i/TFCoeff))/ExtMovingBuffer[i]*sqrt(DaysInYear); //Daily volatility expressed in years

      //Taken from  http://bin-brokers.com/simon52.html - Вайн Саймон. Опционы. Полный курс для профессионалов

      ExtStrikeBuffer[i]=Strike(ExtMovingBuffer[i]);

      DTEBuffer[i]=DTE(time[i]);

      ExtDeFirstBuffer[i]= DF(ExtMovingBuffer[i],ExtStrikeBuffer[i], ExtStdDevBuffer[i],DTEBuffer[i]); 

      //Call and put formulae  https://en.wikipedia.org/wiki/Black–Scholes_model

      //ndtr - cumulative standard normal distribution function from Probability.mqh

      ExtCallBuffer[i]=ExtMovingBuffer[i]* ndtr(ExtDeFirstBuffer[i])- ExtStrikeBuffer[i]*MathExp(-RFreeRate/100*DTEBuffer[i])*ndtr(ExtDeFirstBuffer[i]-ExtStdDevBuffer[i]*MathSqrt(DTEBuffer[i]));

      ExtPutBuffer[i]=ExtStrikeBuffer[i]*MathExp(-RFreeRate/100*DTEBuffer[i])*ndtr(ExtStdDevBuffer[i]*MathSqrt(DTEBuffer[i])- ExtDeFirstBuffer[i])-ndtr(-ExtDeFirstBuffer[i])*ExtMovingBuffer[i] ;

        

      //--- upper line

      //ExtUpperBuffer[i]=ExtMovingBuffer[i]+InpBandsDeviations*ExtStdDevBuffer[i]; - initial formula from the stanadard indicator

      ExtUpperBuffer[i]=ExtMovingBuffer[i]+ExtCallBuffer[i];

      //lower line

      //ExtLowerBuffer[i]=ExtMovingBuffer[i]-InpBandsDeviations*ExtStdDevBuffer[i]; - initial formula from the stanadard indicator

      ExtUpperBuffer[i]=ExtMovingBuffer[i]-ExtPutBuffer[i];

      //---

     }

//---- OnCalculate done. Return new prev_calculated.

   return(rates_total);

  }

//+------------------------------------------------------------------+

//| Calculate Standard Deviation                                     |

//+------------------------------------------------------------------+

//Rogers-Satchell Volatility 

//https://research-journal.org/economical/analiz-razlichnyx-metodov-ocenki-istoricheskoj-volatilnosti-dlya-opcionnoj-torgovli/

double StdDev_Func(int position,const double &open[],const double &close[],const double &high[],const double &low[],int period)

  { 

//--- variables

   double StdDev_rs=0.0; 

//--- check for position

   if(position>=period)

     {

      //--- calcualte StdDev

      for(int i=0; i<period; i++)

         StdDev_rs+=log(high[position-i]*high[position-i]/close[position-i])*log(high[position-i]/open[position-i])+log(low[position-i]/close[position-i])*log(low[position-i]/open[position-i]);

         StdDev_rs=MathSqrt(StdDev_rs/period);

     }     

//--- return calculated value

     return(StdDev_rs);

  }

  

/* Initial function from the stanadard indicator

double StdDev_Func(int position,const double &price[],const double &MAprice[],int period)

  {

//--- variables

   double StdDev_dTmp=0.0;

//--- check for position

   if(position>=period)

     {

      //--- calcualte StdDev

      for(int i=0; i<period; i++)

         StdDev_dTmp+=MathPow(price[position-i]-MAprice[position],2);

      StdDev_dTmp=MathSqrt(StdDev_dTmp/period);

     }

//--- return calculated value

   return(StdDev_dTmp);

  }

*/  

  



double Strike (double x)

   {

     string currency;

     

     if (CurrencySymbol=="") currency=Symbol(); // If currency symbol isn't inserted the indicator takes  it from the current window chart 

        else currency=CurrencySymbol;           //else - inserted string

    

    //Determine the nearest strike with round function.

    //USDCAD,USDCHF - upset paires. At СМЕ they correspond to CADUSD, CHFUSD. Their strikes look like  (CADUSD) 0,7950-0,8000-0,8050

    //E.g.: 1/(round(1/1.334*200)/200)=1.33 

    //Golden strikes look like 1320-1325-1300. E.g: round(0.2*1322)/0.2=1320

    //Oil strikes are 63,0-63,5-64. E.g.: round(2*63.3)/2=63.5

    //USDJPY. Strikes are (JPYUSD) 0,00900-0,00905-0,00910. E.g.: 1/(round(1/110,7*20000)/20000)=110,497

    //Other foreign exchange looks like eurusd, audusd. Their strikes are: 1,2250 - 1,2200 - 1,2150

    //E.g: round(1,2260*200)/200 = 1,2250; round(1,2190*200)/200=1,2200

                       

    if (currency == "USDCAD" || currency == "usdcad" || currency == "USDCHF" || currency == "usdchf" ) return 1/(round(1/x*200)/200);

        else if (currency == "GOLD" || currency == "XAUUSD" || currency == "gold" || currency == "xauusd") return round(0.2*x)/0.2;

              else if (currency == "OIL" || currency == "USOIL" || currency == "oil" || currency == "usoil" || currency == "BRENT" || currency == "brent" || currency == "WTI" || currency == "wti") return round(2*x)/2;

                   else if (currency == "USDJPY" || currency == "usdjpy") return 1/(round(1/x*20000)/20000);

                        else return round(200*x)/200;                                                                                                                                                                                                             

                       

   }  

double DF (double spot, double strk, double s, double dte) // D1 from Black formula https://en.wikipedia.org/wiki/Black–Scholes_model

    {

      return (log(spot/strk)+(RFreeRate/100+s*s/2)*dte)/(s*sqrt(dte));

    }  

double DTE (datetime days)    //DTE -days to expiration for every bar. It uses option expiration date.

    {

      double d;   

      if (((StrToTime(ExpDate)- days)/86400)/DaysInYear>0) d=((StrToTime(ExpDate)-days)/86400)/DaysInYear;

      else d=MathPow(10,-10);

      return d;

    }                            

//+------------------------------------------------------------------+



Files:
indicator.ZIP  21 kb
probability.zip  50 kb
 
When you post code please use the SRC button! Please edit your post.
          General rules and best pratices of the Forum. - General - MQL5 programming forum
Reason: