Графические баги.

MisterRight  

Создаю индикатор под бинарные опционы.
В нём планирую сделать 2 ленты боллинджера с периодом 20 и 100 соответственно. Ещё стохастик. Расчёт угла между импульсом и скользящей средней. И ещё несколько параметров.
Пишу под себя с нуля, сделал расчёт 2 скользящих средних и появились какие-то глюки.
Код прикладываю, помогите пожалуйста. Не знаю, я накосячил (код небольшой) или это глюки терминала?
 

//+------------------------------------------------------------------+
//|                                                  CatchKnifes.mq5 |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#include <MovingAverages.mqh>
//---
#property indicator_chart_window
#property indicator_buffers 6
#property indicator_plots   6
//---First Band
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrMediumSeaGreen
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrMediumSeaGreen
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrMediumSeaGreen
#property indicator_label1  "Bands middle"
#property indicator_label2  "Bands upper"
#property indicator_label3  "Bands lower"
//---Second Band
#property indicator_type4   DRAW_LINE
#property indicator_color4  clrMediumPurple
#property indicator_type5   DRAW_LINE
#property indicator_color5  clrMediumPurple
#property indicator_type6   DRAW_LINE
#property indicator_color6  clrMediumPurple
#property indicator_label4  "Big Bands middle"
#property indicator_label5  "Big Bands upper"
#property indicator_label6  "Big Bands lower"
//--- input parametrs
//---Use two bollinger bands: one from a higher timeframe (5 minutes), the other (1 minute)
input int     InpBandsPeriod=20;       // Period
input int     InpBigBandsPeriod=100;   // BigPeriod
input int     InpBandsShift=0;         // Shift
input int     InpBigBandsShift=0;      // BigShift
input double  InpBandsDeviations=2.0;  // Deviation
input double  InpBigBandsDeviations=2.0;  // BigDeviation
//--- global variables
int           ExtBandsPeriod, ExtBigBandsPeriod, kForBands, kForBigBands;
double        ExtBandsDeviations, ExtBigBandsDeviations, sumForMA=0, sumForBigMA=0;
//--- indicator buffer
//--- 1 Band
double        ExtMLBuffer[];
double        ExtTLBuffer[];
double        ExtBLBuffer[];
//--- 2 Big Band
double        ExtBigMLBuffer[];
double        ExtBigTLBuffer[];
double        ExtBigBLBuffer[];


double        ExtStdDevBuffer[];
double        ExtBigStdDevBuffer[];
double        arrForPreviousPrice[];

enum type_of_price  // перечисление именованных констант 
   { 
    Close, 
    Open,
    High, 
    Low, 
    HighLow2, 
    HighLowClose3, 
    HighLowCloseClose4 
   };

input type_of_price type_price = Close;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit()
{
//--- indicator buffers mapping
//--- check for input values (Band)
   if(InpBandsPeriod<2)
     {
      ExtBandsPeriod=20;
      PrintFormat("Incorrect value for input variable InpBandsPeriod=%d. Indicator will use value=%d for calculations.",InpBandsPeriod,ExtBandsPeriod);
     }
   else
      ExtBandsPeriod=InpBandsPeriod;
   if(InpBandsDeviations==0.0)
     {
      ExtBandsDeviations=2.0;
      PrintFormat("Incorrect value for input variable InpBandsDeviations=%f. Indicator will use value=%f for calculations.",InpBandsDeviations,ExtBandsDeviations);
     }
   else
      ExtBandsDeviations=InpBandsDeviations;
//----------------------------------- 
//--- check for input values (Big Band)
//-----------------------------------
   if(InpBigBandsPeriod<2)
     {
      ExtBigBandsPeriod=ExtBandsPeriod*5;
      PrintFormat("Incorrect value for input variable InpBandsPeriod=%d. Indicator will use value=%d for calculations.",InpBandsPeriod,ExtBandsPeriod);
     }
   else
      ExtBigBandsPeriod=InpBigBandsPeriod;
   if(InpBigBandsDeviations==0.0)
     {
      ExtBigBandsDeviations=2.0;
      PrintFormat("Incorrect value for input variable InpBandsDeviations=%f. Indicator will use value=%f for calculations.",InpBandsDeviations,ExtBandsDeviations);
     }
   else
      ExtBigBandsDeviations=InpBigBandsDeviations;
//--- define buffers
   SetIndexBuffer(0,ExtMLBuffer);
   SetIndexBuffer(1,ExtTLBuffer);
   SetIndexBuffer(2,ExtBLBuffer);
   SetIndexBuffer(3,ExtBigMLBuffer);
   SetIndexBuffer(4,ExtBigTLBuffer);
   SetIndexBuffer(5,ExtBigBLBuffer);
//--- set index labels
   PlotIndexSetString(0,PLOT_LABEL,"Bands("+string(ExtBandsPeriod)+") Middle");
   PlotIndexSetString(1,PLOT_LABEL,"Bands("+string(ExtBandsPeriod)+") Upper");
   PlotIndexSetString(2,PLOT_LABEL,"Bands("+string(ExtBandsPeriod)+") Lower");
   PlotIndexSetString(3,PLOT_LABEL,"Bands("+string(ExtBigBandsPeriod)+") Big Middle");
   PlotIndexSetString(4,PLOT_LABEL,"Bands("+string(ExtBigBandsPeriod)+") Big Upper");
   PlotIndexSetString(5,PLOT_LABEL,"Bands("+string(ExtBigBandsPeriod)+") Big Lower");
//--- indexes draw begin settings
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtBandsPeriod);
   PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,ExtBandsPeriod);
   PlotIndexSetInteger(2,PLOT_DRAW_BEGIN,ExtBandsPeriod);
   PlotIndexSetInteger(3,PLOT_DRAW_BEGIN,ExtBigBandsPeriod);
   PlotIndexSetInteger(4,PLOT_DRAW_BEGIN,ExtBigBandsPeriod);
   PlotIndexSetInteger(5,PLOT_DRAW_BEGIN,ExtBigBandsPeriod);
//--- indicator name
   IndicatorSetString(INDICATOR_SHORTNAME,"Bollinger Bands");
//--- number of digits of indicator value
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1);
   
   ArrayResize(arrForPreviousPrice, ExtBigBandsPeriod, 0);
}   
//+------------------------------------------------------------------+
//| 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[])
{ 
  if(prev_calculated==0)
  {   kForBigBands = 0;
      int i;
      
      for(i=0; i<ExtBandsPeriod && !IsStopped(); i++)
      {
         arrForPreviousPrice[i]  = close[i];
         sumForMA               += arrForPreviousPrice[i];
         sumForBigMA            += arrForPreviousPrice[i];
      }
      
      for(; i<ExtBigBandsPeriod && !IsStopped(); i++)
      {
         ExtMLBuffer[i]        = sumForMA / ExtBandsPeriod;
         arrForPreviousPrice[i]= close[i];
         sumForMA             -= arrForPreviousPrice[i-ExtBandsPeriod];
         sumForMA             += arrForPreviousPrice[i];    
         sumForBigMA          += arrForPreviousPrice[i];
      }
      
      kForBands = i - ExtBandsPeriod;
      for(; i<rates_total && !IsStopped(); i++)
      {
         ExtMLBuffer[i]                     = sumForMA / ExtBandsPeriod;
         ExtBigMLBuffer[i]                  = sumForBigMA / ExtBigBandsPeriod;
         sumForMA                          -= arrForPreviousPrice[kForBands];//[int(MathMod(MathAbs(kForBigBands+(ExtBandsPeriod-ExtBigBandsPeriod)), 100))];
         sumForBigMA                       -= arrForPreviousPrice[kForBigBands];
         arrForPreviousPrice[kForBigBands]  = close[i];
         sumForMA                          += close[i];
         sumForBigMA                       += close[i];
         kForBands++;
         kForBigBands++;
         if(kForBigBands==ExtBigBandsPeriod)
            kForBigBands=0;
         if(kForBands==ExtBigBandsPeriod)
            kForBands=0;
      }
  }
   
   //int pos;
   //if(prev_calculated>1)
   //   pos=prev_calculated-1;
   //else
   //   pos=0;
//--- main cycle
//   for(int i=pos; i<rates_total && !IsStopped(); i++)
//     {
//      //--- First Band
//      //--- middle line
//      ExtMLBuffer[i]=SimpleMA(i,ExtBandsPeriod,close);
//      //--- calculate and write down StdDev
//      ExtStdDevBuffer[i]=StdDev_Func(i,close,ExtMLBuffer,ExtBandsPeriod);
//      //--- upper line
//      ExtTLBuffer[i]=ExtMLBuffer[i]+ExtBandsDeviations*ExtStdDevBuffer[i];
//      //--- lower line
//      ExtBLBuffer[i]=ExtMLBuffer[i]-ExtBandsDeviations*ExtStdDevBuffer[i];
//      
//      //---Second Band
//      //--- middle line
//      ExtBigMLBuffer[i]=SimpleMA(i,ExtBigBandsPeriod,close);
//      //--- calculate and write down StdDev
//      ExtBigStdDevBuffer[i]=StdDev_Func(i,close,ExtBigMLBuffer,ExtBigBandsPeriod);
//      //--- upper line
//      ExtBigTLBuffer[i]=ExtBigMLBuffer[i]+ExtBigBandsDeviations*ExtBigStdDevBuffer[i];
//      //--- lower line
//      ExtBigBLBuffer[i]=ExtBigMLBuffer[i]-ExtBigBandsDeviations*ExtBigStdDevBuffer[i];
//     }
//--- OnCalculate done. Return new prev_calculated.
   return(rates_total);
}
//+------------------------------------------------------------------+
//| Calculate Standard Deviation                                     |
//+------------------------------------------------------------------+
double StdDev_Func(const int position,const double &price[],const double &ma_price[],const int period)
  {
   double std_dev=0.0;
//--- calcualte StdDev
   if(position>=period)
     {
      for(int i=0; i<period; i++)
         std_dev+=MathPow(price[position-i]-ma_price[position],2.0);
      std_dev=MathSqrt(std_dev/period);
     }
//--- return calculated value
   return(std_dev);
  }
//+------------------------------------------------------------------+
Открой новые возможности в MetaTrader 5 с сообществом и сервисами MQL5
Открой новые возможности в MetaTrader 5 с сообществом и сервисами MQL5
  • 2021.03.13
  • www.mql5.com
MQL5: язык торговых стратегий для MetaTrader 5, позволяет писать собственные торговые роботы, технические индикаторы, скрипты и библиотеки функций
MisterRight  
Разобрался кажется. Дело было в других буферах которые у меня пока не заполнены.
Простите, если кого-то дернул не по делу :(
Такой код в секции инициализации решает проблему с вертикальными линиями. Но не решает проблему с исчезновением линий индикатора после перезапуска метатрейдера и прокручивания графика.
int bars = iBars(_Symbol, PERIOD_CURRENT);
PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,bars);
PlotIndexSetInteger(2,PLOT_DRAW_BEGIN,bars);
PlotIndexSetInteger(4,PLOT_DRAW_BEGIN,bars);
PlotIndexSetInteger(5,PLOT_DRAW_BEGIN,bars);
MisterRight  
Разобрался почему пропадает (на самом деле не пропадает, а некорректно рассчитывается!).
Почему-то при перезапуске снова вызывается onCalculate с prev_calculated=0. Значение моей глобальной переменной удваивается!!! Иногда утраивается. Иногда не сразу! Закономерности понять не смог. Пипец.
Специально глобальной её сделал, чтобы при новом вызове onCalculate старое значения использовать, а тут такая подстава!
Ээээээх, затянется моё написание программы на несколько недель. А ведь сегодня планировал дописать...
Пожалуйста не проигнорируйте, если кто знает - скажите, что сделать, чтоб такого ***ца не было. Спасибо!!!

#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
int count = 0;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

//---
   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[])
  {
//---
   if(prev_calculated==0)
      count+=1000;
   else count++;
   printf(count);
//--- return value of prev_calculated for next call
   return(rates_total);
  }
Aleksei Stepanenko  
Не понял полностью, но OnInit() срабатывает один раз при запуске индикатора. Это можно использовать, чтобы сделать что-нибудь с глобальной переменной, или наоборот запретить что-то делать.
Vladimir Karputov  
MisterRight:

1. Обязательно читать справку OnCalculate и особенно

Примечание

***

Если с момента последнего вызова функции OnCalculate() ценовые данные были изменены (была загружена более глубокая история или были заполнены пропуски истории), то значение входного параметра prev_calculated будет установлено в нулевое значение самим терминалом.

***

Необходимо использовать связь между значением, возвращаемым функцией OnCalculate(), и вторым входным параметром prev_calculated. Параметр prev_calculated при вызове функции содержит значение, которое вернула функция OnCalculate() на предыдущем вызове. Это позволяет реализовать экономные алгоритмы расчета пользовательского индикатора с тем, чтобы избежать повторных расчетов для тех баров, которые не изменились с предыдущего запуска этой функции.


2. Помнить, что нет никакого строгого правила вроде: "при запуске OnCalculate должно вызываться один (два, три) раза". Почему? Потому что смотреть п.1.


Лучший вариант для закрепления материала: запустить пример (прикрепить вручную на график)

//+------------------------------------------------------------------+
//|                                                  Indicator 1.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"
#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots   0
//--- input parameters
input int      Input1=9;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
//---
   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[])
  {
//---
   Print("rates_total: ",IntegerToString(rates_total),", prev_calculated: ",IntegerToString(prev_calculated));
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

в торговый день и в выходной

Документация по MQL5: Обработка событий / OnCalculate
Документация по MQL5: Обработка событий / OnCalculate
  • www.mql5.com
OnCalculate - Обработка событий - Справочник MQL5 - Справочник по языку алгоритмического/автоматического трейдинга для MetaTrader 5
Файлы:
MisterRight  
Спасибо, пример такой я уже раньше запускал)
Есть какой-то способ узнать какие данные были загружены: время тиков, например?
На выходных проблема тоже была, значит данные могут загрузиться в любое время. Загрузка хотя бы одного нового тика в истории приводит к обнулению prev_calculated насколько я понял.
Vladimir Karputov  
MisterRight:
***
Есть какой-то способ узнать какие данные были загружены: время тиков, например?
***

Нет. Ибо индикатору это совсем не нужно. 

MisterRight:
***
На выходных проблема тоже была, значит данные могут загрузиться в любое время. Загрузка хотя бы одного нового тика в истории приводит к обнулению prev_calculated насколько я понял.

Нет и не бывает никаких проблем. Ничего Вы не поняли. Проблема возникает у тех, кто упорно не читает документацию и не запускает предложенные примеры. Читать пост выше п.1. и п.2.

MisterRight  
Vladimir Karputov:

Нет и не бывает никаких проблем. Ничего Вы не поняли. Проблема возникает у тех, кто упорно не читает документацию и не запускает предложенные примеры. Читать пост выше п.1. и п.2.

Зачем же вы так категоричны :(
Всегда в документацию обращаюсь, если что-то не понятно. Функция OnCaltulate - первая с которой я ознакомился перед тем как начать писать индикатор. Что показывает пример я понимаю.
На выходных новых тиков по валютной паре GBPJPY не поступает. RatesTotal вроде тоже не менялось (запущу на следующих выходных и проверю). Но при этом prev_calculated обнулилось при перезапуске. Отсюда я сделал вывод, что загрузились пропуски истории (возможно несколько тиков).

Vladimir Karputov  
MisterRight:

Зачем же вы так категоричны :(
Всегда в документацию обращаюсь, если что-то не понятно. Функция OnCaltulate - первая с которой я ознакомился перед тем как начать писать индикатор. Что показывает пример я понимаю.
На выходных новых тиков по валютной паре GBPJPY не поступает. RatesTotal вроде тоже не менялось (запущу на следующих выходных и проверю). Но при этом prev_calculated обнулилось при перезапуске. Отсюда я сделал вывод, что загрузились пропуски истории (возможно несколько тиков).

Естественное поведение: при первом запуске или при подкачке истории prev_calculated равно нулю. Это нормальное и правильное поведение индикатора. При этом может подряд идти несколько входов в OnCalculate и при этом prev_calculated будет равно нулю.

Для индикатора не Важно какие Вы делаете выводы - в индикаторе главное экономично рассчитывать нулевой бар или же выполнить пересчет всего индикатора при prev_calculated равным 0. 

Очень часто применяемая конструкция: 

   int limit=prev_calculated-1;
   if(prev_calculated==0)
     limit=0;
   for(int i=limit; i<rates_total; i++)
     {

     }
Причина обращения: