Особенности языка mql5, тонкости и приёмы работы - страница 32

 

Проверяю готовность индикатора так (в самом начале OnCalculate)

   int calculated=BarsCalculated(IND_handle);
   if(calculated<=0 || !SymbolIsSynchronized(_Symbol) || rates_total<=0 || rates_total-prev_calculated<0) 
      { 
      Comment("Calculate...");
      return(0);
      }

можно еще добавить проверку Периода

SeriesInfoInteger(_Symbol,ind_period,SERIES_SYNCHRONIZED)
 
Alexey Viktorov:

1. Просто уточнение. Теперь понятно что говорим об одном и том-же.

2. Это я понял, но не соглашусь что для этого обязательно переворачивать массивы. Разве обязательно иметь один индикатор для двух терминалов??? Почти так-же как сделать 2в1 косу и топор.

3. Buffer[] как я понял используется приёмником в функции CopyBuffer() для получения всего 1 значения индикатора.

4. На самое главное ты не обратил внимания. Начало копирования значения индикатора надо определять не индексом бара, а временем i-того бара.

1. Хорошо.

2. Массив переворачиваю потому, что переписываю индикатор с четвёрки - в нём-то как раз всё работает как нужно, все данные получаются верно. В нём всё завязано на получении данных именно в той последовательности, в которой они читаются в цикле. Если не переворачивать буфер, то придётся писать индикатор с нуля - зачем? Он достаточно сложный. Этот индикатор привёл лишь как пример ошибочности получения данных с неродного тф.

3. Нет. В Buffer[] в цикле вписываются данные по одному - на каждой итерации цикла вписывается одно значение, получаемое из АО()

4. Что ты имеешь в виду под "начало копирования"?

 
Artyom Trishkin:

1. Хорошо.

2. Массив переворачиваю потому, что переписываю индикатор с четвёрки - в нём-то как раз всё работает как нужно, все данные получаются верно. В нём всё завязано на получении данных именно в той последовательности, в которой они читаются в цикле. Если не переворачивать буфер, то придётся писать индикатор с нуля - зачем? Он достаточно сложный. Этот индикатор привёл лишь как пример ошибочности получения данных с неродного тф.

3. Нет. В Buffer[] в цикле вписываются данные по одному - на каждой итерации цикла вписывается одно значение, получаемое из АО()

4. Что ты имеешь в виду под "начало копирования"?

2. Ничто не мешает построить цикл от 0 до rates_total-1

3. Да, я где-то что-то перепутал.

4.В твоём коде

double AO(int shift){
   double array[];
   ArrayResize(array,1);
   ArrayInitialize(array,EMPTY_VALUE);
   error=ERR_SUCCESS;
   ResetLastError();
   if(CopyBuffer(handle,0,shift,1,array)==1) {
      ArraySetAsSeries(array,false);
      return(array[0]);
      }
   else error=GetLastError();
   return(EMPTY_VALUE);
}


int  CopyBuffer(
   int       indicator_handle,     // handle индикатора
   int       buffer_num,           // номер буфера индикатора
   int       start_pos,            // откуда начнем 
   int       count,                // сколько копируем
   double    buffer[]              // массив, куда будут скопированы данные
   );

надо заменить на

int  CopyBuffer( 
   int       indicator_handle,     // handle индикатора 
   int       buffer_num,           // номер буфера индикатора 
   datetime  start_time,           // с какой даты 
   int       count,                // сколько копируем 
   double    buffer[]              // массив, куда будут скопированы данные 
   );

"Откуда начнём" или "с какой даты" это и есть начало копирования значений индикатора в массив приёмник.


 
Alexey Viktorov:

3. Да, я где-то что-то перепутал.

4.В твоём коде


надо заменить на

"Откуда начнём" или "с какой даты" это и есть начало копирования значений индикатора в массив приёмник.


Зачем передавать дату, если я считываю значение по индексу цикла? Ты запускал этот тестовый индикатор? Он всегда рисует АО только с одного - заданного тф в настройках. Как ни переключай текущий тф, график АО всегда соответствует заданному тф в настройках.

И тут-то как раз все данные с грехом пополам но возвращаются, а вот в моём индикаторе, который переделываю, данные не возвращаются с неродного тф - и хоть тресни...

Этот тестовый индикатор уже не нужен - в нём данные с неродного тф уже возвращаются. А вот в моём - нет, но данные получаю точно таким же способом.


 
Artyom Trishkin:

Зачем передавать дату, если я считываю значение по индексу цикла? Ты запускал этот тестовый индикатор? Он всегда рисует АО только с одного - заданного тф в настройках. Как ни переключай текущий тф, график АО всегда соответствует заданному тф в настройках.

И тут-то как раз все данные с грехом пополам но возвращаются, а вот в моём индикаторе, который переделываю, данные не возвращаются с неродного тф - и хоть тресни...

Этот тестовый индикатор уже не нужен - в нём данные с неродного тф уже возвращаются. А вот в моём - нет, но данные получаю точно таким же способом.


Потому, что в нулевом баре Н4 содержится ЧЕТЫРЕ бара Н1. И если запросить по индексу 2 периода Н1 значение индикатора по периоду Н4 то получишь значение индикатора на баре 2 по периоду Н4.

Сам с трудом понимаю что получилось написать...

В текущий момент время 13:35. Время открытия текущего бара Н1 = 13:00. Пытаешься скопировать значения индикатора по индексу бара =1 то-есть бара 12:00 текущего Н1 периода. А получаешь вместо 12:00 по времени Н4 периода 8:00

Для Н1 первый бар 12:00

Для Н4 первый бар 8:00

И там и там индекс бара первый...

 

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Не получается брать данные индикатора со старшего ТФ

Artyom Trishkin, 2017.04.14 01:23

Уже четвёртый день в индикаторе пытаюсь получить данные стандартного индикатора АО со старшего таймфрейма, и всё никак...

В цикле считываю данные АО, но именно в цикле исторических данных нет. На текущем баре данные есть. В чём подвох? Что делаю не так?

//+------------------------------------------------------------------+
//|                                                       MTF AO.mq5 |
//|              Copyright 2017, Artem A. Trishkin, Skype artmedia70 |
//|                       https://login.mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Artem A. Trishkin, Skype artmedia70"
#property link      "https://login.mql5.com/ru/users/artmedia70"
#property version   "1.00"

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot AO
#property indicator_label1  "AO MTF"
#property indicator_type1   DRAW_SECTION
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- indicator buffers
double         BufferAO[];
//+------------------------------------------------------------------+
//|  Enums                                                           |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|  Input Variables                                                 |
//+------------------------------------------------------------------+
sinput   ENUM_TIMEFRAMES   PeriodForWork  =  PERIOD_M5;  // Таймфрейм, на котором искать дивергенции
//+------------------------------------------------------------------+
//|  Global Variables                                                |
//+------------------------------------------------------------------+
string            Prefix, symbol;
int               handle_ao;                 // Хэндл AO
int               size_ao=0;                 // Количество скопированных данных AO
double            array_ao[];                // Массив данных АО
ENUM_TIMEFRAMES   periodForWork;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,BufferAO);
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0);
   ArrayInitialize(BufferAO,0);
   
   //--- проверка рабочего периода и его смена, если выбран рабочий период меньше текущего
   periodForWork=PeriodForWork;
   if(Period()>periodForWork && PeriodForWork!=PERIOD_CURRENT) {
      Alert("Выбран не корректный период: ",GetNameTF(PeriodForWork),"\nМеняю рабочий период на ",GetNameTF(Period()));
      periodForWork=PERIOD_CURRENT;//GetTFasEnum(Period());
      }

   //--- имена
   symbol=Symbol();                                                        // Symbol()
   Prefix="MTFdiv";                                                        // Префикс имён объектов
   IndicatorSetString(INDICATOR_SHORTNAME,Prefix);                         // Короткое имя индикатора
   
   //--- хэндл AO
   handle_ao=iAO(symbol,periodForWork);
   if(handle_ao==INVALID_HANDLE) {
      Print("Не удалось создать хэндл AO");
      return(INIT_FAILED);
      }
   int count=(int)SeriesInfoInteger(symbol,periodForWork,SERIES_BARS_COUNT);
   size_ao=CopyBuffer(handle_ao,0,0,count,array_ao);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- delete graphics
   ObjectsDeleteAll(0,Prefix);
  }
//+------------------------------------------------------------------+
//| 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(BufferAO,true);
   ArraySetAsSeries(array_ao,true);
   //---
   ArraySetAsSeries(open,true);
   ArraySetAsSeries(high,true);
   ArraySetAsSeries(low,true);
   ArraySetAsSeries(close,true);
   
   int count=(int)SeriesInfoInteger(symbol,periodForWork,SERIES_BARS_COUNT);
   //---
   if(rates_total<1) return(0);
   //---
   int limit=rates_total-prev_calculated;
   if(limit>1) {
      limit=rates_total-1;
      ArrayInitialize(BufferAO,0);
      }
   
   int periodSeconds=PeriodSeconds(periodForWork); // Количество секунд в рабочем периоде
   static datetime lastTime=0;
   int bar_first=TerminalInfoInteger(TERMINAL_MAXBARS);
   //--- основной цикл индикатора
   for(int i=limit; i>=0; i--) {
      //--- Пропускаем отсутствующие бары
      if(i>bar_first) continue;
      
      //--- Получаем данные АО
      ResetLastError();
      size_ao=CopyBuffer(handle_ao,0,0,count,array_ao);
      if(size_ao<0) Print("Ошибка копирования данных AO ",GetLastError());
      
      //--- время открытия бара на рабочем периоде, соответствующее времени бара i на текущем периоде
      datetime timePeriod=GetTimeOpen(symbol,periodForWork,i);
      //--- если нашли открытие нового бара на рабочем таймфрейме (текущее время больше прошлого)
      if(timePeriod>0 && timePeriod>lastTime) { 
         //---
         datetime time_work=GetTimeOpen(symbol,periodForWork,i);                 // время открытия i на рабочем таймфрейме
         int bar_work_to_current=GetBarShift(symbol,PERIOD_CURRENT,time_work);   // бар открытия времени time_work на текущем периоде графика
         double ao_work=GetDataAO(time_work);                                    // значение АО на баре i
         //---
         if(i<5) {
            Print("Work period: ",GetNameTF(periodForWork),
                  ",i=",i,", bar_work_to_current=",bar_work_to_current,
                  ", time_work=",TimeToString(time_work,TIME_MINUTES),
                  ", ao_work=",DoubleToString(ao_work,Digits())
                 );
            }
         BufferAO[bar_work_to_current]=ao_work;
         //--- конец обработки текущего бара
         lastTime=timePeriod; // запомним прошлое время для дальнейшего сравнения с временем следующего бара
         }
      //--- конец цикла индикатора
      }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Functions                                                        |
//+------------------------------------------------------------------+
double GetDataAO(int shift) {
   double array[1];
   if(CopyBuffer(handle_ao,0,shift,1,array)==1) return(array[0]);
   return(0);
}
//+------------------------------------------------------------------+
double GetDataAO(datetime shift) {
   double array[1];
   if(CopyBuffer(handle_ao,0,shift,1,array)==1) return(array[0]);
   return(0);
}
//+------------------------------------------------------------------+
datetime GetTimeOpen(string symbol_name, ENUM_TIMEFRAMES timeframe, int index) {
   datetime array[1]={-1};
   ResetLastError();
   if(CopyTime(symbol_name,timeframe,index,1,array)==1) return(array[0]);
   Print(__FUNCTION__," > Ошибка получения времени бара ",index,"(",GetNameTF(timeframe),"): ",GetLastError());
   return(-1);
}
//+------------------------------------------------------------------+
int GetBarShift(const string symbol_name, const ENUM_TIMEFRAMES timeframe, const datetime time) {
   int res=-1;
   datetime last_bar;
   if(SeriesInfoInteger(symbol_name,timeframe,SERIES_LASTBAR_DATE,last_bar)) {
      if(time>last_bar) res=0;
      else {
         const int shift=Bars(symbol_name,timeframe,time,last_bar);
         if(shift>0) res=shift-1;
         }
      }
   return(res);
}
//+------------------------------------------------------------------+
string GetNameTF(int timeframe=PERIOD_CURRENT) {
   if(timeframe==PERIOD_CURRENT) timeframe=Period();
   switch(timeframe) {
      //--- MQL4
      case 1: return("M1");
      case 5: return("M5");
      case 15: return("M15");
      case 30: return("M30");
      case 60: return("H1");
      case 240: return("H4");
      case 1440: return("D1");
      case 10080: return("W1");
      case 43200: return("MN");
      //--- MQL5
      case 2: return("M2");
      case 3: return("M3");
      case 4: return("M4");      
      case 6: return("M6");
      case 10: return("M10");
      case 12: return("M12");
      case 16385: return("H1");
      case 16386: return("H2");
      case 16387: return("H3");
      case 16388: return("H4");
      case 16390: return("H6");
      case 16392: return("H8");
      case 16396: return("H12");
      case 16408: return("D1");
      case 32769: return("W1");
      case 49153: return("MN");      
      default: return("UnknownPeriod");
   }
}
//+------------------------------------------------------------------+


 
Artyom Trishkin:

Как по мне - много чего делаете "не так". Опишите, пожалуйста, что требуется сделать: последовательно, по пунктам.
 

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Особенности языка mql5, тонкости и приёмы работы

fxsaber, 2017.02.27 18:40

Спасибо за наводку! В дебрях это - SymbolInfoMarginRate. Поэтому теперь так
// Размер свободных средств, необходимых для открытия 1 лота на покупку
double GetMarginRequired( const string Symb )
{
  MqlTick Tick;
  double MarginInit, MarginMain;

  return((SymbolInfoTick(Symb, Tick) && SymbolInfoMarginRate(Symb, ORDER_TYPE_BUY, MarginInit, MarginMain)) ? MarginInit * Tick.ask *
          SymbolInfoDouble(Symb, SYMBOL_TRADE_TICK_VALUE) / (SymbolInfoDouble(Symb, SYMBOL_TRADE_TICK_SIZE) * AccountInfoInteger(ACCOUNT_LEVERAGE)) : 0);
}

Надо четко понимать, что в MT5 в разные стороны могут быть совсем другие маржинальные требования. Т.е. единый MT4-вариант может не прокатывать. На Forex, конечно, такого не будет. Но помнить нужно. Поэтому в общем случае нужно писать так
// Альтернатива OrderCalcMargin
bool MyOrderCalcMargin( const ENUM_ORDER_TYPE action, const string symbol, const double volume, const double price, double &margin )
{
  double MarginInit, MarginMain;

  const bool Res = SymbolInfoMarginRate(symbol, action, MarginInit, MarginMain);
  
  margin = Res ? MarginInit * price * volume * SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE) /
                 (SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE) * AccountInfoInteger(ACCOUNT_LEVERAGE)) : 0;
  
  return(Res);  
}

Выделенное может возвращать 0. В БКС столкнулся.

Сделал так:

//+------------------------------------------------------------------+
//| Альтернатива стандартному OrderCalcMargin()                      |
//+------------------------------------------------------------------+
//--- 
bool CGetClass::OrderCalcMargin(const ENUM_ORDER_TYPE action,const string symbol_name,const double volume,const double price,double &margin){
   double margin_init=0,margin_main=0;
   const bool res=SymbolInfoMarginRate(symbol_name,action,margin_init,margin_main);
   int liverage=int(AccountInfoInteger(ACCOUNT_LEVERAGE)==0?1:AccountInfoInteger(ACCOUNT_LEVERAGE));
   margin=res?margin_init*price*volume*SymbolInfoDouble(symbol_name,SYMBOL_TRADE_TICK_VALUE)/
                 (SymbolInfoDouble(symbol_name,SYMBOL_TRADE_TICK_SIZE)*liverage):0;
   
   return(res);  
}
//+------------------------------------------------------------------+


 
Alexey Kozitsyn:
Как по мне - много чего делаете "не так". Опишите, пожалуйста, что требуется сделать: последовательно, по пунктам.

Что именно не так? Именно вопрос и звучал - что делаю не так для получения данных индикатора с неродного таймфрейма?

Пример: индикатор запущен на М1, а данные от АО нужно получать с М5. Так вот - пока у нас limit>1 (нужно пересчитать историю), то АО с М5 возвращает нули с ошибкой отсутствия данных. Как только история вся просчитана (limit==0), то данные от АО с М5 начинают поступать.