Características da linguagem mql5, subtilezas e técnicas - página 32

 

Eu verifico se o indicador está pronto (no início daOnCalculate)

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

você também pode adicionar uma Verificação de período

SeriesInfoInteger(_Symbol,ind_period,SERIES_SYNCHRONIZED)
 
Alexey Viktorov:

1. Só um esclarecimento. Agora está claro que estamos a falar da mesma coisa.

2. Eu entendo isso, mas não concordo que tenha de inverter as arrays para o fazer. É necessário ter um indicador para dois terminais? Quase como fazer 2 em 1 uma foice e um machado.

3. como eu entendo Buffer[] é usado pelo receptor na função CopyBuffer() para obter apenas 1 valor indicador.

4. Você não prestou atenção ao mais importante. O início da cópia do valor do indicador não deve ser determinado pelo índice de barras, mas pela hora da i-ésima barra.

1. Ok.

2. Eu reverti o array porque reescrevi o indicador dos quatro - tudo funciona corretamente nele e todos os dados estão corretos. Tudo nele está ligado à obtenção de dados na sequência exacta em que são lidos no laço. Se não virarmos o buffer, teremos de escrever o indicador do zero - para quê? É bastante complicado. Citei este indicador apenas como um exemplo de como é errado obter dados de um gf não nativo.

Não. Em Buffer[], os dados são inseridos no laço um a um - a cada iteração do laço, um valor retirado de AO() é inserido.

4. O que você quer dizer com "início de cópia"?

 
Artyom Trishkin:

1. Óptimo.

2. Estou virando a matriz porque estou reescrevendo o indicador a partir de quatro - tudo funciona corretamente nela, todos os dados estão corretos. Tudo está ligado à obtenção de dados na sequência exacta em que estes são lidos no laço. Se não virarmos o buffer, teremos de escrever o indicador do zero - para quê? É bastante complicado. Citei este indicador apenas como um exemplo de como é errado obter dados de um gf não nativo.

Não. No buffer[] os dados são inseridos um a um no laço - a cada iteração do laço é inserido um valor retirado de AO()

4. O que você quer dizer com "início de cópia"?

2. Nada o impede de construir um loop de 0 a taxas_total-1

3. Sim, eu tenho algo errado em algum lugar.

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[]              // массив, куда будут скопированы данные
   );

deve ser mudado para

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

"From where to start" ou "from what date" é o início da cópia dos valores do indicador para a matriz receptora.


 
Alexey Viktorov:

3. Sim, eu tenho algo errado em algum lugar.

4.No seu código.


deve ser mudado para

"De onde começamos" ou "a partir de que data" é o início da cópia dos valores do indicador para a matriz receptora.


Porquê passar a data se estou a ler o valor do índice do laço? Você já executou este indicador de teste? Ele sempre tira AO apenas de um - o fator de corrente especificado nas configurações. Não importa como você muda o período de tempo atual, o gráfico AO sempre corresponde ao que você define nas configurações.

Neste caso todos os dados são devolvidos, mas no meu indicador que estou modificando, os dados não são devolvidos a partir de um preço não nativo.

Você não precisa deste indicador de teste - os dados de uma corrente não nativa já são devolvidos. Mas os dados não são devolvidos no meu, mas eu recebo-os da mesma forma.


 
Artyom Trishkin:

Porquê passar a data se estou a ler o valor do índice do laço? Você já executou este indicador de teste? Ele sempre plota AO a partir de apenas um - o setff nas configurações. Não importa como você muda o período de tempo atual, o gráfico AO sempre corresponde ao que você define nas configurações.

Neste caso todos os dados são devolvidos, mas no meu indicador que estou modificando, os dados não são devolvidos a partir de um preço não nativo.

Você não precisa deste indicador de teste - os dados de uma corrente não nativa já são devolvidos. Mas o meu não, mas recebo dados exactamente da mesma forma.


Porque a barra zero H4 contém QUATRO barras H1. E se você solicitar o índice 2 do período H1, você receberá o valor do indicador na barra 2 do período H4.

Eu mal entendo o que eu consegui escrever.

No momento são 13:35. Hora de abertura da barra H1 actual = 13:00. Você tenta copiar os valores do indicador pelo índice de barra = 1, ou seja, barra 12:00 do período H1 atual. Mas em vez das 12:00, você tem 8:00, à hora H4 do período.

Para H1 o primeiro bar é às 12:00

Para H4 o primeiro bar é às 8:00

Tanto lá como lá o índice de barras é o primeiro...

 

Fórum sobre negociação, sistemas de negociação automatizados e teste de estratégias de negociação

Não consigo obter dados indicadores de um período de tempo elevado.

Artyom Trishkin, 2017.04.14 01:23

Há quatro dias que tento obter os dados do indicador AO padrão do indicador sénior, e ainda não consegui...

Estou lendo dados AO no loop, mas exatamente no loop não há dados históricos. Há dados sobre o bar actual. Qual é o problema? O que estou a fazer mal?

//+------------------------------------------------------------------+
//|                                                       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:

Parece-me que estás a fazer muitas coisas "erradas". Por favor, descreva o que precisa ser feito: sequencialmente, ponto por ponto.
 

Fórum sobre negociação, sistemas de negociação automatizados e teste de estratégias de negociação

Características da linguagem mql5, dicas e truques

fxsaber, 2017.02.27 18:40

Obrigado pela dica! No deserto é SymbolInfoMarginRate. Então agora é assim.
// Размер свободных средств, необходимых для открытия 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);
}

Precisamos ser claros de que pode haver requisitos de margem muito diferentes na MT5 em diferentes direções. Ou seja, uma única variante do MT4 pode não funcionar. No Forex, é claro, este não será o caso. Mas tens de te lembrar. Portanto, em geral, você deve escrevê-lo desta forma
// Альтернатива 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);  
}

Destacado pode retornar 0. O BKS deparou-se com isto.

Fê-lo assim:

//+------------------------------------------------------------------+
//| Альтернатива стандартному 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:
Acho que estás a fazer um monte de coisas "erradas". Por favor, descreva o que você precisa fazer: passo a passo, ponto a ponto.

O que é que se passa exactamente? Essa era a questão - o que estou fazendo de errado para obter dados indicadores a partir de um período de tempo não nativo?

Exemplo: O indicador está a correr em М1, enquanto os dados da AO devem ser obtidos em М5. Assim, enquanto temos limite>1 (o histórico precisa ser recalculado), AO de M5 retorna zeros com ausência de erro de dados. Assim que todo o histórico é calculado (limite==0), os dados de AO com M5 começam a chegar.