Аналог ObjectGetValueByTime может кто то реализовывал ? - страница 5

 
Aleksandr Slavskii #:

Нашёл причину. Галочка "Точная шкала времени.

Если стоит галка то формула тангенса полностью совпадает с ObjectGetValueByTime(), если галки нет, то чем больше угол трендовой тем больше разница в результатах.

Вывод, если хотим, чтоб при убранной галке ваша пользовательская функция совпадала с ObjectGetValueByTime(), то нужно округлять значение времени до времени открытия свечи таймфрейма.

Гифка работает только если на неё кликнуть.


ps вот такой вариант округления в пользовательской функции, даёт одинаковый результат с ObjectGetValueByTime(), не зависимо от галки в настройках.


Думаю здесь все понимают, что вот это 

и то, что написал я, это одно и то же. Формула тангенса. 

Об этом уже сказано. Только есть вариант преобразования попроще, на мой взгляд

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Аналог ObjectGetValueByTime может кто то реализовывал ?

Alexey Viktorov, 2026.04.17 13:24

Ну ведь преобразовать ничего не сто́ит.

double PriceLineTime(datetime tim_0, double pr_0, datetime tim_1, double pr_1, datetime tim_2)
 {
  int perSec = PeriodSeconds();
  tim_0 = datetime(int(tim_0/perSec)*perSec);
  tim_1 = datetime(int(tim_1/perSec)*perSec);

Вот такое время

2026.04.17 16:20:01.158 Test (EURUSD,H1)        2026.04.13 21:59:00 : 2026.04.14 07:53:00

функция ObjectGetValueByTime читает отбросив минуты без округления. Поэтому в написании своей функции надо это учитывать и также отбрасывать если закрались такие поправки.


Ещё: функция ObjectGetValueByTime не видит правую координату если она находится «в будущем».


 
Vladimir Pastushak #:

Экспериментирую

Результат

Не сходятся значения.

Пробовал ставить 0 то же не сходятся.

Исключил бар за пределами.

Вы почему упорно не хотите сказать на каком графике и по каким координатам нарисована линия?

Как я погляжу у всех участников обсуждения в том или ином варианте значения сходятся, а у вас ни при каких условиях не получается…

 
Alexey Viktorov #:

Об этом уже сказано. Только есть вариант преобразования попроще, на мой взгляд

Согласен с вами, это тот же ху# только в левой руке.  Разницы нет. 

Я бы только убрал лишние буквы(приведение к int), а так да, ваше округление немного красивее моего.

  int perSec = PeriodSeconds();
  tim_0 = tim_0/perSec*perSec;
  tim_1 = tim_1/perSec*perSec;
 
Vladimir Pastushak:

Друзья, может кто то реализовывал аналог ObjectGetValueByTime  ?

Пробовал формулу линейной интерполяции но результат сильно отличается от ObjectGetValueByTime.


Может кто то уже решал подобную задачу, поделитесь примером.

Привет, Владимир. 
Да, Игорь правильно все сказал, что нужно все пересчитывать через индексы баров, так как время по оси X распределено не равномерно (имеет разную плотность)
Так как у меня все преобразования Цена-Время <-> XY давно реализованы в iCanvas, то я набросал демонстрирующий пример с правильными преобразованиями. Можешь заглянуть в класс iCanvas чтобы посмотреть все методы.
В примере все координаты сохраняются в формате Цена-Время. На входе имеется тестовое время (вертикальная красная линия) и также тестируется пересечение всех линий с временем указателя мышки. 
#include <Canvas\iCanvas_CB.mqh> //https://www.mql5.com/ru/code/22164
input datetime test_time  = D'2026.04.17 8:00';
struct iPoint {
   double price;
   datetime time;
};
iPoint points[];
int cur_size = 0;
//+------------------------------------------------------------------+
int OnInit() {
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
void OnTick() {
}
//+------------------------------------------------------------------+
void OnChartEvent(const int32_t id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam) {
   if (id == CHARTEVENT_CLICK) {
      cur_size++;
      ArrayResize(points,cur_size,100);
      points[cur_size-1].price = Canvas.Price(W.MouseY);
      points[cur_size-1].time = Canvas.TimePos(double(W.MouseX));
   }
   if (id==CHARTEVENT_MOUSE_MOVE || id == CHARTEVENT_CHART_CHANGE) Draw();
}
//+------------------------------------------------------------------+
void Draw() {
   Canvas.Erase(0x00FFFFFF);
   int total_lines = cur_size/2+cur_size%2;
   Canvas.LineVertical(int(Canvas.X(test_time)),0,W.Height-1,0x40FF0000);
   for (int i = 0; i<total_lines; i++) {
      double p1 = points[2*i].price;
      double p2 = (cur_size%2>0 && i==(total_lines-1))?Price(double(W.MouseY)):points[2*i+1].price;
      datetime t1 = points[2*i].time;
      datetime t2 = (cur_size%2>0 && i==(total_lines-1))?Canvas.TimePos(double(W.MouseX)):points[2*i+1].time;
      double x1 = Canvas.X(t1);
      double x2 = Canvas.X(t2);
      double y1 = Canvas.Y(p1);
      double y2 = Canvas.Y(p2);
      Canvas.LineD(x1,y1,x2,y2,0xFF8000FF);
      Canvas.Circle(int(x1),int(y1),7,0xFF8000FF);iBarShift
      Canvas.Circle(int(x2),int(y2),7,0xFF8000FF);
      Canvas.Circle(int(Canvas.X(test_time)),int(Canvas.Y(InterpolatePrice(t1,p1,t2,p2,test_time))),7,0xFFFF0000);
      Canvas.Circle(int(Canvas.X(W.MouseTime)),int(Canvas.Y(InterpolatePrice(t1,p1,t2,p2,W.MouseTime))),7,0xFF80FF00);
   } 
   Canvas.Update();
}
//+------------------------------------------------------------------+
double InterpolatePrice(datetime t1, double p1, datetime t2, double p2, datetime t) {
   double x1 = Canvas.X(t1);
   double y1 = Canvas.Y(p1);
   double x2 = Canvas.X(t2);
   double y2 = Canvas.Y(p2);
   double x3 = Canvas.X(t);
   double dx = (x1!=x2)?(x2-x1):0.0000001;
   return Price(y1+(x3-x1)*(y2-y1)/dx);
}
//+------------------------------------------------------------------+
double  Price(double y) {
   return (W.Y_max-y*(W.Y_max-W.Y_min)/W.Height);
}
//+------------------------------------------------------------------+

Файлы: