How to get the angle of a trendline and place a text object to it?

 

Hi coders,

this indicator prints a text object as soon as a trendline is drawn. I found the calculation for the angle in the MQL5 forum but it doesn't work correctly. The angle in degrees is always wrong. Just the directon (above or below zero) works. Does anyone have made some experiences with that and can help me?


//+------------------------------------------------------------------+
//|                                                    LabelTest.mq4 |
//|                           Copyright 2015, Marcus Riemenschneider |
//|                   http://www.facebook.com/marcus.riemenschneider |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Marcus Riemenschneider"
#property link      "http://www.facebook.com/marcus.riemenschneider"
#property version   "1.00"
#property strict
#property indicator_chart_window
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   ChartSetInteger(0, CHART_EVENT_OBJECT_CREATE, true);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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 value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   if (id==CHARTEVENT_OBJECT_CREATE) {
      if (ObjectType(sparam)==OBJ_TREND) {
         string objName=sparam;
         datetime time1 = (datetime)ObjectGetInteger(0, objName, OBJPROP_TIME1);
         double price1 = ObjectGetDouble(0, objName, OBJPROP_PRICE1);
         datetime time2 = (datetime)ObjectGetInteger(0, objName, OBJPROP_TIME2);
         double price2 = ObjectGetDouble(0, objName, OBJPROP_PRICE2);
         double angle_in_radians = MathArctan((price2-price1) / (time2-time1));
         double angle_in_degree = 180 * angle_in_radians / MathArccos(-1.0);
         int pips;
         color col;
         string text;
         if (angle_in_degree>=0) {
            pips=-5;
            col=clrLime;
            text="Uptrend";
         }
         else if (angle_in_degree<0) {
            pips=5;
            col=clrRed;
            text="Downtrend";
         }
         objName="Label_"+TimeToString(time1, TIME_DATE|TIME_SECONDS);
         if (ObjectFind(objName)==0) ObjectDelete(0, objName);
         ObjectCreate(0, objName, OBJ_TEXT, 0, time1, price1+pips*10*Point);
         ObjectSetInteger(0, objName, OBJPROP_ANCHOR, ANCHOR_LEFT);
         ObjectSetString(0, objName, OBJPROP_TEXT, text);
         ObjectSetInteger(0, objName, OBJPROP_COLOR, col);
         ObjectSetDouble(0, objName, OBJPROP_ANGLE, angle_in_degree);
      }
   }
  }
//+------------------------------------------------------------------+
 

I have these two function, at least one is normed between -1 and +1.

double angle(double steep, double flat=0.0)     { return((atan(steep)-atan(flat))/M_PI_2); }  
double angleDegr(double steep, double flat=0.0) { return((atan(steep)-atan(flat))*180.0/M_PI); }
...
double steep, flat, ang1, ang2;
steep = Prc_a1 - Prc_a2;
flat  = Prc_b1 - Prc_b2;
ang1 = angle(flat);
ang2 = angleDegr(flat);

You don't need (time1-time2) it's always 1 bar. But to get a kind of smoothing you can use the a time-difference of more than 1 bar!

 

hello,

I am going to write some remarks, regardless of the code you posted but rather about some principles you should have in mind, regarding the subject . Those, maybe in turn will help you implement your own code.

So, regarding angles of trendline in a market chart of price/time, you should have something in mind, that there is no such thing such as an angle, as in a e.g. integer/integer graph. In the case of integer/integer graph, you can specify an angle as a ratio of similar numbers (integers). In a price/time chart, the two axes are not similar (as the saying says, you are basically comparing apples to oranges); what you can do, is to define first what you want to be an angle of reference. So, e.g. you may define as an angle of 45 degrees to be 10 pips per 100 seconds, or 50 pips per open per five 5-minutes bars and so on. Then, you can specify angles relative to that reference

Or, to put it in another way, the angle you are drawing, is valid only in the precise chart you are drawing in. If you change TF and/or price scale in an arbritrary manner your angle may vary, according to the changes you are making 

best regards 

 
Exactly. Can't be done.
  1. There is no angle from 2 anchor points. An angle requires distance/distance a unitless number. A chart has price/time. What is the angle of going 30 miles in 45 minutes? Meaningless!
  2. You can get the slope from a trendline. Delta price/ delta time.  Changing the axes scales changes the apparent angle, the slope is constant. Angle is meaningless.
  3. You can create a angled line using one point and setting the angle. The line is drawn that angle in pixels. Changing the axes scales does NOT change the angle.
 

Hey guys, thanks for your advice. Of course I know it's not possible to determine the real angle because of different units. Slope would have been the better word for it. Because English is not my native language, it can easily get confusing. As you can see in my example it is not important that the slope will be determined 100% exact. It is just a text label for a trendline. The trendline of course is important but the text object has only information purposes. I just wanted it to have a very similar slope like the trendline.

But how can I get the slope of a trendline? How can delta price / delta time be exactly applied? Let's say I have a descending trendline with PRICE1 = 1.50 and PRICE2 = 1.30. TIME1 is 2015.01.01 and TIME2 is 2015.03.01.

Then the slope would be (1.30-1.50) /(2015.03.01-2015.01.01). But that alone doesn't give a clear result, does it?

 

You only need (1.30-1.50)! The angel to a line with a slope of 0 (I hope 1.50 is the early price, 1.30 the latter one):

double ang = angleDegr(1.30-1.50); // ang = atan(1.30-1.50)*180/pi  -11.31°

To compare to slopes a=1.30-1.50, b=1.40-1.55 (if and only if both have the same time span!!):

double ang = angleDegr((1.30-1.50), (1.40-1.55)); // ang = (atan(1.30-1.50)-atan(1.40-1.55))*180/pi  -2.779° 


To get a feeling for functions and their slope look for an online math plotter and play with it.

I am using http://rechneronline.de/funktionsgraphen/ but this is in German.

 
mar:


But how can I get the slope of a trendline? How can delta price / delta time be exactly applied? Let's say I have a descending trendline with PRICE1 = 1.50 and PRICE2 = 1.30. TIME1 is 2015.01.01 and TIME2 is 2015.03.01.

Then the slope would be (1.30-1.50) /(2015.03.01-2015.01.01). But that alone doesn't give a clear result, does it?

 Time, is not stored in 2015.02.01 format, but in seconds elapsed since January 1st, 1970. It is called epoch time/unix time/posix time (i realise Microsoft can not feel really comfortable about that :) ) As you can see here https://docs.mql4.com/basis/types/integer datetime is categorised under integer types; in fact it is a 8 bytes integer and and if we want to get a easily readable format out of it we have to use TimeToString() in MQL (or use #property strict). So, regarding the original question, I can see from the code you posted that the slope calculation (angle, whatever :) )  is like price2-price1/time2-time1. Essentially a double/int measurement, which points to the fact that in that code, points are mapped to seconds as a 1:1 quantity. That can give you some trouble in the case that you can have either a 4 or 5 digits broker, or a stock index with 2 digits etc.

 Edit: The formula given in the code you posted, actually gives really small numbers when dealing with common 5 digits currency pairs. For example, it can usually reach out for a tan of 0.0015/150. I propose, that if you want to receive more usefull numbers to do as such

/* here, i multiply price2-price1 with 100000 - it can be done with whatever number feels better, 

   speicific to a given instrument */

double angle_in_radians = MathArctan( ( (price2-price1)*100000) / (time2-time1) );

 

best regards 

 
double angle_in_radians = MathArctan( ( (price2-price1)*100000) / (time2-time1) );
Arctan takes a pure number, you are passing change in price per change in time. What is the angle of going 30 miles in 45 minutes?
 
WHRoeder:
Arctan takes a pure number, you are passing change in price per change in time. What is the angle of going 30 miles in 45 minutes?

It has a meaning as soon as you want that the angle exceeds a certain limit as you can interpret this (in trading on a chart) as a kind of strength of a trend.

But of course the strength of trend can be measured in different ways too e.g. just by the difference of two prices themselves without converting them into an angel.

On the other hand an angel is limited between +/- 90° (or +/- 1) and in some cases this kind of scaling has some advantages.

 

WHRoeder:

 

 double angle_in_radians = MathArctan( ( (price2-price1)*100000) / (time2-time1) );


Arctan takes a pure number, you are passing change in price per change in time. What is the angle of going 30 miles in 45 minutes?
things can have a meaning as long as we can give them some (i suppose) :) My point is, price, as well as time, can be quantitative , so it is up to us to decide what we would like their relation to be in a chart. Or another example, in P&F charts, as long as all elements have a square bounding rectangle, despite the fact that the x axis is not even made up by a continuous arithemtic series but rather by alternate up and down columns, we can right away tell that there are angles of 45 degrees somewhere.  So, i believe that we can isolate geometry from the underlying objects, as long as we set our facts straight
 

Let me add that if you have only one angle you do compare that number (its degrees) to the angle of a horizontal line with an angle 0° even if you don't mention that.

A single number does in deed have no meaning! Only the relation to another number gives both number a meaning even if the second number is not explicitly mentioned but can be presumed to be zero.