MT5-это терминал для программистов, а не для трейдеров - страница 17

 
Andrey F. Zelinsky:

давно прошли те времена, когда программист перед изучением Си -- прошел машинные команды, ассемблер, фортран, ПЛ/1, паскаль и ещё много чего -- и всё это без учебников, без должного пояснения, как говорил выше Волчанский, с распечатанной кривыми буквами документацией.

сейчас время сложных многофункциональных прикладных систем -- где есть встроенный прикладной язык программирования -- и задача этого языка -- сделать прикладной терминал доступным пользователям-прикладникам, которые без глубококопания в дебри программирования -- быстро и за короткий срок этот терминальный язык могут освоить и использовать.


Согласен! Правильно сформулировано. Торговый терминал, должен способствовать торговле.

 
ILNUR777:
Это Вы по кому судите. Как лицу компании, не красиво  Вам скатываться к троллингу. Вам писали уже что сложности есть даже у тех кто имеет опыт в мт4. И не лего им нужен. 

А вы троллинг увидели?

Я уже много раз написал, что есть предостаточно возможностей для простого и лёгкого написания проверочного советника для своей стратегии.

И даже дал ссылку на справку. Вот если бы тут начали задавать вопросы по этой справке - вот тогда видна была бы заинтересованность хоть в таких знаниях. Но продолжилось про то как всё плохо.

Потому и говорю - наверное поколение теперь у нас такое - 18 лет, родаки-домочадцы обязаны тачку купить, 21 год - хату давай. А учиться - неееет, зачем?

 
Mickey Moose:

насколько сложен ассемблер? мне его функции понадобились

Зачем. Напишите на мкл5. Это ведь легко и просто.
 
Artyom Trishkin:

Потому, что всего лишь 10 лет назад на форуме новичками задавались ой как не такие вопросы - на порядок сложнее и интереснее.

Кстати, нынешние вопросы по MQL4 куда содержательнее вопросов по MQL5. Причина очевидна и это не возраст MQL-версий.

 
Alexey Viktorov:

Нет не знаю. О чём ты?

Алексей, правда, сейчас уже не приведу пример. Но ты же любишь экспериментировать - погоняй и погляди что возвращает при разных входных данных.

Просто мне сейчас вспоминать и  искать сложновато.

Ну вот fxsaber приводил пример (я под себя видоизменил), сравни по коду:

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

Тут видно при каких условиях Bars() возвращает бяку.

 
fxsaber:

Первое, что пишет новичок - торговый скрипт. Второе - простейший индикатор. Третье - простой советник.

Даже первый этап на MQL4 новичком преодолевается значительно быстрее MQL5.

Торговый скрипт ??? А почему не эксперт или даже замену Стандартной Библиотеки ? 

На мой взгляд, написание торгового скрипта - это явная Intermediate задача, и никак не подходит для новичка.

Новичку надо сперва ограничиться простейшим выводом строк. Потом - простейшим индикатором. И лишь потом - переходить к запросу индикаторов и торговых функций.

 
Mickey Moose:

насколько сложен ассемблер? мне его функции понадобились

Какие именно ?

Ассемблер - слишком специфичен, чтобы прям вот так заявлять "мне его функции понадобились". 

 

Свежий пример на тему, что СБ впаривается новичкам на форуме и почему даже далеко не лентяям реально тяжело. Сегодня был задан очень конструктивный вопрос по MQL5 без намека на нытье

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Ошибки, баги, вопросы

damirqa, 2018.01.09 12:14

Здравствуйте! Начал изучать MQL5 с https://www.mql5.com/ru/articles/100. Запустил код, получил ошибку 4756, посмотрел в документации - легче не стало. Ладно, подумал, что начну с простого (Alert/Print...). Одна из важнейших функций это OrderSend. Начал искать по форуму\документации как использовать OrderSend. Наткнулся на эту статью https://www.mql5.com/ru/docs/constants/tradingconstants/enum_trade_request_actions, там увидел код на открытие позиции Buy. Получил ошибку 4756 и retcode 10030. 10030 - понял, что это свойство OrderSend, но не понял как нужно использовать это свойство (смотрел чужой код), а самое главное для чего нужно. Тогда открыл https://www.mql5.com/ru/docs/trading/ordersend, скопировал код, запустил, все отлично, заработало.
Но так и не понял, почему появляется ошибка 4756 и как от нее нужно избавляться, а также 10030. 

Посмотрел код между 

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

и этим

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

Они по-моему практически идентичны, не вижу тех мест, в которых появляются эти ошибки (4756 и 10030). Ткните пальцем и объясните пожалуйста


Ответ модератора

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Ошибки, баги, вопросы

Vladimir Karputov, 2018.01.09 12:20


Используйте торговый класс CTrade - так Вы гарантированно сможете допустить минимум ошибок.

Пример отсылки торгового приказа на открытие Buy:


Наверное, помог разобраться. А на самом деле проблема у новичка очень не новичковская

Т.е. надо идти и читать ссылки по обозначенной теме. В СБ это решается через замечательное место. Т.е. при написании простейшего торгового скрипта (первая прога любого новичка) почти трындец.

 
George Merts:

Торговый скрипт ??? А почему не эксперт или даже замену Стандартной Библиотеки ? 

На мой взгляд, написание торгового скрипта - это явная Intermediate задача, и никак не подходит для новичка.

Новичку надо сперва ограничиться простейшим выводом строк. Потом - простейшим индикатором. И лишь потом - переходить к запросу индикаторов и торговых функций.

Я сразу начал с мультивалютного МТФ советника. И чувствовал себя неплохо в ветке помощи новичкам. Да и много вопросов не задавал - справка же есть и мозг где-то...

 

Да, кстати, о iBarsShift.

Вот моя функция-аналог (CTSTime - это класс-таймсерия времени), думаю, для новичков это сложновато, даже с учетом комментариев. Так что ее реально не хватает в СБ:

// Функция ищет бар, внутри которого находится указанный момент.
// Если такой бар найден - возвращается 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);         
};      


Причина обращения: