Características del lenguaje mql5, sutilezas y técnicas - página 32

 

Compruebo si el indicador está listo (al principio deOnCalculate)

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

también puede añadir un control del período

SeriesInfoInteger(_Symbol,ind_period,SERIES_SYNCHRONIZED)
 
Alexey Viktorov:

1. Sólo una aclaración. Ahora está claro que estamos hablando de lo mismo.

2. Lo entiendo, pero no estoy de acuerdo en que haya que voltear arrays para hacerlo. ¿Es necesario tener un indicador para dos terminales? Casi como hacer 2en1 una guadaña y un hacha.

3. según tengo entendido Buffer[] es utilizado por el receptor en la función CopyBuffer() para obtener sólo 1 valor de indicador.

4. No has prestado atención a lo más importante. El inicio de la copia del valor del indicador no debe estar determinado por el índice de la barra, sino por el momento de la i-ésima barra.

1. Ok.

2. He invertido la matriz porque reescribo el indicador de los cuatro - todo funciona correctamente en él y todos los datos son correctos. Todo en él está ligado a la obtención de datos en la secuencia exacta en la que se leen en el bucle. Si no volteamos el buffer, tendremos que escribir el indicador desde cero, ¿para qué? Es bastante complicado. He citado este indicador sólo como ejemplo de lo erróneo que es obtener datos de un gf no nativo.

No. En Buffer[], los datos se insertan en el bucle uno a uno - en cada iteración del bucle, se inserta un valor tomado de AO().

4. ¿Qué quiere decir con "inicio de la copia"?

 
Artyom Trishkin:

1. Bien.

2. Estoy volteando el array porque estoy reescribiendo el indicador de cuatro - todo funciona correctamente en él, todos los datos son correctos. Todo está ligado a la obtención de datos en la secuencia exacta en la que se leen en el bucle. Si no volteamos el buffer, tendremos que escribir el indicador desde cero, ¿para qué? Es bastante complicado. He citado este indicador sólo como ejemplo de lo erróneo que es obtener datos de una cf no nativa.

No. En Buffer[] los datos se insertan en el bucle uno a uno - en cada iteración del bucle se inserta un valor tomado de AO()

4. ¿Qué quiere decir con "inicio de la copia"?

2. Nada le impide construir un bucle de 0 a rates_total-1

3. Sí, me he equivocado en alguna parte.

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

debe cambiarse por

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

"Desde dónde empezar" o "desde qué fecha" este es el inicio de la copia de los valores del indicador en la matriz del receptor.


 
Alexey Viktorov:

3. Sí, he metido la pata en alguna parte.

4.En su código.


debe cambiarse por

"Desde dónde empezamos" o "desde qué fecha" este es el inicio de la copia de los valores del indicador en el array del receptor.


¿Por qué pasar la fecha si estoy leyendo el valor del índice del bucle? ¿Ha ejecutado este indicador de prueba? Siempre extrae AO sólo de uno: el factor de corriente especificado en los ajustes. Independientemente de cómo se cambie el marco temporal actual, el gráfico AO siempre se corresponde con el que se haya establecido en la configuración.

En este caso se devuelven todos los datos, pero en mi indicador que estoy modificando, no se devuelven los datos de un precio no nativo.

No es necesario este indicador de prueba - los datos de una corriente no nativa ya se devuelven. Pero los datos no se devuelven en el mío, pero los obtengo de la misma manera.


 
Artyom Trishkin:

¿Por qué pasar la fecha si estoy leyendo el valor del índice del bucle? ¿Ha ejecutado este indicador de prueba? Siempre traza AO a partir de uno solo - el setff en la configuración. Independientemente de cómo se cambie el marco temporal actual, el gráfico AO siempre se corresponde con el que se haya establecido en la configuración.

En este caso se devuelven todos los datos, pero en mi indicador que estoy modificando, no se devuelven los datos de un precio no nativo.

No es necesario este indicador de prueba - los datos de una corriente no nativa ya se devuelven. Pero el mío no lo hace, pero obtengo los datos exactamente de la misma manera.


Porque la barra cero H4 contiene CUATRO barras H1. Y si solicita el índice 2 del periodo H1, obtendrá el valor del indicador en la barra 2 del periodo H4.

Apenas entiendo lo que he podido escribir.

En este momento son las 13:35. Hora de apertura de la barra H1 actual = 13:00. Intenta copiar los valores del indicador por el índice de la barra = 1, es decir, la barra 12:00 del período H1 actual. Pero en lugar de las 12:00 se obtienen las 8:00 a la hora H4 del período

Para H1 el primer compás es 12:00

Para H4 la primera barra es la de las 8:00

Tanto allí como allí el índice de barras es el primero...

 
El ArrayCopy incorporado evita el mismo operador.
 

Foro sobre comercio, sistemas de comercio automatizados y prueba de estrategias de comercio

No puedo obtener los datos del indicador del marco temporal alto

Artyom Trishkin, 2017.04.14 01:23

Llevo cuatro días intentando obtener los datos del indicador estándar AO del marco temporal senior en el indicador, y todavía no hay manera...

Estoy leyendo los datos de AO en el bucle, pero exactamente en el bucle no hay datos históricos. Hay datos en la barra actual. ¿Cuál es el problema? ¿Qué estoy haciendo 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:

Me parece que estás haciendo muchas cosas "mal". Por favor, describa lo que hay que hacer: secuencialmente, punto por punto.
 

Foro sobre trading, sistemas de trading automatizados y pruebas de estrategias de trading

Características del lenguaje mql5, consejos y trucos

fxsaber, 2017.02.27 18:40

Gracias por el consejo. En el desierto es SymbolInfoMarginRate. Así que ahora es así
// Размер свободных средств, необходимых для открытия 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);
}

Debemos tener claro que en MT5 puede haber requisitos de margen muy diferentes en las distintas direcciones. Es decir, una sola variante de MT4 puede no funcionar. En Forex, por supuesto, no será así. Pero tienes que recordar. Por lo tanto, en general, se debe escribir así
// Альтернатива 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);  
}

Lo resaltado puede devolver 0. BKS se encontró con esto.

Lo hice así:

//+------------------------------------------------------------------+
//| Альтернатива стандартному 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:
Creo que estás haciendo muchas cosas "mal". Por favor, describa lo que tiene que hacer: paso a paso, punto por punto.

¿Qué ocurre exactamente? Esa era la pregunta: ¿qué estoy haciendo mal para obtener datos de indicadores de un marco temporal no nativo?

Ejemplo: El indicador está funcionando en М1, mientras que los datos de AO deben obtenerse de М5. Así que mientras tenemos límite>1 (la historia necesita ser recalculada), AO de M5 devuelve ceros con ausencia de error de datos. En cuanto se calcula todo el historial (límite==0), empiezan a llegar los datos de AO con M5.