SHI_Mod_vLine_v4

Download script
Author: Copyright � 2004, Shurka & Kevin
SHI_Mod_vLine_v4

This script is designed to automatically identify and draw a price channel on a trading chart based on specific historical price points. It uses geometric logic to determine the "boundaries" of market movement.

Here is a breakdown of how the logic works in non-technical terms:

Core Concept: Fractal Identification

The script starts by scanning the price history to find "Fractals." In this context, a fractal represents a significant peak (high) or valley (low) relative to the bars surrounding it. By finding these turning points, the script can establish the most relevant structural boundaries of the market rather than just picking random prices.

How the Channel is Built

  1. Anchor Points: The tool looks for two primary fractals—one high and one low. It uses these two points to calculate the "slope" or the rate at which the price is moving over time.
  2. Dynamic Range: Once it identifies the slope between these two points, it treats them as the foundation for a channel. It then projects these lines forward into the future.
  3. The Three Lines: The script renders three distinct visual elements on your chart:
    • Upper Boundary: A solid line representing the top of the price channel.
    • Lower Boundary: A solid line representing the bottom of the price channel.
    • Median Line: A dotted center line that represents the average value between the upper and lower boundaries, helping to identify the "fair value" or midpoint of the current trend.

Interactive Positioning (The Vertical Line)

A unique feature of this specific version is the Vertical Line (VLINE) functionality.

  • Instead of the script simply calculating everything based on the very last candle, it looks for a specific time marker defined by a vertical line you place on the chart.
  • You can move this vertical line manually. The script will then "re-calculate" the entire channel based on where that line is positioned. This allows a user to manually select a specific starting point in history to see how the channel would have developed from that exact moment.

Smart Adjustments

The logic includes "protection" checks to ensure the channel remains accurate:

  • Timeframe Awareness: The script automatically adjusts its sensitivity (how many bars it looks back to find fractals) based on whether you are viewing a 1-minute chart versus a Daily chart.
  • Collision Logic: The script contains logic to check if price has "broken" the boundaries. If a price point violates the calculated channel, the tool attempts to adjust the lines to ensure they remain relevant to the most recent price action.

Summary of Visual Output

  • Solid Tomato Lines: These represent the primary established channel boundaries.
  • Dotted Aqua/Lime Lines: These provide extended projections and visual guides for trend continuation.
  • The Vertical Line: Acts as your "anchor" or "starting trigger." Wherever you move this line, the entire mathematical construction of the channel shifts to align with that point in time.
Miscellaneous
Implements a curve of type %1Uses files from the file systemIt reads information from a fileIt issuies visual alerts to the screen
15 Views
0 Downloads
0 Favorites
SHI_Mod_vLine_v4
//+------------------------------------------------------------------+
//|                                                SHI_Mod_vLine.mq4 |
//|                               Copyright © 2004,   Shurka & Kevin |
//|                            Corrected&Upgraded by  Modest         |
//|                                  Additional idea  Rosh           |
//+------------------------------------------------------------------+
// Modest- èñïðàâëåí àëãîðèòì íàõîæäåíèÿ îïîðíîé òî÷êè ìåæäó 
// îáíàðóæåííûìè ôðàêòàëàìè äëÿ ïîñòðîåíèÿ ëèíèè êàíàëà
// Äîáàâëåíà âîçìîæíîñòü òåñòèðîâàíèÿ íà èñòîðèè ïðè ïîìîùè ïðîãðàììû MetaClick.
// Ïðè òåñòèðîâàíèè ëèíèè êàíàëà ïðîäîëæàþòñÿ â áóäóøåå
// Âåðñèÿ SHI_Mod_vLine: ïåðåìåùåíèå âñåãî ïîñòðîåíèÿ ïóòåì ïåðåòàñêèâàíèÿ VLINE - èäåÿ Rosh'a
#property copyright "Copyright © 2004, Shurka & Kevin "
#property link      ""
//----
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Red
//----
double ExtMapBuffer1[];
double UpLabel[];
//----
extern int       BarsForFract=0;
extern bool      DOT_Line_Ray=True;
//----
int CurrentBar=0;
double Step=0;
int B1=-1,B2=-1,iB1=0,iB2=0,flag=0;
int UpDown=0;
double P1=0,P2=0,PP=0,P1f=0,PPf=0;
int i=0,AB=300,BFF=0;
int ishift=0;
double iprice=0;
datetime T1,T2,Tf,myTime;
string fileNAME;
int myYear,myMonth,myDay,myHour,myMinute;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//---- indicators
   SetIndexStyle(0,DRAW_ARROW);
   SetIndexArrow(0,164);
   SetIndexBuffer(0,ExtMapBuffer1);
   SetIndexEmptyValue(0,0.0);
   SetIndexStyle(1,DRAW_ARROW,EMPTY,1,Blue);
   SetIndexBuffer(1,UpLabel);
   SetIndexArrow(1, 251);
   SetIndexEmptyValue(1,0);
   return(0);
  }
//+------------------------------------------------------------------+
//| Custor indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//---- 
   FileDelete(fileNAME);
//----
   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DelObj()
  {
   ObjectDelete("TL1");   ObjectDelete("TL2");   ObjectDelete("MIDL");
   ObjectDelete("Lab1");ObjectDelete("Lab2");ObjectDelete("Lab3");
   ObjectDelete("TL1f");ObjectDelete("TL2f");
   //ObjectDelete("MyBarLine");
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   double iPP,Lab1Val,Lab2Val,Lab3Val;
   int MyBar,lastBarTime,h1,ii;
   string v1,fileFrame;
//----   
   ObjectCreate("MyBarLine",OBJ_VLINE,0,Time[1],High[1]);
   ObjectSet("MyBarLine",OBJPROP_COLOR,Aqua);
   ObjectSet("MyBarLine",OBJPROP_WIDTH,1);
   ObjectSet("MyBarLine",OBJPROP_STYLE,STYLE_DOT);
   //****************************************************************************************  
   //   ×òåíèå äàííûõ (ñòðîêà)  èç âíåøíåãî ôàéëà, ñôîðìèðîâàííîãî ïðîãðàììîé MetaClick,    
   //   ïóò¸ì òûêà â áàð (Z+LeftMouse) óêàçûâàþùåé âðåìÿ, äî êîòîðîãî ñòðîèòñÿ èíäèêàòîð.
   //   Èùåì íóæíûé íîìåð áàðà
   //**************************************************************************************** 
   /*   Âýòîé âåðñèè MetaClick íå èñïîëüçóåòñÿ
        switch (Period())  // Ôîðìèðîâàíèå ÷àñòè èìåíè âíåøíåãî ôàéëà
      {
      case PERIOD_M1:     fileFrame=",M1";break;
      case PERIOD_M5:     fileFrame=",M5";break;
      case PERIOD_M15:    fileFrame=",M15";break;
      case PERIOD_M30:    fileFrame=",M30";break;
      case PERIOD_H1:     fileFrame=",H1";break;
	   case PERIOD_H4:     fileFrame=",H4";break;
	   case PERIOD_D1:     fileFrame=",Daily";break;
	   case PERIOD_W1:     fileFrame=",Weekly";break;
	   case PERIOD_MN1:    fileFrame=",Monthly";break;   
      }
      fileNAME=Symbol()+fileFrame+".csv";
      h1=FileOpen(Symbol()+fileFrame+".csv",FILE_CSV,";");
      v1 = FileReadString(h1);
      FileClose(h1);
      Comment(v1);
      lastBarTime=StrToTime(v1);
      i=0;
      while (i<=Bars-1 )
      {if (lastBarTime==Time[i])
         { MyBar=i;break;}
      i++;
      }
*/
//------- Çàêîí÷èëè èñêàòü ïîñëåäíèé áàð äëÿ ïîñòðîåíèÿ èíäèêàòîðà ------- 
   myTime=ObjectGet("MyBarLine",OBJPROP_TIME1);
   if(myTime>Time[0] || myTime< Time[Bars-1])
   {ObjectDelete("MyBarLine"); Alert("SHI_Mod_vLine: TimeFrames are not correct");  return(0);  
   }
   myYear=TimeYear(myTime); myMonth=TimeMonth(myTime);myDay=TimeDay(myTime);
   myHour=TimeHour(myTime); myMinute=TimeMinute(myTime);
   // Äëÿ âîçìîæíîòè ïåðåêëþ÷åíèÿ òàéìôðåéìîâ ÎÄÍÎÃÎ È ÒÎÃÎ ÆÅ ÃÐÀÔÈÊÀ íàäî âûðîâíÿòü
   // âðåìÿ ðàñïîëîæåíèÿ âåðòèêàëüíîé ëèíèè íà ãðàíèöó ñòàðøåãî òàéìôðåéìà.
   if (Period()==PERIOD_MN1 || Period()==PERIOD_W1)
     {
     Alert("SHI_Mod_vLine can''t work with Weekly and Monthly charts");
     ObjectDelete("MyBarLine"); return(0);}
   switch(Period())  // 
     {
      case PERIOD_M1:     break;
      case PERIOD_M5:     myMinute=MathFloor(myMinute/5)*5; break;
      case PERIOD_M15:    myMinute=MathFloor(myMinute/15)*15; break;
      case PERIOD_M30:    myMinute=MathFloor(myMinute/30)*30; break;
      case PERIOD_H1:     myMinute=0; break;
      case PERIOD_H4:     myHour=MathFloor(myHour/4)*4; myMinute=0; break;
      case PERIOD_D1:     myHour=0; myMinute=0; break;
      case PERIOD_W1:     /*i=0; while(i<=Bars-1) 
	                       {
	                          if (TimeYear(Time[i])==myYear && TimeMonth(Time[i])==myMonth &&
	                              myDay-TimeDay(Time[i])<=6 && myDay-TimeDay(Time[i])>=0)
	                              myDay=TimeDay(Time[i]);  break; 
	                          i++;  //Íåïðàâèëüíî!!
	                       }*/
         break;
      case PERIOD_MN1:    break;
     }
   ObjectDelete("MyBarLine");
   myTime=StrToTime(myYear + "." + myMonth + "." + myDay + " "  + myHour + ":" + myMinute);
   ObjectCreate("MyBarLine",OBJ_VLINE,0,myTime,High[0]);
   ObjectSet("MyBarLine",OBJPROP_COLOR,Aqua);
   ObjectSet("MyBarLine",OBJPROP_WIDTH,1);
   ObjectSet("MyBarLine",OBJPROP_STYLE,STYLE_DOT);
   //Îòëàäêà
   /*
   Alert(myYear + "." + myMonth + "." + myDay + " "  + myHour + ":" + myMinute);
   myYear=TimeYear(myTime); myMonth=TimeMonth(myTime);myDay=TimeDay(myTime);
   myHour=TimeHour(myTime); myMinute=TimeMinute(myTime);
   Alert(myYear + "." + myMonth + "." + myDay + " "  + myHour + ":" + myMinute);
   */
   //return(0);
   i=0;
   while(Time[i]!=myTime) {i++;}
   MyBar=i;
   ArrayInitialize(UpLabel,0.0);
   if (Bars<MyBar+303) {Alert("Too little history");return(-1);}
   int    counted_bars=IndicatorCounted();
//---- 
   //if(Bars<AllBars)  AllBars=Bars;                 //return(-1);
   //if(AllBars<AB) {Comment("Ìàëî áàðîâ"); return(-1);}
   //Alert("MyBar=",MyBar);
   //if ((AllBars==0) || (Bars<AllBars)) AB=Bars; else AB=AllBars; //AB-êîëè÷åñòâî îáñ÷èòûâàåìûõ áàðîâ
   if (BarsForFract>0)
      BFF=BarsForFract;
   else
     {
      switch(Period())
        {
         case 1: BFF=12; break;
         case 5: BFF=48; break;
         case 15: BFF=24; break;
         case 30: BFF=24; break;
         case 60: BFF=12; break;
         case 240: BFF=15; break;
         case 1440: BFF=10; break;
         case 10080: BFF=6; break;
         default: DelObj(); return(-1); break;
        }
     }
   CurrentBar=2+MyBar; //ñ÷èòàåì ñ òðåòüåãî áàðà, ÷òîáû ôðàêòàë "çàêðåïèëñÿ
   B1=-1; B2=-1; UpDown=0; flag=0;
   while(((B1==-1) || (B2==-1)) && (CurrentBar<(AB+MyBar)))
     {
      //UpDown=1 çíà÷èò ïåðâûé ôðàêòàë íàéäåí ñâåðõó, UpDown=-1 çíà÷èò ïåðâûé ôðàêòàë
      //íàéäåí ñíèçó, UpDown=0 çíà÷èò ôðàêòàë åù¸ íå íàéäåí.
      //Â1 è Â2 - íîìåðà áàðîâ ñ ôðàêòàëàìè, ÷åðåç íèõ ñòðîèì îïîðíóþ ëèíèþ.
      //Ð1 è Ð2 - ñîîòâåòñòâåííî öåíû ÷åðåç êîòîðûå áóäåì ëèíèþ ïðîâîäèòü
      // if (CurrentBar==4 ) Alert("CurrentBar=",CurrentBar," ","BFF=",BFF);
      if((UpDown<1) && (CurrentBar==Lowest(Symbol(),Period(),MODE_LOW,BFF*2+1,CurrentBar-BFF)))
         // Âûðàæåíèå CurrentBar-BFF ìîæåò áûòü â äàí ñëó÷àå îòðèöàòåëüíûì. Íî âðîäå ðàáîòàåò
        {
         if(UpDown==0) { UpDown=-1; B1=CurrentBar; iB1=CurrentBar; P1=Low[B1];}
         else { B2=CurrentBar; iB2=CurrentBar; P2=Low[B2];}
        }
      if((UpDown>-1) && (CurrentBar==Highest(Symbol(),Period(),MODE_HIGH,BFF*2+1,CurrentBar-BFF)))
        {
         if(UpDown==0) { UpDown=1; B1=CurrentBar; iB1=CurrentBar; P1=High[B1];}
         else { B2=CurrentBar; iB2=CurrentBar; P2=High[B2];}
        }
      CurrentBar++;
     }
   if((B1==-1) || (B2==-1)) {DelObj(); return(-1);} // Çíà÷èò íå íàøëè ôðàêòàëîâ ñðåäè 300 áàðîâ 8-)
   Step=(P2-P1)/(B2-B1);//Âû÷èñëèëè øàã, åñëè îí ïîëîæèòåëüíûé, òî êàíàë íèñõîäÿùèé
   P1=P1-(B1-MyBar)*Step; B1=0+MyBar;//ïåðåñòàâëÿåì öåíó è ïåðâûé áàð ê íóëþ (çíà÷åíèå îïîðíîé ëèíèè íà 0 áàðå)
   //À òåïåðü îïîðíóþ òî÷êó ïðîòèâîïîëîæíîé ëèíèè êàíàëà.
   ishift=0+MyBar; iprice=0;
   //Alert(UpDown);
   if(UpDown==1)
     {
      //  Èñïðàâëåíî!!  Îïîðíóþ òî÷êó áóäåì èñêàòü ÌÅÆÄÓ îáíàðóæåííûìè ôðàêòàëàìè,
      //  à íå ñ 0-ãî (MyBar) áàðà. iB1-ýòî íå èçìåíåííûé B1
      //PP=Low[2+MyBar]-(2)*Step;
      PP=Low[2+iB1]-(2)*Step;
      iPP=Low[2+iB1]-(2)*Step;
      ii=2+iB1;
      //for(i=3+MyBar;i<=B2;i++) 
      for(i=3+iB1;i<=B2;i++)
        {
         //if(Low[i]<PP+Step*(i-MyBar)) { PP=Low[i]-(i-MyBar)*Step; ii=i;}
         if(Low[i]<iPP+Step*(i-iB1))
            //PP-çíà÷åíèå ëèíèè íà ïîñëåäíåì áàðå
            // iPP-çíà÷åíèå ëèíèè íà áàðå iB1 -ïðàâûé ôðàêòàë
           {
            PP=Low[i]-(i-MyBar)*Step; ii=i;
            iPP=Low[i]-(i-iB1)*Step;
           }
        }
      //Alert(iB1,"  ",iB2,"  ",ii,"  ","Step=",Step,"  ","PP=",PP);
      //Lab1Val=(High[iB1]+5*Point); 	Lab2Val=(High[iB2]+5*Point); 	Lab3Val=(Low[ii]-5*Point);
      UpLabel[iB1]=High[iB1]+5*Point;
      UpLabel[iB2]=High[iB2]+5*Point;
      UpLabel[ii]=Low[ii]-5*Point;
      //Alert(iB1,"  ",ii,"  ",iB2,"  ","Step=",Step,"  ","PP=",PP,"  ","Lab1Val=",Lab1Val);
      if(Low[0+MyBar]<PP) {ishift=0+MyBar; iprice=PP;}
      if(Low[1+MyBar]<PP+Step) {ishift=1+MyBar; iprice=PP+Step;}
      if(High[0+MyBar]>P1) {ishift=0+MyBar; iprice=P1;}
      if(High[1+MyBar]>P1+Step) {ishift=1+MyBar; iprice=P1+Step;}
     }
   else  //òðåíä âíèç
     {
      PP=High[2+MyBar]-(2)*Step;
      iPP=High[2+iB1]-(2)*Step;
      ii=2+iB1;
      //for(i=3+MyBar;i<=B2;i++) 
      for(i=3+iB1;i<=B2;i++)
        {
           if(High[i]>iPP+Step*(i-iB1)) { PP=High[i]-(i-MyBar)*Step;ii=i;
            iPP=High[i]-(i-iB1)*Step;
           } //èùåì çíà÷åíèå âåðõíåé ëèíèè íà 0 áàðå
        }
      //Lab1Val=(Low[iB1]-5*Point);Lab2Val=(Low[iB2]-5*Point);Lab3Val=(High[ii]+5*Point);
      UpLabel[iB1]=Low[iB1]-5*Point;
      UpLabel[iB2]=Low[iB2]-5*Point;
      UpLabel[ii]=High[ii]+5*Point;
      // Alert(iB1,"  ",iB2,"  ","ii=",ii,"  ","Step=",Step,"  ","PP=",PP,"  ",
      // "Lab1Val=",Lab1Val,"Lab3Val=",Lab3Val);
      // îïðåäåëÿåì, áûëî ëè ïåðåñå÷åíèå ëèíèé êàíàëà íà 0 èëè 1 áàðàõ(÷òîáû ñòàâèòü ïñèñó)
      if(Low[0+MyBar]<P1) {ishift=0+MyBar; iprice=P1;}
      if(Low[1+MyBar]<P1+Step) {ishift=1+MyBar; iprice=P1+Step;}
      if(High[0+MyBar]>PP) {ishift=0+MyBar; iprice=PP;}
      if(High[1+MyBar]>PP+Step) {ishift=1+MyBar; iprice=PP+Step;}
     }
   //Òåïåðü ïåðåñòàâèì êîíå÷íóþ öåíó è áàð íà ÀÂ, ÷òîáû ëèíèè êàíàëà ðèñîâàëèñü ïîäëèííåå
   P2=P1+AB*Step;
   T1=Time[B1]; T2=Time[AB+MyBar];
   //Åñëè íå áûëî ïåðåñå÷åíèÿ êàíàëà, òî 0, èíà÷å ñòàâèì ïñèñó.
   //if(iprice!=0) ExtMapBuffer1[ishift]=iprice;
   DelObj();
   // Alert("B1=",B1,"  ","B2=",AB+MyBar,"    ","AB=",AB,"  ","MyBar=",MyBar);
   //	Alert("T1=",T1,"  ","T2=",T2);
   //***************************************** Ðèñóåì ëèíèè êàíàëà ************************
   ObjectCreate("TL1",OBJ_TREND,0,T2,PP+Step*(AB),T1,PP);
   ObjectSet("TL1",OBJPROP_COLOR,Tomato);
   ObjectSet("TL1",OBJPROP_WIDTH,2);
   ObjectSet("TL1",OBJPROP_STYLE,STYLE_SOLID);
   ObjectSet("TL1",OBJPROP_RAY,False);
   ObjectCreate("TL2",OBJ_TREND,0,T2,P2,T1,P1);
   ObjectSet("TL2",OBJPROP_COLOR,Tomato);
   ObjectSet("TL2",OBJPROP_WIDTH,2);
   ObjectSet("TL2",OBJPROP_STYLE,STYLE_SOLID);
   ObjectSet("TL2",OBJPROP_RAY,False);
   ObjectCreate("MIDL",OBJ_TREND,0,T2,(P2+PP+Step*AB)/2,T1,(P1+PP)/2);
   ObjectSet("MIDL",OBJPROP_COLOR,Tomato);
   ObjectSet("MIDL",OBJPROP_WIDTH,1);
   ObjectSet("MIDL",OBJPROP_STYLE,STYLE_DOT);
   ObjectSet("MIDL",OBJPROP_RAY,DOT_Line_Ray);
   //*********************************** Ðèñóåì ïðîäîëæåíèå êàíàëà ************************
     if (MyBar>30) {Tf=Time[MyBar-30];
      PPf=PP-Step*30; P1f=P1-Step*30;
     }
     else          {Tf=Time[0];PPf=PP-Step*MyBar; P1f=P1-Step*MyBar;
     }
   ObjectCreate("TL1f",OBJ_TREND,0,T1,PP,Tf,PPf);
   ObjectSet("TL1f",OBJPROP_COLOR,Lime);
   ObjectSet("TL1f",OBJPROP_WIDTH,1);
   ObjectSet("TL1f",OBJPROP_STYLE,STYLE_DOT);
   ObjectSet("TL1f",OBJPROP_RAY,DOT_Line_Ray);
   ObjectCreate("TL2f",OBJ_TREND,0,T1,P1,Tf,P1f);
   ObjectSet("TL2f",OBJPROP_COLOR,Lime);
   ObjectSet("TL2f",OBJPROP_WIDTH,1);
   ObjectSet("TL2f",OBJPROP_STYLE,STYLE_DOT);
   ObjectSet("TL2f",OBJPROP_RAY,DOT_Line_Ray);
   //************************* Îòìå÷àåì êëèêíóòûé áàð  ************************************    
   /*if (MyBar>0)    
      {
      ObjectCreate("MyBarLine",OBJ_VLINE,0,Time[MyBar],High[MyBar]); 
      ObjectSet("MyBarLine",OBJPROP_COLOR,MediumOrchid); 
		ObjectSet("MyBarLine",OBJPROP_WIDTH,1); 
		ObjectSet("MyBarLine",OBJPROP_STYLE,STYLE_DOT); 
      }
   */
//----
   return(0);
  }
//+------------------------------------------------------------------+

Comments