获取指定线条点的时间或价格坐标

许多图形对象包含一条或多条直线。MQL5 允许对这些直线上的点进行插值和外推,并实现坐标间的相互转换,例如通过时间获取价格,或通过价格获取时间。

插值始终可用:其作用范围在对象“内部”,即在锚点之间。仅当对象在相应方向上的射线特性被启用时,才可以在对象外部进行外推(请参阅 直线对象的射线特性)。

ObjectGetValueByTime函数返回指定时间的价格值。ObjectGetTimeByValue函数返回指定价格的时间值。

double ObjectGetValueByTime(long chartId, const string name, datetime time, int line)

datetime ObjectGetTimeByValue(long chartId, const string name, double value, int line)

计算是针对指定标识符为 chartId的图表上名为name 的对象进行的。timevalue 参数用于指定已知坐标,基于这个已知坐标来计算未知坐标。由于一个对象可能包含多条线条,因此一个坐标可能对应多个值,因此需要在 line参数中指定线条编号。

该函数返回指定初始坐标相对于线条的投影点所对应的价格或时间值。

如果发生错误,将返回 0,并将错误代码写入_LastError。例如,尝试对未启用射线特性的直线进行外推时,将生成 OBJECT_GETVALUE_FAILED (4205) 错误。

这些函数适用于以下对象:

  • 趋势线 (OBJ_TREND)
  • 角度趋势线 (OBJ_TRENDBYANGLE)
  • Gann 线 (OBJ_GANNLINE)
  • 等距通道 (OBJ_CHANNEL),2 条线
  • 线性回归通道 (OBJ_REGRESSION),3 条线
  • 标准差通道 (OBJ_STDDEVCHANNEL),3 条线
  • 带箭头直线 (OBJ_ARROWED_LINE)

我们将通过无缓冲指标ObjectChannels.mq5验证函数的运行情况。该指标会创建两个对象,分别为标准差通道和线性回归通道,随后请求获取未来柱线上通道上轨和下轨的价格,并将这些价格显示在图表注释中。对于标准差通道,已启用 OBJPROP_RAY_RIGHT 特性,但线性回归通道未启用该特性(有意为之)。因此,无法从第二个通道获取值,其在屏幕上始终显示为零。

随着新柱线的形成,通道将自动向右移动。通道长度通过输入参数 WorkPeriod设置(默认 10 根柱线)。

input int WorkPeriod = 10;
   
const string Prefix = "ObjChnl-";
const string ObjStdDev = Prefix + "StdDev";
const string ObjRegr = Prefix + "Regr";
   
void OnInit()
{
   CreateObjects();
   UpdateObjects();
}

CreateObjects函数创建 2 个通道并进行初始设置。

void CreateObjects()
{
   ObjectCreate(0ObjStdDevOBJ_STDDEVCHANNEL000);
   ObjectCreate(0ObjRegrOBJ_REGRESSION000);
   ObjectSetInteger(0ObjStdDevOBJPROP_COLORclrBlue);
   ObjectSetInteger(0ObjStdDevOBJPROP_RAY_RIGHTtrue);
   ObjectSetInteger(0ObjRegrOBJPROP_COLORclrRed);
   // NB: ray is not enabled for the regression channel (intentionally)
}

UpdateObjects函数将通道移动至最后 WorkPeriod 根柱线处。

void UpdateObjects()
{
   const datetime t0 = iTime(NULL0WorkPeriod);
   const datetime t1 = iTime(NULL00);
   
   // we don't use ObjectMove because channels work
   // only with time coordinate (price is calculated automatically)
   ObjectSetInteger(0ObjStdDevOBJPROP_TIME0t0);
   ObjectSetInteger(0ObjStdDevOBJPROP_TIME1t1);
   ObjectSetInteger(0ObjRegrOBJPROP_TIME0t0);
   ObjectSetInteger(0ObjRegrOBJPROP_TIME1t1);
}

OnCalculate处理程序中,我们会在新柱线上更新通道位置,每次收到分时报价时,我们便调用 DisplayObjectData 获取外推并将其显示为注释。

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
{
   static datetime now = 0;
   if(now != iTime(NULL00))
   {
      UpdateObjects();
      now = iTime(NULL00);
   }
   
   DisplayObjectData();
   
   return rates_total;
}

DisplayObjectData函数中,我们将在中线上的锚点上找到价格 (OBJPROP PRICE)。此外,我们将使用 ObjectGetValueByTime请求未来 WorkPeriod 根柱线处通道上下轨的价格值。

void DisplayObjectData()
{
   const double p0 = ObjectGetDouble(0ObjStdDevOBJPROP_PRICE0);
   const double p1 = ObjectGetDouble(0ObjStdDevOBJPROP_PRICE1);
   
   // the following equalities are always true due to the channel calculation algorithm:
   // - the middle lines of both channels are the same,
   // - anchor points always lie on the middle line,
   // ObjectGetValueByTime(0, ObjStdDev, iTime(NULL, 0, 0), 0) == p1
   // ObjectGetValueByTime(0, ObjRegr, iTime(NULL, 0, 0), 0) == p1
   
   // trying to extrapolate future prices from the upper and lower lines
   const double d1 = ObjectGetValueByTime(0ObjStdDeviTime(NULL00)
      + WorkPeriod * PeriodSeconds(), 1);
   const double d2 = ObjectGetValueByTime(0ObjStdDeviTime(NULL00)
      + WorkPeriod * PeriodSeconds(), 2);
   
   const double r1 = ObjectGetValueByTime(0ObjRegriTime(NULL00)
      + WorkPeriod * PeriodSeconds(), 1);
   const double r2 = ObjectGetValueByTime(0ObjRegriTime(NULL00)
      + WorkPeriod * PeriodSeconds(), 2);
   
   // display all received prices in a comment
   Comment(StringFormat("%.*f %.*f\ndev: up=%.*f dn=%.*f\nreg: up=%.*f dn=%.*f",
      _Digitsp0_Digitsp1,
      _Digitsd1_Digitsd2,
      _Digitsr1_Digitsr2));
}

需要注意的是,由于线性回归通道未启用射线特性,其在未来时段始终返回零值(不过如果请求的是通道时间周期内的价格,则会得到正确值)。

通道及其线条上各点的价格值

通道及其线条上各点的价格值

在此,对于长度为 10 根柱线的通道,外推计算也会向前进行 10 根柱线,这使得 "dev:" 行中显示的未来值大致对应窗口的右边框