//+------------------------------------------------------------------+
//|                                                     Quarters.mq4 |
//|                                      Copyright 2017, nicholishen |
//|                         https://www.forexfactory.com/nicholishen |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, nicholishen"
#property link      "https://www.forexfactory.com/nicholishen"
#property version   "1.00"
#property strict
#property indicator_chart_window
#include <Arrays\List.mqh>
#include <ChartObjects\ChartObjectsLines.mqh>


input int InpNumPips = 1000; //Pip Range
input color InpColor = clrRed;

class Line : public CChartObjectHLine
{
   static int  s_instance;
   int         m_instance;
public:
   Line(){  m_instance = ++s_instance; }
   
   bool Create(double number)
   {
      if(!Create(0,"__quarters_"+string(m_instance),0,NormalizeDouble(number,_Digits)))
         return false;
      if(IsWhole(Price(0)))
         Style(STYLE_DASH);
      else
         Style(STYLE_DOT);
      Color(InpColor);
      return true;
   }
protected:
   
   bool IsWhole(double number)
   {
      int points = (_Digits == 5 || _Digits == 3) ? InpNumPips * 10 : InpNumPips;
      number = NormalizeDouble(number,_Digits);
      int num = int(round(number/_Point));
      if(num%points == 0)
         return true;
      return false;
   }
};
int Line::s_instance=0;

CList list;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   double chart_max = ChartGetDouble(0,CHART_PRICE_MAX);
   double chart_min = ChartGetDouble(0,CHART_PRICE_MIN);
   
   double min = chart_min - (chart_max - chart_min) * 2.5;
   double max = chart_max + (chart_max - chart_min) * 2.5;
   
   for(double i=min;i<max;i = NextPrice(i))
   {
      Line *line = new Line();
      line.Create(i);
      list.Add(line);
   }
//---
   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[])
  {
//---
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
double NextPrice(double price)
{
   int points = (_Digits == 5 || _Digits == 3) ? InpNumPips * 10 : InpNumPips;
   double step = NormalizeDouble(points  * _Point * 0.25, _Digits);
   price+=step;
   return step * round(price/step);
}
