//+------------------------------------------------------------------+
//|                                             OLAPTradesCustom.mqh |
//|                                      Copyright © 2020, Marketeer |
//|                          https://www.mql5.com/en/users/marketeer |
//|               Online Analytical Processing of trading hypercubes |
//|                            https://www.mql5.com/en/articles/6602 |
//|                            https://www.mql5.com/en/articles/6603 |
//|                            https://www.mql5.com/en/articles/7535 |
//|                            https://www.mql5.com/en/articles/7656 |
//|                                                  rev. 25.02.2020 |
//+------------------------------------------------------------------+

class CustomTradeRecord;

#define RECORD_CLASS CustomTradeRecord

#include "OLAPTrades.mqh"

class CustomTradeRecord: public TradeRecord
{
  private:
    // Start-up time announcement of custom fields specialization
    class CustomFieldsDescription
    {
      private:
        CustomFieldsDescription()
        {
          Print("Custom fields processing attached:");
          Print("FIELD_CUSTOM1 == Single Trade MFE (%)");
          Print("FIELD_CUSTOM2 == Single Trade MAE (%)");
        }

      public:
        static CustomFieldsDescription *instantiate()
        {
          static CustomFieldsDescription instance;
          return &instance;
        }
    };

  public:
    CustomTradeRecord(): TradeRecord()
    {
    }
    CustomTradeRecord(const double balance): TradeRecord(balance)
    {
      fillCustomFields();
    }
    
    // calculate MFE/MAE in percents
    virtual void fillCustomFields() override
    {
      static CustomFieldsDescription *legend = CustomFieldsDescription::instantiate();

      double positiveExcursion = 0, negativeExcursion = 0;
      string symbol = symbols[(int)get(FIELD_SYMBOL)];
      int t1 = iBarShift(symbol, _Period, (datetime)get(FIELD_OPEN_DATETIME), false);
      int t2 = iBarShift(symbol, _Period, (datetime)get(FIELD_CLOSE_DATETIME), false);
      int type = (int)get(FIELD_TYPE);
      double open = get(FIELD_OPEN_PRICE);
      double close = get(FIELD_CLOSE_PRICE);

      for(int t = t1; t >= t2; t--)
      {
        if(type == OP_BUY)
        {
          positiveExcursion = MathMax(positiveExcursion, MathMax((iHigh(symbol, _Period, t) - close), 0) / close);
          negativeExcursion = MathMin(negativeExcursion, MathMin((iLow(symbol, _Period, t) - open), 0) / open);
        }
        else if(type == OP_SELL)
        {
          positiveExcursion = MathMax(positiveExcursion, MathMax((close - iLow(symbol, _Period, t)), 0) / close);
          negativeExcursion = MathMin(negativeExcursion, MathMin((open - iHigh(symbol, _Period, t)), 0) / open);
        }
      }
      set(TRADE_RECORD_FIELDS::FIELD_CUSTOM_1, positiveExcursion * 100);
      set(TRADE_RECORD_FIELDS::FIELD_CUSTOM_2, negativeExcursion * 100);
    }

    virtual string legend(const int index) const override
    {
      if(index == TRADE_RECORD_FIELDS::FIELD_CUSTOM_1) return "MFE per trade(%)";
      else
      if(index == TRADE_RECORD_FIELDS::FIELD_CUSTOM_2) return "MAE per trade(%)";
      
      return TradeRecord::legend(index);
    }
};
