Не могу понять...© В августе 44-го

 

Доброго дня всем.

В одной из веток, в какой не помню, меня назвали волшебником после моего утверждения, что в тестере можно запросто получить значение трендовой линии на любом баре...

Эта "похвала" не давала мне покоя. И вот я решил убедиться, что хвалили меня не зря.

Написал простенький код. Для более лёгкого контроля ввёл переменную summ. Если low свечи ниже нижней трендовой summ += 1, если high свечи выше верхней трендовой summ -= 1;

   int   summ  = 0;
   
   ObjectDelete(ChartID(),"t_h");
   ObjectDelete(ChartID(),"t_l");
   // in_Vector_Bars = 5
   drawTLine("t_h",rates[2+in_Vector_Bars-1].time,rates[2+in_Vector_Bars-1].high,rates[2].time,rates[2].high,false,clrAliceBlue,STYLE_DOT,1,false,false);
   drawTLine("t_l",rates[2+in_Vector_Bars-1].time,rates[2+in_Vector_Bars-1].low ,rates[2].time,rates[2].low ,false,clrAliceBlue,STYLE_DOT,1,false,false);
   
   for(int i = 0; i < in_Vector_Bars; i++)
   {
     if(rates[2+i].high > NormalizeDouble(ObjectGetValueByTime(ChartID(),"t_h",rates[2+i].time),Digits())) summ -= 1;
     Print("~~if(rates[",2+i,"].high = ",rates[2+i].high," > t_h = ",NormalizeDouble(ObjectGetValueByTime(ChartID(),"t_h",rates[2+i].time),Digits()),") -1 || summ = ",summ);
     if(rates[2+i].low  < NormalizeDouble(ObjectGetValueByTime(ChartID(),"t_l",rates[2+i].time),Digits())) summ += 1;
     Print("~~if(rates[",2+i,"].low = ",rates[2+i].low," < t_l = ",NormalizeDouble(ObjectGetValueByTime(ChartID(),"t_l",rates[2+i].time),Digits()),") +1 || summ = ",summ);
   }

   Print("summ = ",summ);

При создании объекта вызывается ChartRedraw(chart_ID);


2020.03.17 10:20:56.792 2018.01.02 11:00:00   ~~if(rates[2].high = 1.20377 > t_h = 1.20377) -1 || summ = 0
2020.03.17 10:20:56.792 2018.01.02 11:00:00   ~~if(rates[2].low = 1.20233 < t_l = 1.20233) +1 || summ = 0
2020.03.17 10:20:56.792 2018.01.02 11:00:00   ~~if(rates[3].high = 1.20033 > t_h = 1.20377) -1 || summ = 0
2020.03.17 10:20:56.792 2018.01.02 11:00:00   ~~if(rates[3].low = 1.19924 < t_l = 1.20233) +1 || summ = 1
2020.03.17 10:20:56.792 2018.01.02 11:00:00   ~~if(rates[4].high = 1.20102 > t_h = 1.20377) -1 || summ = 1
2020.03.17 10:20:56.792 2018.01.02 11:00:00   ~~if(rates[4].low = 1.19971 < t_l = 1.20233) +1 || summ = 2
2020.03.17 10:20:56.792 2018.01.02 11:00:00   ~~if(rates[5].high = 1.20137 > t_h = 1.20377) -1 || summ = 2
2020.03.17 10:20:56.792 2018.01.02 11:00:00   ~~if(rates[5].low = 1.20066 < t_l = 1.20233) +1 || summ = 3
2020.03.17 10:20:56.792 2018.01.02 11:00:00   ~~if(rates[6].high = 1.20236 > t_h = 1.20377) -1 || summ = 3
2020.03.17 10:20:56.792 2018.01.02 11:00:00   ~~if(rates[6].low = 1.20114 < t_l = 1.20233) +1 || summ = 4
2020.03.17 10:20:56.793 2018.01.02 11:00:00   summ = 4

По логике сумма в данном примере должна быть 3, а она 4. Почему? Начальная точка, по которой строилась трендовая оказалась сдвинута!

А дальше веселее.


2020.03.17 10:45:40.246 2018.01.02 13:00:00   ~~if(rates[2].high = 1.20702 > t_h = 1.20702) -1 || summ = 0
2020.03.17 10:45:40.246 2018.01.02 13:00:00   ~~if(rates[2].low = 1.20417 < t_l = 1.20417) +1 || summ = 0
2020.03.17 10:45:40.246 2018.01.02 13:00:00   ~~if(rates[3].high = 1.20473 > t_h = 1.20702) -1 || summ = 0
2020.03.17 10:45:40.246 2018.01.02 13:00:00   ~~if(rates[3].low = 1.20318 < t_l = 1.20417) +1 || summ = 1
2020.03.17 10:45:40.246 2018.01.02 13:00:00   ~~if(rates[4].high = 1.20377 > t_h = 1.20702) -1 || summ = 1
2020.03.17 10:45:40.246 2018.01.02 13:00:00   ~~if(rates[4].low = 1.20233 < t_l = 1.20417) +1 || summ = 2
2020.03.17 10:45:40.247 2018.01.02 13:00:00   ~~if(rates[5].high = 1.20033 > t_h = 1.20703) -1 || summ = 2
2020.03.17 10:45:40.247 2018.01.02 13:00:00   ~~if(rates[5].low = 1.19924 < t_l = 1.20418) +1 || summ = 3
2020.03.17 10:45:40.247 2018.01.02 13:00:00   ~~if(rates[6].high = 1.20102 > t_h = 1.20703) -1 || summ = 3
2020.03.17 10:45:40.247 2018.01.02 13:00:00   ~~if(rates[6].low = 1.19971 < t_l = 1.20418) +1 || summ = 4
2020.03.17 10:45:40.247 2018.01.02 13:00:00   summ = 4

Эта строка утверждает, что значение трендовой на этой свече равно 1.20417, а при наведении на неё мыши показывает 1.20201

Отсюда вопрос: если значение трендовой определяется корректно, то с какого перепуга в тестер выдаются совершенно неадекватные значения?


Неутешительный вывод - не волшебник я.

И теперь я думаю, что моя ТС, построенная на множестве трендовых, из-за этого и выдавала совершенно не те результаты, которые ожидались? В тестере, само собой....

 
Сергей Таболин:

По логике сумма в данном примере должна быть 3, а она 4. Почему?


Для начала нужно разобраться с двумя вопросами:

1. Как удалось вызвать функцию ObjectGetValueByTime() с тремя аргументами, если у нее четыре обязательных аргумента?

double  ObjectGetValueByTime( 
   long      chart_id,     // идентификатор графика 
   string    name,         // имя объекта 
   datetime  time,         // время 
   int       line_id       // номер линии 
   );
 

2. Почему значения для каждой из линий на разных барах одинаковые? Для t_h значение на любом баре 1.20377, а для t_l - 1.20233.
    Документация по MQL5: Графические объекты / ObjectGetValueByTime
    Документация по MQL5: Графические объекты / ObjectGetValueByTime
    • www.mql5.com
    Функция использует синхронный вызов – это означает, что функция дожидается выполнения всех команд, которые были помещены в очередь графика перед её вызовом, и поэтому данная функция может быть затратной по времени. Нужно иметь это обстоятельство в виду...
     
    Ihor Herasko:

    Для начала нужно разобраться с двумя вопросами:

    1. Как удалось вызвать функцию ObjectGetValueByTime() с тремя аргументами, если у нее четыре обязательных аргумента?

    2. Почему значения для каждой из линий на разных барах одинаковые? Для t_h значение на любом баре 1.20377, а для t_l - 1.20233.

      Четвёртый аргумент имеет значение по умолчанию.


      Второй вопрос не понял...

      Понял. Почему - не знаю...

      Вопрос к разработчикам. ?
       
      Сергей Таболин:

      Второй вопрос не понял...

      Понял. Почему - не знаю...

      Вопрос к разработчикам. ?

      Перед тем, как что-то сообщать разработчикам, лучше убедиться, что вызовы всех функций прошли корректно. Для этого нужно вызов каждой функции сделать отдельной строкой, чтобы в отладчике увидеть возвращаемое значение. Возможно даже время, передаваемое в функцию (rates[2+i].time)  вовсе не то, которое Вы ожидаете.

       
      Ihor Herasko:

      Перед тем, как что-то сообщать разработчикам, лучше убедиться, что вызовы всех функций прошли корректно. Для этого нужно вызов каждой функции сделать отдельной строкой, чтобы в отладчике увидеть возвращаемое значение. Возможно даже время, передаваемое в функцию (rates[2+i].time)  вовсе не то, которое Вы ожидаете.

      И я так же подумал. Добавил в код

           Print(TimeToString(rates[2+i].time));
      

      Время читается правильно, а значение трендовой на всех барах берётся по последней цене построения этой самой трендовой.

      2020.03.17 12:31:32.004 2018.01.04 01:00:00   2018.01.03 23:00
      2020.03.17 12:31:32.004 2018.01.04 01:00:00   ~~if(rates[2].high = 1.20156 > t_h = 1.20156) -1 || summ = 0
      2020.03.17 12:31:32.004 2018.01.04 01:00:00   ~~if(rates[2].low = 1.20097 < t_l = 1.20097) +1 || summ = 0
      2020.03.17 12:31:32.004 2018.01.04 01:00:00   2018.01.03 22:00
      2020.03.17 12:31:32.004 2018.01.04 01:00:00   ~~if(rates[3].high = 1.20286 > t_h = 1.20156) -1 || summ = -1
      2020.03.17 12:31:32.004 2018.01.04 01:00:00   ~~if(rates[3].low = 1.20097 < t_l = 1.20097) +1 || summ = -1
      2020.03.17 12:31:32.004 2018.01.04 01:00:00   2018.01.03 21:00
      2020.03.17 12:31:32.004 2018.01.04 01:00:00   ~~if(rates[4].high = 1.20295 > t_h = 1.20156) -1 || summ = -2
      2020.03.17 12:31:32.008 2018.01.04 01:00:00   ~~if(rates[4].low = 1.20008 < t_l = 1.20097) +1 || summ = -1
      2020.03.17 12:31:32.008 2018.01.04 01:00:00   2018.01.03 20:00
      2020.03.17 12:31:32.008 2018.01.04 01:00:00   ~~if(rates[5].high = 1.20289 > t_h = 1.20156) -1 || summ = -2
      2020.03.17 12:31:32.008 2018.01.04 01:00:00   ~~if(rates[5].low = 1.20215 < t_l = 1.20097) +1 || summ = -2
      2020.03.17 12:31:32.008 2018.01.04 01:00:00   2018.01.03 19:00
      2020.03.17 12:31:32.008 2018.01.04 01:00:00   ~~if(rates[6].high = 1.20313 > t_h = 1.20156) -1 || summ = -3
      2020.03.17 12:31:32.008 2018.01.04 01:00:00   ~~if(rates[6].low = 1.20239 < t_l = 1.20097) +1 || summ = -3
      2020.03.17 12:31:32.008 2018.01.04 01:00:00   summ = -3
      
       
       Когда то давно делал ТС  по паттерну сходящийся треугольник. Там нужны были две трендовые по фракталам. Так я сами трендовые как объекты не создавал, а просто для расчёта уравнения прямых по двум точкам использовал. В тестере на четвёрке нормально работало.
       

      Уравнение прямой:

      //+------------------------------------------------------------------+
      //| Уравнение прямой                                                 |
      //+------------------------------------------------------------------+
      double EquationDirect(const int left_bar,const double left_price,const int right_bar,const double right_price,const int bar_to_search) 
        {
         return(right_bar==left_bar ? left_price : (right_price-left_price)/(right_bar-left_bar)*(bar_to_search-left_bar)+left_price);
        }
      //+------------------------------------------------------------------+
      

      Передаём в функцию: индекс левого бара, цена точки на левом баре, индекс правого бара, цена точки на правом баре, индекс бара, значение цены точки которого будет возвращено.

      И не нужно никаких объектов.

       
      Artyom Trishkin:

      Уравнение прямой:

      Передаём в функцию: индекс левого бара, цена точки на левом баре, индекс правого бара, цена точки на правом баре, индекс бара, значение цены точки которого будет возвращено.

      И не нужно никаких объектов.

      Вот-вот.

      Мне тоже странно, что простейшая аналитическая задача решается такими серьезными методами.

      И без проблем получается значение линии тренда не только на любом баре, но даже между ними !

      Артем, и будет забавно, когда в твоем предложении случайно будет right_bar = left_bar. Народ будет возмущен неработающим экспертом...В таких местах должен быть, как минимум, ASSERT, а то и прямая проверка условия.
       
      Artyom Trishkin:

      Уравнение прямой:

      Передаём в функцию: индекс левого бара, цена точки на левом баре, индекс правого бара, цена точки на правом баре, индекс бара, значение цены точки которого будет возвращено.

      И не нужно никаких объектов.

      Артём, спасибо. Работает.

      Однако саму проблему не решает. Как я понял, выдаёт результат только между двумя крайними барами? А трендовая линия рисуется "в будущее", и через, к примеру, 10 баров, по идее, можно прочитать значение объекта. А в Вашей формуле, я не пробовал, но сомневаюсь, что можно указать искомый бар с индексом [-10]... 

       

      Сергей, это аналитическая функция, она работает  с любыми входными данными.

      Можно подставлять даже комплексные входные значения.

      Единственное ограничение -  right_bar <> left_bar, эта проверка обязательно должна делаться перед вызовом функции, и если вдруг значения равны - то вместо вызова должна выполняться обработка этой исключительной ситуации.

       
      Georgiy Merts:

      Вот-вот.

      Мне тоже странно, что простейшая аналитическая задача решается такими серьезными методами.

      И без проблем получается значение линии тренда не только на любом баре, но даже между ними !

      Артем, и будет забавно, когда в твоем предложении случайно будет right_bar = left_bar. Народ будет возмущен неработающим экспертом...В таких местах должен быть, как минимум, ASSERT, а то и прямая проверка условия.

      Смотрим внимательно выше:

      //+------------------------------------------------------------------+
      //| Уравнение прямой                                                 |
      //+------------------------------------------------------------------+
      double EquationDirect(const int left_bar,const double left_price,const int right_bar,const double right_price,const int bar_to_search) 
        {
         return(right_bar==left_bar ? left_price : (right_price-left_price)/(right_bar-left_bar)*(bar_to_search-left_bar)+left_price);
        }
      //+------------------------------------------------------------------+
      Причина обращения: