Preguntas de los principiantes MQL5 MT5 MetaTrader 5 - página 1469

 
Artyom Trishkin #:

¿Qué cree que he escrito mal? Justifíquelo, por favor.

Cuál es el límite y de dónde vendrá el bucle en mi ejemplo y en el tuyo.

Bueno, entonces Buffer0 debe ser indexado como en la serie de tiempo ArraySetAsSeries(Buffer0,true); de lo contrario el ejemplo no es claro.

 

En general, es así. Creo que no es muy correcto calcular los indicadores desde la barra cero hacia el pasado.

Yo siempre los calculo del pasado al presente. Aquí, vamos a dibujar una línea en Close:

//+------------------------------------------------------------------+
//|                                                TestCalculate.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot BufferClose
#property indicator_label1  "BufferClose"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- indicator buffers
double         BufferClose[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,BufferClose,INDICATOR_DATA);
   ArraySetAsSeries(BufferClose,true);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   ArraySetAsSeries(close,true);
   ArraySetAsSeries(time,true);
   string txt="";
   int limit=rates_total-prev_calculated;
   
//--- Первый запуск или изменение исторических данных
   if(limit>1)
     {
      limit=rates_total-1;
      txt=StringFormat
        ("Первый запуск или изменение исторических данных. \nrates_total=%ld, prev_calculated=%ld, rates_total-prev_calculated=%ld, limit=%ld\nИнициализируем буфер",
         rates_total,prev_calculated,rates_total-prev_calculated,limit
        );
      Print(txt);
      ArrayInitialize(BufferClose,EMPTY_VALUE);
     }
     
//--- Новый бар
   if(limit==1)
     {
      txt="Новый бар, рассчитываем 2 бара - первый и нулевой";
      PrintFormat("%s. %s, limit=%ld",(string)time[0],txt,limit);
     }
     
//--- Текущий бар
   if(limit==0)
     {
      txt=StringFormat
        ("Рассчитываем текущий бар. rates_total=%ld, prev_calculated=%ld, rates_total-prev_calculated=%ld, limit=%ld",
         rates_total,prev_calculated,rates_total-prev_calculated,limit
        );
     }
   Comment(txt);
     
//--- Основной цикл
   for(int i=limit;i>=0;i--)
     {
      BufferClose[i]=close[i];
     }
     
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
 

Especificar el número de compases a contar:

//+------------------------------------------------------------------+
//|                                                TestCalculate.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot BufferClose
#property indicator_label1  "BufferClose"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- input parameters
input int InpBarsCalc = 100;  /* Number of calculated bars */  // Количество рассчитываемых баров
//--- indicator buffers
double         BufferClose[];
//--- global variables
int calc_total;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,BufferClose,INDICATOR_DATA);
   ArraySetAsSeries(BufferClose,true);
   calc_total=(InpBarsCalc<1 ? 1 : InpBarsCalc);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- indicator buffers mapping
   Comment("");
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   ArraySetAsSeries(close,true);
   ArraySetAsSeries(time,true);
   string txt="";
   int limit=rates_total-prev_calculated;
   
//--- Первый запуск или изменение исторических данных
   if(limit>1)
     {
      limit=rates_total-1;
      txt=StringFormat
        ("Первый запуск или изменение исторических данных. \nrates_total=%ld, prev_calculated=%ld, rates_total-prev_calculated=%ld, limit=%ld\nИнициализируем буфер",
         rates_total,prev_calculated,rates_total-prev_calculated,limit
        );
      Print(txt);
      ArrayInitialize(BufferClose,EMPTY_VALUE);
     }
     
//--- Новый бар
   if(limit==1)
     {
      txt="Новый бар, рассчитываем 2 бара - первый и нулевой";
      PrintFormat("%s. %s, limit=%ld",(string)time[0],txt,limit);
     }
     
//--- Текущий бар
   if(limit==0)
     {
      txt=StringFormat
        ("Рассчитываем текущий бар. rates_total=%ld, prev_calculated=%ld, rates_total-prev_calculated=%ld, limit=%ld",
         rates_total,prev_calculated,rates_total-prev_calculated,limit
        );
     }
   Comment(txt);
     
//--- Количество просчитываемых баров (начало расчёта)
   int total=fmin(limit,calc_total);
//--- Основной цикл
   for(int i=total;i>=0;i--)
     {
      BufferClose[i]=close[i];
     }
     
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
 
Artyom Trishkin #:

Especificar el número de compases a contar:

Gracias. Es una respuesta muy detallada.

Es así. Creo que no es muy correcto calcular los indicadores desde la barra cero hacia atrás en el tiempo.

Usted está confundiendo a los principiantes de nuevo)

En los indicadores MQL5, hasta que se invierte la indexación, la barra cero es el pasado.


P.D. Artem tiene razón de nuevo. He utilizado el término equivocado, en lugar de "barra cero" debería haber escrito "índice cero".

 
Aleksandr Slavskii #:

Muchas gracias. Es una respuesta muy detallada.

Vuelves a confundir a los novatos)

En los indicadores MQL5, hasta que invierta la indexación, la barra cero es el pasado.

Creo que he dado una respuesta exhaustiva. He adjuntado dos indicadores que son ligeramente diferentes. Un recién llegado que ha visto el significado se convertirá en un veterano normal, y luego él mismo dará pistas. Y que se confundirá - bueno, significa "¿qué es necesario?".

Tengo todos los buffers, su indexación, desplegados. Y la barra cero está en el gráfico. En el indicador, en su buffer dibujado (y en el calculado también) sólo puede haber un índice de matriz cero. Prefiero que la barra cero en el gráfico coincida con el índice cero del array del buffer del indicador - para que los principiantes no se confundan.

 

He intentado describir el código, espero que sea correcto. Tal vez ayude a alguien más también, si es correcto.

//+------------------------------------------------------------------+
//|                                                TestCalculate.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window                //
#property indicator_buffers 1                   //  Тут понятно. Задаём  1 буфер и одно отображение.
#property indicator_plots   1                   //  На самом графике.


//--- plot BufferClose
#property indicator_label1  "BufferClose"       //     
#property indicator_type1   DRAW_LINE           //
#property indicator_color1  clrRed              //  Тут тоже понятно. Свойства для описания отображаемой линии.
#property indicator_style1  STYLE_SOLID         //  Название, линия, цвет, стиль, толщина. 
#property indicator_width1  1                   //  Если бы было 2 таких #property indicator_plots   2,
                                                //  то было бы 2 таких блока, на каждую линию отдельно. И бувера 2 минимум,
                                                //  если не нужно промежуточных вычислений без вывода.




//--- indicator buffers
double         BufferClose[];                   //  Объявляем динамический массив типа double ,
                                                //  в который в будущем будем скидывать значения типа double,
                                                //  которые и будут являться значениями, по которым будет строиться индикатор,
                                                //  в данном случае линия.


//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()                                    //  функция инициализации программы
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,BufferClose,INDICATOR_DATA);//  соединяем индикаторный буфер с нашим объявленным массивом, 
                                                //  так как индикаторный буфер у нас всего 1, это буде первый,
                                                //  а индексация у него будет начинаться с 0 как в массиве, далее передаём в функцию
                                                //  название самого массива, из которого будем брать значения-BufferClose,
                                                //  далее устанавливаем INDICATOR_DATA что говори о том что 
                                                //  данный буфер не для промежуточных вычислений, который не нужно выводить
                                                //  на экран. А именно то, что это отображаемый буфер.
   
   
   ArraySetAsSeries(BufferClose,true);          //  Поскольку направление индексации у всех массивов и индикаторах буферов
                                                //  не совпадает с направлением индексации тайм серий (а работать мы будем с ними),
                                                //  то функцией ArraySetAsSeries меняем направление индексации,
                                                //  передаём название нашего массива, и вторым значением 
                                                //  устанавливаем true, что означает что нумерация в массиве теперь будет производиться 
                                                //  в обратном порядке, вернее так же как и в  массивах тайм серий.
//---
   return(INIT_SUCCEEDED);                      // оператор return возвращает нам что инициализация прошла успешно
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,          //  инициализируем (вызываем) функцию обработки событий есть 2-х видов, на основе обработки массивов,
                const int prev_calculated,      //  и на основе обработки тайм серий (наш вариант). Потому в функцию передаём перечень
                const datetime &time[],         //  массивов тайм серий, к которым можно будет обращаться внутри функции. 
                const double &open[],           //  Не забываем массивы в функцию передаются по ссылкам  (&).
                const double &high[],           //  Так же передаём в функцию 2 параметра. 
                const double &low[],            //  rates_total Размер массива price[] или входных тайм серий, доступных индикатору для расчета
                const double &close[],          //  Наш вариант для входных тайм серий, поэтому Во втором варианте функции значение параметра
                const long &tick_volume[],      //  соответствует количеству баров на графике, на котором он запущен.
                const long &volume[],           //  Второй prev_calculated Содержит значение, которое вернула функция OnCalculate() на предыдущем вызове. 
                const int &spread[])            //  Предназначено для пропуска в расчетах тех баров, которые не изменились с предыдущего запуска этой функции.
  {
//---
   ArraySetAsSeries(close,true);                //
   ArraySetAsSeries(time,true);//               //  Переданные в функцию массивы отражают ценовые данные, т.е. эти массивы имеют признак тайм серии 
                                                //  и функция ArrayIsSeries() вернет true при проверке этих массивов. Но тем не менее,
                                                //  направление индексации необходимо в любом случае проверять только функцией ArrayGetAsSeries().
                                                //  Чтобы не зависеть от умолчаний, необходимо безусловно вызывать функцию
                                                //  ArraySetAsSeries() для тех массивов, с которыми предполагается работать, 
                                                //  и установить требуемое направление индексации.
                                                //  В нашем случае вызовем её для массивов close и time.
   
   
   
   
   string txt="";                               //  Объявим строковую переменную txt и присвоим ей пустое значение .
   int limit=rates_total-prev_calculated;       //  Так как пример учебный, она нам понадобится для наглядного выведения далее информации.
                                                //  Так же объявим целочисленную переменную limit и присвоим ей значение rates_total-prev_calculated.
                                                //  Она нам будет нужна в дальнейшем для работы в цикле, в котором мы будем проходиться циклом и 
                                                //  записывать полученные значения цен в созданный массив, от которого потом и будет 
                                                //  строиться линия индикатора.
                                                
   
//--- Первый запуск или изменение исторических данных
   if(limit>1)
     {
      limit=rates_total-1;
      txt=StringFormat
        ("Первый запуск или изменение исторических данных. \nrates_total=%ld, prev_calculated=%ld, rates_total-prev_calculated=%ld, limit=%ld\nИнициализируем буфер",
         rates_total,prev_calculated,rates_total-prev_calculated,limit
        );
      Print(txt);
      ArrayInitialize(BufferClose,EMPTY_VALUE);
     }
  
                                                 //  При первом запуске, или смене исторических данных, prev_calculated=0,
                                                 //  так как предыдущего вызова ещё не было, это первый.  
                                                 //  Поэтому вводим проверку  if(limit>1), и если это правда, то это значит,
                                                 //  что обсчета ещё не было, и цикл начнём с переменной limit.
                                                 //  При этом последний элемент индикаторного буфера будет заполняться с индексом rates_total-1
                                                 //  Далее (потом в конце, когда пойдём по циклу) 
                                                 //  в основном цикле заполнится массив именно этим размером rates_total.
                                                 //  
                                                 //  А пока инициализируем наш массив пустым.
  
     
//--- Новый бар
   if(limit==1)
     {
      txt="Новый бар, рассчитываем 2 бара - первый и нулевой";
      PrintFormat("%s. %s, limit=%ld",(string)time[0],txt,limit);
     }
                                                 //  Это условие  для того,  чтобы показать изменение
                                                 //  переменной limit на каждом шаге.
                                                 //  В данном случае пришёл новый бар, то есть 
                                                 //  rates_total увеличился на один бар, а prev_calculated стал равен прошлому rates_total,
                                                 //  то есть limit=rates_total-prev_calculated=1
                                                 //  то есть цикл будет с 1 до 0, то есть в массив пишем не все прошлые значения, 
                                                 //  а 2 последних на 0-м и 1-м баре (поскольку массивы мы развернули это несформированный 
                                                 //  первый бар на графике, и второй за ним) обсчет идет 2-х последних баров.
      
      
//--- Текущий бар
   if(limit==0)
     {
      txt=StringFormat
        ("Рассчитываем текущий бар. rates_total=%ld, prev_calculated=%ld, rates_total-prev_calculated=%ld, limit=%ld",
         rates_total,prev_calculated,rates_total-prev_calculated,limit
        );
     }
   Comment(txt);
                                                  //  То же самое, промежуточный показ данных на следующем шаге.
                                                  //  Поскольку на текущем баре цена меняется, он ещё не сформирован.
                                                  //  То получается что он не входит в новый rates_total,
                                                  //  Но при этом обрабатывается, так как цена меняется.
                                                  //  В этом случае несформированный бар внутри бара будет иметь
                                                  //  limit=rates_total-prev_calculated=0, то есть rates_total=prev_calculated
                                                  //  то есть обсчитывается только нулевой бар.
   
   
   
     
//--- Основной цикл
   for(int i=limit;i>=0;i--)                      //  Это цикл, который после каждой новой обработки событий
                                                  //  работает с массивом, но при первом запуске заполняет его весь
                                                  //  Размеров в данном случае rates_total.
                                                  //  А при последующих обработках обсчитывает и добавляет в него только 
                                                  //  2 последних бара.
     {
      BufferClose[i]=close[i];
     }
     
//--- return value of prev_calculated for next call
   return(rates_total);                           //  В конце программы обработчику событий нужно вернуть
                                                  //  значение rates_total, чтобы при следующей обработке 
                                                  //  обсчёт вёлся с учётом этой информации. Атак как при первой обработке 
                                                  //  значение prev_calculated равно 0, то при следующем обращении  
                                                  //  prev_calculated будет равно этому возвращённому значению.
                                                  
  }
//+------------------------------------------------------------------+

                                                  // Примечание.  rates_total Размер массива price[] или входных тайм серий, 
                                                  // доступных индикатору для расчета. При том если прокрутить историю графика глубоко назад, 
                                                  // то история подгружается, но при этом это не первый запуск индикатора.
                                                  // Получается что rates_total увеличивается при этом  prev_calculated сбрасывается на 0,
                                                  // как при первом запуске.
 

Realmente no me gusta el rollover de la indexación del buffer. Es por eso que decidí mostrar una variante alternativa del indicador

//+------------------------------------------------------------------+
//|                                                TestCalculate.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot BufferClose
#property indicator_label1  "BufferClose"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDarkOrchid
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2
//--- indicator buffers
double         BufferClose[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
 {
//--- indicator buffers mapping
  SetIndexBuffer(0,BufferClose); //,INDICATOR_DATA); INDICATOR_DATA — по умолчанию. Поэтому это можно не писать.
//---
  return(INIT_SUCCEEDED);
 }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
 {
//---
  string txt="";
  int limit=rates_total-prev_calculated;
//--- Первый запуск или изменение исторических данных
  if(limit>1)
   {
    limit=rates_total-1;
    txt=StringFormat
        ("Первый запуск или изменение исторических данных. \nrates_total=%ld, prev_calculated=%ld, rates_total-prev_calculated=%ld, limit=%ld\nИнициализируем буфер",
         rates_total,prev_calculated,rates_total-prev_calculated,limit
        );
    Print(txt);
//--- Заполнять индикаторный буфер пустыми значениями желательно, но не обязательно если индикатор не DRAW_ARROW или DRAW_COLOR_ARROW.
    ArrayInitialize(BufferClose,EMPTY_VALUE); 
//--- Обнулять исключительно когда prev_calculated == 0 или как в этом случае rates_total-prev_calculated > 1
   }

//--- Новый бар
  if(limit==1)
   {
    txt="Новый бар, рассчитываем 2 бара - первый и нулевой";
    PrintFormat("%s. %s, limit=%ld",(string)time[0],txt,limit);
   }

//--- Текущий бар
  if(limit==0)
   {
    txt=StringFormat
        ("Рассчитываем текущий бар. rates_total=%ld, prev_calculated=%ld, rates_total-prev_calculated=%ld, limit=%ld",
         rates_total,prev_calculated,rates_total-prev_calculated,limit
        );
   }
  Comment(txt);
//--- ВСЁ ОТ СТРОКИ №44 И ВКЛЮЧАЯ ЭТУ СТРОКУ НОСИТ ИСКЛЮЧИТЕЛЬНО ИНФОРМАЦИОННЫЙ ХАРАКТЕР И В РАБОЧЕМ ИНДИКАТОРЕ СОВЕРШЕННО НЕОБЯЗАТЕЛЬНО.


//---
  if(prev_calculated > 0 && rates_total-prev_calculated > 1)
    return 0; // Если во время работы индикатора подгрузились новые бары, запустим пересчёт индикатора с нуля…
//--- Основной цикл
//--- Пересчитаем индикатор или от начала истории (от нулевого бара) или только последний бар
  int i=fmax(0, prev_calculated-1);
  while(i < rates_total && !IsStopped())
   {
    BufferClose[i]=close[i];
    i++;
   }

//--- return value of prev_calculated for next call
  return(rates_total);
 }
//+------------------------------------------------------------------+
 

Buenas tardes.

Por favor, ¿podrían decirme cómo copiar precios diarios del futuro en el probador de estrategias?

Digamos que el robot terminó su trabajo en el día D. Necesito descargar los precios diarios de los días D+1, D+2, ..., D+60 (por supuesto, todos estos días están en el pasado).

Me gustaría utilizar algo como

MqlRates DayRate[]; // Contendrá los precios, volúmenes y spread de cada barra diaria

ArraySetAsSeries(DayRate,true);

CopyRates(_Symbol,PERIOD_D1,60,60,DayRate); // Obtener datos históricos mensuales para 60 días en el futuro


Saludos, Alexander


 
klycko ArraySetAsSeries(DayRate,true);

CopyRates(_Symbol,PERIOD_D1,60,60,DayRate); // Obtener datos históricos mensuales para 60 días en el futuro


Saludos, Alexander


¿No necesita precios del futuro en el comercio real?

 
no
Razón de la queja: