Функция CustomTicksAdd() содержит серьезную ошибку. Надеюсь, администратор поможет решить эту проблему. Спасибо! - страница 3

 
Aleksey Vyazmikin #:

это недокументированные серверные возможности.

Я также думаю, только у вас получилось лучше сформулировать.

 
Aleksey Vyazmikin #:

Это настройка пользовательского символа, по идеи от неё зависеть должна интерпретация поступающих тиков - рисовать по цене тика ask/bid или по last бары.

Вот нашёл у себя, на полке пылилось. 

Выложил сюда.  https://www.mql5.com/ru/code/60406

Простенький код конвертера периодов, в нём довольно просто понять, что от флагов тиков формирование баров не зависит.

Period Converter Mod
Period Converter Mod
  • www.mql5.com
Аналог Period Converter в МТ4
 
Aleksandr Slavskii #:

Вот нашёл у себя, на полке пылилось. 

Выложил сюда.  https://www.mql5.com/ru/code/60406

Простенький код конвертера периодов, в нём довольно просто понять, что от флагов тиков формирование баров не зависит.

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

 
Aleksey Vyazmikin #:

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

Хотя вижу, что и потом добавляете вроде как тики. В общем не вникал глубоко в код. Корректно сравнивать два режима построения графиков было бы.

 
Aleksandr Slavskii #:

Приложите короткий код, который воспроизводит ошибку. 

Я создал скрипт и мне нужно проверить эту проблему на платформе MT5 брокера AMP. Для этого я скачал установочный пакет программного обеспечения MT5 и мне нужно его установить. Я заранее загрузил файл TICK[] обычного контракта EPM25 в файл «EP_2025.06.02_05_EPM25_TICK_YZ.csv». Мне нужно скопировать этот файл в папку «Файлы». После запуска скрипта сравните обычный контракт EPM25 и пользовательский контракт EPM25_HF, и эта проблема проявится.


Файлы:
 
Aleksey Vyazmikin #:

Если добавить в скрипт флаг 1300, то получим сообщение

Как вообще такое может быть, что флаг неизвестен?

Как я понимаю, проблема в том, что по этому флагу формируется открытие, и в последствии тело свечи/бара/К-линии, а ожидается, что тик будет пропущен.

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

 
xiezhiqi #:

Я создал скрипт и мне нужно проверить эту проблему на платформе MT5 брокера AMP. Для этого я скачал установочный пакет программного обеспечения MT5 и мне нужно его установить. Я заранее загрузил файл TICK[] обычного контракта EPM25 в файл «EP_2025.06.02_05_EPM25_TICK_YZ.csv». Мне нужно скопировать этот файл в папку «Файлы». После запуска скрипта сравните обычный контракт EPM25 и пользовательский контракт EPM25_HF, и эта проблема проявится.


//+------------------------------------------------------------------+
//|                                          ProblemReproduction.mq5 |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   string bhymc, hfhymc; //本合约名称,回放合约名称
   bool sfwzdyjypz; //是否为自定义交易品种
   long id_chat_ls, id_chat_bhymc, id_chat_hfhymc; //临时图表ID,本合约图表ID,回放合约图表ID
   string filename_str_tick_yz; //TICK预装文件名称
   int size_tick_yz; //预装TICK数组大小
   MqlTick tick_yz[]; //预装TICK数组
   int i_tick;
   int handle_tick_yz; //预装TICK文件句柄

   bhymc = "EPM25"; //本合约名称赋值
   hfhymc = "EPM25_HF"; //回放合约名称赋值

   if(!SymbolExist(hfhymc, sfwzdyjypz)) //如果回放交易品种不存在
     {
      if(CustomSymbolCreate(hfhymc, NULL, bhymc)) //如果成功创建回放交易品种
        {
         Print("CustomSymbolCreate(" + hfhymc + ",NULL," + bhymc + ")=true");
        }
      else
        {
         Print("CustomSymbolCreate(" + hfhymc + ",NULL," + bhymc + ")=false");
         Print("GetLastError()=", GetLastError());
        }
     }

   if(!SymbolInfoInteger(bhymc, SYMBOL_SELECT)) //如果在市场报价中未选择交易品种
     {
      if(SymbolSelect(bhymc, true)) //如果成功在市场报价中选择交易品种
        {
         Print("SymbolSelect(" + bhymc + ",true)=true");
        }
      else
        {
         Print("SymbolSelect(" + bhymc + ",true)=false");
         Print("GetLastError()=", GetLastError());
        }
     }

   if(!SymbolInfoInteger(hfhymc, SYMBOL_SELECT)) //如果在市场报价中未选择交易品种
     {
      if(SymbolSelect(hfhymc, true)) //如果成功在市场报价中选择交易品种
        {
         Print("SymbolSelect(" + hfhymc + ",true)=true");
        }
      else
        {
         Print("SymbolSelect(" + hfhymc + ",true)=false");
         Print("GetLastError()=", GetLastError());
        }
     }

   for(id_chat_bhymc = -1, id_chat_ls = ChartFirst(); id_chat_ls >= 0; id_chat_ls = ChartNext(id_chat_ls)) //遍历所有图表
     {
      if(ChartSymbol(id_chat_ls) == bhymc) //如果该图表为本合约图表
        {
         id_chat_bhymc = id_chat_ls; //本合约图表ID赋值
         break;
        }
     }

   if(id_chat_bhymc < 0) //如果本合约图表不存在
     {
      id_chat_bhymc = ChartOpen(bhymc, PERIOD_M1); //打开本合约图表
      Print("ChartOpen(" + bhymc + ",dqzqmj)=", id_chat_bhymc);
     }

   if(id_chat_bhymc < 0) //如果本合约图表未打开
     {
      Print("error_ChartOpen_", GetLastError());
     }

   for(id_chat_hfhymc = -1, id_chat_ls = ChartFirst(); id_chat_ls >= 0; id_chat_ls = ChartNext(id_chat_ls)) //遍历所有图表
     {
      if(ChartSymbol(id_chat_ls) == hfhymc) //如果该图表为回放合约图表
        {
         id_chat_hfhymc = id_chat_ls; //回放合约图表ID赋值
         break;
        }
     }

   if(id_chat_hfhymc < 0) //如果回放合约图表不存在
     {
      id_chat_hfhymc = ChartOpen(hfhymc, PERIOD_M1); //打开回放合约图表
      Print("ChartOpen(" + hfhymc + ",dqzqmj)=", id_chat_hfhymc);
     }

   if(id_chat_hfhymc < 0) //如果回放合约图表未打开
     {
      Print("error_ChartOpen_", GetLastError());
     }

   Print("CustomTicksDelete=", CustomTicksDelete(hfhymc, long(D'1970.01.01 00:00:00') * 1000, long(D'2080.01.01 00:00:00') * 1000)); //清空回放图表所有TICK数据
   Print("CustomRatesDelete=", CustomRatesDelete(hfhymc, D'1970.01.01 00:00:00', D'2080.01.01 00:00:00')); //清空回放图表中回放预装起始柱编号起的RATE数据

   filename_str_tick_yz = "EP_2025.06.02_05_EPM25_TICK_YZ.csv"; //根据预装截止时间形成文件名
   handle_tick_yz = FileOpen(filename_str_tick_yz, FILE_ANSI | FILE_READ, '\t', CP_UTF8); //获取句柄,创建文件
   if(handle_tick_yz == INVALID_HANDLE)
     {
      Print("error_FileOpen_READ_" + filename_str_tick_yz);
     }
   else
     {
      Print("success_FileOpen_READ_" + filename_str_tick_yz);

      size_tick_yz = (int)FileReadNumber(handle_tick_yz); //读取TICK数组指定大小
      Print("size_tick_yz=", size_tick_yz);

      ArrayResize(tick_yz, size_tick_yz, 0); //预装TICK数组按指定大小分配内存
      for(i_tick = 0; !FileIsEnding(handle_tick_yz); i_tick++)
        {
         tick_yz[i_tick].time = FileReadDatetime(handle_tick_yz);
         tick_yz[i_tick].bid = FileReadNumber(handle_tick_yz);
         tick_yz[i_tick].ask = FileReadNumber(handle_tick_yz);
         tick_yz[i_tick].last = FileReadNumber(handle_tick_yz);
         tick_yz[i_tick].volume = (ulong)FileReadNumber(handle_tick_yz);
         tick_yz[i_tick].time_msc = (long)FileReadNumber(handle_tick_yz);
         tick_yz[i_tick].flags = (uint)FileReadNumber(handle_tick_yz);
         tick_yz[i_tick].volume_real = FileReadNumber(handle_tick_yz);

         if((tick_yz[i_tick].flags & TICK_FLAG_BID) != TICK_FLAG_BID)
            tick_yz[i_tick].bid = 0;
         if((tick_yz[i_tick].flags & TICK_FLAG_ASK) != TICK_FLAG_ASK)
            tick_yz[i_tick].ask = 0;
         if((tick_yz[i_tick].flags & TICK_FLAG_LAST) != TICK_FLAG_LAST)
            tick_yz[i_tick].last = 0;
         if((tick_yz[i_tick].flags & TICK_FLAG_VOLUME) != TICK_FLAG_VOLUME)
           {
            tick_yz[i_tick].volume = 0;
            tick_yz[i_tick].volume_real = 0;
           }
        }
     }

   if(CustomTicksAdd(hfhymc, tick_yz, WHOLE_ARRAY) > 0) //根据预装TICK数组起止点装载TICK数据至回放图表
     {
      Print("tick_yz[0].time=", tick_yz[0].time);
     }

  }
//+------------------------------------------------------------------+

Если убрать лишние цены из тика, то график рисует правильно. По цене ласт.

 
Aleksandr Slavskii #:
Если убрать лишние цены из тика, то график рисует правильно. По цене ласт.

Я знаю это. На самом деле я хочу реализовать динамическое воспроизведение исторических цен с помощью пользовательских графиков. При использовании этого решения часть информации будет потеряна. То есть, когда фактической транзакции нет, но цены BID и ASK меняются, информацию невозможно перенести в пользовательский график. Если устранить ошибку в механизме формирования графиков японских свечей с помощью CustomTicksAdd(), можно добиться точного воспроизведения.

 
xiezhiqi #:

Я знаю это. На самом деле я хочу реализовать динамическое воспроизведение исторических цен с помощью пользовательских графиков. При использовании этого решения часть информации будет потеряна. То есть, когда фактической транзакции нет, но цены BID и ASK меняются, информацию невозможно перенести в пользовательский график. Если устранить ошибку в механизме формирования графиков японских свечей с помощью CustomTicksAdd(), можно добиться точного воспроизведения.

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


Посмотрите справку, почему MqlTick заполняет все поля. 

В CustomTicksAdd ошибки нет.

В этом скрипте вообще то нужно было использовать CustomTicksReplace, а вот при использовании как вы пишите "динамическое воспроизведение цен", то тут нужно использовать CustomTicksAdd 

 
xiezhiqi #:

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

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

Всё соответствует реальным тикам. Я не могу её здесь показать, но я точно уверен, что ошибка не в функции CustomTicksAdd  , а в вашем представлении как она должна работать.

Измените своё мнение о ней и сможете найти правильное решение. 

С уважением.