Author: George Egroeg (egro1egro at yahoo dot com)
S_R_lines
Indicators Used
Fractals
Miscellaneous
Implements a curve of type %1
1 Views
0 Downloads
0 Favorites
S_R_lines
///////////////////////////////////////////////////////
// George Egroeg (C) 2006 e-m: egro1egro at yahoo dot com
// aka "egro1egro"
//
// "Support/resistance lines" Version 3.0
//
///////////////////////////////////////////////////////
// The package contains two files:
// 1. S_R_lines.mq4 (script) should be placed into experts/indicators folder
// 2. S_R_lines.tpl (chart template) should be placed into templates folder
///////////////////////////////////////////////////////
// This indicator has only one parameter: lineIndex = 1,...,20
// In order to make it work you will have to place 20 indicators 
// all with different parameter values. A chart template
// with 20 indicators of this type is included for
// your convenience.
//
// There are two global variable that you might want to set before running this script:
//
// "sr_last_screens" - number of last screens to start drawing s/r lines from
// One screen is assumed to have 150 bars/candles
// If you specify global value 2 it will mean that 300 candles back s/r lines 
// can be started only. Using this parameter should improve performance significantly.
//
// "sr_spread_multiple" - number of (Bid-Ask) spreads to use as a delta when merging two s/r 
// lines together. If you specify value 2 and current spread is 0.0003 then two lines within 
// 6 pips will be merged into one. You might want to increase this parameter if you are 
// planning to use bigger time-frames (for instance, for hourly charts you might need 5-10 
// spreads to use as a delta in order to unclutter the screen). By default, it is set to 1.5 spreads.
//
// !!! After applying global variables or after recompiling this script it is necessary to
// de-select the chart template and then select it again to apply a new.
//
// Also, some parameters are defined as constants in the code
// and can be changed sensibly. These parameters cannot be made external
// because they need to be exactly the same on all instances of the indicator.
//
// MAX_NUM_LINES is a number of indicators on a chart
// If you think that 20 is overkill try to reduce this constant and
// accordingly delete some of the indicators from the chart template
// It might be enough to have 10, but if you notice that some lines are 
// not drawn where they should be - increase the number (make it even bigger than 20)
// The point is - always maintain the same number of indicators 
// on the chart al with different indices
//
// MAX_PERCENT_OUT is how far from the last price potential s/r lines 
// should be maintained (I think 3% is quite enough for intraday, but...)
//
// DELTA_PERIODS a number of candles/bars after which s/r lines "expire"
// indicator script discards old line and stops drawing them to the right.
//
// DEFAULT_NUM_SCREENS how many screens back shell we start the first s/r line
// if the global variable "sr_last_screens" is not defined or invalid
///////////////////////////////////////////////////////
#property copyright "George Egroeg (egro1egro at yahoo dot com)"

#property indicator_chart_window
#property indicator_buffers 8

#property indicator_color1 LimeGreen
#property indicator_color2 LimeGreen
#property indicator_color3 LimeGreen
#property indicator_color4 LimeGreen

#property indicator_color5 Red
#property indicator_color6 Red
#property indicator_color7 Red
#property indicator_color8 Red

// maximum number of support/resistance line pairs
#define MAX_NUM_LINES      5
#define MAX_NUM_LINES_REAL 20 // has to be exactly 4 times the previous number

// max deviation from current price
#define MAX_PERCENT_OUT    3.0

// 2 lines within (Bid-Ask)* DELTA_SPREAD_MULTIPLE are merged into one
#define DELTA_SPREAD_MULTIPLE 1.5

#define DELTA_PERIOD       600

// 10 screens back from now with 150 bars/canldes in each - the very first s/r/ line can possibly start
#define DEFAULT_NUM_SCREENS 10

//////////////////////////////////////////////////////////////////////////////
// the following constants are for internal use and should not be changed
//////////////////////////////////////////////////////////////////////////////
// number of bars left behind in a fractal
#define NUM_BARS_FRACTAL   2
// constants that denote empty values (i.e. don't draw if empty)
#define LINE_EMPTY_VALUE   0.0
#define FRACTAL_EMPTY_VALUE 0.0
#define DATE_EMPTY_VALUE 0 // 0 am 1 Jan 1970
#define NUM_BARS_SCREEN 150 // number of bars in a screen normally


// which one of s/r pair of lines to show (can be from 1 to 20)
extern int lineIndex = 1;

double lineDelta = 0.0005;

//---- buffers
double resLine1[];
double resLine2[];
double resLine3[];
double resLine4[];

double suppLine1[];
double suppLine2[];
double suppLine3[];
double suppLine4[];


// list of resistance lines
// we maintain the whole list of them but use only the requested one
double upper_f[MAX_NUM_LINES_REAL]; // f is for tracking previous fractal values (hi/lo of candles)
double upper_l[MAX_NUM_LINES_REAL]; // l is for tracking previous r/s lines levels (open/close of candles)
datetime upper_s[MAX_NUM_LINES_REAL]; // s is for tracking start time of s/r lines

// queue of support lines
double lower_f[MAX_NUM_LINES_REAL];
double lower_l[MAX_NUM_LINES_REAL];
datetime lower_s[MAX_NUM_LINES_REAL];

double valHigh = LINE_EMPTY_VALUE;
double valLow = LINE_EMPTY_VALUE;

datetime startTime = DATE_EMPTY_VALUE;
double deltaSpreadMultiple = DELTA_SPREAD_MULTIPLE;

// loop variable
int i;
int j;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+  

void initRunningLists()
{
   for(j = 0; j < MAX_NUM_LINES_REAL; j++)
   {
      upper_f[j] = LINE_EMPTY_VALUE;
      upper_l[j] = LINE_EMPTY_VALUE;
      upper_s[j] = DATE_EMPTY_VALUE;
      lower_f[j] = LINE_EMPTY_VALUE;
      lower_l[j] = LINE_EMPTY_VALUE;
      lower_s[j] = DATE_EMPTY_VALUE;
   }
}

int init()
  {
  // adjust input values
  if ( lineIndex < 1 )
   lineIndex = 1;
  if ( lineIndex > MAX_NUM_LINES )
   lineIndex = MAX_NUM_LINES;
   
  j = (lineIndex-1)*4;
//----  
   SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, 1, LimeGreen);
   SetIndexEmptyValue(0, LINE_EMPTY_VALUE);
   SetIndexDrawBegin(0, 1);
   SetIndexBuffer(0, resLine1);
   SetIndexLabel(0,"Resistance " + (j + 1));
   
   SetIndexStyle(1, DRAW_LINE, STYLE_SOLID, 1, LimeGreen);
   SetIndexEmptyValue(1, LINE_EMPTY_VALUE);
   SetIndexDrawBegin(1, 1);
   SetIndexBuffer(1, resLine2);
   SetIndexLabel(1,"Resistance " + (j + 2));
   
   SetIndexStyle(2, DRAW_LINE, STYLE_SOLID, 1, LimeGreen);
   SetIndexEmptyValue(2, LINE_EMPTY_VALUE);
   SetIndexDrawBegin(2, 1);
   SetIndexBuffer(2, resLine3);
   SetIndexLabel(2,"Resistance " + (j + 3));
   
   SetIndexStyle(3, DRAW_LINE, STYLE_SOLID, 1, LimeGreen);
   SetIndexEmptyValue(3, LINE_EMPTY_VALUE);
   SetIndexDrawBegin(3, 1);
   SetIndexBuffer(3, resLine4);
   SetIndexLabel(3,"Resistance " + (j + 4));
//----    
   SetIndexStyle(4,DRAW_LINE, STYLE_SOLID,1, Red);
   SetIndexEmptyValue(4, LINE_EMPTY_VALUE);
   SetIndexDrawBegin(4,1);
   SetIndexBuffer(4, suppLine1);
   SetIndexLabel(4,"Support " + (j + 1));
   
   SetIndexStyle(5,DRAW_LINE, STYLE_SOLID,1, Red);
   SetIndexEmptyValue(5, LINE_EMPTY_VALUE);
   SetIndexDrawBegin(5,1);
   SetIndexBuffer(5, suppLine2);
   SetIndexLabel(5,"Support " + (j + 2));
   
   SetIndexStyle(6,DRAW_LINE, STYLE_SOLID,1, Red);
   SetIndexEmptyValue(6, LINE_EMPTY_VALUE);
   SetIndexDrawBegin(6,1);
   SetIndexBuffer(6, suppLine3);
   SetIndexLabel(6,"Support " + (j + 3));
   
   SetIndexStyle(7,DRAW_LINE, STYLE_SOLID,1, Red);
   SetIndexEmptyValue(7, LINE_EMPTY_VALUE);
   SetIndexDrawBegin(7,1);
   SetIndexBuffer(7, suppLine4);
   SetIndexLabel(7,"Support " + (j + 4));
   
   IndicatorShortName("S/R lines " + lineIndex);
      
   if ( GlobalVariableCheck("sr_last_screens") )
   {
      double sn = GlobalVariableGet("sr_last_screens");
      if ( sn > 0 )
      {
         startTime = TimeCurrent() - (Period() * 60 * sn * NUM_BARS_SCREEN);
      }
      else
      {
         startTime = TimeCurrent() - (Period() * 60 * DEFAULT_NUM_SCREENS * NUM_BARS_SCREEN);
      }
   }
   else
      startTime = TimeCurrent() - (Period() * 60 * DEFAULT_NUM_SCREENS * NUM_BARS_SCREEN);
   
   if ( GlobalVariableCheck("sr_spread_multiple") )
   {
      double sm = GlobalVariableGet("sr_spread_multiple");
      if ( sm > 0 )
          deltaSpreadMultiple = sm;
      else
          deltaSpreadMultiple = DELTA_SPREAD_MULTIPLE;
   }
   
   initRunningLists();
   
//---- 
   return(0);
  }
  
 double myFractal(int mode, int shift)
 {
   if ( (shift < 2) || (shift > (Bars - 2)) )
      return (0.0);
      
   if ( NUM_BARS_FRACTAL > 2 )
      return (iFractals(NULL, 0, mode, shift));
   
   // need to compare High of (shift-1, shift, shift+1)
   if ( mode == MODE_UPPER )
   {
      if ( (High[shift] >= High[shift-1]) && (High[shift] >= High[shift+1]) )
        return(High[shift]);
        
      /*
      // check right side
      int k = shift - 1;
      while( (k >= 0) && (High[k] == High[shift]) )
      {
         k--;
      }
      if ( k >= 0 && (High[k] > High[shift]) )
         return (0.0);
       
      // now check left side  
      k = shift + 1;
      while( (k < Bars) && (High[k] == High[shift]) )
      {
         k++;
      }
      if ( (k < Bars) && (High[k] > High[shift]) )
         return (0.0);
         
      return (High[shift]);
      */
   }
   else
   {
      if ( (Low[shift] <= Low[shift-1]) && (Low[shift] <= Low[shift+1]) )
         return(Low[shift]);
       
      /*
      // check right side
      k = shift - 1;
      while( (k >= 0) && (Low[k] == Low[shift]) )
      {
         k--;
      }
      if ( k >= 0 && (Low[k] < Low[shift]) )
         return (0.0);
       
      // now check left side  
      k = shift + 1;
      while( (k < Bars) && (Low[k] == Low[shift]) )
      {
         k++;
      }
      if ( (k < Bars) && (Low[k] > Low[shift]) )
         return (0.0);
         
      return (Low[shift]);
      */
   }
   
   return (0.0);
 }

double updateViewResistance(int li, double vhPrevious, double NewLow)
{
     if ( upper_s[li] == DATE_EMPTY_VALUE )
     {
         // no line no picture
         return (LINE_EMPTY_VALUE);
     }
     else
     {
        // new line can be cancelled if a candle has printed over it
        if ( NewLow > (upper_l[li] + lineDelta) )
        {
            upper_f[li] = LINE_EMPTY_VALUE;
            upper_l[li] = LINE_EMPTY_VALUE;
            upper_s[li] = DATE_EMPTY_VALUE;
            return (LINE_EMPTY_VALUE);
        }
        else
        {
            // we have a line but if we have an old line we will have to cancel it first
            if ( vhPrevious != LINE_EMPTY_VALUE )
            {
                // we have a line already
                if ( vhPrevious != upper_l[li] ) // got a new line instead now
                    return (LINE_EMPTY_VALUE); // cancel the old one
                else
                    return (vhPrevious); // continue the same old one
            }
            else
            {
                return (upper_l[li]); // start a new one here
            }
         
         }
     }
}
  
double updateViewSupport(int li, double vlPrevious, double NewHigh)
{
     if ( lower_s[li] == DATE_EMPTY_VALUE )
     {
         // no line no picture
         return (LINE_EMPTY_VALUE);
     }
     else
     {
        // new line can be cancelled if a candle has printed over it
        if ( NewHigh < (lower_l[li] - lineDelta) )
        {
            lower_f[li] = LINE_EMPTY_VALUE;
            lower_l[li] = LINE_EMPTY_VALUE;
            lower_s[li] = DATE_EMPTY_VALUE;
            return (LINE_EMPTY_VALUE);
        }
        else
        {
            // we have a line but if we have an old line we will have to cancel it first
            if ( vlPrevious != LINE_EMPTY_VALUE )
            {
                // we have a line already
                if ( vlPrevious != lower_l[li] ) // got a new line instead now
                    return (LINE_EMPTY_VALUE); // cancel the old one
                else
                    return (vlPrevious); // continue the same old one
            }
            else
            {
                return(lower_l[li]); // start a new one here
            }
         
         }
     }
}
 
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int start()
{
   initRunningLists();
   
   lineDelta = MathAbs(Ask - Bid) * deltaSpreadMultiple;
   
   int td1 = MathAbs(Time[Bars-1] - Time[Bars-2]); // number of seconds in one period
   int td = td1 * DELTA_PERIOD;
   
   i = Bars-1;
   
   // skip old dates
   while( (i >= 0) && (Time[i] < startTime) )
   {
      i--;
   }
   
   while( i >= 0 )
   { 
       double rangeMax = Close[i] * ( 1.0 + (MAX_PERCENT_OUT/100.0) );
       double rangeMin = Close[i] * ( 1.0 - (MAX_PERCENT_OUT/100.0) );
       datetime t = Time[i];

        // when fractal function returns non-zero value we get a new potential resistance line
       valHigh = myFractal(MODE_UPPER, i);
       
       double body_max = MathMax(Close[i], Open[i]);
        
       if ( valHigh > FRACTAL_EMPTY_VALUE )
       {
         // fractal is getting reported only on the very last bar of it
         // so we need to select the highest body top out of 5 bars
         
         for(j = MathMin((i + NUM_BARS_FRACTAL - 1), Bars); j >= MathMax((i - NUM_BARS_FRACTAL + 1),0); j--)
         {
             if ( body_max < MathMax(Close[j], Open[j]) )
               body_max = MathMax(Close[j], Open[j]);
         }
         j = MathMax((i - NUM_BARS_FRACTAL),0);
         while( (j >= 0) && (MathMax(Close[j], Open[j]) < valHigh) && (MathMax(Close[j], Open[j]) > body_max) )
         {
             body_max = MathMax(Close[j], Open[j]);
             j--;
         }
       }
       
       valLow = myFractal(MODE_LOWER, i);
       
       double body_min = MathMin(Close[i], Open[i]);
       if ( valLow > FRACTAL_EMPTY_VALUE )
       {
         // fractal is getting reported only on the very last bar of it
         // so we need to select the highest body top out of 5 bars
         for(j = MathMin((i + NUM_BARS_FRACTAL - 1), Bars); j >= MathMax((i - NUM_BARS_FRACTAL + 1),0); j--)
         {
           if ( body_min > MathMin(Close[j], Open[j]) )
             body_min = MathMin(Close[j], Open[j]);
         } 
         j = MathMax((i - NUM_BARS_FRACTAL),0);
         while( (j >= 0) && (MathMin(Close[j], Open[j]) > valLow) && (MathMin(Close[j], Open[j]) < body_min) )
         {
             body_min = MathMin(Close[j], Open[j]);
             j--;
         }
       }
       
     // First, cancel old resistance lines because of overlapping
     for(j = 0; j < MAX_NUM_LINES_REAL; j++ )
     {
       if ( ((upper_l[j] /*+ lineDelta*/) < body_max) 
           || (upper_l[j] > rangeMax) 
           || ((upper_s[j] + td) < t)
           )
       {
         upper_f[j] = LINE_EMPTY_VALUE; // cancel the item
         upper_l[j] = LINE_EMPTY_VALUE;
         upper_s[j] = DATE_EMPTY_VALUE;
       }
     }
     
     if ( valHigh > FRACTAL_EMPTY_VALUE ) 
     {

       // Next, cancel old resistance lines because of new fractals
       for(j = 0; j < MAX_NUM_LINES_REAL; j++ )
       {
         if (upper_f[j] < valHigh)
         {
           upper_f[j] = LINE_EMPTY_VALUE; // cancel the item
           upper_l[j] = LINE_EMPTY_VALUE;
           upper_s[j] = DATE_EMPTY_VALUE;
         }
       }
       
       bool bExistsAlready = false;
       for(j = 0; j < MAX_NUM_LINES_REAL; j++)
       {
          if ( upper_f[j] != LINE_EMPTY_VALUE )
          {
            if ( ((upper_l[j] - lineDelta) < body_max) 
                && ((upper_l[j] + lineDelta) > body_max) )
            {
              bExistsAlready = true;
              break;
            }
          }
       }
       
       // if we have a new fractal up - insert a new s/r line
       if ( !bExistsAlready )
       {
         for(j = 0; j < MAX_NUM_LINES_REAL; j++)
         {
           if ( upper_f[j] == LINE_EMPTY_VALUE )
           {
             upper_f[j] = valHigh;
             upper_l[j] = body_max;
             upper_s[j] = t;
             break;
           }
         }
       }
     }     

     // First, cancel old s/r lines because of candle-overlapping
     for(j = 0; j < MAX_NUM_LINES_REAL; j++ )
     {
       if ( ((lower_l[j] /*- lineDelta*/) > body_min) 
           || (lower_l[j] < rangeMin) 
           || ((lower_s[j] + td) < t)
           )
       {
         lower_f[j] = LINE_EMPTY_VALUE; // cancel the item
         lower_l[j] = LINE_EMPTY_VALUE;
         lower_s[j] = DATE_EMPTY_VALUE;
       }
     }
     
     if ( valLow > FRACTAL_EMPTY_VALUE ) 
     {

       // First, cancel old resistance lines
       for(j = 0; j < MAX_NUM_LINES_REAL; j++)
       {
         if (lower_f[j] > valLow)
         {
           lower_f[j] = LINE_EMPTY_VALUE; // cancel the item
           lower_l[j] = LINE_EMPTY_VALUE;
           lower_s[j] = DATE_EMPTY_VALUE;
         }
       }
       
       bExistsAlready = false;
       for(j = 0; j < MAX_NUM_LINES_REAL; j++)
       {
          if ( lower_f[j] != LINE_EMPTY_VALUE )
          {
            if ( ((lower_l[j] - lineDelta) < body_min) 
               && ((lower_l[j] + lineDelta) > body_min) )
            {
              bExistsAlready = true;
              break;
            }
          }
       }
       
       // if we have a new fractal down - insert a new s/r line
       if ( !bExistsAlready )
       {
         for(j = 0; j < MAX_NUM_LINES_REAL; j++)
         {
           if ( lower_f[j] == LINE_EMPTY_VALUE )
           {
             lower_f[j] = valLow;
             lower_l[j] = body_min;
             lower_s[j] = t;
             break;
           }
         }
       }
     }  

     j = (lineIndex-1)*4;
     resLine1[i]  = updateViewResistance(j, resLine1[i+1], Low[i]);
     resLine2[i]  = updateViewResistance(j+1, resLine2[i+1], Low[i]);
     resLine3[i]  = updateViewResistance(j+2, resLine3[i+1], Low[i]);
     resLine4[i]  = updateViewResistance(j+3, resLine4[i+1], Low[i]);
     
     suppLine1[i] = updateViewSupport(j, suppLine1[i+1], High[i]);
     suppLine2[i] = updateViewSupport(j+1, suppLine2[i+1], High[i]);
     suppLine3[i] = updateViewSupport(j+2, suppLine3[i+1], High[i]);
     suppLine4[i] = updateViewSupport(j+3, suppLine4[i+1], High[i]);

     i--;
   }   
   return(0);
}
//+------------------------------------------------------------------+

Comments

Markdown supported. Formatting help

Markdown Formatting Guide

Element Markdown Syntax
Heading # H1
## H2
### H3
Bold **bold text**
Italic *italicized text*
Link [title](https://www.example.com)
Image ![alt text](image.jpg)
Code `code`
Code Block ```
code block
```
Quote > blockquote
Unordered List - Item 1
- Item 2
Ordered List 1. First item
2. Second item
Horizontal Rule ---