//-----------------------------------------------------------------------------
//                                                 Mn Fractal                  |
//-----------------------------------------------------------------------------

#property copyright "Mn"
#property link      ""

#property indicator_chart_window
#property indicator_buffers 3
#property indicator_color1 Red
#property indicator_color2 Blue
#property indicator_color3 White
#property indicator_width1  0
#property indicator_width2  0
#property indicator_width3  2

extern int  mSize = 6, 
            mHist = 600, 
            mFractCount = 2;
extern bool mDrawMid = false, 
            mShowLine = false,
            mDrawArrows = true,
            mShowRetrace = true;
extern int  mCorner = 1,
            mTextSize = 10;
extern color mCol = Blue;

double mPeak[], mTrough[], mZline[], mPrevVals[4];
double mPk, mTr, mHrev, mLrev;

//-----------------------------------------------------------------------------
void init() {
  SetIndexBuffer(0, mPeak);
  SetIndexBuffer(1, mTrough);
  SetIndexBuffer(2, mZline);
  
  SetIndexEmptyValue(0, 0);
  SetIndexEmptyValue(1, 0);
  SetIndexEmptyValue(2, 0);
  
  if(mDrawArrows)
   {
    SetIndexStyle(0, DRAW_ARROW);
    SetIndexArrow(0, 234);

    SetIndexStyle(1, DRAW_ARROW);
    SetIndexArrow(1, 233);  
   }
  else
   {
    SetIndexStyle(0, DRAW_NONE);
    SetIndexStyle(1, DRAW_NONE);
   }
   
  SetIndexStyle(2, DRAW_SECTION, 0, 2);
  
  ObjectCreate("mMidLine", OBJ_HLINE, 0, 0, 0, 0, 0);
  ObjectSet("mMidLine", OBJPROP_WIDTH, 3);
  ObjectSet("mMidLine", OBJPROP_COLOR, LightCyan);
  ObjectSet("mMidLine", OBJPROP_PRICE1, 0);
  ObjectSet("mMidLine", OBJPROP_BACK, true);

  ObjectCreate("mEntryLine", OBJ_HLINE, 0, 0, 0, 0, 0);
  ObjectSet("mEntryLine", OBJPROP_WIDTH, 2);
  ObjectSet("mEntryLine", OBJPROP_COLOR, Gold);
  ObjectSet("mEntryLine", OBJPROP_PRICE1, 0);
  ObjectSet("mEntryLine", OBJPROP_BACK, true);

   ObjectCreate("mFracPcnt", OBJ_LABEL, 0, 0, 0, 0); 
   ObjectSet("mFracPcnt", OBJPROP_CORNER, mCorner);
   ObjectSet("mFracPcnt", OBJPROP_XDISTANCE, 2);      
   ObjectSet("mFracPcnt", OBJPROP_YDISTANCE, 2);
   ObjectSet("mFracPcnt", OBJPROP_COLOR, mCol);

  ArrayInitialize(mPrevVals, 0);
  mPrevVals[2] = 9999; mPrevVals[3] = 9999;
  
}

//-----------------------------------------------------------------------------
void start() 
{
  double mPcnt;
  static int LastPk, LastLow;
  int mHcnt, mLcnt;
  static bool mWasPk;
    
  for (int i = mHist + mSize; i >= 1; i--) 
  {
    if ((!mWasPk || mPk < High[i]) && IsPeak(i, mSize) && High[i]  != High[i+1]) 
      {
        if(mWasPk)
         {
          mPeak[LastPk] = 0;
          mZline[LastPk] = 0;
         }
        mPeak[i] = High[i]; 
        mPk = mPeak[i]; 
        LastPk = i;
        if(mShowLine)
          mZline[i] = High[i];
        mWasPk = true;
        mPrevVals[1] = mPrevVals[0];  mPrevVals[0] = mPeak[i];  
      }
    if ((mWasPk || mTr > Low[i]) && IsTrough(i, mSize) && Low[i] != Low[i+1]) 
      {
        if(!mWasPk)
         {
          mTrough[LastLow] = 0;
          mZline[LastLow] = 0;
         }
        mTrough[i] = Low[i]; 
        mTr = mTrough[i]; 
        LastLow = i;
        if(mShowLine)
          mZline[i] = Low[i];
        mWasPk = false;
        mPrevVals[3] = mPrevVals[2];  mPrevVals[2] = mTrough[i];  
      }
  }

 /*    if(mPrevVals[1] < mPrevVals[0] && !mWasPk)     // new high
       ObjectSet("mEntryLine", OBJPROP_PRICE1, (mPrevVals[0] + mPrevVals[3]) / 2);
     else if(mWasPk)
       ObjectSet("mEntryLine", OBJPROP_PRICE1, (mPrevVals[0] + mPrevVals[2]) / 2);
     if(mPrevVals[3] > mPrevVals[2])     // new low
       ObjectSet("mEntryLine", OBJPROP_PRICE1, (mPrevVals[0] + mPrevVals[2]) / 2);
     else if(!mWasPk)
       ObjectSet("mEntryLine", OBJPROP_PRICE1, (mPrevVals[1] + mPrevVals[2]) / 2);
*/
  mHrev = 0;  mLrev = 9999; mHcnt = 0; mLcnt = 0;
  for (int z = 1; z < 300; z++) 
   {
     if(mPeak[z] > 0 && mHcnt < mFractCount)
       {
         if(mPeak[z] > mHrev)
           mHrev = mPeak[z];
         mHcnt ++;
       }
     if(mTrough[z] > 0 && mLcnt < mFractCount)
       {
         if(mTrough[z] < mLrev)
           mLrev = mTrough[z];
         mLcnt ++;
       }
   }

   if(mDrawMid)
     ObjectSet("mMidLine", OBJPROP_PRICE1, (mHrev + mLrev) / 2);
   
   if(mShowRetrace)
     {
         mPcnt = (Close[0] - mLrev) / (mHrev - mLrev) * 100;
         ObjectSetText("mFracPcnt", DoubleToStr(mPcnt, 1) + "%  " + DoubleToStr(mHrev, Digits) + 
                      " : " + DoubleToStr(mLrev, Digits), mTextSize, "Arial Bold", mCol);
     }
}

//-----------------------------------------------------------------------------
void deinit()
 {
   ObjectDelete("mMidLine");
   ObjectDelete("mEntryLine");
   ObjectDelete("mFracPcnt");
 }

//-----------------------------------------------------------------------------
bool IsPeak(int mBar, int mPrd) 
{
  for (int i = 1; i <= mPrd; i++) 
  {
    if (mBar + i >= Bars || mBar - i < 0) return (false);

    if (High[mBar] < High[mBar + i]) return (false);
    if (High[mBar] < High[mBar - i]) return (false);
  }
  
  return (true);
}

//-----------------------------------------------------------------------------
bool IsTrough(int mBar, int mPrd) 
{
  for (int i = 1; i <= mPrd; i++) 
  {
    if (mBar + i >= Bars || mBar - i < 0) return (false);
    
    if (Low[mBar] > Low[mBar + i]) return (false);
    if (Low[mBar] > Low[mBar - i]) return (false);
  }
  
  return (true);
}

//-----------------------------------------------------------------------------

