Новая версия платформы MetaTrader 5 build 4260: общие улучшения

 

В пятницу 22 марта 2024 года будет выпущена обновленная версия платформы MetaTrader 5.

В новой версии расширены возможности работы с событиями клавиатуры в MQL5-программах. Теперь разработчики могут получать события отжатия клавиш, а также события «мертвых» клавиш. Это позволит улучшить взаимодействие программ с пользователями.

Помимо этого, в MetaEditor появилась возможность поиска по книге «Нейросети в алготрейдинге на MQL5». Также в веб-приложении исправлено выставлении лимитных заявок для биржевых инструментов.

Новая версия платформы MetaTrader 5 build 4260: общие улучшения


MetaTrader 5 Client Terminal

  1. Terminal: Исправлена ошибка подписки на бесплатные продукты в сервисе «Подписки». В некоторых случаях соответствующая кнопка могла отсутствовать в диалоге.
  2. Terminal: Обновлены переводы пользовательского интерфейса.
  3. MQL5: Расширена поддержка событий клавиатуры:

    • Добавлено событие CHARTEVENT_KEYUP для обработчика OnChartEvent. Оно позволяет отслеживать, когда пользователь отпускает клавишу на клавиатуре.
    • Добавлена обработка «Мертвых» клавиш (Dead keys) — это клавиши, позволяющие изменить вид следующего вводимого символа. Например, в греческой раскладке для установки ударений над гласными ά, έ, ύ и т.д. требуется нажать клавишу «;», а затем ввести букву. Теперь нажатие таких клавиш можно отслеживать при помощи функции TranslateKey.
    • Доработаны функции TranslateKey и TerminalInfoInteger. Теперь при получении событий CHARTEVENT_KEYUP или CHARTEVENT_KEYDOWN в OnChartEvent вы можете получить полное состояние клавиатуры на момент возникновения события. Например, если пользователь нажал клавишу Z, вы сможете узнать, была ли в тот момент нажата клавиша Ctrl или Shift. Для остальных событий функции будут работать как раньше — возвращать состояние клавиатуры на текущий момент.

  4. MQL5: Обновлена библиотека Alglib. В связи с обновлением изменены следующие методы в классах CMatrixDouble и CMatrixComplex:
    vector<double/complex> operator[](const int i) const;
    vector<double/complex> operator[](const ulong i) const;
    Теперь вместо них используется один метод с константным возвращаемым значением:
    const vector<double/complex> operator[](const ulong i) const;
    Внесенная правка позволит отловить некорректное использование результата по месту: в новой версии Alglib код mat[row][col]=x работает не так, как в старой. Ранее это была запись в матрицу, а теперь — запись во временный объект vector<double/complex>, который после записи сразу же уничтожается.

    Добавление const к возвращаемому значению делает невозможным использование записи mat[row][col]=x. Поскольку mat[row] теперь возвращает константный вектор, попытка перезаписать его элемент через mat[row][col] приведет к ошибке компиляции.

  5. MQL5: Исправлена ошибка, в некоторых случаях приводившая к некорректной работе функций ChartGet*.
  6. MetaEditor: Добавлен поиск по книге «Нейросети в алготрейдинге на MQL5». Теперь он объединен в одном разделе с ранее вышедшей книгой «Программирование на MQL5 для трейдеров».


    Добавлен поиск по недавно вышедшей книге «Нейросети в алготрейдинге на MQL5»


  7. Tester: Исправлена оптимизация на большом количестве удаленных агентов. В некоторых случаях ошибка могла приводить к чрезмерной нагрузке на CPU.
  8. Исправления по крешлогам.

MetaTrader 5 Web Terminal

  1. Исправлено выставление лимитных ордеров для инструментов с биржевым исполнением. Теперь при изменении цены выставляемого ордера относительно текущей (выше или ниже) предлагаемый тип ордера не будет изменяться с Buy Limit на Sell Limit и обратно, как это происходит для инструментов остальных типов. Таким образом, пользователь при необходимости сможет выставлять ордера Buy Limit выше рынка и Sell Limit ниже рынка, чтобы гарантированно ограничить цену сделки.
  2. Исправлено отображение счетчиков выбранных символов в «Обзоре рынка».


Обновление будет доступно через систему Live Update.

 

Спасибо за обновление!

Добавьте, пожалуйста, возможность включать в ресурсы эксперта скрипты и сервисы, если это возможно.  

 

вот отчего-то выскакивает Alert 1

злополучный CustomSymbol :-)

#property service
#property copyright "Maxim A.Kuznetsov"
#property link      "https://www.luxtrade.tk"
#property version   "1.00"

string basis="";
const string symbol="BBCRTD";
const string group="mycustom";
const string base="BBC";
const string quote="RTD";
const string bank="RGB";
const string exchange="RGB";
const string category="joke";
const int digits=5;
const double point=0.00001;
const double contract=1.0;
const double ticksize=point;
const double tickvalue=point;    
const double lotStep=0.00001;
const double minLot=0.01;
const double maxLot=1000.0;
const double depth=0;
const int stops=0;
const int freeze=0;
const string descr="sample joke custom";

bool MyCustomCreate() {
   if (CustomSymbolCreate(symbol,group)) {
      if (basis==NULL || basis=="") {
         basis = "EURUSD";
      }
      if (!CustomSymbolSetString(symbol,SYMBOL_CURRENCY_BASE,base)) {
         Print("CURRENCY BASE :"+IntegerToString(GetLastError()));
      }
      CustomSymbolSetInteger(symbol,SYMBOL_TRADE_CALC_MODE,SYMBOL_CALC_MODE_FUTURES);  // First!!
      CustomSymbolSetString(symbol,SYMBOL_BASIS,basis);
      CustomSymbolSetString(symbol,SYMBOL_CURRENCY_PROFIT,quote);
      CustomSymbolSetString(symbol,SYMBOL_CURRENCY_MARGIN,quote);

      CustomSymbolSetString(symbol,SYMBOL_BANK,"ByBit");
      CustomSymbolSetString(symbol,SYMBOL_EXCHANGE,"ByBit");
      CustomSymbolSetString(symbol,SYMBOL_CATEGORY,category);
      
      CustomSymbolSetInteger(symbol,SYMBOL_DIGITS,digits);
      CustomSymbolSetDouble(symbol,SYMBOL_POINT,point);
      CustomSymbolSetDouble(symbol,SYMBOL_TRADE_CONTRACT_SIZE,1.0);
      CustomSymbolSetDouble(symbol,SYMBOL_TRADE_TICK_SIZE,point);
      CustomSymbolSetDouble(symbol,SYMBOL_TRADE_TICK_VALUE,point);
      CustomSymbolSetDouble(symbol,SYMBOL_VOLUME_STEP,lotStep);   //! step,max,min
      CustomSymbolSetDouble(symbol,SYMBOL_VOLUME_MAX,maxLot);
      CustomSymbolSetDouble(symbol,SYMBOL_VOLUME_MIN,minLot);
      CustomSymbolSetInteger(symbol,SYMBOL_TICKS_BOOKDEPTH,(long)depth);
      CustomSymbolSetInteger(symbol,SYMBOL_TRADE_STOPS_LEVEL,0);
      CustomSymbolSetInteger(symbol,SYMBOL_TRADE_FREEZE_LEVEL,0);
      CustomSymbolSetInteger(symbol,SYMBOL_TRADE_MODE,SYMBOL_TRADE_MODE_FULL);
      CustomSymbolSetString(symbol,SYMBOL_DESCRIPTION,descr);
      datetime dayOpen=TimeCurrent();
      MqlDateTime dt; TimeToStruct(dayOpen,dt);
      dt.hour=0;dt.min=0;dt.sec=0;
      dayOpen=StructToTime(dt);
      datetime dayClose=dayOpen+24*60*60-1;
      for(int day=0;day<7;day++) {
         CustomSymbolSetSessionQuote(symbol,(ENUM_DAY_OF_WEEK)day,0,dayOpen,dayClose);
         CustomSymbolSetSessionTrade(symbol,(ENUM_DAY_OF_WEEK)day,0,dayOpen,dayClose);
      }
      SymbolSelect(symbol,false);
      CustomSymbolSetInteger(symbol,SYMBOL_SELECT,0);
   } else {
      // не шмогла
      return false;
   }
   return true;
}

void MyCustomShow() {
   SymbolSelect(symbol,true);
   CustomSymbolSetInteger(symbol,SYMBOL_SELECT,1);
}
void MyCustomHide() {
   SymbolSelect(symbol,false);
   CustomSymbolSetInteger(symbol,SYMBOL_SELECT,0);
}
void CheckMyCustomSelected(bool shouldSelected) {
   // в основной программе - используется цикл просмотра символов,
   // поэтому тут он просто эмулируется
   // ---
   // просматриваются только Selected (те которые в MarketWatch)
   for(int pos=SymbolsTotal(true)-1;pos>=0;pos--) {
      string _symbol=SymbolName(pos,true);
      if (_symbol==NULL || _symbol=="") continue;
      if (_symbol!=symbol) continue;
      bool selected=(SymbolInfoInteger(_symbol,SYMBOL_SELECT)!=0);
      if (!shouldSelected && selected) {
         // не должно быть выбрано, но всё-таки выбрано
         Alert("Alert 1");
      } else if (shouldSelected && !selected) {
         // должно быть выбрано, но не склалось
         Alert("Alert 2");
      }
   }
}
void MyCustomDelete() {
   CustomSymbolDelete(symbol);
}

void OnStart()
{
   MyCustomCreate(); // создаём новый символ. Он создаётся с SELECT=0 и это действительно так
   // то есть он создаётся и изначально в Watch его нет видимого
   while(!IsStopped()) {
      Sleep(3000);                  // ждём 3 секунды
      if (IsStopped())  break;
      CheckMyCustomSelected(false); // проверяем что скрыт
      MyCustomShow();               // помещаем в Watch
      Sleep(3000);                  // ждём ещё 3 секунды
      if (IsStopped())  break;
      CheckMyCustomSelected(true);  // проверяем что показан
      MyCustomHide();               // убираем из Watch
   }
   MyCustomDelete(); // удаляем новый символ
}

По крайней в Service - что-то не так ... либо что-то недокументировано

 
b4242, неоднозначность оптимизации компилятора.
#define BENCH(A)                                                             \
  {                                                                          \
    const ulong StartTime = GetMicrosecondCount();                           \
    A;                                                                       \
    Print(#A + ":" + (string)(GetMicrosecondCount() - StartTime) + " mcs."); \
  } 

// Возвращает себя.
template <typename T>
T Me( const T &Value )
{
  return(Value);
}

template <typename T>
int Bench1( T Value )
{
  int Res = 0;

  for (int i = 0; i < 1e8; i++)
  {
    Res += (Me(Value) != NULL); // Строка отличия
    
    if (!Res)
      Value = NULL;
  }
    
  return(Res);
}

template <typename T>
int Bench2( T Value )
{
  int Res = 0;

  for (int i = 0; i < 1e8; i++)
  {
    Res += (Value != NULL); // Строка отличия
    
    if (!Res)
      Value = NULL;
  }
    
  return(Res);
}

void OnStart()
{  
  int Tmp;

  BENCH(Tmp = Bench1("qwe"))
  BENCH(Tmp = Bench1(123))

  BENCH(Tmp = Bench2("qwe"))
  BENCH(Tmp = Bench2(123))
  
  BENCH(Tmp += Bench1(123))
  
  Print(Tmp);  
}


Результат.

Tmp = Bench1(qwe):1318922 mcs. // Почему не ноль?
Tmp = Bench1(123):0 mcs.       // OK.
Tmp = Bench2(qwe):53371 mcs.   // Почему не ноль?
Tmp = Bench2(123):101601 mcs.  // OK.
Tmp += Bench1(123):102368 mcs. // OK.
200000000


Помимо того, что ненулевые значения вышли для string-варианта, еще оказалось, что разный итоговый код у этих условий:

Me(Str) != NULL
Str != NULL


Зачем компилятор создает лишний string  в таком случае?

string Func()
{
  string Str;

  // ........

  return(Str);
}


Оказалось, что разный код создается и для таких строк.

if (Str != NULL) Str = NULL;
Str = (Str != NULL) ? Str : NULL;

Строка для поискаOshibka 102.

 

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

Новая версия платформы MetaTrader 5 build 4260: общие улучшения

fxsaber, 2024.03.22 12:46

разный итоговый код у этих условий:

Me(Str) != NULL
Str != NULL


Зачем компилятор создает лишний string  в таком случае?

string Func()
{
  string Str;

  // ........

  return(Str);
}


Складывается впечатление, что в таком коде плодятся лишние сущности, понижая производительность.

struct A
{
  uchar Bytes[64];
  
  string GetString() const
  {
    return(CharArrayToString(Bytes)); // 1-й и 2-й раз создался string.
  }
};

string Func()
{
  A a = {};
  
  return(a.GetString()); // 3-й раз создался string.
}

void OnStart()
{
  Print(Func());
}

Ошибаюсь?

 
Maxim Kuznetsov #:

вот отчего-то выскакивает Alert 1

злополучный CustomSymbol :-)

По крайней в Service - что-то не так ... либо что-то недокументировано

Решено:

перед вызовам SymbolsTotal(true) надо ВСЕГДА вызывать SymbolsTotal(false).  

SymbolsTotal c false не просто выбирает символы, но и синхронизует(обновляет) их данные. C true - только выбирает символы из Watch

 

в сервисах ExpertRemove() не выставляет флаг _IsStopped, либо (что вряд-ли)  IsStopped() его игнорирует.

по крайней мере такое

void Service::Run()
{
   int type=MQLInfoInteger(MQL_PROGRAM_TYPE);
   if (type!=PROGRAM_SCRIPT && type!=PROGRAM_SERVICE) {
      EventSetMillisecondTimer(30);
      mscStamp=GetMicrosecondCount()/1000;
      OnStart();
      return;
   }
   while(!IsStopped()) {
      mscStamp=GetMicrosecondCount()/1000;
      OnStart();  // основная работа
      if (IsStopped()) {
         break;
      }
      if (GetMicrosecondCount()/1000-mscStamp<100) {
         // практически ничего не делали - можно спать
         OnIdle(); // всякие фоновые действия
         if (GetMicrosecondCount()/1000-mscStamp<100) {
            Sleep(5);
         } else {
            SwitchToThread();
         } 
      } else {
         // что-то большое делали - вероятно что снова накидано сообщений
         SwitchToThread();      
      }
   }
}

при вызове ExpertRemove() внутри, вызывает бесконечные предупреждение "ExpertRemove() function called" но IsStopped() возвращает false и цикл не прерывается

возможно ExpertRemove только для экспертов и скриптов, сервисы должны выкручиваться сами

 
Maxim Kuznetsov #:

возможно ExpertRemove только для экспертов и скриптов, сервисы должны выкручиваться сами

Так Сервис - это скрипт без чарта. Вы же скрипту такой функционал не создаете.

 
fxsaber #:

Так Сервис - это скрипт без чарта. Вы же скрипту такой функционал не создаете.

создаю..

всякие всплывающие окошки по hot-key - скрипт с подобным циклом работы

 
Maxim Kuznetsov #:

создаю..

bool _StopFlagMy = false;
bool IsStoppedMy() { return(_StopFlagMy); }
void ExpertRemoveMy() { _StopFlagMy = true; }

void OnStart()
{
  while (!IsStopped() && !IsStoppedMy())
  {
    // ....
    
    Sleep(100);
        
    ExpertRemoveMy();
  }  
}
 
fxsaber #:

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

тут буквально доска объявлений "г-да разработчики, обратите внимание на функционирование XXX - оно отличается от явно ожидаемого, или документируйте отличия"

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