MT5 es para programadores, no para traders - página 17

 
Andrey F. Zelinsky:

Atrás quedaron los días en los que un programador, antes de aprender C, pasaba por comandos de máquina, ensamblador, Fortran, PL/1, Pascal y muchas otras cosas, todo ello sin libros de texto, sin explicaciones adecuadas, como decía Volchansky más arriba, con documentación impresa con letras torcidas.

es la época de los complejos sistemas de aplicaciones multifuncionales -- con un lenguaje de programación de aplicaciones integrado -- y la tarea de este lenguaje es poner el terminal de aplicaciones a disposición de los usuarios de las mismas, quienes, sin profundizar en la programación, pueden aprender y utilizar rápidamente este lenguaje de terminales en un corto período de tiempo.


Estoy de acuerdo. Correctamente dicho. El terminal de comercio debe facilitar la negociación.

 
ILNUR777:
¿A quién juzgas? Como cara de la empresa, no está bien que te deslices hacia el trolling. Ya has escrito que incluso los que tienen experiencia en MT4 tienen dificultades. Y no lo necesitan.

¿Ves el trolling?

Ya he escrito muchas veces que hay un montón de oportunidades para escribir un EA de prueba para su estrategia de forma sencilla y fácil.

Incluso di un enlace a la ayuda. Pero si empezáramos a hacer preguntas sobre la ayuda, veríamos que nos interesa este tipo de conocimiento. Pero no paraba de hablar de lo mal que está todo.

Por eso digo que, tal vez, la generación que tenemos ahora, de 18 años, los padres y la nuera tienen que comprar un coche, de 21, una casa. Pero para estudiar... no, ¿por qué?

 
Mickey Moose:

¿Qué tan complicado es el ensamblador? Necesito sus funciones

Por qué. Escríbelo en µl5. Es fácil y sencillo.
 
Artyom Trishkin:

Porque hace sólo 10 años los principiantes hacían preguntas muy diferentes en este foro, mucho más complicadas e interesantes.

Por cierto, las preguntas de hoy en MQL4 son mucho más informativas que en MQL5. La razón es obvia, y no es la edad de las versiones MQL.

 
Alexey Viktorov:

No, no lo sé. ¿Qué quieres decir?

Alexey, realmente, no puedo darte un ejemplo ahora mismo. Pero le gusta experimentar: ejecútelo y vea lo que devuelve con diferentes datos de entrada.

Es que ahora me resulta difícil recordarlo y buscarlo.

Bueno, fxsaber dio un ejemplo (lo he modificado para mí), comparar el código:

//+------------------------------------------------------------------+
//| Возвращает смещение бара таймфрейма по времени                   |
//+------------------------------------------------------------------+
int CTimes::BarShift(const string symbol_name,const ENUM_TIMEFRAMES timeframe,const datetime time) const
  {
   int res=WRONG_VALUE;
   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);
  }
//+------------------------------------------------------------------+

Aquí puede ver bajo qué condiciones Bars() devuelve una falta.

 
fxsaber:

Lo primero que escribe un principiante es un script de trading. El segundo es un simple indicador. El tercero - un simple Asesor Experto.

Incluso la primera etapa en MQL4 es más rápida que en MQL5.

¿Un guión de comercio? ¿Por qué no un Asesor Experto o incluso un sustituto de la Biblioteca Estándar?

En mi opinión, escribir un script de trading es una tarea claramente intermedia, y de ninguna manera adecuada para un principiante.

Un principiante debería limitarse primero a la salida de línea más sencilla. Entonces - un simple indicador. Y sólo entonces - pasar a solicitar indicadores y funciones de comercio.

 
Mickey Moose:

¿Qué tan complicado es el ensamblador? Necesito sus funciones.

¿Qué funciones?

El ensamblador es demasiado específico para decir "necesito sus funciones".

 

Un nuevo ejemplo sobre el tema de lo que el SB está vendiendo a los novatos en el foro y por qué incluso lejos de los perezosos lo están pasando realmente mal. Hoy he recibido una pregunta muy constructiva sobre MQL5 sin ningún tipo de queja.

Este es el foro para el comercio, los sistemas automatizados de comercio y la prueba de las estrategias de comercio

Bichos, errores, preguntas

damirqa, 2018.01.09 12:14

Hola! He empezado a estudiar MQL5 desdehttps://www.mql5.com/ru/articles/100. Inicié el código y recibí el error 4756. He pensado en empezar con algo sencillo (Alerta/Impresión...). Una de las funciones más importantes es OrderSend. Empecé a buscar en el foro/documentación sobre cómo utilizar OrderSend. Encontré este artículohttps://www.mql5.com/ru/docs/constants/tradingconstants/enum_trade_request_actions y encontré el código para abrir una posición de compra. Tengo el error 4756 y el retcódigo 10030. He entendido que 10030 - es la propiedad OrderSend, pero no he entendido cómo se debe utilizar esta propiedad (he mirado el código de otra persona) y para qué se utiliza principalmente. Entonces abríhttps://www.mql5.com/ru/docs/trading/ordersend, copié el código, lo ejecuté y funcionó bien.
Pero sigo sin entender por qué aparece el error 4756 y cómo deshacerse de él, así como del 10030.

Miré el código entre

void OnTick(){
      //--- объявление и инициализация запроса и результата
      MqlTradeRequest request={0};
      MqlTradeResult  result={0};
      //--- параметры запроса
      request.action   =TRADE_ACTION_DEAL;                     // тип торговой операции
      request.symbol   =Symbol();                              // символ
      request.volume   =0.1;                                   // объем в 0.1 лот
      request.type     =ORDER_TYPE_BUY;                        // тип ордера
      request.price    =SymbolInfoDouble(Symbol(),SYMBOL_ASK); // цена для открытия
      request.deviation=5;                                     // допустимое отклонение от цены
      request.magic    =EXPERT_MAGIC;                          // MagicNumber ордера
      //--- отправка запроса
      if(!OrderSend(request,result))
         PrintFormat("OrderSend error %d",GetLastError());     // если отправить запрос не удалось, вывести код ошибки
         Alert(GetLastError());
      //--- информация об операции
      PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
   }

y esta otra.

uint SendRandomPendingOrder(long const magic_number) 
  { 
//--- готовим запрос 
   MqlTradeRequest request={0}; 
   request.action=TRADE_ACTION_PENDING;         // установка отложенного ордера 
   request.magic=magic_number;                  // ORDER_MAGIC 
   request.symbol=_Symbol;                      // инструмент 
   request.volume=0.1;                          // объем в 0.1 лот 
   request.sl=0;                                // Stop Loss не указан 
   request.tp=0;                                // Take Profit не указан    
//--- сформируем тип ордера 
   request.type=GetRandomType();                // тип ордера 
//---сформируем цену для отложенного ордера 
   request.price=GetRandomPrice(request.type);  // цена для открытия 
//--- отправим торговый приказ 
   MqlTradeResult result={0}; 
   OrderSend(request,result); 
//--- выведем в лог ответ сервера   
   Print(__FUNCTION__,":",result.comment); 
   if(result.retcode==10016) Print(result.bid,result.ask,result.price); 
//--- вернем код ответа торгового сервера 
   return result.retcode; 
  } 

Me parecen casi idénticos, no veo los lugares donde aparecen estos errores (4756 y 10030). Señala el dedo y explica por favor


Respuesta del moderador

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

Errores, fallos, preguntas

Vladimir Karputov, 2018.01.09 12:20


Utilice la clase de comercio de CTrade: así se garantiza que cometa el menor número de errores posible.

Ejemplo de envío de una orden de apertura de compra:


Probablemente ayudó a resolverlo. Pero en realidad el novato tiene un problema muy serio.

Es decir, tienes que ir a leer los enlaces del tema designado. En SB esto se resuelve a través de un lugar maravilloso. Es decir, al escribir el script de trading más sencillo (el primer programa de cualquier principiante) es casi trindetz.

 
George Merts:

El guión del comercio es un poco más complicado de lo que parece. ¿Por qué no un Asesor Experto o incluso un sustituto de la Biblioteca Estándar?

En mi opinión, escribir un guión comercial es una tarea claramente intermedia, y de ninguna manera adecuada para un principiante.

Un principiante debería limitarse primero a la salida de línea más sencilla. Entonces - un simple indicador. Y sólo entonces - pasar a solicitar indicadores y funciones de comercio.

Empecé con el Asesor Experto MTF multidivisa de inmediato. Y me sentí bien en la rama de los novatos. Y no hice demasiadas preguntas: tengo ayuda y un cerebro en alguna parte...

 

Ah, y hablando de iBarsShift.

Aquí está mi función homóloga (CTSTime es una clase de serie de tiempo), creo que es un poco complicado para los novatos, incluso con los comentarios. Así que realmente le falta el SB:

// Функция ищет бар, внутри которого находится указанный момент.
// Если такой бар найден - возвращается true и ссылка rIdx устанавливает нужное значение 
// Если такой бар не найден - возвращается false и ссылка rIdx устанавливает значение на ближайший индекс,
// время которого меньше, требуемого.
// При недостаточности буффера функция возвращает false, ссылка устанавливается на отрицательное значение.   
// NOTE !!! ненаступивший момент может лежать внутри нулевого бара, в этом случае вернется true,
// даже если фактически данный момент еще не наступил. false вернется только если данный момент лежит позже
// нулевого бара. 
// Если искомый момент находится раньше самого раннего бара, возвращается false и  rIdx = INT_MAX

bool CTSTime::FindIdxOf(datetime dtMomentToFind,int& rIdx)
{
   ASSERT(dtMomentToFind > MIN_DATETIME && dtMomentToFind < NEVER_EXPIRES);

   // Пока найденный индекс - невалиден.
   rIdx = WRONG_VALUE;

   // Если данных нет - возвращаем отрицательный результат поиска.
   if(GetTSSize() == 0)
      return(false);

   // Найдем продолжительность текущего бара
   int iSecondsInBar = PeriodSeconds(m_etTimeframe);
   
   ASSERT(iSecondsInBar >= SECS_IN_MINUTE);

   datetime dtMomentOfZeroBar = GetTime(0);
   datetime dtMomentOfLastBar = GetTime(GetTSSize()-1);
   
   // Искомый момент лежит внутри или позже, чем нулевой бар ?  
   if(dtMomentToFind >= dtMomentOfZeroBar)   
      {
      rIdx = 0;
      
      // Искомый момент лежит на открытии минус первого бара или позже ?  
      if(dtMomentToFind >= dtMomentOfZeroBar + iSecondsInBar) 
         return (false);   // Искомый момент лежит после нулевого бара. 
      
      // Искомый момент лежит внутри нулевого бара.
      return(true);               
      };
      
   // Здесь ясно, что искомый момент был ранее нулевого бара. 
   
   // Проверим, может быть искомый момент лежит раньше последнего бара ? 
   if(dtMomentToFind < dtMomentOfLastBar)
      {
      // Увы, такого раннего момента в таймсерии нет. 
      // Возвращаем самый большой индекс бара, какой можем возвратить
      // (Потому, что бара со временем меньше требуемого - в таймсерии нет).
      rIdx = INT_MAX;
      return(false);
      };

   // Здесь ясно, что искомый момент был позже начала самого раннего бара, но раньше начала самого нового бара.

   ASSERT(GetTSSize()  > 1);  // Проверим, размер буффера должен быть минимум два бара. (Иначе условие не выполняется, что искомый момент был позже начала самого раннего бара, но раньше начала самого нового бара, не выполняется)

   // Ищем примерно, где был данный момент.
   ASSERT(dtMomentOfZeroBar > dtMomentToFind);
   ASSERT(dtMomentOfZeroBar > dtMomentOfLastBar);
   
   ulong ulSecFromSearchToLatest = dtMomentOfZeroBar - dtMomentToFind;   
   ulong ulSecFromEarlestToLatest = dtMomentOfZeroBar - dtMomentOfLastBar;
   
   ASSERT(ulSecFromEarlestToLatest > ulSecFromSearchToLatest);
    
   double dResIdx = (double)ulSecFromSearchToLatest*(double)(GetTSSize()-1)/(double)ulSecFromEarlestToLatest;
   
   ASSERT(dResIdx <INT_MAX && dResIdx >= 0);
   
   int iResIdx = (int)MathRound(dResIdx);
   
   ASSERT(iResIdx >= 0 && iResIdx<(int)GetTSSize());   // По идее, мы должны уложиться в этот диапазон.
   
   // Поскольку мы исследуем минимум два бара (текущий и следующий),
   // Текущий бар не должен быть нулевым.
   // Поскольку случай с буффером в один бар у нас был отсеян раньше, мы не должны получить ошибку.
   
   if(iResIdx == 0)  
      iResIdx = 1;

   // Получен приблизительный индекс (uiResIdx).
   
   // Уточняем. Берем два бара, текущий и следующий.
   datetime dtResMoment;
   datetime dtNextMoment;
   
   
   dtResMoment = GetTime(iResIdx);
   dtNextMoment = GetTime(iResIdx-1);
   
   int iShift = 0;
   bool bUp = false;
   bool bDown = false;
   
   do
      {
      if(dtResMoment > dtMomentToFind)       // Если искомый момент раньше начала первого бара
         {
         iShift = 1;                         // Возьмем на один бар раньше.
         bUp = true;                         // Запомним направление
         }
      else                                   // Иначе - Искомый момент равен или позже начала первого бара. 
         {
         if(dtNextMoment <= dtMomentToFind)  // Если искомый момент больше или равен началу второго бара
            {
            iShift = -1;                     // Возьмем на один бар позже
            bDown = true;                    // Запомним направление
            }
         else                          // Иначе - искомый момент равен или позже начала перого бара и раньше начала  второго бара   
            {         
            iShift = 0;                // То есть, можно выходить из цикла коррекции.
            }
         }  

      iResIdx += iShift;               // Смещаемся

      if(iResIdx > (int)GetTSSize() || iResIdx <= 0) // Проверим на допустимый диапазон
         {
         ASSERT(false);    // В серии недостаточно данных (мал буффер)
         rIdx = INT_MAX;
         return(false);
         };
                  
      dtResMoment = GetTime(iResIdx);  // Запрашиваем новые данные 
      dtNextMoment = GetTime(iResIdx-1);
            
      if(bUp == true && bDown == true) // Контроль направления коррекции
         {
         ASSERT(false);                // Сменилось направление коррекции !!!
         iShift = 0;
         }           
      }
   while(iShift != 0);
   
   // В этой точке искомый момент равен или позже начала перого бара и раньше начала  второго бара.
   // Проверим, может быть, искомый момент позже конца первого бара, но раньше начала второго бара 
   // (между барами разрыв, и искомый момент находится именно там)
   
   // Ясно, что ссылка должна показывать на первый бар в любом случае 
   
   rIdx = iResIdx;
   
   if(dtMomentToFind >= dtResMoment+iSecondsInBar)
      // Действительно, искомый момент - внутри разрыва между барами.
      return(false);
   
   return(true);         
};