//+------------------------------------------------------------------+
//|                                                   SignalWVAE.mqh |
//|                             Copyright 2000-2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signals of Inference Learning with ADX and Ichimoku.       |
//| Type=SignalAdvanced                                              |
//| Name=IL_Ichimoku_ADXWilder                                       |
//| ShortName=IL_Ichimoku_ADXWilder                                  |
//| Class=CSignalIL_Ichimoku_ADXWilder                               |
//| Page=signal_il_ichimoku_wilder                                   |
//| Parameter=Pattern_0,int,50,Pattern 0 [0...100]                   |
//| Parameter=Pattern_1,int,50,Pattern 1 [0...100]                   |
//| Parameter=Pattern_5,int,50,Pattern 5 [0...100]                   |
//| Parameter=PatternUsed,uchar,0,Pattern Used [0...8]               |
//| Parameter=PeriodUsed,int,8,Used Period [3...55]                  |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CSignalIL_Ichimoku_ADXWilder.                              |
//| Purpose: Class of generator of trade signals based on            |
//|          Inference Learning with ADX and Ichimoku.               |
//| Is derived from the CExpertSignal class.                         |
//+------------------------------------------------------------------+
//
#resource "Python/81_.onnx" as uchar __81[]
//
#define  __PATTERNS 1
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CSignalIL_Ichimoku_ADXWilder : public CExpertSignal
{
protected:
   CiIchimoku        m_ichimoku;
   CiADXWilder       m_adxwilder;

   //long              m_handles[__PATTERNS];
   //--- adjusted parameters

   //--- "weights" of market models (0-100)
   int               m_pattern_0;      // model 0
   int               m_pattern_1;      // model 1
   int               m_pattern_5;      // model 5

   int               m_periods;

   uchar             m_pattern_used;
   //
   //int               m_patterns_usage;   //

public:
   CSignalIL_Ichimoku_ADXWilder(void);
   ~CSignalIL_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              PatternUsed(uchar value)
   {  m_pattern_used = value;
   }

   void              PeriodUsed(int value)
   {  m_periods = value;
   }

   long              m_handles[__PATTERNS];

   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the oscillator and timeseries
   //--- 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);
   virtual int       ShortCondition(void);

protected:
   //--- 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
   bool              IsPattern_0(ENUM_POSITION_TYPE T);
   bool              IsPattern_1(ENUM_POSITION_TYPE T);
   bool              IsPattern_5(ENUM_POSITION_TYPE T);

   double   Infer(ENUM_POSITION_TYPE T, vectorf &X);
};
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CSignalIL_Ichimoku_ADXWilder::CSignalIL_Ichimoku_ADXWilder(void) : m_pattern_1(50),
   m_pattern_0(50),
   m_pattern_5(50)
//m_patterns_usage(255)
{
//--- initialization of protected data
   m_used_series = USE_SERIES_CLOSE + USE_SERIES_TIME;
   PatternsUsage(m_patterns_usage);
//--- create model from static buffer
   m_handles[0] = OnnxCreateFromBuffer(__81, ONNX_DEFAULT);
}
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CSignalIL_Ichimoku_ADXWilder::~CSignalIL_Ichimoku_ADXWilder(void)
{
}
//+------------------------------------------------------------------+
//| Validation settings protected data.                              |
//+------------------------------------------------------------------+
bool CSignalIL_Ichimoku_ADXWilder::ValidationSettings(void)
{
//--- validation settings of additional filters
   if(!CExpertSignal::ValidationSettings())
      return(false);
//--- initial data checks
   // Set input shapes
   const long _in_shape[] = {1, 6};
   const long _out_shape[] = {1, 1};
   if(!OnnxSetInputShape(m_handles[0], ONNX_DEFAULT, _in_shape))
   {  Print("OnnxSetInputShape error ", GetLastError());
      return(false);
   }
   // Set output shapes
   if(!OnnxSetOutputShape(m_handles[0], 0, _out_shape))
   {  Print("OnnxSetOutputShape error ", GetLastError());
      return(false);
   }
//--- ok
   return(true);
}
//+------------------------------------------------------------------+
//| Initialize MA indicators.                                        |
//+------------------------------------------------------------------+
bool CSignalIL_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);
//--- initialize object
   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);
}
//+------------------------------------------------------------------+
//| "Voting" that price will grow.                                   |
//+------------------------------------------------------------------+
int CSignalIL_Ichimoku_ADXWilder::LongCondition(void)
{  int result  = 0, results = 0;
   vectorf _x(6);
   _x.Fill(0.0f);
//--- if the model 0 is used
   if(IsPattern_0(POSITION_TYPE_BUY))
   {  _x[0] = 1.0f;
      result += m_pattern_0;
      results++;
   }
//--- if the model 1 is used
   if(IsPattern_1(POSITION_TYPE_BUY))
   {  _x[2] = 1.0f;
      result += m_pattern_1;
      results++;
   }
//--- if the model 5 is used
   if(IsPattern_1(POSITION_TYPE_BUY))
   {  _x[4] = 1.0f;
      result += m_pattern_5;
      results++;
   }
   double _y = Infer(POSITION_TYPE_BUY, _x);
//--- return the result
   if(_y > 0.0 && results > 0)
   {  return(int(round(result / results)));
   }
   return(0);
}
//+------------------------------------------------------------------+
//| "Voting" that price will fall.                                   |
//+------------------------------------------------------------------+
int CSignalIL_Ichimoku_ADXWilder::ShortCondition(void)
{  int result  = 0, results = 0;
   vectorf _x(6);
   _x.Fill(0.0f);
//--- if the model 0 is used
   if(IsPattern_0(POSITION_TYPE_SELL))
   {  _x[1] = 1.0f;
      result += m_pattern_0;
      results++;
   }
//--- if the model 1 is used
   if(IsPattern_1(POSITION_TYPE_SELL))
   {  _x[3] = 1.0f;
      result += m_pattern_1;
      results++;
   }
//--- if the model 5 is used
   if(IsPattern_5(POSITION_TYPE_SELL))
   {  _x[5] = 1.0f;
      result += m_pattern_5;
      results++;
   }
   double _y = Infer(POSITION_TYPE_SELL, _x);
//--- return the result
   if(_y < 0.0 && results > 0)
   {  return(int(round(result / results)));
   }
   return(0);
}
//+------------------------------------------------------------------+
//| Check for Pattern 0.                                             |
//+------------------------------------------------------------------+
bool CSignalIL_Ichimoku_ADXWilder::IsPattern_0(ENUM_POSITION_TYPE T)
{  if(T == POSITION_TYPE_BUY && Close(X() + 1) < Ichimoku_SenkouSpanA(X() + 1) && Close(X()) > Ichimoku_SenkouSpanA(X()) && ADX(X()) >= 25.0)
   {  return(true);
   }
   else if(T == POSITION_TYPE_SELL && Close(X() + 1) > Ichimoku_SenkouSpanA(X() + 1) && Close(X()) < Ichimoku_SenkouSpanA(X()) && ADX(X()) >= 25.0)
   {  return(true);
   }
   return(false);
}
//+------------------------------------------------------------------+
//| Check for Pattern 1.                                             |
//+------------------------------------------------------------------+
bool CSignalIL_Ichimoku_ADXWilder::IsPattern_1(ENUM_POSITION_TYPE T)
{  if(T == POSITION_TYPE_BUY && Ichimoku_TenkanSen(X() + 1) < Ichimoku_KijunSen(X() + 1) && Ichimoku_TenkanSen(X()) > Ichimoku_KijunSen(X()) && ADX(X()) >= 20.0)
   {  return(true);
   }
   else if(T == POSITION_TYPE_SELL && Ichimoku_TenkanSen(X() + 1) > Ichimoku_KijunSen(X() + 1) && Ichimoku_TenkanSen(X()) < Ichimoku_KijunSen(X()) && ADX(X()) >= 20.0)
   {  return(true);
   }
   return(false);
}
//+------------------------------------------------------------------+
//| Check for Pattern 5.                                             |
//+------------------------------------------------------------------+
bool CSignalIL_Ichimoku_ADXWilder::IsPattern_5(ENUM_POSITION_TYPE T)
{  if(T == POSITION_TYPE_BUY &&
         Close(X() + 2) > Close(X() + 1) && Close(X() + 1) < Close(X()) &&
         Close(X() + 2) > Ichimoku_TenkanSen(X() + 2) && Close(X()) > Ichimoku_TenkanSen(X()) &&
         Close(X() + 1) <= Ichimoku_TenkanSen(X() + 1) &&
         ADX_Plus(X()) > ADX_Minus(X()) && ADX(X()) >= 25.0
     )
   {  return(true);
   }
   else if(T == POSITION_TYPE_SELL &&
           Close(X() + 2) < Close(X() + 1) && Close(X() + 1) > Close(X()) &&
           Close(X() + 2) < Ichimoku_TenkanSen(X() + 2) && Close(X()) < Ichimoku_TenkanSen(X()) &&
           Close(X() + 1) >= Ichimoku_TenkanSen(X() + 1) &&
           ADX_Plus(X()) < ADX_Minus(X()) && ADX(X()) >= 25.0
          )
   {  return(true);
   }
   return(false);
}
//+------------------------------------------------------------------+
//| Inference Learning Forward Pass.                                 |
//+------------------------------------------------------------------+
double CSignalIL_Ichimoku_ADXWilder::Infer(ENUM_POSITION_TYPE T, vectorf &X)
{  vectorf _y(1);
   _y.Fill(0.0);
   Print(" x: ", __FUNCTION__, X);
   ResetLastError();
   if(!OnnxRun(m_handles[0], ONNX_NO_CONVERSION, X, _y))
   {  printf(__FUNCSIG__ + " failed to get y forecast, err: %i", GetLastError());
      return(double(_y[0]));
   }
   printf(__FUNCSIG__ + " post y is: ", DoubleToString(_y[0], 5));
   return(double(_y[0]));
}
//+------------------------------------------------------------------+
