MT5 est destiné aux programmeurs, pas aux traders - page 17

 
Andrey F. Zelinsky:

Il est loin le temps où un programmeur, avant d'apprendre le C, passait par les commandes machine, l'assembleur, le Fortran, le PL/1, le Pascal et bien d'autres choses encore, le tout sans manuels, sans explications appropriées, comme Volchansky l'a dit plus haut, avec une documentation imprimée en lettres tordues.

nous sommes à l'époque des systèmes d'application multifonctionnels complexes - avec un langage de programmation d'application intégré - et la tâche de ce langage est de mettre le terminal d'application à la disposition des utilisateurs de l'application, qui, sans se plonger dans la programmation, peuvent rapidement apprendre et utiliser ce langage de terminal en peu de temps.


Je suis d'accord ! Correctement dit. Le terminal de négociation doit faciliter la négociation.

 
ILNUR777:
Par qui jugez-vous ? En tant que visage de l'entreprise, ce n'est pas bien que vous glissiez dans le trolling. Vous avez déjà écrit que même ceux qui ont de l'expérience dans MT4 ont des difficultés. Et ils n'ont pas besoin de lego.

Vous voyez le troll ?

J'ai déjà écrit à plusieurs reprises qu'il existe de nombreuses possibilités d'écrire un EA de test simple et facile pour votre stratégie.

J'ai même donné un lien vers l'aide. Mais si nous commencions à poser des questions concernant l'aide, nous verrions que nous sommes intéressés par ce type de connaissances. Mais ça n'a pas arrêté de dire à quel point tout est mauvais.

C'est pourquoi je dis - peut-être que la génération que nous avons maintenant - 18 ans, parents-belles-filles doivent acheter une voiture, 21 ans - obtenir une maison. Mais pour étudier - non, pourquoi ?

 
Mickey Moose:

l'assembleur est-il compliqué ? j'ai besoin de ses fonctions

Pourquoi ? Écrivez-le en µl5. C'est simple et direct.
 
Artyom Trishkin:

Parce qu'il y a seulement 10 ans, les débutants posaient des questions bien différentes sur ce forum - bien plus compliquées et intéressantes.

D'ailleurs, les questions d'aujourd'hui dans MQL4 sont beaucoup plus instructives que dans MQL5. La raison est évidente, et ce n'est pas l'âge des versions MQL.

 
Alexey Viktorov:

Non, je ne le fais pas. Qu'est-ce que tu veux dire ?

Alexey, vraiment, je ne peux pas vous donner d'exemple pour le moment. Mais vous aimez expérimenter - exécutez-le et voyez ce qu'il retourne avec différentes données d'entrée.

C'est juste difficile pour moi de m'en souvenir et de le chercher maintenant.

Eh bien, fxsaber a donné un exemple (je l'ai modifié pour moi), comparez le code :

//+------------------------------------------------------------------+
//| Возвращает смещение бара таймфрейма по времени                   |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+

Vous pouvez voir ici dans quelles conditions Bars() renvoie une faute.

 
fxsaber:

La première chose qu'un débutant écrit est un script de trading. Le second est un simple indicateur. Le troisième est un simple conseiller expert.

Même la première étape dans MQL4 est plus rapide que dans MQL5.

Un script de trading ? Pourquoi pas un conseiller expert ou même un remplacement de la bibliothèque standard?

À mon avis, l'écriture d'un script de trading est une tâche clairement intermédiaire, qui ne convient en aucun cas à un débutant.

Un débutant doit d'abord se limiter à la sortie de ligne la plus simple. Ensuite - un simple indicateur. Et seulement ensuite - passez à la demande d'indicateurs et de fonctions de trading.

 
Mickey Moose:

L'assembleur est-il compliqué ? J'ai besoin de ses fonctions.

Quelles fonctions ?

L'assembleur est trop spécifique pour dire "j'ai besoin de ses fonctions".

 

Un nouvel exemple sur le sujet de ce que le SB vend aux nouveaux venus sur le forum et pourquoi même ceux qui sont loin de lazybones ont beaucoup de mal. Aujourd'hui, j'ai reçu une question très constructive sur MQL5, sans aucune plainte.

Il s'agit du forum pour le trading, les systèmes de trading automatisés et les tests de stratégies de trading.

Bugs, bugs, questions

damirqa, 2018.01.09 12:14

Bonjour ! J'ai commencé à étudier le MQL5 à partir dehttps://www.mql5.com/ru/articles/100. J'ai essayé et j'ai reçu l'erreur 4756. J'ai regardé la documentation et ce n'était pas mieux. Je pensais commencer par quelque chose de simple (Alerte/Imprimer...). L'une des fonctions les plus importantes est OrderSend. J'ai commencé à chercher dans le forum/documentation sur la façon d'utiliser OrderSend. J'ai trouvé cet articlehttps://www.mql5.com/ru/docs/constants/tradingconstants/enum_trade_request_actions et j' ai trouvé le code pour ouvrir une position d'achat. J'ai obtenu l'erreur 4756 et le retcode 10030. J'ai compris que 10030 - c'est la propriété OrderSend, mais je n'ai pas compris comment cette propriété doit être utilisée (j'ai regardé le code de quelqu'un d'autre) et à quoi elle sert principalement. Puis j'ai ouverthttps://www.mql5.com/ru/docs/trading/ordersend, copié le code, lancé, tout va bien, ça a marché.
Mais je ne comprends toujours pas pourquoi l'erreur 4756 apparaît et comment s'en débarrasser, ainsi que de la 10030.

J'ai regardé le code 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);
   }

et celui-ci.

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

Ils me semblent presque identiques, je ne vois pas les endroits où ces erreurs apparaissent (4756 et 10030). Montrez-nous du doigt et expliquez-nous, s'il vous plaît.


Réponse du modérateur

Forum sur le trading, les systèmes de trading automatisés et le testeur de stratégie

Erreurs, bogues, questions

Vladimir Karputov, 2018.01.09 12:20


Utilisez la classe de commerce CTrade - de cette façon, vous êtes assuré de faire le moins d'erreurs possible.

Exemple d'envoi d'un ordre de transaction pour ouvrir un achat :


Ça a probablement aidé à faire le tri. Mais en fait, la recrue a un problème très sérieux.

C'est-à-dire que vous devez aller lire les liens sur le sujet désigné. En SB, ce problème est résolu grâce à un endroit merveilleux. Par exemple, pour écrire le script de trading le plus simple (le premier programme de tout débutant), c'est presque du trindetz.

 
George Merts:

Script de commerce ? ?? Pourquoi pas un conseiller expert ou même un remplacement de la bibliothèque standard?

À mon avis, la rédaction d'un script commercial est une tâche clairement intermédiaire, qui ne convient en aucun cas à un débutant.

Un débutant doit d'abord se limiter à la sortie de ligne la plus simple. Ensuite - un simple indicateur. Et seulement ensuite - passez à la demande d'indicateurs et de fonctions de trading.

J'ai tout de suite commencé à utiliser le conseiller expert MTF multidevises. Et je me sentais bien dans la branche des débutants. Et je n'ai pas posé trop de questions - j'ai de l'aide et un cerveau quelque part...

 

Oh, et au fait, à propos de iBarsShift.

Voici ma fonction équivalente (CTSTime est une classe de séries temporelles), je pense que c'est un peu compliqué pour les débutants, même avec les commentaires. Il manque donc vraiment de 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);         
};      


Raison: