Navigation:Home > Content >

SS_SupportResistance_v04b.mq4

Time: 2016-11-03 | Download file:SS_SupportResistance_v04b.mq4

//+------------------------------------------------------------------+
//|                                         SS_SupportResistance.mq4 |
//|                                  Copyright © 2012, Andrew Sumner |
//|                                                                  |
//| You are allowed to copy and distribute this file as you see fit, |
//| and modify it to suit your purposes on the following condition:- |
//|                                                                  |
//| 1. You must charge no money for this indicator or any derivative |
//|    that you create from it.  It was released freely, please keep |
//|    it free.                                                      |
//|                                                                  |
//| 2. If you make alterations, please don't release a new version   |
//|    using the name "SS_SupportResistance".  Either release it     |
//|    using a new name, or contact me about getting your changes    |
//|    included in my indicator ([email protected]).            |
//|                                                                  |
//| 3. If you make a killer EA based on this indicator, please do me |
//|    a favour and send me a copy :)                                |
//|                                                                  |
//| My thanks to Enrico "brax64" Carpita for his help in completing  |
//| the zone.show.info text positioning code.                        |
//+------------------------------------------------------------------+

#property copyright "Copyright © 2012 Andrew Sumner"
#property link      ""

#property indicator_chart_window
#property indicator_buffers 4
#property indicator_color1 Red
#property indicator_color2 Red
#property indicator_color3 DodgerBlue
#property indicator_color4 DodgerBlue

extern int BackLimit   = 10000;
extern int TimeFrame   = 0;
extern string TimeString  = "0=Current, 60=H1, 240=H4, 1440=Day, 10080=Week, 43200=Month";

extern color color.support.weak     = DarkSlateGray;
extern color color.support.untested = SeaGreen;
extern color color.support.verified = Green;
extern color color.support.proven   = LimeGreen;
extern color color.support.turncoat = OliveDrab;
extern color color.resist.weak      = Indigo;
extern color color.resist.untested  = Orchid;
extern color color.resist.verified  = Crimson;
extern color color.resist.proven    = Red;
extern color color.resist.turncoat  = DarkOrange;

extern bool zone.show.weak  = true;
extern double zone.fuzzfactor = 0.75;
extern bool zone.solid = false;
extern int zone.linewidth = 1;
extern int zone.style = 0;
extern bool zone.show.info    = true;
extern int zone.label.shift  = 5;
extern bool zone.show.alerts  = false;
extern bool zone.alert.popups = true;
extern bool zone.alert.sounds = true;
extern int zone.alert.waitseconds = 300; 
extern bool zone.merge = true;
extern bool zone.extend = true;

extern bool fractals.show = false;
extern double fractal.fast.factor = 3.0;
extern double fractal.slow.factor = 6.0;
extern bool SetGlobals = true;

double FastDnPts[], FastUpPts[];
double SlowDnPts[], SlowUpPts[];

double zone.hi[1000], zone.lo[1000];
int    zone.start[1000], zone.hits[1000], zone.type[1000], zone.strength[1000], zone.count = 0;
bool   zone.turn[1000];

#define ZONE_SUPPORT 1
#define ZONE_RESIST  2

#define ZONE_WEAK      0
#define ZONE_TURNCOAT  1
#define ZONE_UNTESTED  2
#define ZONE_VERIFIED  3
#define ZONE_PROVEN    4

#define UP_POINT 1
#define DN_POINT -1

int time.offset = 0;

int init()
{
   IndicatorBuffers(4);

   SetIndexBuffer(0, SlowDnPts);
   SetIndexBuffer(1, SlowUpPts);
   SetIndexBuffer(2, FastDnPts);
   SetIndexBuffer(3, FastUpPts);

   if (fractals.show == true)
   {
      SetIndexStyle(0, DRAW_ARROW, 0, 3);
      SetIndexStyle(1, DRAW_ARROW, 0, 3);
      SetIndexStyle(2, DRAW_ARROW, 0, 1);
      SetIndexStyle(3, DRAW_ARROW, 0, 1);
      SetIndexArrow(0, 218);
      SetIndexArrow(1, 217);
      SetIndexArrow(2, 218);
      SetIndexArrow(3, 217);
   }
   else
   {
      SetIndexStyle(0, DRAW_NONE);
      SetIndexStyle(1, DRAW_NONE);
      SetIndexStyle(2, DRAW_NONE);
      SetIndexStyle(3, DRAW_NONE);
   }

   if (TimeFrame != 1 && TimeFrame != 5 && TimeFrame != 15 &&
       TimeFrame != 60 && TimeFrame != 240 && TimeFrame != 1440 &&
       TimeFrame != 10080 && TimeFrame != 43200)
      TimeFrame = 0;

   if (TimeFrame < Period())
      TimeFrame = Period();

   return(0);
}

int deinit()
{
   DeleteZones();
   DeleteGlobalVars();
   return(0);
}

int start()
{
   if (NewBar() == true)
   {
      int old_zone.count = zone.count;

      FastFractals();
      SlowFractals();
      DeleteZones();
      FindZones();
      DrawZones();
      if (zone.count < old_zone.count)
         DeleteOldGlobalVars(old_zone.count);
   }

   if (zone.show.info == true)
   {
      for (int i=0; i 0 && zone.strength[i] > ZONE_UNTESTED)
         {
            if (zone.hits[i] == 1)
               lbl = lbl + ", Test Count=" + zone.hits[i];
            else
               lbl = lbl + ", Test Count=" + zone.hits[i];
         }

         int adjust.hpos;
         int wbpc = WindowBarsPerChart();
         int k;
         
         k = Period() * 60 + (20 + StringLen(lbl));
         
         if (wbpc < 80)  
            adjust.hpos = Time[0] + k * 4;
         else if (wbpc < 125)  
            adjust.hpos = Time[0] + k * 8;
         else if (wbpc < 250)
            adjust.hpos = Time[0] + k * 15;
         else if (wbpc < 480)
            adjust.hpos = Time[0] + k * 29;
         else if (wbpc < 950)
            adjust.hpos = Time[0] + k * 58;
         else
            adjust.hpos = Time[0] + k * 115;
         
         //

         int shift = k * zone.label.shift;
         double vpos = zone.hi[i] - (zone.hi[i] - zone.lo[i]) / 2;

         string s = "SSSR#"+i+"LBL";
         ObjectCreate(s, OBJ_TEXT, 0, 0, 0);
         ObjectSet(s, OBJPROP_TIME1, adjust.hpos + shift);
         ObjectSet(s, OBJPROP_PRICE1, vpos);
         ObjectSetText(s, StringRightPad(lbl, 36, " "), 8, "Courier New");
      }
   }

   CheckAlerts();

   return(0);
}

void CheckAlerts()
{
   static int lastalert = 0;

   if (zone.show.alerts == false)
      return;

   if (Time[0] - lastalert > zone.alert.waitseconds)
      if (CheckEntryAlerts() == true)
         lastalert = Time[0];
}

bool CheckEntryAlerts()
{
   // check for entries
   for (int i=0; i= zone.lo[i] && Close[0] < zone.hi[i])
      {
         if (zone.show.alerts == true)
         {
            if (zone.alert.popups == true)
            {
               if (zone.type[i] == ZONE_SUPPORT)
                  Alert(Symbol() + TimeFrameToString(TimeFrame) + ": Support Zone Entered");
               else
                  Alert(Symbol() + TimeFrameToString(TimeFrame) + ": Resistance Zone Entered");
            }

            if (zone.alert.sounds == true)
               PlaySound("alert.wav");
         }

         return(true);
      }
   }

   return(false);
}

void DeleteGlobalVars()
{
   if (SetGlobals == false)
      return;

   GlobalVariableDel("SSSR_Count_"+Symbol()+TimeFrame);
   GlobalVariableDel("SSSR_Updated_"+Symbol()+TimeFrame);

   int old_count = zone.count;
   zone.count = 0;
   DeleteOldGlobalVars(old_count);
}

void DeleteOldGlobalVars(int old_count)
{
   if (SetGlobals == false)
      return;

   for (int i=zone.count; i5; shift--)
   {
      double atr = iATR(NULL, TimeFrame, 7, shift);
      double fu = atr/2 * zone.fuzzfactor;
      bool isWeak;
      bool touchOk = false;
      bool isBust = false;
      double close = iClose(NULL, TimeFrame, shift);
      double high  = iHigh(NULL, TimeFrame, shift);
      double low   = iLow(NULL, TimeFrame, shift);
      double hi_i;
      double lo_i;

      if (FastUpPts[shift] > 0.001)
      {
         // a zigzag high point
         isWeak = true;
         if (SlowUpPts[shift] > 0.001)
            isWeak = false;

         hival = high;
         if (zone.extend == true)
            hival += fu;

         loval = MathMax(MathMin(close, high-fu), high-fu*2);
         turned = false;
         hasturned = false;
         isBust = false;

         bustcount = 0;
         testcount = 0;

         for (i=shift-1; i>=0; i--)
         {
            hi_i = iHigh(NULL, TimeFrame, i);
            lo_i = iLow(NULL, TimeFrame, i);

            if ((turned == false && FastUpPts[i] >= loval && FastUpPts[i] <= hival) ||
                (turned == true && FastDnPts[i] <= hival && FastDnPts[i] >= loval))
            {
               // Potential touch, just make sure its been 10+candles since the prev one
               touchOk = true;
               for (j=i+1; j= loval && FastUpPts[j] <= hival) ||
                      (turned == true && FastDnPts[j] <= hival && FastDnPts[j] >= loval))
                  {
                     touchOk = false;
                     break;
                  }
               }

               if (touchOk == true)
               {
                  // we have a touch.  If its been busted once, remove bustcount
                  // as we know this level is still valid & has just switched sides
                  bustcount = 0;
                  testcount++;
               }
            }

            if ((turned == false && hi_i > hival) ||
                (turned == true && lo_i < loval))
            {
               // this level has been busted at least once
               bustcount++;

               if (bustcount > 1 || isWeak == true)
               {
                  // busted twice or more
                  isBust = true;
                  break;
               }

               if (turned == true)
                  turned = false;
               else if (turned == false)
                  turned = true;

               hasturned = true;

               // forget previous hits
               testcount = 0;
            }
         }

         if (isBust == false)
         {
            // level is still valid, add to our list
            temp.hi[temp.count] = hival;
            temp.lo[temp.count] = loval;
            temp.turn[temp.count] = hasturned;
            temp.hits[temp.count] = testcount;
            temp.start[temp.count] = shift;
            temp.merge[temp.count] = false;
            
            if (testcount > 3)
               temp.strength[temp.count] = ZONE_PROVEN;
            else if (testcount > 0)
               temp.strength[temp.count] = ZONE_VERIFIED;
            else if (hasturned == true)
               temp.strength[temp.count] = ZONE_TURNCOAT;
            else if (isWeak == false)
               temp.strength[temp.count] = ZONE_UNTESTED;
            else
               temp.strength[temp.count] = ZONE_WEAK;

            temp.count++;
         }
      }
      else if (FastDnPts[shift] > 0.001)
      {
         // a zigzag low point
         isWeak = true;
         if (SlowDnPts[shift] > 0.001)
            isWeak = false;

         loval = low;
         if (zone.extend == true)
            loval -= fu;

         hival = MathMin(MathMax(close, low+fu), low+fu*2);
         turned = false;
         hasturned = false;

         bustcount = 0;
         testcount = 0;
         isBust = false;

         for (i=shift-1; i>=0; i--)
         {
            hi_i = iHigh(NULL, TimeFrame, i);
            lo_i = iLow(NULL, TimeFrame, i);

            if ((turned == true && FastUpPts[i] >= loval && FastUpPts[i] <= hival) ||
                (turned == false && FastDnPts[i] <= hival && FastDnPts[i] >= loval))
            {
               // Potential touch, just make sure its been 10+candles since the prev one
               touchOk = true;
               for (j=i+1; j= loval && FastUpPts[j] <= hival) ||
                      (turned == false && FastDnPts[j] <= hival && FastDnPts[j] >= loval))
                  {
                     touchOk = false;
                     break;
                  }
               }

               if (touchOk == true)
               {
                  // we have a touch.  If its been busted once, remove bustcount
                  // as we know this level is still valid & has just switched sides
                  bustcount = 0;
                  testcount++;
               }
            }

            if ((turned == true && hi_i > hival) ||
                (turned == false && lo_i < loval))
            {
               // this level has been busted at least once
               bustcount++;

               if (bustcount > 1 || isWeak == true)
               {
                  // busted twice or more
                  isBust = true;
                  break;
               }

               if (turned == true)
                  turned = false;
               else if (turned == false)
                  turned = true;

               hasturned = true;

               // forget previous hits
               testcount = 0;
            }
         }

         if (isBust == false)
         {
            // level is still valid, add to our list
            temp.hi[temp.count] = hival;
            temp.lo[temp.count] = loval;
            temp.turn[temp.count] = hasturned;
            temp.hits[temp.count] = testcount;
            temp.start[temp.count] = shift;
            temp.merge[temp.count] = false;

            if (testcount > 3)
               temp.strength[temp.count] = ZONE_PROVEN;
            else if (testcount > 0)
               temp.strength[temp.count] = ZONE_VERIFIED;
            else if (hasturned == true)
               temp.strength[temp.count] = ZONE_TURNCOAT;
            else if (isWeak == false)
               temp.strength[temp.count] = ZONE_UNTESTED;
            else
               temp.strength[temp.count] = ZONE_WEAK;

            temp.count++;
         }
      }
   }

   // look for overlapping zones...
   if (zone.merge == true)
   {
      merge.count = 1;
      int iterations = 0;
      while (merge.count > 0 && iterations < 3)
      {
         merge.count = 0;
         iterations++;

         for (i = 0; i < temp.count; i++)
            temp.merge[i] = false;

         for (i = 0; i < temp.count-1; i++)
         {
            if (temp.hits[i] == -1 || temp.merge[j] == true)
               continue;

            for (j = i+1; j < temp.count; j++)
            {
               if (temp.hits[j] == -1 || temp.merge[j] == true)
                  continue;

               if ((temp.hi[i] >= temp.lo[j] && temp.hi[i] <= temp.hi[j]) ||
                   (temp.lo[i] <= temp.hi[j] && temp.lo[i] >= temp.lo[j]) ||
                   (temp.hi[j] >= temp.lo[i] && temp.hi[j] <= temp.hi[i]) ||
                   (temp.lo[j] <= temp.hi[i] && temp.lo[j] >= temp.lo[i]))
               {
                  merge1[merge.count] = i;
                  merge2[merge.count] = j;
                  temp.merge[i] = true;
                  temp.merge[j] = true;
                  merge.count++;
               }
            }
         }

         // ... and merge them ...
         for (i=0; i 3)
               temp.strength[target] = ZONE_PROVEN;

            if (temp.hits[target] == 0 && temp.turn[target] == false)
            {
               temp.hits[target] = 1;
               if (temp.strength[target] < ZONE_VERIFIED)
                  temp.strength[target] = ZONE_VERIFIED;
            }

            if (temp.turn[target] == false || temp.turn[source] == false)
               temp.turn[target] = false;
            if (temp.turn[target] == true)
               temp.hits[target] = 0;

            temp.hits[source] = -1;
         }
      }
   }

   // copy the remaining list into our official zones arrays
   zone.count = 0;
   for (i=0; i= 0 && zone.count < 1000)
      {
         zone.hi[zone.count]       = temp.hi[i];
         zone.lo[zone.count]       = temp.lo[i];
         zone.hits[zone.count]     = temp.hits[i];
         zone.turn[zone.count]     = temp.turn[i];
         zone.start[zone.count]    = temp.start[i];
         zone.strength[zone.count] = temp.strength[i];
         
         if (zone.hi[zone.count] < Close[4])
            zone.type[zone.count] = ZONE_SUPPORT;
         else if (zone.lo[zone.count] > Close[4])
            zone.type[zone.count] = ZONE_RESIST;
         else
         {
            for (j=5; j<1000; j++)
            {
               if (iClose(NULL, TimeFrame, j) < zone.lo[zone.count])
               {
                  zone.type[zone.count] = ZONE_RESIST;
                  break;
               }
               else if (iClose(NULL, TimeFrame, j) > zone.hi[zone.count])
               {
                  zone.type[zone.count] = ZONE_SUPPORT;
                  break;
               }
            }

            if (j == 1000)
               zone.type[zone.count] = ZONE_SUPPORT;
         }

         zone.count++;
      }
   }
}

void DrawZones()
{
   if (SetGlobals == true)
   {
      GlobalVariableSet("SSSR_Count_"+Symbol()+TimeFrame, zone.count);
      GlobalVariableSet("SSSR_Updated_"+Symbol()+TimeFrame, TimeCurrent());
   }

   for (int i=0; i P)
      P = TimeFrame;
   
   P = P / TimeFrame*2 + MathCeil(P / TimeFrame / 2);
   
   if (shift < P)
      return(false);

   if (shift > iBars(Symbol(), TimeFrame)-P)
      return(false); 
   
   for (int i=1; i<=P; i++)
   {
      if (M == UP_POINT)
      {
         if (iHigh(NULL, TimeFrame, shift+i) > iHigh(NULL, TimeFrame, shift))
            return(false);
         if (iHigh(NULL, TimeFrame, shift-i) >= iHigh(NULL, TimeFrame, shift))
            return(false);     
      }
      if (M == DN_POINT)
      {
         if (iLow(NULL, TimeFrame, shift+i) < iLow(NULL, TimeFrame, shift))
            return(false);
         if (iLow(NULL, TimeFrame, shift-i) <= iLow(NULL, TimeFrame, shift))
            return(false);
      }        
   }
   return(true);   
}  

void FastFractals()
{
   int shift;
   int limit = MathMin(Bars-1, BackLimit);
   int P = TimeFrame * fractal.fast.factor;

   FastUpPts[0] = 0.0; FastUpPts[1] = 0.0;
   FastDnPts[0] = 0.0; FastDnPts[1] = 0.0;

   for (shift=limit; shift>1; shift--)
   {
      if (Fractal(UP_POINT, P, shift) == true)
         FastUpPts[shift] = iHigh(NULL, TimeFrame, shift);
      else
         FastUpPts[shift] = 0.0;

      if (Fractal(DN_POINT, P, shift) == true)
         FastDnPts[shift] = iLow(NULL, TimeFrame, shift);
      else
         FastDnPts[shift] = 0.0;
   }
}

void SlowFractals()
{
   int shift;
   int limit = MathMin(iBars(Symbol(), TimeFrame) - 1, BackLimit);
   int P = TimeFrame * fractal.slow.factor;

   SlowUpPts[0] = 0.0; SlowUpPts[1] = 0.0;
   SlowDnPts[0] = 0.0; SlowDnPts[1] = 0.0;

   for (shift=limit; shift>1; shift--)
   {
      if (Fractal(UP_POINT, P, shift) == true)
         SlowUpPts[shift] = iHigh(NULL, TimeFrame, shift);
      else
         SlowUpPts[shift] = 0.0;

      if (Fractal(DN_POINT, P, shift) == true)
         SlowDnPts[shift] = iLow(NULL, TimeFrame, shift);
      else
         SlowDnPts[shift] = 0.0;
   }
}

bool NewBar()
{
   static datetime LastTime = 0;
   if (iTime(NULL, TimeFrame, 0) != LastTime)
   {
      LastTime = iTime(NULL, TimeFrame, 0)+time.offset;
      return (true);
   }
   else
      return (false);
}

void DeleteZones()
{
   int len = 5;
   int i;

   while (i < ObjectsTotal())
   {
      string objName = ObjectName(i);
      if (StringSubstr(objName, 0, len) != "SSSR#")
      {
         i++;
         continue;
      }
      ObjectDelete(objName);
   }
}

string TimeFrameToString(int tf) //code by TRO
{
   string tfs;

   switch(tf)
   {
      case PERIOD_M1:
         tfs = "M1"  ;
         break;
      case PERIOD_M5:
         tfs = "M5"  ;
         break;
      case PERIOD_M15:
         tfs = "M15" ;
         break;
      case PERIOD_M30:
         tfs = "M30" ;
         break;
      case PERIOD_H1:
         tfs = "H1"  ;
         break;
      case PERIOD_H4:
         tfs = "H4"  ;
         break;
      case PERIOD_D1:
         tfs = "D1"  ;
         break;
      case PERIOD_W1:
         tfs = "W1"  ;
         break;
      case PERIOD_MN1:
         tfs = "MN";
   }

   return(tfs);
}

string StringRepeat(string str, int n = 1)
{
  string outstr = "";
  for(int i = 0; i < n; i++) outstr = outstr + str;
  return(outstr);
}

string StringRightPad(string str, int n=1, string str2=" ")
{
  return(str + StringRepeat(str2,n-StringLen(str)));
}

Recommend