Price and time coordinates

For objects of the types that exist in the quotes coordinate system, the MQL5 API supports a couple of properties for specifying time and price bindings. In the event that an object has several anchor points, properties require the specification of a modifier parameter containing the index of the anchor point when calling the ObjectSet and ObjectGet functions.

Identifier

Description

Value type

OBJPROP_TIME

Time coordinate

datetime

OBJPROP_PRICE

Price coordinate

double

These properties are available for absolutely all objects, but it makes no sense to set or read them for objects with screen coordinates.

To demonstrate how to work with coordinates, let's analyze the bufferless indicator ObjectHighLowChannel.mq5. For a given segment of bars, it draws two trend lines. Their start and end points on the time axis coincide with the first and last bar of the segment, and along the price axis, the values are calculated differently for each of the lines: the highest and lowest High prices are used for the upper line and the highest and lowest Low prices are used for the lower line. As the chart updates, our impromptu channel should move with prices.

The range of bars is set using two input variables: the number of the initial bar BarOffset and the number of bars BarCount. By default, the lines are drawn at the most recent prices, because bar offset = 0.

input int BarOffset = 0;
input int BarCount = 10;
   
const string Prefix = "HighLowChannel-";

Objects have a common name prefix "HighLowChannel-".

In the OnCalculate handler, we monitor the emergence of new bars over the iTime time of the 0-th bar. As soon as the bar is formed, the prices are analyzed on the specified segment, the maximum and minimum values of the prices of each of the two types (MODE_HIGH, MODE_LOW) are taken and the auxiliary function DrawFigure is called for them, and this is where the work with objects takes place: the creation and modification of coordinates.

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
{
   static datetime now = 0;
   if(now != iTime(NULL00))
   {
      const int hh = iHighest(NULL0MODE_HIGHBarCountBarOffset);
      const int lh = iLowest(NULL0MODE_HIGHBarCountBarOffset);
      const int ll = iLowest(NULL0MODE_LOWBarCountBarOffset);
      const int hl = iHighest(NULL0MODE_LOWBarCountBarOffset);
   
      datetime t[2] = {iTime(NULL0BarOffset + BarCount), iTime(NULL0BarOffset)};
      double ph[2] = {iHigh(NULL0fmax(hhlh)), iHigh(NULL0fmin(hhlh))};
      double pl[2] = {iLow(NULL0fmax(llhl)), iLow(NULL0fmin(llhl))};
    
      DrawFigure(Prefix + "Highs"tphclrBlue);
      DrawFigure(Prefix + "Lows"tplclrRed);
   
      now = iTime(NULL00);
   }
   return rates_total;
}

And here is the DrawFigure function itself.

bool DrawFigure(const string nameconst datetime &t[], const double &p[],
   const color clr)
{
   if(ArraySize(t) != ArraySize(p)) return false;
   
   ObjectCreate(0nameOBJ_TREND000);
   
   for(int i = 0i < ArraySize(t); ++i)
   {
      ObjectSetInteger(0nameOBJPROP_TIMEit[i]);
      ObjectSetDouble(0nameOBJPROP_PRICEip[i]);
   }
   
   ObjectSetInteger(0nameOBJPROP_COLORclr);
   return true;
}

After the ObjectCreate call that guarantees the existence of an object, the appropriate ObjectSet functions for OBJPROP_TIME and OBJPROP_PRICE are called at all anchor points (two in this case).

The image below shows the result of the indicator.

Channel on two trend lines at High and Low prices

Channel on two trend lines at High and Low prices

You can run the indicator in the visual tester to see how the line coordinates change on the go.