//+------------------------------------------------------------------+
//|                                                    SignalCNN.mqh |
//|                   Copyright 2009-2017, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
#include <My\Ccnn__.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signals based on Convolution Neural Network r1             |
//| Type=SignalAdvanced                                              |
//| Name=CNN                                                         |
//| ShortName=CNN                                                    |
//| Class=CSignalCNN                                                 |
//| Page=signal_cgan                                                 |
//| Parameter=TrainSet,int,20,Training Set Size                      |
//| Parameter=Epochs,int,1,Epochs                                    |
//| Parameter=LearningRate,double,0.00000005,LearningRate            |
//| Parameter=InputSize,int,5,Input Size                             |
//| Parameter=Alpha,double,0.01,Alpha                                |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CSignalCNN.                                                |
//| Purpose: Class of Convolution Neural Network r1.                 |
//|            Derives from class CExpertSignal.                     |
//+------------------------------------------------------------------+

#define __KERNEL 3
int __KERNEL_SIZES[3] = {__KERNEL, __KERNEL, __KERNEL};

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CSignalCNN   : public CExpertSignal
{
protected:
   CiMA                          m_ma[];             // object-indicator

   int                           m_train_set;                       //
   int                           m_epochs;                              // Epochs
   double                        m_learning_rate;                       // 

   int                           m_input_size;
   double                        m_alpha;                       // 

   double                        m_train_deposit;
   double                        m_train_criteria;

public:
                     CSignalCNN(void);
                    ~CSignalCNN(void);

   //--- methods of setting adjustable parameters
   void                          TrainSet(int value)
   {  m_train_set = value;
   }
   void                          Epochs(int value)
   {  m_epochs = value;
   }
   void                          LearningRate(double value)
   {  m_learning_rate = value;
   }
   void                          InputSize(int value)
   {  m_input_size = value;
   }
   void                          Alpha(double value)
   {  m_alpha = value;
   }

   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the indicator and timeseries
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- methods of checking if the market models are formed
   virtual int       LongCondition(void);
   virtual int       ShortCondition(void);

protected:
   double                        GetOutput();
   void                          SetOutput();

   Ccnn                          *CNN;
};
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
void CSignalCNN::CSignalCNN(void) :    m_train_set(20),
   m_epochs(1),
   m_learning_rate(0.00000005),
   m_input_size(5)

{
//--- initialization of protected data
   m_used_series = USE_SERIES_OPEN + USE_SERIES_HIGH + USE_SERIES_LOW + USE_SERIES_CLOSE + USE_SERIES_SPREAD + USE_SERIES_TIME;
}
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
void CSignalCNN::~CSignalCNN(void)
{  delete CNN;
}
//+------------------------------------------------------------------+
//| Validation settings protected data.                              |
//+------------------------------------------------------------------+
bool CSignalCNN::ValidationSettings(void)
{  if(!CExpertSignal::ValidationSettings())
      return(false);
//--- initial data checks
   if(m_epochs < 1)
   {  printf(__FUNCSIG__ + " epochs size should at least be 1! ");
      return(false);
   }
   if(m_learning_rate < 0.0)
   {  printf(__FUNCSIG__ + " learning rate should be greater than 0.0! ");
      return(false);
   }
   CNN = new Ccnn(m_input_size, __KERNEL_SIZES, PADDING_EDGE, POOLING_AVERAGE,1.0,0.0,m_alpha);
   if(!CNN.validated)
   {  printf(__FUNCSIG__ + " invalid network settings ");
      return(false);
   }
   ArrayResize(m_ma,m_input_size*m_input_size);
   m_train_deposit = AccountInfoDouble(ACCOUNT_BALANCE);
   m_train_criteria = 0.0;
   
//--- ok
   return(true);
}
//+------------------------------------------------------------------+
//| Create indicators.                                               |
//+------------------------------------------------------------------+
bool CSignalCNN::InitIndicators(CIndicators *indicators)
{
//--- check pointer
   if(indicators == NULL)
      return(false);
//--- initialization of indicators and timeseries of additional filters
   if(!CExpertSignal::InitIndicators(indicators))
      return(false);
   int _period = 5;
   for(int i=0;i<m_input_size*m_input_size;i++)
   {  if(!m_ma[i].Create(m_symbol.Name(),m_period,_period,0,MODE_SMA,PRICE_CLOSE))
      {  return(false);
      }
      _period++;
   }
//--- ok
   return(true);
}
//+------------------------------------------------------------------+
//| "Voting" that price will grow.                                   |
//+------------------------------------------------------------------+
int CSignalCNN::LongCondition(void)
{  int result = 0;
   double _output = GetOutput();
   if(_output > 0.5)
   {  //printf(__FUNCSIG__ + " output is: %.5f", GetOutput());
      result = 100;
   }
   return(result);
}
//+------------------------------------------------------------------+
//| "Voting" that price will fall.                                   |
//+------------------------------------------------------------------+
int CSignalCNN::ShortCondition(void)
{  int result = 0;
   double _output = GetOutput();
   if(_output < 0.5)
   {  //printf(__FUNCSIG__ + " output is: %.5f", GetOutput());
      result = 100;
   }
   return(result);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CSignalCNN::GetOutput()
{  int _index = 5;
   matrix _inputs;
   vector _ma, _h, _l, _c;
   _inputs.Init(m_input_size, m_input_size);
   for(int g = 0; g < m_epochs; g++)
   {  for(int h = m_train_set - 1; h >= 0; h--)
      {  _inputs.Fill(0.0);
         _index = 0;
         _h.CopyRates(m_symbol.Name(), m_period, 2, h, __KERNEL + 1);
         _l.CopyRates(m_symbol.Name(), m_period, 4, h, __KERNEL + 1);
         _c.CopyRates(m_symbol.Name(), m_period, 8, h, __KERNEL + 1);
         //Print(" inputs are: \n", _inputs);
         for(int i = 0; i < m_input_size; i++)
         {  for(int j = 0; j < m_input_size; j++)
            {  if(_ma.CopyIndicatorBuffer(m_ma[_index].Handle(), 0, h, __KERNEL + 1) 
                  && _c.CopyRates(m_symbol.Name(), m_period, COPY_RATES_CLOSE, h, __KERNEL + 1))
               {  _inputs[i][j] = _c[0] - _ma[0];
                  _index++;
               }
            }
         }
         //
         CNN.Set(_inputs);
         CNN.Pad();
         //Print(" padded inputs are: \n", CNN.inputs);
         CNN.Convolve();
         CNN.Activate();
         CNN.Pool();
         // targets as eventual price changes with each matrix a proxy for bullishness, bearishness, or whipsaw action
         // implying matrices for eventual:
         // high price changes
         // low price changes
         // close price changes,
         // respectively
         //
         // price changes in each column are over 1 bar, 2 bar and 3 bars respectively
         // & price changes in each row are over different weightings of the applied price with other applied prices
         // so high is: highs only(H); (Highs + Highs + Close)/3 (HHC); and (Highs + Close)/3 (HC)
         // while low is: lows only(L); (Lows + Lows + Close)/3 (LLC); and (Lows + Close)/3 (LC)
         // and close is: closes only(C); (Highs + Lows + Close + Close)/3 (HLCC); and (Highs + Lows + Close)/3 (HLC)
         //
         // assumptions here are:
         // large values in highs mean bullishness
         // large values in lows mean bearishness
         // and small magnitude in close imply a whipsaw market
         matrix _targets[];
         ArrayResize(_targets, __KERNEL_SIZES.Size());
         for(int i = 0; i < int(__KERNEL_SIZES.Size()); i++)
         {  _targets[i].Init(__KERNEL_SIZES[i], __KERNEL_SIZES[i]);
            //
            for(int j = 0; j < __KERNEL_SIZES[i]; j++)
            {  if(i == 0)// highs for 'bullishness'
               {  _targets[i][j][0] = _h[j] - _h[j + 1];
                  _targets[i][j][1] = ((_h[j] + _h[j] + _c[j]) / 3.0) - ((_h[j + 1] + _h[j + 1] + _c[j + 1]) / 3.0);
                  _targets[i][j][2] = ((_h[j] + _c[j]) / 2.0) - ((_h[j + 1] + _c[j + 1]) / 2.0);
               }
               else if(i == 1)// lows for 'bearishness'
               {  _targets[i][j][0] = _l[j] - _l[j + 1];
                  _targets[i][j][1] = ((_l[j] + _l[j] + _c[j]) / 3.0) - ((_l[j + 1] + _l[j + 1] + _c[j + 1]) / 3.0);
                  _targets[i][j][2] = ((_l[j] + _c[j]) / 2.0) - ((_l[j + 1] + _c[j + 1]) / 2.0);
               }
               else if(i == 2)// close for 'whipsaw'
               {  _targets[i][j][0] = _c[j] - _c[j + 1];
                  _targets[i][j][1] = ((_h[j] + _l[j] + _c[j] + _c[j]) / 3.0) - ((_h[j + 1] + _l[j + 1] + _c[j + 1] + _c[j + 1]) / 3.0);
                  _targets[i][j][2] = ((_h[j] + _l[j] + _c[j]) / 2.0) - ((_h[j + 1] + _l[j + 1] + _c[j + 1]) / 2.0);
               }
            }
            //
            //Print(" targets for: "+IntegerToString(i)+" are: \n", _targets[i]);
         }
         CNN.Get(_targets);
         CNN.Evolve(m_learning_rate);
      }
   }
   _index = 0;
   _h.CopyRates(m_symbol.Name(), m_period, 2, 0, __KERNEL + 1);
   _l.CopyRates(m_symbol.Name(), m_period, 4, 0, __KERNEL + 1);
   _c.CopyRates(m_symbol.Name(), m_period, 8, 0, __KERNEL + 1);
   for(int i = 0; i < m_input_size; i++)
   {  for(int j = 0; j < m_input_size; j++)
      {  if(_ma.CopyIndicatorBuffer(m_ma[_index].Handle(), 0, 0, __KERNEL + 1))
         {  _inputs[i][j] = _c[__KERNEL] - _ma[__KERNEL];
            _index++;
         }
      }
   }
   CNN.Set(_inputs);
   CNN.Pad();
   CNN.Convolve();
   CNN.Activate();
   CNN.Pool();
   double _long = 0.0, _short = 0.0;
   if(CNN.output[0].Median() > 0.0)
   {  _long = fabs(CNN.output[0].Median());
   }
   if(CNN.output[1].Median() < 0.0)
   {  _short = fabs(CNN.output[1].Median());
   }
   double _neutral = fabs(CNN.output[2].Median());
   if(_long+_short+_neutral == 0.0)
   {  return(0.0);
   }
   return((_long-_short)/(_long+_short+_neutral));
}
//+------------------------------------------------------------------+
//| Weights & Biases exporting function for network                  |
//+------------------------------------------------------------------+
void CSignalCNN::SetOutput(void)
{
}
//+------------------------------------------------------------------+
