//+------------------------------------------------------------------+
//|                                                        Rates.mqh |
//|                                                      nicholishen |
//|                                   www.reddit.com/u/nicholishenFX |
//+------------------------------------------------------------------+
#property copyright "nicholishen"
#property link      "www.reddit.com/u/nicholishenFX"
#property version   "1.00"
#property strict
#include <Arrays\ArrayObj.mqh>
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CRates : public CObject
{
private:
   string            m_symbol;
   ENUM_TIMEFRAMES   m_period;
   MqlRates          m_rates[];
   int               m_total;
   bool              m_setAsSeries;
   int               m_highest;
   int               m_lowest;
   
public:
//--- default is the symbol and period of chart. This can only be set on declaration and cannot be changed after.
                     CRates(const string symbol = NULL,ENUM_TIMEFRAMES period = PERIOD_CURRENT);
                    ~CRates();
//--- methods to copy rates
   int               CopyAllRates(); //copies all available rates
   int               CopyRates(int start_pos, int count);
   int               CopyRates(datetime start_time, int count);
   int               CopyRates(datetime start_time, datetime stop_time);
//--- access to change AsSeries
   void              SetAsSeries(bool set)   { m_setAsSeries = set; ArraySetAsSeries(m_rates,m_setAsSeries); }
   bool              SetAsSeries()           { return m_setAsSeries ;   }
//--- accesst to object status
   int               Total()                 { return m_total;          }
   string            Symbol()                { return m_symbol;         }
   ENUM_TIMEFRAMES   Period()                { return m_period;         }
//--- access to rates information
   int               HighestHigh();
   int               LowestLow();
   datetime          Time(int i)       { if(ch(i))return m_rates[i].time;        else return -1;}
   double            Open(int i)       { if(ch(i))return m_rates[i].open;        else return -1;}
   double            High(int i)       { if(ch(i))return m_rates[i].high;        else return -1;}
   double            Low(int i)        { if(ch(i))return m_rates[i].low;         else return -1;}
   double            Close(int i)      { if(ch(i))return m_rates[i].close;       else return -1;}
   long              TickVolume(int i) { if(ch(i))return m_rates[i].tick_volume; else return -1;}
   int               Spread(int i)     { if(ch(i))return m_rates[i].spread;      else return -1;}
   long              RealVolume(int i) { if(ch(i))return m_rates[i].real_volume; else return -1;}
protected:
   bool              ch(int i);
};
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

CRates::CRates(const string symbol= NULL,ENUM_TIMEFRAMES period = PERIOD_CURRENT): m_setAsSeries(true)                                                        
{
   ArraySetAsSeries(m_rates,m_setAsSeries);
   m_symbol = symbol == NULL ? ::Symbol() : symbol;
   m_period = period == PERIOD_CURRENT ? (ENUM_TIMEFRAMES)::Period() : period;
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CRates::~CRates()
{
}
//+------------------------------------------------------------------+
int CRates::CopyAllRates(void)
{
   m_highest = -1; m_lowest = -1;
   int total = ::Bars(m_symbol,m_period);
   return CopyRates(0,total);
}
//+------------------------------------------------------------------+
int CRates::CopyRates(datetime start_time,int count)
{
   m_highest = -1; m_lowest = -1;
   m_total = ::CopyRates(m_symbol,m_period,start_time,count,m_rates);
   return m_total;
}
//+------------------------------------------------------------------+
int CRates::CopyRates(datetime start_time,datetime stop_time)
{
   m_highest = -1; m_lowest = -1;
   m_total = ::CopyRates(m_symbol,m_period,start_time,stop_time,m_rates);
   return m_total;
}
//+------------------------------------------------------------------+
int CRates::CopyRates(int start_pos,int count)
{
   m_highest = -1; m_lowest = -1;
   m_total = ::CopyRates(m_symbol,m_period,start_pos,count,m_rates);
   return m_total;
}
//+------------------------------------------------------------------+
int CRates::HighestHigh(void)
{
   if(m_highest >= 0)
      return m_highest;
   double highest = DBL_MIN;
   for(int i=0;i<m_total;i++)
   {
      if(m_rates[i].high > highest)
      {
         m_highest = i;
         highest = m_rates[i].high;
      }
   }
   return m_highest;
}
//+------------------------------------------------------------------+
int CRates::LowestLow(void)
{
   if(m_lowest >= 0)
      return m_lowest;
   double lowest = DBL_MAX;
   for(int i=0;i<m_total;i++)
   {
      if(m_rates[i].low < lowest)
      {
         m_lowest = i;
         lowest = m_rates[i].low;
      }
   }
   return m_lowest;
}
//+------------------------------------------------------------------+
bool CRates::ch(int i)
{
   if(i < 0 || i >= m_total)
   {
      Print(__FUNCTION__," OutOfRangeError");
      return false;
   }
   return true;
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+


class CTick : public CObject
{
private:
   string            m_symbol;
   MqlTick           m_tick;   
public:
//--- default is the symbol and period of chart. This can only be set on declaration and cannot be changed after.
                     CTick(const string symbol = NULL);
//--- methods to copy rates
   double            Refresh();
   string            Symbol()       { return m_symbol;      }
   datetime          Time()         { return m_tick.time;   }
   double            Bid()          { return m_tick.bid;    }
   double            Ask()          { return m_tick.ask;    }
   double            Last()         { return m_tick.last;   }
   ulong             Volume()       { return m_tick.volume; }
};

CTick::CTick(const string symbol=NULL)
{
   m_symbol = symbol == NULL ? ::Symbol() : symbol;
}

double CTick::Refresh(void)
{
   if(SymbolInfoTick(m_symbol,m_tick))
      return m_tick.last;
   else 
      return -1;
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

class CTickVector : public CArrayObj
{
public:
   CTick    *operator[](const int index)const{return (CTick*)At(index);}
   double   NewTick(string symbol = NULL);
   double   NewTick(CTick *tick);
};

double CTickVector::NewTick(string symbol=NULL)
{
   CTick *tick = new CTick(symbol);
   double res = tick.Refresh();
   this.Add(tick);
   return res;
}
double CTickVector::NewTick(CTick *tick)
{
   double res = tick.Last();
   if(res <=0)
      tick.Refresh();
   this.Add(tick);
   return res;
}