//+------------------------------------------------------------------+
//|                                              Peak_and_Trough.mq4 |
//|                                        Copyright © 2010, k-matsu |
//|                               http://www.age.jp/~k-matsu/FX/MT4/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2010, k-matsu"
#property link      "http://www.age.jp/~k-matsu/FX/MT4/"

#property indicator_chart_window
#property indicator_buffers 4
//#property indicator_buffers 2
#property indicator_color1 Aqua
#property indicator_color2 Yellow
//#property indicator_color3 Red
//#property indicator_color4 Green
//---- input parameters
extern int       SwingMargin=4;
extern double    ArrowMarginPoint=1;
//---- buffers
double PeakBuffer[];
double TroughBuffer[];
//double LowPeakBuffer[];
//double HighTroughBuffer[];
//----
double ArrowMargin;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//---- indicators
   IndicatorBuffers(2);
//   IndicatorBuffers(4);
   SetIndexStyle(0,DRAW_ARROW);
   SetIndexArrow(0,218);
   SetIndexBuffer(0,PeakBuffer);
   SetIndexEmptyValue(0,0.0);
   SetIndexStyle(1,DRAW_ARROW);
   SetIndexArrow(1,217);
   SetIndexBuffer(1,TroughBuffer);
   SetIndexEmptyValue(1,0.0);
/*
   SetIndexStyle(2,DRAW_ARROW);
   SetIndexArrow(2,218);
   SetIndexBuffer(2,LowPeakBuffer);
   SetIndexEmptyValue(2,0.0);
   SetIndexStyle(3,DRAW_ARROW);
   SetIndexArrow(3,217);
   SetIndexBuffer(3,HighTroughBuffer);
   SetIndexEmptyValue(3,0.0);
*/
//----

   // parameter check
   if (SwingMargin < 1) SwingMargin = 1;

   ArrowMargin = ArrowMarginPoint * Point;
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
    int limit;
    int prevpeakidx, prevtroughidx;
    int counted_bars = IndicatorCounted();
    if (counted_bars > 0) counted_bars--;

    limit = Bars - counted_bars;
    for (int i = 1; i< limit; i++) {
      PeakBuffer[i] = EMPTY_VALUE;
      TroughBuffer[i] = EMPTY_VALUE;
/*
      LowPeakBuffer[i] = EMPTY_VALUE;
      HighTroughBuffer[i] = EMPTY_VALUE;
*/
    }

    prevpeakidx = 1;
    for (limit = 3; limit < Bars-1 && PeakBuffer[limit] == EMPTY_VALUE; limit++) {}
    if (limit > SwingMargin) {
      for (i = 2; i< limit && High[i] == High[1]; i++) {}
      if (High[i] < High[1]) {
        i = searchNextTroughIdx(MODE_HIGH, i, limit, 1) + 1;
      }
      while (i < limit) {
        i = searchNextPeakIdx(MODE_HIGH, i, limit, SwingMargin);
        if (PeakBuffer[i] == EMPTY_VALUE) {
          if (i - prevpeakidx >= SwingMargin) {
            if (iHighest(NULL, 0, MODE_HIGH, SwingMargin*2+1, i-SwingMargin) == i) {
              PeakBuffer[i] = High[i] + ArrowMargin;
              prevpeakidx = i;
            }
          }
          i = searchNextTroughIdx(MODE_HIGH, i+1, limit, 1);
//          HighTroughBuffer[i] = High[i] - ArrowMargin;
          i++;
        } else {
          i = limit;
        }
      }
    }

    prevtroughidx = 1;
    for (limit = 3; limit < Bars-1 && TroughBuffer[limit] == EMPTY_VALUE; limit++) {}
    if (limit > SwingMargin) {
      for (i = 2; i< limit && Low[i] == Low[1]; i++) {}
      if (Low[i] > Low[1]) {
        i = searchNextPeakIdx(MODE_LOW, i, limit, 1) + 1;
      }
      while (i < limit) {
        i = searchNextTroughIdx(MODE_LOW, i, limit, SwingMargin);
        if (TroughBuffer[i] == EMPTY_VALUE) {
          if (i - prevtroughidx >= SwingMargin) {
            if (iLowest(NULL, 0, MODE_LOW, SwingMargin*2+1, i-SwingMargin) == i) {
              TroughBuffer[i] = Low[i] - ArrowMargin;
              prevtroughidx = i;
            }
          }
          i = searchNextPeakIdx(MODE_LOW, i+1, limit, 1);
//          LowPeakBuffer[i] = Low[i] + ArrowMargin;
          i++;
        } else {
          i = limit;
        }
      }
    }
//----
   
//----
   return(0);
  }
//+------------------------------------------------------------------+

// subfunction

// need call after searchNextTroughIdx
int searchNextPeakIdx(int mode, int startidx, int limit, int margin)
{
  int retidx, nextstartidx = startidx, prevpeakidx = nextstartidx, count;

  count = margin*2+1;  
  if (nextstartidx+count > limit) count = limit-nextstartidx+1;

  retidx = iHighest(NULL, 0, mode, count, nextstartidx);
  while (retidx > prevpeakidx && retidx < limit) {
    prevpeakidx = retidx;

    nextstartidx =prevpeakidx-margin;
    if (nextstartidx <= startidx) nextstartidx = startidx+1;

    count = margin*2+1;
    if (nextstartidx+count >= limit) count = limit-nextstartidx+1;

    retidx = iHighest(NULL, 0, mode, count, nextstartidx);
  }

  return(retidx);
}

// need call after searchNextPeakIdx
int searchNextTroughIdx(int mode, int startidx, int limit, int margin)
{
  int retidx, nextstartidx = startidx, prevtroughidx = nextstartidx, count;

  count = margin*2+1;
  if (nextstartidx+count > limit) count = limit-nextstartidx+1;

  retidx = iLowest(NULL, 0, mode, count, nextstartidx);
  while (retidx > prevtroughidx && retidx < limit) {
    prevtroughidx = retidx;

    nextstartidx =prevtroughidx-margin;
    if (nextstartidx <= startidx) nextstartidx = startidx+1;

    count = margin*2+1;
    if (nextstartidx+count >= limit) count = limit-nextstartidx+1;

    retidx = iLowest(NULL, 0, mode, count, nextstartidx);  
  }

  return(retidx);
}

