//+------------------------------------------------------------------+
//|                                                    Ozymandis.mqh |
//|                      Copyright 2020, Igor Ryabchikov (aka Rigal) |
//|                     https://tlap.com/forum/profile/109537-rigal/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, Igor Ryabchikov (aka Rigal)"
#property link      "https://tlap.com/forum/profile/109537-rigal/"
#property strict
#include <Indicators/Indicators.mqh>
#include <PolyLine.mqh>

class COzymandis : public CIndicator {
   string  symbol;
   ENUM_TIMEFRAMES timeFrame;
   int amplitude;
   bool nexttrend;
   double minh, maxl, up[], down[], atrlo[], atrhi[];
   int trend[];
   int workingBar;
   bool draw;
   CiMA maLow, maHigh;
   CiATR iatr;
   int countedBars;
   
   void CheckResize() {
      int bars = iBars(symbol, timeFrame);
      if(ArraySize(trend) < bars){
         ArraySetAsSeries(up, false);
         ArraySetAsSeries(down, false);
         ArraySetAsSeries(trend, false);
         ArraySetAsSeries(atrlo, false);
         ArraySetAsSeries(atrhi, false);

         ArrayResize(up, bars);
         ArrayResize(down, bars);
         ArrayResize(trend, bars);
         ArrayResize(atrlo, bars);
         ArrayResize(atrhi, bars);

         ArraySetAsSeries(up, true);
         ArraySetAsSeries(down, true);
         ArraySetAsSeries(trend, true);
         ArraySetAsSeries(atrlo, true);
         ArraySetAsSeries(atrhi, true);
      }
   }   


public:
   COzymandis(){
      nexttrend = 0;
      countedBars = 0;
   }
   ~COzymandis(){};
   
   void Create(const string  _symbol,
               const ENUM_TIMEFRAMES _timeFrame,
               const int _amplitude,
               int _workingBar,
               bool _draw = true)  {
      symbol = _symbol;
      timeFrame = _timeFrame;
      amplitude = _amplitude;
      workingBar =  _workingBar;
      draw =  _draw;
      minh = iHigh(symbol, timeFrame, iBars(symbol, timeFrame) - 1);
      maxl = iLow(symbol, timeFrame, iBars(symbol, timeFrame) - 1);
      maLow.Create(symbol, timeFrame, amplitude, 0, MODE_SMA, PRICE_LOW);
      maHigh.Create(symbol, timeFrame, amplitude, 0, MODE_SMA, PRICE_HIGH);
      iatr.Create(symbol, timeFrame, 100);
      SetSymbolPeriod(symbol, timeFrame);
   }
   
   void Refresh(const int flags=OBJ_ALL_PERIODS) {
      CheckResize();
      maLow.Refresh();
      maHigh.Refresh();
      iatr.Refresh();
      double atr, ll, hh, lma, hma;
      int limit = iBars(symbol, timeFrame) - countedBars;
      if(countedBars == 0)
         limit -= 2;
      if(limit < workingBar)
         limit = workingBar;
      for (int i = limit; i >= workingBar; i --) {
       ll = iLow (symbol, timeFrame,
         iLowest (symbol, timeFrame, MODE_LOW, amplitude, i));
       hh = iHigh (symbol, timeFrame,
         iHighest (symbol, timeFrame, MODE_HIGH, amplitude, i));
       lma = maLow.Main(i);
       hma = maHigh.Main(i);
       trend[i] = trend[i + 1];
       atr = iatr.Main(i) / 2;
      
       if (nexttrend == OP_SELL) {
         maxl = MathMax (ll, maxl);
      
         if (hma < maxl
         && iClose(symbol, timeFrame, i) < iLow(symbol, timeFrame, i + 1)) {
           trend[i] = OP_SELL;
           nexttrend = OP_BUY;
           minh = hh;
         }
       }
      
       if (nexttrend == OP_BUY) {
         minh = MathMin (hh, minh);
      
         if (lma > minh
         && iClose(symbol, timeFrame, i) > iHigh(symbol, timeFrame, i + 1)) {
           trend[i] = OP_BUY;
           nexttrend = OP_SELL;
           maxl = ll;
         }
       }
      
       if (trend[i] == OP_BUY) {
         if (trend[i + 1] != OP_BUY) {
           up[i] = down[i + 1];
           up[i + 1] = up[i];
         } else {
           up[i] = MathMax (maxl, up[i + 1]);
         }
      
         atrhi[i] = up[i] + atr;
         atrlo[i] = up[i] - atr;
         down[i] = 0.0;
       } else {
         if (trend[i + 1] != OP_SELL) {
           down[i] = up[i + 1];
           down[i + 1] = down[i];
         } else {
           down[i] = MathMin (minh, down[i + 1]);
         }
      
         atrhi[i] = down[i] + atr;
         atrlo[i] = down[i] - atr;
         up[i] = 0.0;
       }
      }
       if(draw) {
          if(trend[workingBar] == OP_BUY)
            PolyLine::Draw("OZY", up[workingBar], clrSkyBlue);
          else
            PolyLine::Draw("OZY", down[workingBar], clrTomato);
       }
      countedBars = iBars(symbol, timeFrame);
   }
   double GetData(const int buffer_num,  const int index) const { 
      switch(buffer_num)  {
      case 0: return (up[index]); break;
      case 1: return (down[index]); break;
      case 2: return (atrlo[index]); break;
      case 3: return (atrhi[index]); break;
      case 4: return (trend[index]); break;
      }
      return (0); 
   }
   int GetTrend(const int index) const {
      return (trend[index]);
   }
   
};