//+------------------------------------------------------------------+
//|                                         FeatureExtractor.mqh     |
//|                OHLCV Feature Outlier Detection Engine            |
//+------------------------------------------------------------------+
#ifndef FEATURE_EXTRACTOR_MQH
#define FEATURE_EXTRACTOR_MQH

//+------------------------------------------------------------------+
//| Feature Extractor Class                                          |
//+------------------------------------------------------------------+
class CFeatureExtractor
  {
private:
   double             m_body[];
   double             m_upper_wick[];
   double             m_lower_wick[];
   double             m_volume[];
   int                m_count;

public:
                     CFeatureExtractor(void);
                    ~CFeatureExtractor(void);
   bool               Extract(const double &open[],
                              const double &high[],
                              const double &low[],
                              const double &close[],
                              const long   &tick_volume[],
                              int           count);
   int                GetCount(void) const;
   double             GetBody(int index) const;
   double             GetUpperWick(int index) const;
   double             GetLowerWick(int index) const;
   double             GetVolume(int index) const;
  };

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CFeatureExtractor::CFeatureExtractor(void)
   : m_count(0)
  {
  }

//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CFeatureExtractor::~CFeatureExtractor(void)
  {
   ArrayFree(m_body);
   ArrayFree(m_upper_wick);
   ArrayFree(m_lower_wick);
   ArrayFree(m_volume);
  }

//+------------------------------------------------------------------+
//| Extract OHLCV features for all bars in the window                |
//+------------------------------------------------------------------+
bool CFeatureExtractor::Extract(const double &open[],
                                const double &high[],
                                const double &low[],
                                const double &close[],
                                const long   &tick_volume[],
                                int           count)
  {
   m_count = count;

   if(m_count <= 0)
      return(false);

   ArrayResize(m_body,       m_count);
   ArrayResize(m_upper_wick, m_count);
   ArrayResize(m_lower_wick, m_count);
   ArrayResize(m_volume,      m_count);

   for(int i = 0; i < m_count; i++)
     {
      double o = open[i];
      double h = high[i];
      double l = low[i];
      double c = close[i];

      m_body[i]       = MathAbs(c - o);                     // Body size
      m_upper_wick[i] = h - MathMax(o, c);                  // Upper wick
      m_lower_wick[i] = MathMin(o, c) - l;                  // Lower wick
      m_volume[i]     = (double)tick_volume[i];                // Tick volume
     }

   return(true);
  }

//+------------------------------------------------------------------+
//| Get total processed elements count                               |
//+------------------------------------------------------------------+
int CFeatureExtractor::GetCount(void) const
  {
   return(m_count);
  }

//+------------------------------------------------------------------+
//| Get body size at specified index                                 |
//+------------------------------------------------------------------+
double CFeatureExtractor::GetBody(int index) const
  {
   return(m_body[index]);
  }

//+------------------------------------------------------------------+
//| Get upper wick size at specified index                           |
//+------------------------------------------------------------------+
double CFeatureExtractor::GetUpperWick(int index) const
  {
   return(m_upper_wick[index]);
  }

//+------------------------------------------------------------------+
//| Get lower wick size at specified index                           |
//+------------------------------------------------------------------+
double CFeatureExtractor::GetLowerWick(int index) const
  {
   return(m_lower_wick[index]);
  }

//+------------------------------------------------------------------+
//| Get tick volume at specified index                               |
//+------------------------------------------------------------------+
double CFeatureExtractor::GetVolume(int index) const
  {
   return(m_volume[index]);
  }

#endif // FEATURE_EXTRACTOR_MQH
//+------------------------------------------------------------------+