//+------------------------------------------------------------------+
//|                                                   ExpertBase.mqh |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include <Trade\SymbolInfo.mqh>
#include <Trade\AccountInfo.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\OrderInfo.mqh>
#include <Trade\DealInfo.mqh>
#include <Trade\HistoryOrderInfo.mqh>
#include <Indicators\Indicators.mqh>
//+------------------------------------------------------------------+
//| enumerations                                                     |
//+------------------------------------------------------------------+
//--- constants of identification of trend
enum ENUM_TYPE_TREND
  {
   TYPE_TREND_HARD_DOWN  =0,           // strong down trend
   TYPE_TREND_DOWN       =1,           // down trend
   TYPE_TREND_SOFT_DOWN  =2,           // weak down trend
   TYPE_TREND_FLAT       =3,           // no trend
   TYPE_TREND_SOFT_UP    =4,           // weak up trend
   TYPE_TREND_UP         =5,           // up trend
   TYPE_TREND_HARD_UP    =6            // strong up trend
  };
//--- flags of used timeseries
enum ENUM_USED_SERIES
  {
   USE_SERIES_OPEN       =0x1,
   USE_SERIES_HIGH       =0x2,
   USE_SERIES_LOW        =0x4,
   USE_SERIES_CLOSE      =0x8,
   USE_SERIES_SPREAD     =0x10,
   USE_SERIES_TIME       =0x20,
   USE_SERIES_TICK_VOLUME=0x40,
   USE_SERIES_REAL_VOLUME=0x80
  };
//--- phases of initialization of an object
enum ENUM_INIT_PHASE
  {
   INIT_PHASE_FIRST      =0,           // start phase (only Init(...) can be called)
   INIT_PHASE_TUNING     =1,           // phase of tuning (set in Init(...))
   INIT_PHASE_VALIDATION =2,           // phase of checking of parameters(set in ValidationSettings(...))
   INIT_PHASE_COMPLETE   =3            // end phase (set in InitIndicators(...))
  };
//+------------------------------------------------------------------+
//| Macro definitions.                                               |
//+------------------------------------------------------------------+
//--- check the use of timeseries
#define IS_OPEN_SERIES_USAGE         ((m_used_series&USE_SERIES_OPEN)!=0)
#define IS_HIGH_SERIES_USAGE         ((m_used_series&USE_SERIES_HIGH)!=0)
#define IS_LOW_SERIES_USAGE          ((m_used_series&USE_SERIES_LOW)!=0)
#define IS_CLOSE_SERIES_USAGE        ((m_used_series&USE_SERIES_CLOSE)!=0)
#define IS_SPREAD_SERIES_USAGE       ((m_used_series&USE_SERIES_SPREAD)!=0)
#define IS_TIME_SERIES_USAGE         ((m_used_series&USE_SERIES_TIME)!=0)
#define IS_TICK_VOLUME_SERIES_USAGE  ((m_used_series&USE_SERIES_TICK_VOLUME)!=0)
#define IS_REAL_VOLUME_SERIES_USAGE  ((m_used_series&USE_SERIES_REAL_VOLUME)!=0)
//+------------------------------------------------------------------+
//| Class CExpertBase.                                               |
//| Purpose: Base class of component of Expert Advisor.              |
//| Derives from class CObject.                                      |
//+------------------------------------------------------------------+
class CExpertBase : public CObject
  {
protected:
   //--- variables
   ulong             m_magic;          // expert magic number
   ENUM_INIT_PHASE   m_init_phase;     // the phase (stage) of initialization of object
   bool              m_other_symbol;   // flag of a custom work symbols (different from one of the Expert Advisor)
   CSymbolInfo      *m_symbol;         // pointer to the object-symbol
   bool              m_other_period;   // flag of a custom timeframe (different from one of the Expert Advisor)
   ENUM_TIMEFRAMES   m_period;         // work timeframe
   double            m_adjusted_point; // "weight" 2/4 of a point
   CAccountInfo      m_account;        // object-deposit
   ENUM_TYPE_TREND   m_trend_type;     // identifier of trend
   bool              m_every_tick;     // flag of starting the analysis from current (incomplete) bar
   //--- timeseries
   int               m_used_series;    // flags of using of series
   CiOpen           *m_open;           // pointer to the object for access to open prices of bars
   CiHigh           *m_high;           // pointer to the object for access to high prices of bars
   CiLow            *m_low;            // pointer to the object for access to low prices of bars
   CiClose          *m_close;          // pointer to the object for access to close prices of bars
   CiSpread         *m_spread;         // pointer to the object for access to spreads
   CiTime           *m_time;           // pointer to the object for access to time of closing of bars
   CiTickVolume     *m_tick_volume;    // pointer to the object for access to tick volumes of bars
   CiRealVolume     *m_real_volume;    // pointer to the object for access to real volumes of bars

public:
                     CExpertBase(void);
                    ~CExpertBase(void);
   //--- methods of access to protected data
   ENUM_INIT_PHASE   InitPhase(void)            const { return(m_init_phase); }
   void              TrendType(ENUM_TYPE_TREND value) { m_trend_type=value;   }
   int               UsedSeries(void) const;
   void              EveryTick(bool value)            { m_every_tick=value;   }
   //--- methods of access to protected data
   double            Open(int ind) const;
   double            High(int ind) const;
   double            Low(int ind) const;
   double            Close(int ind) const;
   int               Spread(int ind) const;
   datetime          Time(int ind) const;
   long              TickVolume(int ind) const;
   long              RealVolume(int ind) const;
   //--- methods of initialization of the object
   virtual bool      Init(CSymbolInfo *symbol,ENUM_TIMEFRAMES period,double point);
   bool              Symbol(string name);
   bool              Period(ENUM_TIMEFRAMES value);
   void              Magic(ulong value) { m_magic=value; }
   //--- method of verification of settings
   virtual bool      ValidationSettings();
   //--- methods of creating the indicator and timeseries
   virtual bool      SetPriceSeries(CiOpen *open,CiHigh *high,CiLow *low,CiClose *close);
   virtual bool      SetOtherSeries(CiSpread *spread,CiTime *time,CiTickVolume *tick_volume,CiRealVolume *real_volume);
   virtual bool      InitIndicators(CIndicators *indicators=NULL);

protected:
   //--- methods initialization of timeseries
   bool              InitOpen(CIndicators *indicators);
   bool              InitHigh(CIndicators *indicators);
   bool              InitLow(CIndicators *indicators);
   bool              InitClose(CIndicators *indicators);
   bool              InitSpread(CIndicators *indicators);
   bool              InitTime(CIndicators *indicators);
   bool              InitTickVolume(CIndicators *indicators);
   bool              InitRealVolume(CIndicators *indicators);
   //--- method of getting the measure units of price levels
   virtual double    PriceLevelUnit(void)      { return(m_adjusted_point); }
   //--- method of getting index of bar the analysis starts with
   virtual int       StartIndex(void) { return((m_every_tick?0:1)); }
   virtual bool      CompareMagic(ulong magic) { return(m_magic==magic);   }
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
void CExpertBase::CExpertBase(void) : m_magic(0),
                                      m_init_phase(INIT_PHASE_FIRST),
                                      m_other_symbol(false),
                                      m_symbol(NULL),
                                      m_other_period(false),
                                      m_period(PERIOD_CURRENT),
                                      m_adjusted_point(1.0),
                                      m_trend_type(TYPE_TREND_FLAT),
                                      m_every_tick(false),
                                      m_used_series(0),
                                      m_open(NULL),
                                      m_high(NULL),
                                      m_low(NULL),
                                      m_close(NULL),
                                      m_spread(NULL),
                                      m_time(NULL),
                                      m_tick_volume(NULL),
                                      m_real_volume(NULL)

  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
void CExpertBase::~CExpertBase(void)
  {
//--- if the symbol is "custom", delete it
   if(m_other_symbol && m_symbol!=NULL)
      delete m_symbol;
//--- release of "custom" timeseries
   if(m_other_symbol || m_other_period)
     {
      if(IS_OPEN_SERIES_USAGE && CheckPointer(m_open)==POINTER_DYNAMIC)
         delete m_open;
      if(IS_HIGH_SERIES_USAGE && CheckPointer(m_high)==POINTER_DYNAMIC)
         delete m_high;
      if(IS_LOW_SERIES_USAGE && CheckPointer(m_low)==POINTER_DYNAMIC)
         delete m_low;
      if(IS_CLOSE_SERIES_USAGE && CheckPointer(m_close)==POINTER_DYNAMIC)
         delete m_close;
      if(IS_SPREAD_SERIES_USAGE && CheckPointer(m_spread)==POINTER_DYNAMIC)
         delete m_spread;
      if(IS_TIME_SERIES_USAGE && CheckPointer(m_time)==POINTER_DYNAMIC)
         delete m_time;
      if(IS_TICK_VOLUME_SERIES_USAGE && CheckPointer(m_tick_volume)==POINTER_DYNAMIC)
         delete m_tick_volume;
      if(IS_REAL_VOLUME_SERIES_USAGE && CheckPointer(m_real_volume)==POINTER_DYNAMIC)
         delete m_real_volume;
     }
  }
//+------------------------------------------------------------------+
//| Get flags of used timeseries                                     |
//+------------------------------------------------------------------+
int CExpertBase::UsedSeries(void) const
  {
   if(m_other_symbol || m_other_period)
      return(0);
//---
   return(m_used_series);
  }
//+------------------------------------------------------------------+
//| Initialization of object.                                        |
//+------------------------------------------------------------------+
bool CExpertBase::Init(CSymbolInfo *symbol,ENUM_TIMEFRAMES period,double point)
  {
//--- check the initialization phase
   if(m_init_phase!=INIT_PHASE_FIRST)
     {
      printf(__FUNCTION__+": attempt of re-initialization");
      return(false);
     }
//--- check of pointer
   if(symbol==NULL)
     {
      printf(__FUNCTION__+": error initialization");
      return(false);
     }
//--- initialization
   m_symbol        =symbol;
   m_period        =period;
   m_adjusted_point=point;
   m_other_symbol  =false;
   m_other_period  =false;
//--- primary initialization is successful, pass to the phase of tuning
   m_init_phase=INIT_PHASE_TUNING;
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Changing work symbol.                                            |
//+------------------------------------------------------------------+
bool CExpertBase::Symbol(string name)
  {
//--- check the initialization phase
   if(m_init_phase!=INIT_PHASE_TUNING)
     {
      printf(__FUNCTION__+": changing of symbol is forbidden");
      return(false);
     }
   if(m_symbol!=NULL)
     {
      //--- symbol has been already set
      if(m_symbol.Name()==name)
         return(true);
      //--- symbol is not the one required, but is already "custom"
      if(m_other_symbol)
        {
         if(!m_symbol.Name(name))
           {
            //--- failed to initialize the symbol
            delete m_symbol;
            return(false);
           }
         return(true);
        }
     }
   m_symbol=new CSymbolInfo;
//--- check of pointer
   if(m_symbol==NULL)
     {
      printf(__FUNCTION__+": error of changing of symbol");
      return(false);
     }
   if(!m_symbol.Name(name))
     {
      //--- failed to initialize the symbol
      delete m_symbol;
      return(false);
     }
   m_other_symbol=true;
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Changing work timeframe.                                         |
//+------------------------------------------------------------------+
bool CExpertBase::Period(ENUM_TIMEFRAMES value)
  {
//--- check the initialization phase
   if(m_init_phase!=INIT_PHASE_TUNING)
     {
      printf(__FUNCTION__+": changing of timeframe is forbidden");
      return(false);
     }
   if(m_period==value)
      return(true);
//--- change work timeframe
   m_period=value;
   m_other_period=true;
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Checking adjustable parameters                                   |
//+------------------------------------------------------------------+
bool CExpertBase::ValidationSettings()
  {
//--- rechecking parameters
   if(m_init_phase==INIT_PHASE_VALIDATION)
      return(true);
//--- check the initialization phase
   if(m_init_phase!=INIT_PHASE_TUNING)
     {
      printf(__FUNCTION__+": not the right time to check parameters");
      return(false);
     }
//--- initial check of parameters is successful, phase of tuning is over
   m_init_phase=INIT_PHASE_VALIDATION;
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Setting pointers of price timeseries.                            |
//+------------------------------------------------------------------+
bool CExpertBase::SetPriceSeries(CiOpen *open,CiHigh *high,CiLow *low,CiClose *close)
  {
//--- check the initialization phase
   if(m_init_phase!=INIT_PHASE_VALIDATION)
     {
      printf(__FUNCTION__+": changing of timeseries is forbidden");
      return(false);
     }
//--- check pointers
   if((IS_OPEN_SERIES_USAGE  && open==NULL) ||
      (IS_HIGH_SERIES_USAGE  && high==NULL) ||
      (IS_LOW_SERIES_USAGE   && low==NULL)  || 
      (IS_CLOSE_SERIES_USAGE && close==NULL))
     {
      printf(__FUNCTION__+": NULL pointer");
      return(false);
     }
   m_open =open;
   m_high =high;
   m_low  =low;
   m_close=close;
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Setting pointers of other timeseries.                            |
//+------------------------------------------------------------------+
bool CExpertBase::SetOtherSeries(CiSpread *spread,CiTime *time,CiTickVolume *tick_volume,CiRealVolume *real_volume)
  {
//--- check the initialization phase
   if(m_init_phase!=INIT_PHASE_VALIDATION)
     {
      printf(__FUNCTION__+": changing of timeseries is forbidden");
      return(false);
     }
//--- check pointers
   if((IS_SPREAD_SERIES_USAGE && spread==NULL) || 
      (IS_TIME_SERIES_USAGE && time==NULL) || 
      (IS_TICK_VOLUME_SERIES_USAGE && tick_volume==NULL) ||
      (IS_REAL_VOLUME_SERIES_USAGE && real_volume==NULL))
     {
      printf(__FUNCTION__+": NULL pointer");
      return(false);
     }
   m_spread     =spread;
   m_time       =time;
   m_tick_volume=tick_volume;
   m_real_volume=real_volume;
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of indicators and timeseries.                     |
//+------------------------------------------------------------------+
bool CExpertBase::InitIndicators(CIndicators *indicators)
  {
//--- this call is for compatibility with the previous version
   if(!ValidationSettings())
      return(false);
//--- check the initialization phase
   if(m_init_phase!=INIT_PHASE_VALIDATION)
     {
      printf(__FUNCTION__+": parameters of setting are not checked");
      return(false);
     }
   if(!m_other_symbol && !m_other_period)
      return(true);
//--- check pointers
   if(m_symbol==NULL)
      return(false);
   if(indicators==NULL)
      return(false);
//--- initialization of required timeseries
   if(IS_OPEN_SERIES_USAGE && !InitOpen(indicators))
      return(false);
   if(IS_HIGH_SERIES_USAGE && !InitHigh(indicators))
      return(false);
   if(IS_LOW_SERIES_USAGE && !InitLow(indicators))
      return(false);
   if(IS_CLOSE_SERIES_USAGE && !InitClose(indicators))
      return(false);
   if(IS_SPREAD_SERIES_USAGE && !InitSpread(indicators))
      return(false);
   if(IS_TIME_SERIES_USAGE && !InitTime(indicators))
      return(false);
   if(IS_TICK_VOLUME_SERIES_USAGE && !InitTickVolume(indicators))
      return(false);
   if(IS_REAL_VOLUME_SERIES_USAGE && !InitRealVolume(indicators))
      return(false);
//--- initialization of object (from the point of view of the base class) has been performed successfully
//--- now it's impossible to change anything in the settings
   m_init_phase=INIT_PHASE_COMPLETE;
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Access to data of the Open timeseries.                           |
//+------------------------------------------------------------------+
double CExpertBase::Open(int ind) const
  {
//--- check pointer
   if(m_open==NULL)
      return(EMPTY_VALUE);
//--- return the result
   return(m_open.GetData(ind));
  }
//+------------------------------------------------------------------+
//| Access to data of the High timeseries.                           |
//+------------------------------------------------------------------+
double CExpertBase::High(int ind) const
  {
//--- check pointer
   if(m_high==NULL)
      return(EMPTY_VALUE);
//--- return the result
   return(m_high.GetData(ind));
  }
//+------------------------------------------------------------------+
//| Access to data of the Low timeseries.                            |
//+------------------------------------------------------------------+
double CExpertBase::Low(int ind) const
  {
//--- check pointer
   if(m_low==NULL)
      return(EMPTY_VALUE);
//--- return the result
   return(m_low.GetData(ind));
  }
//+------------------------------------------------------------------+
//| Access to data of the Close timeseries.                          |
//+------------------------------------------------------------------+
double CExpertBase::Close(int ind) const
  {
//--- check pointer
   if(m_close==NULL)
      return(EMPTY_VALUE);
//--- return the result
   return(m_close.GetData(ind));
  }
//+------------------------------------------------------------------+
//| Access to data of the Spread timeseries.                         |
//+------------------------------------------------------------------+
int CExpertBase::Spread(int ind) const
  {
//--- check pointer
   if(m_spread==NULL)
      return(INT_MAX);
//--- return the result
   return(m_spread.GetData(ind));
  }
//+------------------------------------------------------------------+
//| Access to data of the Time timeseries.                           |
//+------------------------------------------------------------------+
datetime CExpertBase::Time(int ind) const
  {
//--- check pointer
   if(m_time==NULL)
      return(0);
//--- return the result
   return(m_time.GetData(ind));
  }
//+------------------------------------------------------------------+
//| Access to data of the TickVolume timeseries.                     |
//+------------------------------------------------------------------+
long CExpertBase::TickVolume(int ind) const
  {
//--- check pointer
   if(m_tick_volume==NULL)
      return(0);
//--- return the result
   return(m_tick_volume.GetData(ind));
  }
//+------------------------------------------------------------------+
//| Access to data of the RealVolume timeseries.                     |
//+------------------------------------------------------------------+
long CExpertBase::RealVolume(int ind) const
  {
//--- check pointer
   if(m_real_volume==NULL)
      return(0);
//--- return the result
   return(m_real_volume.GetData(ind));
  }
//+------------------------------------------------------------------+
//| Initialization of the Open timeseries.                           |
//+------------------------------------------------------------------+
bool CExpertBase::InitOpen(CIndicators *indicators)
  {
//--- create object
   if((m_open=new CiOpen)==NULL)
     {
      printf(__FUNCTION__+": error creating object");
      return(false);
     }
//--- add object to collection
   if(!indicators.Add(m_open))
     {
      printf(__FUNCTION__+": error adding object");
      delete m_open;
      return(false);
     }
//--- initialize object
   if(!m_open.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the High timeseries.                           |
//+------------------------------------------------------------------+
bool CExpertBase::InitHigh(CIndicators *indicators)
  {
//--- create object
   if((m_high=new CiHigh)==NULL)
     {
      printf(__FUNCTION__+": error creating object");
      return(false);
     }
//--- add object to collection
   if(!indicators.Add(m_high))
     {
      printf(__FUNCTION__+": error adding object");
      delete m_high;
      return(false);
     }
//--- initialize object
   if(!m_high.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the Low timeseries.                            |
//+------------------------------------------------------------------+
bool CExpertBase::InitLow(CIndicators *indicators)
  {
//--- create object
   if((m_low=new CiLow)==NULL)
     {
      printf(__FUNCTION__+": error creating object");
      return(false);
     }
//--- add object to collection
   if(!indicators.Add(m_low))
     {
      printf(__FUNCTION__+": error adding object");
      delete m_low;
      return(false);
     }
//--- initialize object
   if(!m_low.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the Close timeseries.                          |
//+------------------------------------------------------------------+
bool CExpertBase::InitClose(CIndicators *indicators)
  {
//--- create object
   if((m_close=new CiClose)==NULL)
     {
      printf(__FUNCTION__+": error creating object");
      return(false);
     }
//--- add object to collection
   if(!indicators.Add(m_close))
     {
      printf(__FUNCTION__+": error adding object");
      delete m_close;
      return(false);
     }
//--- initialize object
   if(!m_close.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the Spread timeseries.                         |
//+------------------------------------------------------------------+
bool CExpertBase::InitSpread(CIndicators *indicators)
  {
//--- create object
   if((m_spread=new CiSpread)==NULL)
     {
      printf(__FUNCTION__+": error creating object");
      return(false);
     }
//--- add object to collection
   if(!indicators.Add(m_spread))
     {
      printf(__FUNCTION__+": error adding object");
      delete m_spread;
      return(false);
     }
//--- initialize object
   if(!m_spread.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the Time timeseries.                           |
//+------------------------------------------------------------------+
bool CExpertBase::InitTime(CIndicators *indicators)
  {
//--- create object
   if((m_time=new CiTime)==NULL)
     {
      printf(__FUNCTION__+": error creating object");
      return(false);
     }
//--- add object to collection
   if(!indicators.Add(m_time))
     {
      printf(__FUNCTION__+": error adding object");
      delete m_time;
      return(false);
     }
//--- initialize object
   if(!m_time.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the TickVolume timeseries.                     |
//+------------------------------------------------------------------+
bool CExpertBase::InitTickVolume(CIndicators *indicators)
  {
//--- create object
   if((m_tick_volume=new CiTickVolume)==NULL)
     {
      printf(__FUNCTION__+": error creating object");
      return(false);
     }
//--- add object to collection
   if(!indicators.Add(m_tick_volume))
     {
      printf(__FUNCTION__+": error adding object");
      delete m_tick_volume;
      return(false);
     }
//--- initialize object
   if(!m_tick_volume.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the RealVolume timeseries.                     |
//+------------------------------------------------------------------+
bool CExpertBase::InitRealVolume(CIndicators *indicators)
  {
//--- create object
   if((m_real_volume=new CiRealVolume)==NULL)
     {
      printf(__FUNCTION__+": error creating object");
      return(false);
     }
//--- add object to collection
   if(!indicators.Add(m_real_volume))
     {
      printf(__FUNCTION__+": error adding object");
      delete m_real_volume;
      return(false);
     }
//--- initialize object
   if(!m_real_volume.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
