MT5 é para programadores, não para comerciantes - página 17

 
Andrey F. Zelinsky:

Há muito tempo se foram os dias em que um programador antes de aprender C -- passou por comandos de máquina, assembler, Fortran, PL/1, Pascal e muitas outras coisas -- tudo sem livros didáticos, sem explicação adequada, como Volchansky disse acima, com a documentação impressa em letras tortas.

este é o tempo dos complexos sistemas de aplicação multifuncional -- com uma linguagem de programação de aplicação embutida -- e a tarefa desta linguagem é tornar o terminal de aplicação disponível aos usuários de aplicação, que, sem se aprofundar na programação, podem aprender e usar rapidamente esta linguagem de terminal em um curto período de tempo.


Eu concordo! Corretamente colocado. O terminal comercial deve facilitar a negociação.

 
ILNUR777:
Por quem você está julgando? Como a cara da empresa, não é agradável para você escorregar para o corrico. Você já escreveu que mesmo aqueles que têm experiência na MT4 têm dificuldades. E eles não precisam disso.

Você vê o corrico?

Já escrevi muitas vezes que há muitas oportunidades para escrever facilmente um EA de teste para sua estratégia.

Eu até dei um link para a ajuda. Mas se começássemos a fazer perguntas a respeito da ajuda, veríamos que estávamos interessados neste tipo de conhecimento. Mas não parou de falar de como tudo é ruim.

É por isso que eu digo - talvez a geração que temos agora - 18 anos de idade, pais e sogros têm que comprar um carro, 21 - adquirir uma casa. Mas para estudar - não, por quê?

 
Mickey Moose:

quão complicado é o assembler? Preciso de suas funções

Por que. Escreva-o em µl5. É fácil e direto.
 
Artyom Trishkin:

Porque há apenas 10 anos os iniciantes faziam perguntas muito diferentes sobre este fórum - muito mais complicadas e interessantes.

A propósito, as perguntas de hoje na MQL4 são muito mais esclarecedoras do que na MQL5. A razão é óbvia, e não é a idade das versões MQL.

 
Alexey Viktorov:

Não, não tenho. O que você quer dizer?

Alexey, realmente, não posso lhe dar um exemplo neste momento. Mas você gosta de experimentar - correr e ver o que ele retorna com dados de entrada diferentes.

É difícil para mim lembrá-lo e procurá-lo agora.

Bem, o fxsaber deu um exemplo (eu o modifiquei para mim), compare o 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);
  }
//+------------------------------------------------------------------+

Aqui você pode ver sob quais condições Bars() devolve uma falta.

 
fxsaber:

A primeira coisa que um novato escreve é um roteiro comercial. O segundo é um indicador simples. O terceiro - um simples Expert Advisor.

Mesmo a primeira etapa na MQL4 é mais rápida do que na MQL5.

Um roteiro comercial? Por que não um Expert Advisor ou mesmo um substituto da Biblioteca Padrão?

Na minha opinião, escrever um roteiro comercial é uma clara tarefa intermediária, e de forma alguma adequada para um iniciante.

Um iniciante deve ser limitado primeiro à saída da linha mais simples. Então - um indicador simples. E só então - passar a solicitar indicadores e funções comerciais.

 
Mickey Moose:

Quão complicado é o montador? Eu preciso de suas funções.

Quais funções?

Assembler é muito específico para dizer "eu preciso de suas funções".

 

Um novo exemplo sobre o que a SB está vendendo para novatos no fórum e por que mesmo longe de ser preguiçoso está passando por um momento realmente difícil. Hoje recebi uma pergunta muito construtiva sobre a MQL5 sem nenhuma lamúria.

Este é o fórum para negociação, sistemas automatizados de negociação e teste de estratégias comerciais.

Bichos, insetos, perguntas

damirqa, 2018.01.09 12:14

Olá! Comecei a estudar a MQL5 a partir dehttps://www.mql5.com/ru/articles/100. Eu iniciei o código e recebi o erro 4756. Eu pensei em começar com algo simples (Alerta/Impressão...). Uma das funções mais importantes é a de OrderSend. Comecei a pesquisar no fórum/documentação sobre como usar o OrderSend. Encontrei este artigohttps://www.mql5.com/ru/docs/constants/tradingconstants/enum_trade_request_actions e encontrei o código para abrir uma posição de compra. Recebi erro 4756 e retcode 10030. Entendi que 10030 - é a propriedade OrderSend, mas não entendi como esta propriedade deve ser usada (olhei o código de outra pessoa) e para o que ela é usada principalmente. Depois abrihttps://www.mql5.com/ru/docs/trading/ordersend, copiei o código, executei-o, funcionou bem.
Mas ainda não entendo por que o erro 4756 aparece e como se livrar dele, assim como o 10030.

Vejam o 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);
   }

e este aqui.

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; 
  } 

Eles me parecem quase idênticos, não vejo os lugares onde estes erros aparecem (4756 e 10030). Aponte o dedo e explique por favor


Resposta do moderador

Fórum sobre comércio, sistemas automatizados de comércio e testador de estratégias

Erros, Erros, Perguntas

Vladimir Karputov, 2018.01.09 12:20


Use a classe CTrade - dessa forma você tem a garantia de cometer o menor número possível de erros.

Exemplo de envio de uma ordem comercial para abrir a Buy:


Provavelmente ajudou a dar sentido a isso. Mas na verdade, o novato tem um problema muito sério.

Isto é, você tem que ir e ler os links sobre o tópico designado. Em SB isto se resolve através de um lugar maravilhoso. Isto é, ao escrever o roteiro comercial mais simples (o primeiro progama de qualquer novato) é quase trindetz.

 
George Merts:

Roteiro comercial ???? Por que não um Expert Advisor ou mesmo um substituto para a Biblioteca Padrão?

Na minha opinião, escrever um roteiro comercial é uma clara tarefa intermediária, e de forma alguma adequada para um iniciante.

Um iniciante deve ser limitado primeiro à saída da linha mais simples. Então - um indicador simples. E só então - passar a solicitar indicadores e funções comerciais.

Comecei imediatamente com o MTF Expert Advisor de múltiplas moedas. E eu me senti bem no ramo dos novatos. E não fiz muitas perguntas - tenho ajuda e um cérebro em algum lugar...

 

Ah, e a propósito, sobre o iBarsShift.

Aqui está minha função contraparte (CTSTime é uma aula da série do tempo), acho que é um pouco complicado para os novatos, mesmo com os comentários. Por isso, falta realmente na 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);         
};