MT4 - Point to point Horizontal line with price level label

 

Hi All,


I am struggling to find either a standard or custom drawing tool in MT4 version 4.00 build 1280 that will allow me to draw a horizontal line between two chosen points on a chart, and then show the level in the price axis, or next to the drawn line. Today I am drawing the horizontal levels as best I can using the draw trendline function. However, this does not draw horizontally (180 degrees) as standard, so it takes time to correct the unintended angle of my intended flat line, and I thne have to use the cross-hairs to work out the price level, and use the text function to write down the level.


Here is a manual view of what i am looking for:



Please let me know if anyone has seen this drawing tool functionality available.

Thanks for your help in advance.


Regards

Jason

 

Here you go ,place it in indicators .Enjoy

#property copyright "Mql5.com forum thread >>"
#property link      "https://www.mql5.com/en/forum/350019"
#property description "Telegram  : https://t.me/lorentzor\nInstagram : @rlorentzo\nTwitter : @lorentzo_r\nLinkedIn : https://www.linkedin.com/in/lorentzor\nYoutube : https://www.youtube.com/channel/UCM0Lj06cAJagFWvSpb9N5zA\nFacebook  : @LorentzoR"
/* 
ways to connect .> : 
Telegram  : https://t.me/lorentzor
Instagram : https://www.instagram.com/rlorentzo /OR/ @rlorentzo
Twitter   : https://twitter.com/lorentzo_r /OR/ @lorentzo_r
LinkedIn  : https://www.linkedin.com/in/lorentzor
Youtube   : https://www.youtube.com/channel/UCM0Lj06cAJagFWvSpb9N5zA
Facebook  : https://www.facebook.com/LorentzoR /OR/ @LorentzoR
Mql5.com  : https://www.mql5.com/en/users/lorio
*/
#property version   "1.00"
#property strict
#property indicator_chart_window
input bool AnchorStep=true;//Have Tag Anchor Step ? 
input bool CommentGuides=true;//Comment Guides ? 
input bool TagTimeframes=true;//Tag Timeframes ? 
input color LinesColor=clrDodgerBlue;//Lines Color 
input int LinesWidth=2;//Lines Width 
input ENUM_LINE_STYLE LinesStyle=STYLE_SOLID;//Lines Style
input bool WithTags=true;//With Tags ? 
input ENUM_ANCHOR_POINT TagAnchor=ANCHOR_RIGHT_LOWER;//Default Tag Anchor 
input string TagFont="Arial";//Tags font 
input int TagFontSize=12;//Tags Font Size 
input color TagColor=clrOrangeRed;//Tags Color
input int MouseClickDeflector=400;//Deflector milliseconds
input int ButtonPx=20;//Button Position X 
input int ButtonPy=20;//Button Position Y 
input int ButtonSx=200;//Button Size X 
input int ButtonSy=20;//Button Size Y 
input int ButtonFontSize=10;//Button Font Size
input string ButtonFont="Arial";//Button Font 
input string ButtonText="New Line>";//Button text 
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
string SystemTag="mrLines_",LinesTag="FL_";
string state_comment[],tfname="";
int OnInit()
  {
  //--- indicator buffers mapping
  tfname=TFtoString(PeriodToTF(Period()));
  ArrayResize(state_comment,4,0);
  state_comment[0]="Position Price <==\nPosition Start\nPosition End";
  state_comment[1]="Position Price\nPosition Start <==\nPosition End";
  state_comment[2]="Position Price\nPosition Start\nPosition End <==";
  if(AnchorStep){for(int i=0;i<3;i++){state_comment[i]+="\nAlign Tag";}}
  state_comment[3]="Position Price\nPosition Start\nPosition End\nAlign Tag <==";
  mrLines.Abort(true);
  ChartSetInteger(ChartID(),CHART_EVENT_MOUSE_MOVE,true);
  //---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
uint ClickMS=0;
int Mcx=0,Mcy=0,PreMcx=0,PreMcy=0;
string Mcc,PreMcc;
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
  //mousemove 
    //just a click 
    bool click_through=false;
    if(id==CHARTEVENT_CLICK&&mrLines.State!=eol_none){click_through=true;}
    if(id==CHARTEVENT_MOUSE_MOVE||click_through)
    {
    PreMcx=Mcx;PreMcy=Mcy;PreMcc=Mcc;
    Mcx=(int)lparam;Mcy=(int)dparam;Mcc=sparam;
    if(click_through){Mcc="1";}
      if(PreMcc=="0"&&Mcc!="0")
      {
      uint now=GetTickCount();
      int diff=(int)(now-ClickMS);
      if(now<ClickMS){diff=(int)(now)+(int)(UINT_MAX-ClickMS);}
      if(diff<=MouseClickDeflector){Mcc="0";}
      if(diff>MouseClickDeflector){ClickMS=now;}
      }
      //tag positioning 
      if(mrLines.State==eol_anchor)
      {
      double pr=0;datetime ti=0;int subw=0;
      bool get_price=ChartXYToTimePrice(ChartID(),Mcx,Mcy,subw,ti,pr);
      //if price is accesed 
      if(get_price){mrLines.ChangeTagAnchor(pr,ti);}
      //if click mouse button 2 - kill 
      if(Mcc=="2"){mrLines.Abort(true);}
      //if click mouse button 1 - finish 
      if(Mcc=="1"){mrLines.Abort(false);}     
      }
      //tag positioning ends here
      //point b positioning 
      if(mrLines.State==eol_pB)
      {
      double pr=0;datetime ti=0;int subw=0;
      bool get_price=ChartXYToTimePrice(ChartID(),Mcx,Mcy,subw,ti,pr);
      //if price is accesed 
      if(get_price){mrLines.ChangePointB(ti);}   
      //if click mouse button 2 - kill 
      if(Mcc=="2"){mrLines.Abort(true);}
      //if click mouse button 1 - proceed to anchor positioning 
      if(Mcc=="1")
        {
        PreMcc="0";
        Mcc="0";
        mrLines.DeleteGuide();
        if(WithTags&&AnchorStep){mrLines.State=eol_anchor;Comment(state_comment[3]);}
        if(!WithTags||!AnchorStep){mrLines.Abort(false);}
        }     
      }
      //point b positioning ends here       
      //point a positioning 
      if(mrLines.State==eol_pA)
      {
      double pr=0;datetime ti=0;int subw=0;
      bool get_price=ChartXYToTimePrice(ChartID(),Mcx,Mcy,subw,ti,pr);
      //if price is accesed 
      if(get_price){mrLines.ChangePointA(ti);}   
      //if click mouse button 2 - kill 
      if(Mcc=="2"){mrLines.Abort(true);}
      //if click mouse button 1 - proceed to point 2 positioning 
      if(Mcc=="1"){mrLines.State=eol_pB;PreMcc="0";Mcc="0";if(CommentGuides){Comment(state_comment[2]);}}         
      }
      //point a positioning ends here 
      //if moving the price 
      if(mrLines.State==eol_price)
      {
      double pr=0;datetime ti=0;int subw=0;
      bool get_price=ChartXYToTimePrice(ChartID(),Mcx,Mcy,subw,ti,pr);
      //if price is accesed 
      if(get_price){mrLines.ChangePrice(pr);}
      //if click mouse button 2 - kill 
      if(Mcc=="2"){mrLines.Abort(true);}
      //if click mouse button 1 - proceed to point 1 positioning 
      if(Mcc=="1"){mrLines.State=eol_pA;PreMcc="0";Mcc="0";mrLines.BuildGuide(LinesColor);if(CommentGuides){Comment(state_comment[1]);}}
      }
      //if moving the price ends here 
    }
  //mousemove ends here 
  //click on new line 
    if(id==CHARTEVENT_OBJECT_CLICK&&sparam==SystemTag+"_Make_Line")
    {
    double pr=0;datetime ti=0;int subw=0;
    bool get_price=ChartXYToTimePrice(ChartID(),Mcx,Mcy,subw,ti,pr);
    //if price is accesed 
    if(get_price)
      {
      ObjectsDeleteAll(ChartID(),SystemTag);
    //get mouse scroll state
      mrLines.ScrollState=(bool)ChartGetInteger(ChartID(),CHART_MOUSE_SCROLL);
      if(mrLines.ScrollState){ChartSetInteger(ChartID(),CHART_MOUSE_SCROLL,false);}
    //set to stage 1 price positioning 
      //initial price 
      mrLines.Price=pr;
      mrLines.State=eol_price;
      ClickMS=GetTickCount();
      PreMcc="0";Mcc="0";
      mrLines.LineName=LinesTag+"_"+IntegerToString(TimeLocal());
      mrLines.TagAnchored=TagAnchor;
      mrLines.TagSide=1;//B
      mrLines.HasTag=WithTags;
      mrLines.Cid=ChartID();
      mrLines.SubW=0;
      if(CommentGuides){Comment(state_comment[0]);}
      string tag_text=DoubleToString(pr,Digits());
      if(TagTimeframes){tag_text+=" ["+tfname+"]";}
      CreateHLWT(ChartID(),0,mrLines.LineName,WithTags,TagAnchor,tag_text,true,Time[100],true,Time[1],pr,pr,LinesColor,LinesWidth,LinesStyle,TagColor,TagFontSize,false,false,false,false);
      }
    //if price is accessed ends here
    }
  //click on new line ends here  
  }
//+------------------------------------------------------------------+
enum editor_state{
eol_none=0,
eol_price=1,//placing price
eol_pA=2,//placing point A 
eol_pB=3,//placing point B
eol_anchor=4//placing Anchor
};
struct editor_of_lines
{
editor_state State;
long Cid;
int SubW;
bool ScrollState,HasTag;
string LineName;
double Price;
datetime PointA,PointB;
ENUM_ANCHOR_POINT TagAnchored;
int TagSide;//0 point a ,1 point b
editor_of_lines(void){State=eol_none;}
//NEW PRICE : 
void ChangePrice(double new_price){
Price=new_price;
ObjectSetDouble(Cid,LineName,OBJPROP_PRICE1,new_price);
ObjectSetDouble(Cid,LineName,OBJPROP_PRICE2,new_price);
if(HasTag){
  ObjectSetDouble(Cid,LineName+"_tag",OBJPROP_PRICE,new_price);
  string tag_text=DoubleToString(Price,Digits());
  if(TagTimeframes){tag_text+=" ["+tfname+"]";}
  ObjectSetString(Cid,LineName+"_tag",OBJPROP_TEXT,tag_text);
  }
}
//CHANGE POINT A 
void ChangePointA(datetime new_point_a){
PointA=new_point_a;
ObjectSetInteger(Cid,LineName,OBJPROP_RAY,false);
ObjectSetInteger(Cid,LineName,OBJPROP_TIME1,new_point_a);
if(HasTag&&TagSide==0){ObjectSetInteger(Cid,LineName+"_tag",OBJPROP_TIME,new_point_a);}
ObjectSetInteger(Cid,SystemTag+"_Guide_Arrow",OBJPROP_TIME,new_point_a);
ObjectSetInteger(Cid,SystemTag+"_Guide_Line",OBJPROP_TIME,new_point_a);
}
//CHANGE POINT B 
void ChangePointB(datetime new_point_b){
PointB=new_point_b;
ObjectSetInteger(Cid,LineName,OBJPROP_RAY_RIGHT,false);
ObjectSetInteger(Cid,LineName,OBJPROP_TIME2,new_point_b);
if(HasTag&&TagSide==1){ObjectSetInteger(Cid,LineName+"_tag",OBJPROP_TIME,new_point_b);}
ObjectSetInteger(Cid,SystemTag+"_Guide_Arrow",OBJPROP_TIME,new_point_b);
ObjectSetInteger(Cid,SystemTag+"_Guide_Line",OBJPROP_TIME,new_point_b);
}
//CHANGE ANCHOR 
void ChangeTagAnchor(double mouseprice,datetime mousetime){
//midtime 
datetime midtime=(datetime)((PointA+PointB)/2);
//find new side 
if(mousetime<=midtime){TagSide=0;ObjectSetInteger(Cid,LineName+"_tag",OBJPROP_TIME,PointA);}
if(mousetime>midtime){TagSide=1;ObjectSetInteger(Cid,LineName+"_tag",OBJPROP_TIME,PointB);}
//find new anchor 
//above price 
  if(mouseprice>Price){
  //and left side 
    if(TagSide==0){TagAnchored=ANCHOR_LEFT_LOWER;}
  //and right side 
    if(TagSide==1){TagAnchored=ANCHOR_RIGHT_LOWER;}
  }
//below price 
  if(mouseprice<=Price){
  //and left side 
    if(TagSide==0){TagAnchored=ANCHOR_LEFT_UPPER;}
  //and right side 
    if(TagSide==1){TagAnchored=ANCHOR_RIGHT_UPPER;}
  }
ObjectSetInteger(Cid,LineName+"_tag",OBJPROP_ANCHOR,TagAnchored);
}
//build guide
void BuildGuide(color guide_color){
bool v_build=ObjectCreate(Cid,SystemTag+"_Guide_Line",OBJ_VLINE,SubW,0,0);
  if(v_build){
  ObjectSetInteger(Cid,SystemTag+"_Guide_Line",OBJPROP_COLOR,guide_color);
  ObjectSetInteger(Cid,SystemTag+"_Guide_Line",OBJPROP_STYLE,STYLE_DASH);
  ObjectSetInteger(Cid,SystemTag+"_Guide_Line",OBJPROP_SELECTABLE,false);
  ObjectSetInteger(Cid,SystemTag+"_Guide_Line",OBJPROP_BACK,false);
  ObjectSetInteger(Cid,SystemTag+"_Guide_Line",OBJPROP_WIDTH,1);
  bool a_build=ObjectCreate(Cid,SystemTag+"_Guide_Arrow",OBJ_TEXT,SubW,0,Price);
    if(a_build){
    ObjectSetInteger(Cid,SystemTag+"_Guide_Arrow",OBJPROP_COLOR,guide_color);
    ObjectSetInteger(Cid,SystemTag+"_Guide_Arrow",OBJPROP_ANCHOR,ANCHOR_CENTER);
    ObjectSetString(Cid,SystemTag+"_Guide_Arrow",OBJPROP_FONT,"Wingdings");
    ObjectSetString(Cid,SystemTag+"_Guide_Arrow",OBJPROP_TEXT,CharToString(162));
    ObjectSetInteger(Cid,SystemTag+"_Guide_Arrow",OBJPROP_FONTSIZE,12);
    }
  }
}
//delete guide
void DeleteGuide(){
ObjectsDeleteAll(Cid,SystemTag+"_Guide");
}
//Abort
void Abort(bool kill_line_under_edit){
  if(CommentGuides){Comment("");}
//delete objects created 
  if(kill_line_under_edit){ObjectsDeleteAll(Cid,LineName);}
//reset state 
  State=eol_none;
//restore mouse scroll
  if(ScrollState){ChartSetInteger(Cid,CHART_MOUSE_SCROLL,true);}
//create btn 
  DeckUp();
}
//Button 
void DeckUp(){
  ObjectsDeleteAll(ChartID(),SystemTag);
  HS_Create_Btn(ChartID(),0,SystemTag+"_Make_Line",ButtonSx,ButtonSy,ButtonPx,ButtonPy,ButtonFont,ButtonFontSize,clrRoyalBlue,clrDodgerBlue,BORDER_FLAT,clrGoldenrod,ALIGN_CENTER,ButtonText,false,false);
}
};
editor_of_lines mrLines;
//Period to Timeframe 
ENUM_TIMEFRAMES PeriodToTF(int period)
{
if(period==1) return(PERIOD_M1);
if(period==5) return(PERIOD_M5);
if(period==15) return(PERIOD_M15);
if(period==30) return(PERIOD_M30);
if(period==60) return(PERIOD_H1);
if(period==240) return(PERIOD_H4);
if(period==1440) return(PERIOD_D1);
if(period==10080) return(PERIOD_W1);
if(period==43200) return(PERIOD_MN1);
return(PERIOD_CURRENT);
}
//Timeframe To String 
string TFtoString(ENUM_TIMEFRAMES TF)
{
string returnio="";
if(TF==PERIOD_M1) returnio="M1";
if(TF==PERIOD_M5) returnio="M5";
if(TF==PERIOD_M15) returnio="M15";
if(TF==PERIOD_M30) returnio="M30";
if(TF==PERIOD_H1) returnio="H1";
if(TF==PERIOD_H4) returnio="H4";
if(TF==PERIOD_D1) returnio="D1";
if(TF==PERIOD_W1) returnio="W1";
if(TF==PERIOD_MN1) returnio="MN1";
return(returnio);
}
//CREATE HORIZONTAL LINE WITH TAG 
  void CreateHLWT(long cid,
                  int subw,
                  string line_name,
                  bool has_tag,
                  ENUM_ANCHOR_POINT tag_anchor,
                  string tag_text,
                  bool infinite_left,
                  datetime start_time,
                  bool infinite_right,
                  datetime end_time,
                  double start_price,
                  double end_price,
                  color line_color,
                  int line_width,
                  ENUM_LINE_STYLE line_style,
                  color tag_color,
                  int tag_font_size,
                  bool back,
                  bool selectable,
                  bool tag_back,
                  bool tag_selectable)
          {
          bool obji=ObjectCreate(cid,line_name,OBJ_TREND,subw,0,start_price,end_time,end_price);
                  ObjectSetInteger(cid,line_name,OBJPROP_BACK,back);
                  ObjectSetInteger(cid,line_name,OBJPROP_SELECTABLE,selectable);
                  ObjectSetInteger(cid,line_name,OBJPROP_COLOR,line_color);
                  ObjectSetInteger(cid,line_name,OBJPROP_STYLE,line_style);
                  ObjectSetInteger(cid,line_name,OBJPROP_WIDTH,line_width);
                  if(!infinite_left) ObjectSetInteger(cid,line_name,OBJPROP_RAY,false);
                  if(infinite_left)  ObjectSetInteger(cid,line_name,OBJPROP_RAY,true);
                  if(!infinite_right) ObjectSetInteger(cid,line_name,OBJPROP_RAY_RIGHT,false);
                  if(infinite_right)  ObjectSetInteger(cid,line_name,OBJPROP_RAY_RIGHT,true);
        //if tag 
          if(has_tag)
          {
          string objna=line_name+"_tag";
          obji=ObjectCreate(cid,objna,OBJ_TEXT,subw,end_time,end_price);
          ObjectSetInteger(cid,objna,OBJPROP_COLOR,tag_color);
          ObjectSetInteger(cid,objna,OBJPROP_ANCHOR,tag_anchor);
          ObjectSetInteger(cid,objna,OBJPROP_FONTSIZE,tag_font_size);
          ObjectSetInteger(cid,objna,OBJPROP_BACK,tag_back);
          ObjectSetInteger(cid,objna,OBJPROP_SELECTABLE,tag_selectable);
          ObjectSetString(cid,objna,OBJPROP_TEXT,tag_text);
          }
        //if tag ends here 
        }

//CREATE LINE WITH TAG ENDS HERE 

//CREATE BTN OBJECT
  void HS_Create_Btn(long cid,
                     int subw,
                     string name,
                     int sx,
                     int sy,
                     int px,
                     int py,
                     string font,
                     int fontsize,
                     color bck_col,
                     color brd_col,
                     ENUM_BORDER_TYPE brd_type,
                     color txt_col,
                     ENUM_ALIGN_MODE align,
                     string text,
                     bool selectable,
                     bool back)  
  {
    if(!IsTesting()||IsVisualMode())
    {
  bool obji=ObjectCreate(cid,name,OBJ_BUTTON,subw,0,0);
  if(obji)
    {
    ObjectSetString(0,name,OBJPROP_FONT,font);
    ObjectSetInteger(0,name,OBJPROP_ALIGN,align);
    ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fontsize);
    ObjectSetInteger(0,name,OBJPROP_XSIZE,sx);
    ObjectSetInteger(0,name,OBJPROP_YSIZE,sy);
    ObjectSetInteger(0,name,OBJPROP_XDISTANCE,px);
    ObjectSetInteger(0,name,OBJPROP_YDISTANCE,py);
    ObjectSetInteger(0,name,OBJPROP_BGCOLOR,bck_col);
    ObjectSetInteger(0,name,OBJPROP_BORDER_COLOR,brd_col);
    ObjectSetInteger(0,name,OBJPROP_COLOR,txt_col);
    ObjectSetInteger(0,name,OBJPROP_BORDER_TYPE,brd_type);
    ObjectSetInteger(0,name,OBJPROP_SELECTABLE,selectable);
    ObjectSetInteger(0,name,OBJPROP_BACK,back);
    ObjectSetString(0,name,OBJPROP_TEXT,text);
    }
    }
  }                   
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {return(rates_total);}
Files:
FunLines.ex4  28 kb
FunLines.mq4  17 kb
 

Dear Lorentzos,


The indicator is exactly what i was looking for.

Thank you so much, you are a star.


Good trading to you.


Regards

Jason

 

Hi Lorentzos


How do I save the levels, so when i change timeframe the levels do not automatically delete?


Regards

Jason

 
FX77:

Hi Lorentzos


How do I save the levels, so when i change timeframe the levels do not automatically delete?


Regards

Jason

Here you go , i altered it to not delete them.

Files:
FunLines.ex4  28 kb
FunLines.mq4  17 kb
 
Lorentzos Roussos:

Here you go , i altered it to not delete them.

very interesting indy thanks! but how can i delet the lines after creation?! they are unselectable!
 

Hi ! Thanks for this useful indicator. How can I delete those lines ?

 

Thank you, but is deleted when I change timeframe and not easy to adjust it or edit.

 

Hi  Lorentzos, thanks for the fantastic indicator. 

I was wondering if you could add the option of clicking a line to adjust it's length or move it to another level.

Many thanks George

 
do you have the same indicator for mt5?