//+------------------------------------------------------------------+
//|                                  SignalRL_Ichimoku_ADXWilder.mqh |
//|                             Copyright 2000-2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>

#resource "Python/0_1_actor.onnx" as uchar __81_0[]
#resource "Python/1_1_actor.onnx" as uchar __81_1[]
#resource "Python/5_1_actor.onnx" as uchar __81_5[]
#include <SRI\PipeLine.mqh>
#define __PATTERNS 3
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signals of Reinforcement Learning with Ichimoku and ADXWilder |
//| Type=SignalAdvanced                                              |
//| Name=Ichimoku and ADXWilder                                      |
//| ShortName=RL_Ichimoku_ADXWilder                                  |
//| Class=CSignalRL_Ichimoku_ADXWilder                               |
//| Page=signal_sar_rvi                                              |
//| Parameter=Pattern_0,int,50,Pattern 0                             |
//| Parameter=Pattern_1,int,50,Pattern 1                             |
//| Parameter=Pattern_5,int,50,Pattern 5                             |
//| Parameter=Look_Back,int,30,Scaler Look Back Period               |
//| Parameter=Scaler_Type,int,1,Scaler Type 0-MinMax, 1-Standard, 2-Robust |
//| Parameter=PatternsUsed,int,255,Patterns Used BitMap              |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CSignalRL_Ichimoku_ADXWilder.                              |
//| Purpose: Class of generator of trade signals based on            |
//|          Signals of ML with Ichimoku and ADXWilder               |
//| Is derived from the CExpertSignal class.                         |
//+------------------------------------------------------------------+
#define __PERIOD 15
class CSignalRL_Ichimoku_ADXWilder : public CExpertSignal
{
protected:
   CiIchimoku        m_ichimoku;
   CiADXWilder       m_adxwilder;

   int               m_patterns_used;

   long              m_handles[__PATTERNS];
   //--- adjusted parameters

   //--- "weights" of market models (0-100)
   int               m_pattern_0;      // model 2
   int               m_pattern_1;      // model 3
   int               m_pattern_5;      // model 5
   //
   int               m_look_back;
   int               m_scaler_type;
   CPreprocessingPipeline m_pipeline;

public:
   CSignalRL_Ichimoku_ADXWilder(void);
   ~CSignalRL_Ichimoku_ADXWilder(void);
   //--- methods of setting adjustable parameters
   //--- methods of adjusting "weights" of market models
   void              Pattern_0(int value)
   {  m_pattern_0 = value;
   }
   void              Pattern_1(int value)
   {  m_pattern_1 = value;
   }
   void              Pattern_5(int value)
   {  m_pattern_5 = value;
   }
   //
   void              Look_Back(int value)
   {  m_look_back = value;
   }
   void              Scaler_Type(int value)
   {  m_scaler_type = value;
   }
   //
   void              PatternsUsed(int value)
   {  m_patterns_used = value;
      PatternsUsage(value);
   }
   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the oscillator and timeseries
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- methods of checking if the market models are formed
   virtual int       LongCondition(void) override;
   virtual int       ShortCondition(void) override;
   //virtual double    Direction(void) override;

protected:
   //--- method of initialization of the oscillator
   bool              InitRL_Ichimoku_ADXWilder(CIndicators *indicators);
   //--- methods of getting data
   double            Ichimoku_TenkanSen(int ind)
   {  //
      m_ichimoku.Refresh(-1);
      return(m_ichimoku.TenkanSen(ind));
   }
   double            Ichimoku_KijunSen(int ind)
   {  //
      m_ichimoku.Refresh(-1);
      return(m_ichimoku.KijunSen(ind));
   }
   double            Ichimoku_SenkouSpanA(int ind)
   {  //
      m_ichimoku.Refresh(-1);
      return(m_ichimoku.SenkouSpanA(ind));
   }
   double            Ichimoku_SenkouSpanB(int ind)
   {  //
      m_ichimoku.Refresh(-1);
      return(m_ichimoku.SenkouSpanB(ind));
   }
   double            Ichimoku_ChinkouSpan(int ind)
   {  //
      m_ichimoku.Refresh(-1);
      return(m_ichimoku.ChinkouSpan(ind));
   }
   double            ADX(int ind)
   {  //
      m_adxwilder.Refresh(-1);
      return(m_adxwilder.Main(ind));
   }
   double            ADX_Plus(int ind)
   {  //
      m_adxwilder.Refresh(-1);
      return(m_adxwilder.Plus(ind));
   }
   double            ADX_Minus(int ind)
   {  //
      m_adxwilder.Refresh(-1);
      return(m_adxwilder.Minus(ind));
   }
   double            Close(int ind)
   {  //
      m_close.Refresh(-1);
      return(m_close.GetData(ind));
   }
   double            High(int ind)
   {  //
      m_high.Refresh(-1);
      return(m_high.GetData(ind));
   }
   double            Low(int ind)
   {  //
      m_low.Refresh(-1);
      return(m_low.GetData(ind));
   }
   int               X()
   {  //
      return(StartIndex());
   }
   //--- methods to check for patterns
   matrixf              IsPattern_0();
   matrixf              IsPattern_1();
   matrixf              IsPattern_5();

   double            RunModel(int Index, ENUM_POSITION_TYPE T, vectorf &X);
};
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CSignalRL_Ichimoku_ADXWilder::CSignalRL_Ichimoku_ADXWilder(void) : m_pattern_0(50),
   m_pattern_1(50),
   m_pattern_5(50)
//m_patterns_usage(255)
{
//--- initialization of protected data
   m_used_series = USE_SERIES_OPEN + USE_SERIES_HIGH + USE_SERIES_LOW + USE_SERIES_CLOSE + USE_SERIES_TICK_VOLUME;
   PatternsUsage(m_patterns_usage);
//--- create model from static buffer
   m_handles[0] = OnnxCreateFromBuffer(__81_0, ONNX_DEFAULT);
   m_handles[1] = OnnxCreateFromBuffer(__81_1, ONNX_DEFAULT);
   m_handles[2] = OnnxCreateFromBuffer(__81_5, ONNX_DEFAULT);
   // 4) Scaling (choose one; scaling applies to all numeric columns now)
   if(m_scaler_type == 0) m_pipeline.AddMinMaxScaler(0.0, 1.0);
   else if(m_scaler_type == 1) m_pipeline.AddStandardScaler();
   else if(m_scaler_type == 2) m_pipeline.AddRobustScaler();
}
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CSignalRL_Ichimoku_ADXWilder::~CSignalRL_Ichimoku_ADXWilder(void)
{
}
//+------------------------------------------------------------------+
//| Validation settings protected data.                              |
//+------------------------------------------------------------------+
bool CSignalRL_Ichimoku_ADXWilder::ValidationSettings(void)
{
//--- validation settings of additional filters
   if(!CExpertSignal::ValidationSettings())
      return(false);
//--- initial data checks
   const ulong _out_shape[] = {1, 1};
   for(int i = 0; i < __PATTERNS; i++)
   {  // Set input shapes
      int _in = 3;
      if(i == __PATTERNS - 1)
      {  _in = 7;
      }
      const ulong _in_shape[] = {1, _in};
      if(!OnnxSetInputShape(m_handles[i], ONNX_DEFAULT, _in_shape))
      {  Print("OnnxSetInputShape error ", GetLastError(), " for feature: ", i);
         return(false);
      }
      // Set output shapes
      if(!OnnxSetOutputShape(m_handles[i], 0, _out_shape))
      {  Print("OnnxSetOutputShape error ", GetLastError(), " for feature: ", i);
         return(false);
      }
   }
//--- ok
   return(true);
}
//+------------------------------------------------------------------+
//| Create indicators.                                               |
//+------------------------------------------------------------------+
bool CSignalRL_Ichimoku_ADXWilder::InitIndicators(CIndicators *indicators)
{
//--- check pointer
   if(indicators == NULL)
      return(false);
//--- initialization of indicators and timeseries of additional filters
   if(!CExpertSignal::InitIndicators(indicators))
      return(false);
//--- create and initialize MA oscillator
   if(!InitRL_Ichimoku_ADXWilder(indicators))
      return(false);
//--- ok
   return(true);
}
//+------------------------------------------------------------------+
//| Initialize MA indicators.                                        |
//+------------------------------------------------------------------+
bool CSignalRL_Ichimoku_ADXWilder::InitRL_Ichimoku_ADXWilder(CIndicators *indicators)
{
//--- check pointer
   if(indicators == NULL)
      return(false);
//--- add object to collection
//--- add object to collection
   if(!indicators.Add(GetPointer(m_ichimoku)))
   {  printf(__FUNCTION__ + ": error adding object");
      return(false);
   }
   if(!indicators.Add(GetPointer(m_adxwilder)))
   {  printf(__FUNCTION__ + ": error adding object");
      return(false);
   }
//--- initialize object
   if(!m_ichimoku.Create(m_symbol.Name(), m_period, 9, 26, 52))
   {  printf(__FUNCTION__ + ": error initializing object");
      return(false);
   }
   if(!m_adxwilder.Create(m_symbol.Name(), m_period, 14))
   {  printf(__FUNCTION__ + ": error initializing object");
      return(false);
   }
//--- ok
   return(true);
}
//+------------------------------------------------------------------+
//| Detecting the "weighted" direction                               |
//+------------------------------------------------------------------+
//double CSignalRL_Ichimoku_ADXWilder::Direction(void)
//{  //return(LongCondition() - ShortCondition());
//}
//+------------------------------------------------------------------+
//| "Voting" that price will grow.                                   |
//+------------------------------------------------------------------+
int CSignalRL_Ichimoku_ADXWilder::LongCondition(void)
{  int result  = 0, results = 0;
   vectorf _x;
//--- if the model 0 is used
   if(((m_patterns_usage & 0x01) != 0))
   {  matrixf _raw = IsPattern_0();
      //Print(" in 0 raw: ", __FUNCTION__, _raw);
      matrixf _fitted(_raw.Rows(), _raw.Cols());
      if(m_pipeline.FitTransformPipeline(_raw, _fitted))
      {  _x = _fitted.Row(0);
         //Print(" buy x: ", __FUNCTION__, _x);
         double _y = RunModel(0, POSITION_TYPE_BUY, _x);
         if(_y > 0.0)
         {  result += m_pattern_0;
            results++;
         }
      }
   }
//--- if the model 1 is used
   if(((m_patterns_usage & 0x02) != 0))
   {  matrixf _raw = IsPattern_1();
      //Print(" in 1 raw: ", __FUNCTION__, _raw);
      matrixf _fitted(_raw.Rows(), _raw.Cols());
      if(m_pipeline.FitTransformPipeline(_raw, _fitted))
      {  _x = _fitted.Row(0);
         double _y = RunModel(1, POSITION_TYPE_BUY, _x);
         if(_y > 0.0)
         {  result += m_pattern_1;
            results++;
         }
      }
   }
//--- if the model 5 is used
   if(((m_patterns_usage & 0x20) != 0))
   {  matrixf _raw = IsPattern_5();
      //Print(" in 5 raw: ", __FUNCTION__, _raw);
      matrixf _fitted(_raw.Rows(), _raw.Cols());
      if(m_pipeline.FitTransformPipeline(_raw, _fitted))
      {  _x = _fitted.Row(0);
         double _y = RunModel(2, POSITION_TYPE_BUY, _x);
         if(_y > 0.0)
         {  result += m_pattern_5;
            results++;
         }
      }
   }
//--- return the result
//if(result > 0)printf(__FUNCSIG__+" result is: %i",result);
   if(results > 0 && result > 0)
   {  return(int(round(result / results)));
   }
   return(0);
}
//+------------------------------------------------------------------+
//| "Voting" that price will fall.                                   |
//+------------------------------------------------------------------+
int CSignalRL_Ichimoku_ADXWilder::ShortCondition(void)
{  int result  = 0, results = 0;
   vectorf _x;
//--- if the model 0 is used
   if(((m_patterns_usage & 0x01) != 0))
   {  matrixf _raw = IsPattern_0();
      matrixf _fitted(_raw.Rows(), _raw.Cols());
      if(m_pipeline.FitTransformPipeline(_raw, _fitted))
      {  _x = _fitted.Row(0);
         //Print(" sell x: ", __FUNCTION__, _x);
         double _y = RunModel(0, POSITION_TYPE_SELL, _x);
         if(_y > 0.0)
         {  result += m_pattern_0;
            results++;
         }
      }
   }
//--- if the model 1 is used
   if(((m_patterns_usage & 0x02) != 0))
   {  matrixf _raw = IsPattern_1();
      matrixf _fitted(_raw.Rows(), _raw.Cols());
      if(m_pipeline.FitTransformPipeline(_raw, _fitted))
      {  _x = _fitted.Row(0);
         double _y = RunModel(1, POSITION_TYPE_SELL, _x);
         if(_y > 0.0)
         {  result += m_pattern_1;
            results++;
         }
      }
   }
//--- if the model 5 is used
   if(((m_patterns_usage & 0x20) != 0))
   {  matrixf _raw = IsPattern_5();
      matrixf _fitted(_raw.Rows(), _raw.Cols());
      if(m_pipeline.FitTransformPipeline(_raw, _fitted))
      {  _x = _fitted.Row(0);
         double _y = RunModel(2, POSITION_TYPE_SELL, _x);
         if(_y > 0.0)
         {  result += m_pattern_5;
            results++;
         }
      }
   }
//--- return the result
//if(result > 0)printf(__FUNCSIG__+" result is: %i",result);
   if(results > 0 && result > 0)
   {  return(int(round(result / results)));
   }
   return(0);
}

//+------------------------------------------------------------------+
//| Check for Pattern 0.                                             |
//+------------------------------------------------------------------+
matrixf CSignalRL_Ichimoku_ADXWilder::IsPattern_0()
{  matrixf _x(m_look_back, 3);
   // Impute missing values with median
   for(int i = 0; i < 3; i++)
   {  m_pipeline.AddImputeMedian(i);
   }
   for(int i = 0; i < m_look_back; i++)
   {  _x[i][0] = float(Close(X() + 1) - Ichimoku_SenkouSpanA(X() + 1));
      _x[i][1] = float(Close(X()) - Ichimoku_SenkouSpanA(X()));
      _x[i][2] = float(ADX(X()) - 25.0);
   }
   return(_x);
}
//+------------------------------------------------------------------+
//| Check for Pattern 1.                                             |
//+------------------------------------------------------------------+
matrixf CSignalRL_Ichimoku_ADXWilder::IsPattern_1()
{  matrixf _x(m_look_back, 3);
   // Impute missing values with median
   for(int i = 0; i < 3; i++)
   {  m_pipeline.AddImputeMedian(i);
   }
   for(int i = 0; i < m_look_back; i++)
   {  _x[i][0] = float(Ichimoku_TenkanSen(X() + 1) - Ichimoku_KijunSen(X() + 1));
      _x[i][1] = float(Ichimoku_TenkanSen(X()) - Ichimoku_KijunSen(X()));
      _x[i][2] = float(ADX(X()) - 20.0);
   }
   return(_x);
}
//+------------------------------------------------------------------+
//| Check for Pattern 5.                                             |
//+------------------------------------------------------------------+
matrixf CSignalRL_Ichimoku_ADXWilder::IsPattern_5()
{  matrixf _x(m_look_back, 7);
   // Impute missing values with median
   for(int i = 0; i < 7; i++)
   {  m_pipeline.AddImputeMedian(i);
   }
   for(int i = 0; i < m_look_back; i++)
   {  _x[i][0] = float(Close(X() + 2 + i) - Close(X() + 1 + i));
      _x[i][1] = float(Close(X() + 1 + i) - Close(X() + i));
      _x[i][2] = float(Close(X() + 2 + i) - Ichimoku_TenkanSen(X() + 2 + i));
      _x[i][3] = float(Close(X() + i) - Ichimoku_TenkanSen(X() + i));
      _x[i][4] = float(Close(X() + 1 + i) - Ichimoku_TenkanSen(X() + 1 + i));
      _x[i][5] = float(ADX_Plus(X() + i) - ADX_Minus(X() + i));
      _x[i][6] = float(ADX(X()) - 25.0);
   }
   return(_x);
}
//+------------------------------------------------------------------+
//| Forward Feed Network, to Get Forecast State.                     |
//+------------------------------------------------------------------+
double CSignalRL_Ichimoku_ADXWilder::RunModel(int Index, ENUM_POSITION_TYPE T, vectorf &X)
{  vectorf _y(1);
   _y.Fill(0.0);
   //Print(" in x: ", __FUNCTION__, X);
   ResetLastError();
   if(!OnnxRun(m_handles[Index], ONNX_NO_CONVERSION, X, _y))
   {  printf(__FUNCSIG__ + " failed to get y forecast, err: %i", GetLastError());
      return(double(_y[0]));
   }
   //printf(__FUNCSIG__ + " pre y is: " + DoubleToString(_y[0], 5));
   if(T == POSITION_TYPE_BUY && _y[0] > 0.5f)
   {  _y[0] = 2.0f * (_y[0] - 0.5f);
   }
   else if(T == POSITION_TYPE_SELL && _y[0] < 0.5f)
   {  _y[0] = 2.0f * (0.5f - _y[0]);
   }
   //printf(__FUNCSIG__ + " post y is: ", DoubleToString(_y[0], 5));
   return(double(_y[0]));
}
//+------------------------------------------------------------------+
