Скачать MetaTrader 5
Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий
Знаешь C++? MQL5 очень схож с ним, убедись в этом сам!
Victor Demihov
618
Victor Demihov 2015.09.20 19:27 

 Я особо индикаторы не писал. Чаще эксперты. Вот пришлось написать. Т.к. весь алгоритм расписывать сложно и долго, решил привести простой пример, который я придумал, дабы показать в чём суть моего вопроса.

Имеется задача рисовать стрелочки или что-нить ещё ( не принципиально) в момент, когда соблюдаются определённые условия. Я решил, что пусть будет так, что если максимальная цена на определённом баре выше максимальной цены на предыдущем баре, то рисует, скажем так, стрелочку вверх или вниз.

Написал такой простой индюк:

//+---------------------------------------------------------------------------------------------------------------------------------------+
//|                                                                                                               MaxVolumeBySomeBars.mq4 |
//|                                                                                                                                Shanty |
//|                                                                                                                           icq:3333021 |
//+---------------------------------------------------------------------------------------------------------------------------------------+
#property copyright "Shanty"
#property link      "icq:3333021"
#property version   "1.00"
#property strict

input  bool  i_bNeedLogs = false,           // Флаг необходимости вывода лога в журнал и( или ) на экран терминала
             i_bPrintUP = true,             // Флаг печати комментариев
             i_bCommentUP = true;           // Флаг показа комментариев на графике

#property indicator_separate_window         // Индикатор выводится в отдельном окне
#property indicator_buffers 1               // Используется 1 буфер индикатора
#property indicator_color1 Blue             // Цвет отображения данных 1-го буфера

#property indicator_width1 1                // Толщина линий 1-го буфера

double   MaxValue[];                        // Буфер максимальных значение объёма за N-баров

#property indicator_minimum 1
#property indicator_maximum 2500

static      DrawGrafics CDraw;

//+---------------------------------------------------------------------------------------------------------------------------------------+
//|                                             Custom indicator initialization function                                                  |
//+---------------------------------------------------------------------------------------------------------------------------------------+
int OnInit()
{
   IndicatorBuffers(2);
   
   string name = WindowExpertName();
   
   // Связывание буфферов с индексами и определение стилей
   SetIndexBuffer (0, MaxValue);
   SetIndexStyle (0,  DRAW_HISTOGRAM);
   SetIndexDrawBegin (0, 100);
//---
   return(INIT_SUCCEEDED);
}
//+---------------------------------------------------------------------------------------------------------------------------------------+
//|                                         Определение наличия максимумов на расчётном баре                                              |
//+---------------------------------------------------------------------------------------------------------------------------------------+
void DefinitionMaxValue (int fi_Index)
{
   if (High[fi_Index] > High[fi_Index + 1])
   {
      MaxValue[fi_Index] = High[fi_Index];
      CDraw.DrawObject (_Symbol, _Period,  OBJ_ARROW_UP, fi_Index, Time[fi_Index], Open[fi_Index]);
   }
}
//+---------------------------------------------------------------------------------------------------------------------------------------+
//|                              Определение индекса бара, с которого необходимо производить перерасчет                                   |
//+---------------------------------------------------------------------------------------------------------------------------------------+
int GetRecalcIndex()
{
   int counted_bars = IndicatorCounted();
   
   if (counted_bars == 0)                           // Кол-во посчитанных баров - 0. Будут
   {                                                // ..пересчитаны все буфера с самого..
      ArrayInitialize (MaxValue, EMPTY_VALUE);      // ..начала. Очистка буферов

      return (Bars - 2);                            // Начинаем со второго бара истории
   }
   
   return (Bars - counted_bars - 1);                // Начинаем с нового бара
}
//+---------------------------------------------------------------------------------------------------------------------------------------+
//|                                               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[])
{
//---
   int index = GetRecalcIndex();    // Определяем расчётный бар
   
   DefinitionMaxValue (index);
   
//--- return value of prev_calculated for next call
   return (rates_total);
}

 Рисует индюк стрелку только у одного бара и всё! Дальше он стрелки не рисует почему-то. Почему?

Методы рисования, на которые обращается индюк вот:

//=========================================================================================================================================
// Поиск объекта по имени. ================================================================================================================
bool DrawGrafics::FindObject (string fs_ObjName)
{
   if (ObjectFind (fs_ObjName) == -1)
      return (false);
   
   return (true);
}
//=========================================================================================================================================
// Отрисовка объета. ======================================================================================================================
void DrawGrafics::DrawObject (string       fs_Symbol,           // Символ инструмента, на графике которого рисуется стрелка
                              int          fi_TF,               // ТФ инструмента, на котором рисуется стрелочка
                              ENUM_OBJECT  fe_ObjType,          // Тип рисуемого объекта
                              int          fi_Number,           // Порядковый номер бара, с которого берутся данные ( Время и Цена )
                              datetime     fdt_Time1,           // Время открытия бара на заданном индексе
                              double       fd_Price1,           // Цена открытия бара на заданном индексе
                              datetime     fdt_Time2 = 0,       // Время открытия бара на заданном индексе
                              double       fd_Price2 = 0.0)     // Цена открытия бара на заданном индексе
{
   string objName = "";
   
   objName = StringConcatenate (_Symbol, "_", GetTFName (fi_TF), "_", GetObjName (fe_ObjType), "_",  fi_Number);
   
   if (!FindObject (objName))
   {
      ObjectCreate (objName, fe_ObjType, 0, fdt_Time1, fd_Price1);
   
      // Перерисуем объект
      WindowRedraw();
   }
   else
   {
      DeleteOneObject (objName, fe_ObjType);
      
      ObjectCreate (objName, fe_ObjType, 0, fdt_Time1, fd_Price1);
      
      // Перерисуем объект
      WindowRedraw();
   }
}
Рустам
3602
Рустам 2015.09.20 19:49  
Распринтуйте - увидите. или у вас так условия просчитываются, или имя объекта одно и то же. вообще то по хорошему сначала создают пустой объект, а потом при помощи ObjectSet() ему добавляют свойств - время,цена, цвет ширина, видимость ... и прочия
TarasBY
1742
TarasBY 2015.09.20 20:29  
Загляните внутрь любого работающего индикатора и сравните со своим. И найдите принципиальное отличие.
Victor Demihov
618
Victor Demihov 2015.09.21 17:20  
TarasBY:
Загляните внутрь любого работающего индикатора и сравните со своим. И найдите принципиальное отличие.

Ну...  логика то верная. Почему нет? Пересчёт происходит.. Касяк был в том, что имя не изменялась. Для советников, этот вариант был подходящ, а тут т.к. пересчёт происходит бара с индексом тем же идентичным т.е. функция пересчёта его возвращает, то имя объекта было одинаковым. Я изменил последний параметр индекса на время открытия бара выбранного, на котором рисуем объект и индюк начел работать адекватно.

Если так, то какие тутпринципиальные отличия?

Изменили строку тут(выделенр жёлтым):

// Отрисовка объета. ======================================================================================================================
void DrawGrafics::DrawObject (string       fs_Symbol,           // Символ инструмента, на графике которого рисуется стрелка
                              int          fi_TF,               // ТФ инструмента, на котором рисуется стрелочка
                              ENUM_OBJECT  fe_ObjType,          // Тип рисуемого объекта
                              int          fi_Number,           // Порядковый номер бара, с которого берутся данные ( Время и Цена )
                              datetime     fdt_Time1,           // Время открытия бара на заданном индексе
                              double       fd_Price1,           // Цена открытия бара на заданном индексе
                              datetime     fdt_Time2 = 0,       // Время открытия бара на заданном индексе
                              double       fd_Price2 = 0.0)     // Цена открытия бара на заданном индексе
{
   string objName = "";
   
   objName = StringConcatenate (_Symbol, "_", GetTFName (fi_TF), "_", GetObjName (fe_ObjType), "_" fdt_Time1);
   
   if (!FindObject (objName))
   {
      ObjectCreate (objName, fe_ObjType, 0, fdt_Time1, fd_Price1);
   
      // Перерисуем объект
      WindowRedraw();
   }
   else
   {
      DeleteOneObject (objName, fe_ObjType);
      
      ObjectCreate (objName, fe_ObjType, 0, fdt_Time1, fd_Price1);
      
      // Перерисуем объект
      WindowRedraw();
   }
}
TarasBY
1742
TarasBY 2015.09.21 20:16  
Вы упоминаете термин "расчетный бар". Сразу возникает вопрос: "Сколько их у Вас?" ;)
Victor Demihov
618
Victor Demihov 2015.09.21 21:29  
TarasBY:
Вы упоминаете термин "расчетный бар". Сразу возникает вопрос: "Сколько их у Вас?" ;)

Расчётный бар один в процессе работы индюка. Хотя изначально, когда просчитанный баров нет после инициализации индюка расчитываются все бары, разумеется. Я переписал всё проще. Так будет корректно?

//+---------------------------------------------------------------------------------------------------------------------------------------+
//|                                             Custom indicator initialization function                                                  |
//+---------------------------------------------------------------------------------------------------------------------------------------+
int OnInit()
{
   IndicatorBuffers(1);
   
   string name = WindowExpertName();
   
   // Связывание буфферов с индексами и определение стилей
   SetIndexBuffer (0, MaxValue);
   SetIndexStyle (0,  DRAW_NONE);
   SetIndexDrawBegin (0, 100);
//---
   return (INIT_SUCCEEDED);
}
//+---------------------------------------------------------------------------------------------------------------------------------------+
//|                                     Определение значение положительной дельты ClusterDelta_Delta                                      |
//+---------------------------------------------------------------------------------------------------------------------------------------+

//+---------------------------------------------------------------------------------------------------------------------------------------+
//|                                         Определение наличия максимумов на расчётном баре                                              |
//+---------------------------------------------------------------------------------------------------------------------------------------+
void DefinitionMaxValue (int fi_Index)
{
   if (High[fi_Index] > High[fi_Index + 1])
   {
      MaxValue[fi_Index] = High[fi_Index];
      CDraw.DrawObject (_Symbol, _Period,  OBJ_ARROW_UP, fi_Index, Time[fi_Index], Open[fi_Index]);
   }
}
//+---------------------------------------------------------------------------------------------------------------------------------------+
//|                                               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[])
{
//---
   int limit = rates_total - prev_calculated;
   if (prev_calculated == 0) limit--;
   else limit++;
   
   for (int i = 0; i < limit && !IsStopped(); i++)
   {
      DefinitionMaxValue (i);
   }
   
//--- return value of prev_calculated for next call
   return (rates_total);
}
Рустам
3602
Рустам 2015.09.21 21:39  
эээ   я извиняюсь , а вот это "!IsStopped()" там зачем ???
Victor Demihov
618
Victor Demihov 2015.09.21 21:49  
FAQ:
эээ   я извиняюсь , а вот это "!IsStopped()" там зачем ???
Смотрел как пишут индюки другие, т.к. опыта в написании индюков нет. Нашёл.. вроде бы у Косицина. Судя по всем, если значение данного флага не нулевое, то может возникнуть принудительное завершение работы. И в этом случае не резон продолжать работы индюка. Не правильно?
Рустам
3602
Рустам 2015.09.21 22:46  
для зацикленных экспертов или скриптов этот флаг действует так как они работают в собственном потоке, и терминал сможет перехватить команду остановки. но индикатор работает в интерфейсном потоке того чарта к которому он прикреплен, и если он уж зависнет, то эта инструкция ему не поможет точно.
/
Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий