Custom Line Study

 
Is it possible to create a custom line study in mt4? I wish to create "dynamic gann levels" line study.
 
In general words, it's possible. See for example, "Новый клиентский терминал MetaTrader 4 build 199"
Here is endless looped custom script which drawing Andrew's Pitchfork.
 
Is there a guide in English?
 
Is there a guide in english?
 
Put script into MetaEditor and learn how it works.
//+------------------------------------------------------------------+
//|                                             AndrewsPitchfork.mq4 |
//|                                                             Rosh |
//|                    http://www.alpari-idc.ru/ru/experts/articles/ |
//+------------------------------------------------------------------+
#property copyright "Rosh"
#property link      "http://www.alpari-idc.ru/ru/experts/articles/"


extern color mainLineColor=Blue;
extern color bandsLineColor=Blue;

int range=20;// initial index bar of first reper;
// coordinates of repers
double price1,price2,price3;
datetime time1,time2,time3;
double A; // coeff for Y=A*X+B
string medianLine="mainAP";
string upLine="upAP";
string downLine="downAP";
double PriceMediana;
datetime TimeMediana; 
double t2,t3,bar1,bar2,bar3;
int intBar1,intBar2,intBar3,barMediana;
//+------------------------------------------------------------------+
//| checking shift of  Number reper                                  |
//+------------------------------------------------------------------+
int Delta(int Number)
  {
//----
   int res=0; 
   if (Number<0||Number>3) return(0);
   switch (Number)
      {
      case 1:if (MathAbs(price1-ReperPrice(1))>Point || MathAbs(time1-ReperTime(1))>0)
         {
         res=1;
         break;
         }
      case 2:if (MathAbs(price2-ReperPrice(2))>Point || MathAbs(time2-ReperTime(2))>0)
         {
         res=2;
         break;
         }
      case 3:if (MathAbs(price3-ReperPrice(3))>Point || MathAbs(time3-ReperTime(3))>0)
         {
         res=3;
         break;
         }
      default: res=0;break;
      }
   return(res);
  }

//+------------------------------------------------------------------+
//| checking repers                                                  |
//+------------------------------------------------------------------+
bool isChanged()
  {
//----
   bool res=false; 
   if (Delta(1)!=0) return(true);   
   if (Delta(2)!=0) return(true);   
   if (Delta(3)!=0) return(true);   
   return(res);
  }

//+------------------------------------------------------------------+
//| redraw pitchforks                                                |
//+------------------------------------------------------------------+
void Redraw()
  {
//----
   if (ObjectFind(medianLine)==-1) ObjectCreate(medianLine,OBJ_TREND,0,time1,price1,TimeMediana,PriceMediana);
   else 
      {
      ObjectSet(medianLine,OBJPROP_PRICE1,price1);
      ObjectSet(medianLine,OBJPROP_PRICE2,PriceMediana);
      ObjectSet(medianLine,OBJPROP_TIME1,time1);
      ObjectSet(medianLine,OBJPROP_TIME2,TimeMediana);
      }
   ObjectSet(medianLine,OBJPROP_COLOR,mainLineColor);

   if (ObjectFind(upLine)==-1) ObjectCreate(upLine,OBJ_TREND,0,time2,price2,Time[0],price2+A*iBarShift(Symbol(),0,time2));
   else 
      {
      ObjectSet(upLine,OBJPROP_PRICE1,price2);
      ObjectSet(upLine,OBJPROP_PRICE2,price2+A*iBarShift(Symbol(),0,time2));
      ObjectSet(upLine,OBJPROP_TIME1,time2);
      ObjectSet(upLine,OBJPROP_TIME2,Time[0]);
      }
   ObjectSet(upLine,OBJPROP_COLOR,bandsLineColor);

   if (ObjectFind(downLine)==-1) ObjectCreate(downLine,OBJ_TREND,0,time3,price3,Time[0],price3+A*iBarShift(Symbol(),0,time3));
   else 
      {
      ObjectSet(downLine,OBJPROP_PRICE1,price3);
      ObjectSet(downLine,OBJPROP_PRICE2,price3+A*iBarShift(Symbol(),0,time3));
      ObjectSet(downLine,OBJPROP_TIME1,time3);
      ObjectSet(downLine,OBJPROP_TIME2,Time[0]);
      }
   ObjectSet(downLine,OBJPROP_COLOR,bandsLineColor);

   //Print("Перерисовываем");
   WindowRedraw();
   return;
  }

//+------------------------------------------------------------------+
//| return time of reper                                             |
//+------------------------------------------------------------------+
datetime ReperTime(int Number)
  {
//----
   datetime res=0;
   //Print("Возвращаем время репера №",Number);
   if (Number==1)
      {
      if (ObjectFind(medianLine)==-1) return(res);
      else res=ObjectGet(medianLine,OBJPROP_TIME1); 
      }
   if (Number==2)
      {
      if (ObjectFind(upLine)==-1) return(res);
      else res=ObjectGet(upLine,OBJPROP_TIME1); 
      }
   if (Number==3)
      {
      if (ObjectFind(downLine)==-1) return(res);
      else res=ObjectGet(downLine,OBJPROP_TIME1); 
      }

   return(res);
  }

//+------------------------------------------------------------------+
//| return price of reper                                            |
//+------------------------------------------------------------------+
double ReperPrice(int Number)
  {
//----
   double res=0;
   //Print("Возвращаем цену репера #",Number);
   if (Number==1)
      {
      if (ObjectFind(medianLine)==-1) return(res);
      else res=ObjectGet(medianLine,OBJPROP_PRICE1); 
      }
   if (Number==2)
      {
      if (ObjectFind(upLine)==-1) return(res);
      else res=ObjectGet(upLine,OBJPROP_PRICE1); 
      }
   if (Number==3)
      {
      if (ObjectFind(downLine)==-1) return(res);
      else res=ObjectGet(downLine,OBJPROP_PRICE1); 
      }

   return(res);
  }


//+------------------------------------------------------------------+
//| scrypt initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
//----
   double drop_price=WindowPriceOnDropped();
   datetime drop_time=WindowTimeOnDropped();
   if (drop_time>0)
      {
      price1=drop_price;
      time1=drop_time;
      Redraw();
      }
   else 
      {
      time1=ReperTime(1);
      //Print("Время первого репера ",TimeToStr(time1));
      if (time1==0) 
         {
         time1=Time[range];
         price1=(High[iHighest(Symbol(),0,MODE_HIGH,range,0)]+Low[iLowest(Symbol(),0,MODE_LOW,range,0)])/2;
         bar1=range;
         }
      else 
         {
         price1=ReperPrice(1);
         bar1=iBarShift(Symbol(),0,time1);
         }
      //Print("Выполняем блок без броска скрипта");
      
      time2=ReperTime(2);
      if (time2==0)
         {         
         intBar2=iHighest(Symbol(),0,MODE_HIGH,range/2.0,0);
         bar2=intBar2;
         time2=Time[intBar2];
         price2=High[intBar2];
         }
      else price2=ReperPrice(2);   
      
      time3=ReperTime(3);
      if (time3==0)
         {
         intBar3=iLowest(Symbol(),0,MODE_LOW,range/2.0,0);
         bar3=intBar3;
         time3=Time[intBar3];
         price3=Low[intBar3];
         }
      else price3=ReperPrice(3);   

      bar2=iBarShift(Symbol(),0,time2);
      bar3=iBarShift(Symbol(),0,time3);
      if (MathMod(MathAbs(bar3-bar2),2)==0) // четное число промежутков между барами
         {
         PriceMediana=(price2+price3)/2.0;
         t2=time2;
         t3=time3;
         TimeMediana=(t2+t3)/2.0;
         A=(PriceMediana-price1)/(bar1-(bar3+bar2)/2.0);
         //Print("Первый вариант, barMediana=",(bar3+bar2)/2,"  bar2=",bar2,"   bar3=",bar3,"   bar1=",bar1);
         }
      else  // нечетное число промежутков между барами
         {
         barMediana=(bar3+bar2+1.0)/2.0;
         TimeMediana=Time[barMediana];
         PriceMediana=(price2+price3)/2.0;
         A=(PriceMediana-price1)/(bar1-(bar3+bar2)/2.0);
         PriceMediana=price1+A*(bar1-barMediana);
         //Print("Второй вариант, barMediana=",barMediana,"  bar2=",bar2,"   bar3=",bar3,"   bar1=",bar1);
         }            
      Redraw();   
      }   
   return(0);
  }

//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start()
  {
//----
   while (!IsStopped())
      {
      if (isChanged())
         {
         time1=ReperTime(1);
         time2=ReperTime(2);
         time3=ReperTime(3);
         price1=ReperPrice(1);
         price2=ReperPrice(2);
         price3=ReperPrice(3);
         bar1=iBarShift(Symbol(),0,time1);
         bar2=iBarShift(Symbol(),0,time2);
         bar3=iBarShift(Symbol(),0,time3);
         if (MathMod(MathAbs(bar3-bar2),2)==0) // четное число промежутков между барами
            {
            PriceMediana=(price2+price3)/2.0;
            t2=time2;
            t3=time3;
            TimeMediana=(t2+t3)/2.0;
            A=(PriceMediana-price1)/(bar1-(bar3+bar2)/2.0);
            //Print("Первый вариант, barMediana=",(bar3+bar2)/2,"  bar2=",bar2,"   bar3=",bar3,"   bar1=",bar1);
            }
         else  // нечетное число промежутков между барами
            {
            barMediana=(bar3+bar2+1.0)/2.0;
            TimeMediana=Time[barMediana];
            PriceMediana=(price2+price3)/2.0;
            A=(PriceMediana-price1)/(bar1-(bar3+bar2)/2.0);
            PriceMediana=price1+A*(bar1-barMediana);
            //Print("Второй вариант, barMediana=",barMediana,"  bar2=",bar2,"   bar3=",bar3,"   bar1=",bar1);
            }            

         Redraw();
         }
      Sleep(100);
      }
//----
   return(0);
  }
//+------------------------------------------------------------------+



There is not complex.

Reason: