Заготовка для робота на MQL5

  1. Аватар Дмитрий Тюриков
    Спасибо! Я так и подозревал)
  2. Аватар tranquility
    Дмитрий Тюриков,

    Я не работал с Плаза2, но насколько понимаю, по нему подключаются через собственное приложение. Т.е. бота будете писать на том языке, на котором приложение (С# или С++ скорее всего). Вот, почитайте коммент и тему:
    www.mql5.com/ru/forum/219095#comment_6318217 А сравнить lua и mql5 в принципе можно. Только я подозреваю, что в спредовой стратегии нет громоздких вычислений, поэтому скорости будут практически одинаковые. В случае больших вычислений mql должен выигрывать.
  3. Аватар Дмитрий Тюриков
    Приветствую!
    Вопрос по языкам: Для Плаза 2 пропуск 30 мс на каком языке лучше иметь спредера?
    Сейчас тестируются на LUA, есть смысл делать на MQL5?
    Если что, сможем доработать?

    Спасибо!)

Заготовка для робота на MQL5

По просьбам коллег выкладываю своего советника-обертку для MT5. Обертку — потому, что я изначально писал стратегию на С++ и, соответственно, она может быть физически размещена либо в dll, либо в другом процессе, к которому подключается dll. В моем случае подключение происходит через сокеты. Так или иначе, здесь выкладывается только обертка, которая заинтересованным поможет быстрее поднять своего бота на MT5:
yadi.sk/d/WPgi-8fd3QoetS
Этот код тестировался с dll, которую он использует в тестере стратегий MT5, при этом не падал и не зависал)) Единственное, там какой-то глюк был с кнопкой «Finalize», но с этим разобраться так и не получилось. Я даже задавал вопрос на соответствующем форуме, но проблему выявить не получилось, только местная публика успела выразить свою обиду на мои ругательства в адрес платформы МетаТрейдер)

Так уж вышло, я не пишу комментарии к коду, зато стараюсь делать так, чтобы он хорошо читался. Для написания собственного эксперта на основе этой обертки надо просто заменить вызовы функций из dll:
#import «MyLib.dll»
bool initialize( double startBalance, double _point, double leverage, double volumeStep,  double spread, int brokerTimeZone );
bool finalalize();
bool passTick( datetime time, double ask, double bid, uint volume, double interest );
bool passBook( datetime time, MqlBookInfo& book[], uint bookSize );
bool addOrder( ulong orderTicket, uint orderType, datetime time, double volume, double openPice );
int closeOrder( ulong orderTicket, datetime time, double closePice );
void reportRequestCompletion( uint reqId );
bool isTimeToOpenOrder( uint& reqId, uint& srvOrderType, double& volume, double& openPice );
bool isTimeToCloseOrder( ulong& orderTickets[], uint idsInBuffer, uint& idsWritten );
#import

Функции выделенные цветом при написании собственного советника придется реализовать самостоятельно. А точнее — полностью переписать по-своему. В моем случае они работали следующим образом.
isTimeToOpenOrder — вызывается при получении каждого тика, если условия для входа в сделку соблюдаются, она возвращает true и параметры заявки (на тот момент я не различал такие понятия как ордера и позиции, поэтому вы тут видите словосочетания вроде «открыть ордер»), среди которых есть уникальный идентификатор запроса reqId, который ассоциируется с данной заявкой. Этот код
   if( isTimeToOpenOrder( reqId, srvOrderType, volume, openPrice ) )
      OpenOrder( reqId, srvOrderType, volume );
асинхронно посылает заявку на сервер, после чего надо дождаться ее подтверждения в вызове системной функции OnTrade().
addOrder — вызывается внутри OnTrade() и посылает в dll актуальные данные об изменении позиции, ссылаясь на соответствующий reqId. Главным образом нужно отправлять столько параметров потому, что цена совершенной сделки может отличаться от той, что была получена в isTimeToOpenOrder (запросе на открытие позиции).
reportRequestCompletion — сейчас даже не вспомню, но зачем-то сильно была нужна, хотя по идее вызова addOrder с переданным параметром reqId должно было быть достаточно.
isTimeToCloseOrder — возвращает true когда необходимо закрыть позицию. Параметры которые она должна при этом получить — список идентификаторов запросов соответствующих ордеров (на самом деле там всегда передавался только один идентификатор) idsBuff и его длина idsWritten. Данный блок
   ulong idsBuff[10];
   uint idsWritten;   
   if( isTimeToCloseOrder( idsBuff, 10, idsWritten ) )
   {      
      for( unsigned i = 0; i < idsWritten; i++ )
      {
         if( !currOrder.cancelclose && currOrder.reqId == idsBuff[i] )
           {
            currOrder.cancelclose = true;
               CloseOrder( idsBuff[i] );
         }
      }
   }
в конечном итоге вызывает асинхронно посылает заявку на закрытие позиции. А уже подтверждение этой заявки будет при вызове OnTrade:
   if( currOrder.cancelclose && !currOrder.closed )
   {
      if( abs( currOrder.volume + posVolumeChange ) >= volumeStep / 2.0 ) // на самом деле позиция должна быть точно равна нулю, но она и не может быть меньше volumeStep
          Print( __FUNCTION__, ": Something strange (closing), actual volume change doesn't correspond current order" );
       datetime closeTime = SymbolInfoInteger( _Symbol, SYMBOL_TIME );
      double closePrice = ( currOrder.volume >= 0.0 )? SymbolInfoDouble( _Symbol, SYMBOL_BID ): SymbolInfoDouble( _Symbol, SYMBOL_ASK );;  
      closeOrder( currOrder.reqId, closeTime, closePrice );
               
       currOrder.passedToServer = false;
       currOrder.closed = true;
      return;
   }

closeOrder — отправляет в dll данные по соответствующему ордеру (reqId) с актуальной ценой закрытия позиции и временем.

В общем, надеюсь, это будет для кого-то полезным. Вопросы по коду приветствуются)
Чтобы купить акции, выберите надежного брокера: