ФОРТС: Учимся писать эксперта для торговли фьючерсами

 

Добрый день!

Часто, новичку сложно разобраться в огромном потоке информации для

написания советника Срочного рынка ФОРТС.

Поэтому, в этой теме, я постараюсь выкладывать конкретные примеры советника для ФОРТС.

Многие функции, используемые для торговли на ФОРТС, можно взять здесь

https://www.mql5.com/ru/forum/67298 

1. Пример советника с использованием времени торговли, стакана и кнопки Старт-стоп (торговля)

//+------------------------------------------------------------------+
//|                                                  Expert_Demo.mq5 |
//|                                          Copyright 2016, Mikalas |
//|                            https://www.mql5.com/ru/users/mikalas |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, Mikalas"
#property link      "https://www.mql5.com/ru/users/mikalas"
#property version   "1.00"
//
//--- Основные настройки эксперта
input string  p_expert  = "=== Параметры эксперта ==="; //  
input string  TimeStDay = "14:04:00";                    //Время начала дневной сессии
input string  TimeStEvn = "19:00:00";                    //Время начала вечерней сессии
input int     TimerTime = 500;                           //Период таймера (0,5 сек.)       
input string  p_chart   = "=== Параметры графика ===";  //  
input color   ButtDown  = clrMagenta;                    //Цвет нажатой кнопки
input color   ButtUp    = clrMediumSeaGreen;             //Цвет отжатой кнопки

//--- Переменные
ulong         time_st_day;
ulong         time_st_evn;
//
bool          stop_trading;  
bool          is_tdading_time; 
//
//+------------------------------------------------------------------+
//| Expert Get string time function                                  |
//+------------------------------------------------------------------+
ulong GetStringTime( const string a_string )
{
  int k = 0;
  string s_sec, s_min, s_hour;
  int str_size = StringLen( a_string );
//---
  if ( str_size != 8 ) return( 0 );  
//---  
  for( int i = str_size - 1; i >= 0; i-- )
  {
    ushort let_symbol = StringGetCharacter( a_string, i );
    
    if ( let_symbol == ':')
    {
      k++;
      switch( k )
      {
        case 1: s_sec = StringSubstr( a_string, i + 1, str_size - i - 1 );
                break;
                 
        case 2: s_min = StringSubstr( a_string, i + 1, str_size - i - 4 );
                s_hour = StringSubstr( a_string, 0, i );
                break;
      }
    }
  }  
  ulong t_sec = ulong( StringToInteger( s_sec ) );
  ulong t_min = ulong( StringToInteger( s_min ) ) * 60;
  ulong t_hour = ulong( StringToInteger( s_hour ) ) * 3600;
//---
  if ( k != 2 ) return( 0 ); 
//---    
  return( t_hour + t_min + t_sec );
}
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
//--- Проверка версии терминала
  if ( TerminalInfoInteger( TERMINAL_BUILD ) < 1241 )
  {
    MessageBox( "Билд терминала должен быть 1241 или выше!", "Ошибка", MB_OK | MB_ICONHAND );
    return( INIT_FAILED );
  }
//--- Установка переменных
  time_st_day = GetStringTime( TimeStDay );   //Время начала дневной сессии (целое число)
  time_st_evn = GetStringTime( TimeStEvn );   //Время начала вечерней сессии (целое число)
  stop_trading = true;                        //Советник создаётся в режиме "Стоп торговля"
  is_tdading_time = false;                    //Режим "Не торговое время"              
  
//--- Добавление стакана по инструменту
  if ( !MarketBookAdd( _Symbol ) )
  {
    MessageBox( "Не добавлен стакан фьючерса!", "Ошибка", MB_OK | MB_ICONHAND );
    return( INIT_FAILED );
  }   
  
//--- Создание кнопки старт-стоп
  if( !ObjectCreate( 0, "stop_button", OBJ_BUTTON, 0, 0, 0 ) )
  {
    MessageBox( "Кнопка 'Старт-стоп' не создана!", "Ошибка", MB_OK | MB_ICONHAND );
    return( INIT_FAILED );
  }
  else
  {
    ObjectSetInteger( 0, "stop_button", OBJPROP_CORNER, CORNER_RIGHT_LOWER );
    ObjectSetInteger( 0, "stop_button", OBJPROP_XDISTANCE, 40 );             
    ObjectSetInteger( 0, "stop_button", OBJPROP_YDISTANCE, 18 );
    ObjectSetInteger( 0, "stop_button", OBJPROP_XSIZE, 40 );
    ObjectSetInteger( 0, "stop_button", OBJPROP_YSIZE, 18 );
//---  
    if ( stop_trading )
    {
      ObjectSetInteger( 0, "stop_button", OBJPROP_BGCOLOR, ButtDown );
      ObjectSetInteger( 0, "stop_button", OBJPROP_STATE, true );
      ObjectSetString( 0, "stop_button", OBJPROP_TEXT, "Старт" );
    }
    else
    {
      ObjectSetInteger( 0, "stop_button", OBJPROP_BGCOLOR, ButtUp );
      ObjectSetInteger( 0, "stop_button", OBJPROP_STATE, false );
      ObjectSetString( 0, "stop_button", OBJPROP_TEXT, "Стоп" );
    }  
  }  
//--- Установка таймера
  if ( !EventSetMillisecondTimer(TimerTime) )
  {
    MessageBox( "Таймер не установлен!", "Ошибка", MB_OK | MB_ICONHAND );
    return( INIT_FAILED );
  }
  return( INIT_SUCCEEDED );
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit( const int reason )
{
//--- удаление таймера
  EventKillTimer();
  
//--- Удаление кнопки старт-стоп
  ObjectDelete( 0, "stop_button" ); 
 
//--- Удаление стакана
  MarketBookRelease( _Symbol );   
}
//+------------------------------------------------------------------+
//| Expert Check traiding time function                              |
//+------------------------------------------------------------------+
bool CheckTradingTime( MqlDateTime &tick_time )
{
  TimeTradeServer( tick_time );
  ulong start_value;
//---
  if ( ( tick_time.day_of_week == 0 ) || ( tick_time.day_of_week == 6 ) ) //Проверка на субботу и воскресенье
  {
    return( false );
  }
//---
  if ( ( tick_time.hour >= 0 ) && ( tick_time.hour < 10 ) )              //Проверка на ночное время
  {
    return( false );
  }
  else start_value = 10 * 3600;
// 14 * 3600           = 50400 - 14:00:00
// 18 * 3600 + 45 * 60 = 67500 - 18:45:00
// 23 * 3600 + 50 * 60 = 85800 - 23:50:00
//---
  ulong trade_time = tick_time.hour * 3600 + tick_time.min * 60 + tick_time.sec;  
//---                                                         
  if ( ( ( trade_time >= start_value ) && ( trade_time < 50400 ) ) ||
       ( ( trade_time >= time_st_day ) && ( trade_time < 67500 ) ) ||
       ( ( trade_time >= time_st_evn ) && ( trade_time < 85800 ) ) )
  {
    return( true );
  }
  return( false );
}
//+------------------------------------------------------------------+
//| Expert timer function                                            |
//+------------------------------------------------------------------+
void OnTimer()
{
    MqlDateTime tick_time;
//---  
  if ( CheckTradingTime( tick_time ) )  //таймер с частотой 0,5 сек проверяет торговое время
  {
    is_tdading_time = true;             //Торговое время  
  }
  else
  {
    is_tdading_time = false;           //Не торговое время
  }
}  

//+------------------------------------------------------------------+
//| Expert Chart event function                                      |
//+------------------------------------------------------------------+
void OnChartEvent( const int id, const long& lparam, const double& dparam, const string& sparam )
{
  long b_state;
//---  
  if ( id == CHARTEVENT_OBJECT_CLICK )
  {
    if ( sparam == "stop_button" )
    {
      if ( ObjectGetInteger( 0, "stop_button", OBJPROP_STATE, 0, b_state ) )
      {
        if ( b_state == 1 )
        {
          stop_trading = true;
          ObjectSetInteger( 0, "stop_button", OBJPROP_BGCOLOR, ButtDown );
          ObjectSetString( 0, "stop_button", OBJPROP_TEXT, "Старт" );
        }
        else
        {
          stop_trading = false;
          ObjectSetInteger( 0, "stop_button", OBJPROP_BGCOLOR, ButtUp );
          ObjectSetString( 0, "stop_button", OBJPROP_TEXT, "Стоп" );
        }
      }
    }
  }
  ChartRedraw(ChartID());
} 
//+------------------------------------------------------------------+
//| Expert Book event function                                       |
//+------------------------------------------------------------------+  
void OnBookEvent( const string &a_symbol )
{
  if ( stop_trading ) return;  //Мы запретили торговлю, нажав кнопку Старт-стоп 
 //---  
  if ( a_symbol == _Symbol )  //Поверка, что изменился именно наш стакан
  {
    if ( is_tdading_time )
    {
      //Торговое время, можно торговать
    }
  }
}  
 
Код без комментариев (общая задача), советник без предварительных объяснений, что он делает известно только самому автору, возможно, а уж новичку точно не разобраться для чего он.
 
Alexander:
Код без комментариев (общая задача), советник без предварительных объяснений, что он делает известно только самому автору, возможно, а уж новичку точно не разобраться для чего он.
Эта тема для тех кто знает mql4 и хоть чуток разбирается в mql5, вот они-то при желании разберутся.
 
В советнике не хватает блока проверки исполнения ордеров. Т.к. mql5 только отправляет ордер и не ждет его исполнения.
 
Отсутствие OnTick() и использование исключительно OnBookEvent() это действительно требования фортс. Т.е. для фортс нужно писать только так и никак иначе? Или же это какие-то личные особенности автора темы?
 
Dmitry Fedoseev:
Отсутствие OnTick() и использование исключительно OnBookEvent() это действительно требования фортс. Т.е. для фортс нужно писать только так и никак иначе? Или же это какие-то личные особенности автора темы?
Заглядывать в стакан нужно только если Вы хотите примерно оценить ликвидность рынка (вдруг Вы хотите залить свой лимитник на 100 контрактов?). Хотя - зачем усложнять. Выставляете лимитник и ждёте, а текущие цены (bid, ask, last) можно и через SymbolInfoTick(). А можно и через CopyTicks().
 
Dmitry Fedoseev:
Отсутствие OnTick() и использование исключительно OnBookEvent() это действительно требования фортс. Т.е. для фортс нужно писать только так и никак иначе? Или же это какие-то личные особенности автора темы?
События изменения стакана происходят гораздо чаще событий нового тика, так что если логика строится на использовании стакана - так лучше.
 
Alexey Kozitsyn:
События изменения стакана происходят гораздо чаще событий нового тика, так что если логика строится на использовании стакана - так лучше.
А как ведет себя тестер на обработке события в стакане, поддерживает ли ?  
 
Alexander Antoshkin:
А как ведет себя тестер на обработке события в стакане, поддерживает ли ?  
Не обрабатывает.