ФОРТС: В помощь начинающим

 

Добрый день!

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

ВАЖНО: Чтобы не "растягивать" топик, при возникновении замечаний,

или есть вопросы - создать в этом разделе отдельную тему (здесь отвечать не буду). 

 

Рекомендация

Стандартная библиотека MQL5 "заточена" на рынок ФОРЕКС, поэтому для

разработки экспертов для ФОРТС рекомендую всё писать самим.

 

Часто используемые и полезные функции: 

Функция проверки торговых параметров сервера брокера.

В этой функции необходимо проверять те параметры, которые

Вы будете использовать в своём советнике. Вот пример: 

(использовать ТОЛЬКО в OnInit() )

//+------------------------------------------------------------------+
//| Expert Check Market Parameters function                          |
//+------------------------------------------------------------------+
bool CheckMarketParam( const string a_symbol )
{
//--- Check for full mode
  ENUM_SYMBOL_TRADE_MODE trade_mode = ENUM_SYMBOL_TRADE_MODE( SymbolInfoInteger( a_symbol, SYMBOL_TRADE_MODE ) );
  
  if ( trade_mode != SYMBOL_TRADE_MODE_FULL )
  {
    MessageBox( "Символ " + a_symbol + " не поддерживает полную торговлю!", "Ошибка", MB_OK | MB_ICONHAND );
    return( false );
  }
//--- Check trade execution mode
  ENUM_SYMBOL_TRADE_EXECUTION market_info = ENUM_SYMBOL_TRADE_EXECUTION( SymbolInfoInteger( a_symbol, SYMBOL_TRADE_EXEMODE ) );
    
  if ( market_info != SYMBOL_TRADE_EXECUTION_EXCHANGE )
  {
    MessageBox( "Символ " + a_symbol + " не поддерживает TRADE EXECUTION EXCHANGE режим!", "Ошибка", MB_OK | MB_ICONHAND );
    return( false );
  }
//--- Check orders mode
  int order_mode = int( SymbolInfoInteger( a_symbol, SYMBOL_ORDER_MODE ) );
  
  if ( ( SYMBOL_ORDER_MARKET & order_mode )!= SYMBOL_ORDER_MARKET )
  {
    MessageBox( "Символ " + a_symbol + " не поддерживает Market Execution режим установки ордеров!", "Ошибка", MB_OK | MB_ICONHAND );
    return( false );
  }
  
  if ( ( SYMBOL_ORDER_LIMIT & order_mode )!= SYMBOL_ORDER_LIMIT )
  {
    MessageBox( "Символ " + a_symbol + " не поддерживает Limit режим установки ордеров!", "Ошибка", MB_OK | MB_ICONHAND );
    return( false );
  }
  
  if ( ( SYMBOL_ORDER_STOP_LIMIT & order_mode ) != SYMBOL_ORDER_STOP_LIMIT )
  {
    MessageBox( "Символ " + a_symbol + " не поддерживает Stop Limit режим установки ордеров!", "Ошибка", MB_OK | MB_ICONHAND );
    return( false );
  }
  
  if ( ( SYMBOL_ORDER_STOP & order_mode )!= SYMBOL_ORDER_STOP )
  {
    MessageBox( "Символ " + a_symbol + " не поддерживает Stop режим установки ордеров!", "Ошибка", MB_OK | MB_ICONHAND );
    return( false );
  }
  
  if ( ( SYMBOL_ORDER_SL & order_mode) != SYMBOL_ORDER_SL )
  {
    MessageBox( "Символ " + a_symbol + " не поддерживает Stop Loss режим установки ордеров!", "Ошибка", MB_OK | MB_ICONHAND );
    return( false );
  }
  
  if ( ( SYMBOL_ORDER_TP & order_mode) != SYMBOL_ORDER_TP )
  {
    MessageBox( "Символ " + a_symbol + " не поддерживает Take Profit режим установки ордеров!", "Ошибка", MB_OK | MB_ICONHAND );
    return( false );
  }
//---Filing mode
  int filling_mode = int( SymbolInfoInteger( a_symbol, SYMBOL_FILLING_MODE ) );
  
  if ( ( SYMBOL_FILLING_IOC & filling_mode ) != SYMBOL_FILLING_IOC )
  {
    MessageBox( "Символ " + a_symbol + " не поддерживает filling IOC режим исполнения ордеров!", "Ошибка", MB_OK | MB_ICONHAND );
    return( false );
  }
  
  if ( ( SYMBOL_FILLING_FOK & filling_mode ) != SYMBOL_FILLING_FOK )
  {
    MessageBox( "Символ " + a_symbol + " не поддерживает filling FOK режим исполнения ордеров!", "Ошибка", MB_OK | MB_ICONHAND );
    return( false );
  }      
//---Ckeck expiration
  int symbol_exp_type = int( SymbolInfoInteger( a_symbol, SYMBOL_EXPIRATION_MODE ) );
//---  
  if ( ( symbol_exp_type & SYMBOL_EXPIRATION_DAY ) != SYMBOL_EXPIRATION_DAY )
  {
    MessageBox( "Символ " + a_symbol + " не поддерживает экспирацию DAY!", "Ошибка", MB_OK | MB_ICONHAND );
    return( false );
  }
  if ( ( symbol_exp_type & SYMBOL_EXPIRATION_SPECIFIED_DAY ) != SYMBOL_EXPIRATION_SPECIFIED_DAY )
  {
    MessageBox( "Символ " + a_symbol + " не поддерживает экспирацию SPECIFIED DAY!", "Ошибка", MB_OK | MB_ICONHAND );
    return( false );
  }
  return( true );
} 

Пример использования:

int OnInit()
{
  if ( !CheckMarketParam( _Symbol ) ) return( INIT_FAILED );
  return( INIT_SUCCEEDED );
}

 

Получение количества дней, оставшихся до экспирации инструмента:

#define YEAR          365

int GetExpiration( const string aSymbol )
{
  MqlDateTime ExpData, CurData;
    
  datetime exp_time = datetime( SymbolInfoInteger( aSymbol, SYMBOL_EXPIRATION_TIME ) );
      
  TimeToStruct( exp_time, ExpData );
  TimeTradeServer( CurData );
      
  if ( ExpData.year != CurData.year )
  {
    return( YEAR * ( ExpData.year - CurData.year ) - CurData.day_of_year + ExpData.day_of_year );
  }
  else
  {
    return( ExpData.day_of_year - CurData.day_of_year );
  }
}

 

Получение "чистой" цены позиции, без учёта клирингов:

//+------------------------------------------------------------------+
//| Expert Get position price function                               |
//+------------------------------------------------------------------+
double GetPositionPrice( const string aSymbol )
{
  double price_in = 0;
  double volume_in = 0;
  double price_out = 0;
  double volume_out = 0;
  double price = 0;
  double volume = 0;
  
  if ( PositionSelect( aSymbol ) )
  {
    ulong pos_id = ulong( PositionGetInteger( POSITION_IDENTIFIER ) );
    
    if ( pos_id > 0 )
    {
      if ( HistorySelectByPosition( pos_id ) )
      {
        int deals = HistoryDealsTotal();
      
        for( int i = 0; i < deals; i++ )
        {
          ulong deal_ticket = HistoryDealGetTicket( i );
          ulong order_ticket = ulong( HistoryDealGetInteger( deal_ticket, DEAL_ORDER ) );
        
          if ( order_ticket > 0 )
          {
            ENUM_DEAL_ENTRY deal_entry = ENUM_DEAL_ENTRY( HistoryDealGetInteger( deal_ticket, DEAL_ENTRY ) );
              
            if ( deal_entry == DEAL_ENTRY_IN )
            {
              price = HistoryDealGetDouble( deal_ticket, DEAL_PRICE );
              volume = HistoryDealGetDouble( deal_ticket, DEAL_VOLUME );
                                
              price_in += price * volume;
              volume_in += volume;  
            }
            else
            if ( deal_entry == DEAL_ENTRY_OUT )
            {
              price = HistoryDealGetDouble( deal_ticket, DEAL_PRICE );
              volume = HistoryDealGetDouble( deal_ticket, DEAL_VOLUME );
                                
              price_out += price * volume;
              volume_out += volume;  
            }
          }
        }
        if ( volume_out > 0 )
        {
          if ( volume_in > 0 ) { price_in = price_in / volume_in; } else return( 0 );
          price_out = price_out / volume_out;
          price = ( price_in - price_out ) * ( volume_in - volume_out );
        }
        else
        {
          if ( volume_in > 0 ) { price = price_in / volume_in; } else return( 0 );
        }
        return( NormalizeDouble( price, _Digits ) );
      }
      else
      {
        Print( "GetPositionPrice: Невозможно получить историю позиции по символу ", aSymbol );
      }
    }
    else
    {
      Print( "GetPositionPrice: Невозможно определить идентификатор позиции по символу ", aSymbol );
    }
  }
  return( 0 );
} 

 

Создание глобальной переменной терминала для подсчёта транзакций:

( Использовать ТОЛЬКО в OnInit() ) 

  if ( !GlobalVariableCheck( "trans_count" ) )
  {
    datetime a_time = GlobalVariableSet( "trans_count", 0 );
    
    if ( ulong( a_time ) == 0 )
    {
      MessageBox( "Глобальная переменная терминала 'Счётчик транзакций' не создана!", "Ошибка", MB_OK | MB_ICONHAND );
      return( INIT_FAILED );
    }
  }

 

 Защищённая запись в глобальную переменную терминала ( счётчик транзакций ):

//+------------------------------------------------------------------+
//| Expert Set transaction count function                            |
//+------------------------------------------------------------------+
void SetTransCount( const bool up_down )
{
  double tr_count;
  uint i = 0;
  do
  {
    i++;
    if ( GlobalVariableGet( "trans_count", tr_count ) )
    {
      if ( up_down )
      {
        if ( GlobalVariableSetOnCondition( "trans_count", tr_count + 1, tr_count ) )
        {
          i = 100;
        }
      }
      else
      {
        if ( GlobalVariableSetOnCondition( "trans_count", tr_count - 1, tr_count ) )
        {
          i = 100;
        }
      }
    }
  }  
  while( i < 100 );
}

 Если параметр up_down = true, то увеличиваем глобальную переменную терминала,

и наоборот. 

 

Проверка денежных средств с автоматическим понижением объёма, при нехватке денег:

//| Expert Check money function                                      |
//+------------------------------------------------------------------+ 
bool CheckMoney( long &volume )
{
  if ( volume <= 0 ) return( false );
//---
  double symbol_go = SymbolInfoDouble( _Symbol, SYMBOL_MARGIN_INITIAL );
  double free_margin = ( AccountInfoDouble( ACCOUNT_FREEMARGIN ) / 100 ) * 90; //90% от свободных средств
  double real_go = NormalizeDouble( symbol_go * volume, 2 );
//---     
  if ( real_go <= free_margin )
  {
    return( true );
  }
  else
  {
    while ( real_go > free_margin )
    {
      volume--;
      
      if ( volume <= 0 )
      {
        Print( "CheckMoney: Не хватает средств!" );
        return( false );
      }  
      real_go = NormalizeDouble( symbol_go * volume, 2 );
    }
    return( true );
  }
   Print( "CheckMoney: Не хватает средств!" ); 
  return( false );
}

 

Установка рыночного / лимитного ордера командой OrderSend()

если price = ''0" - ордер рыночный:

//+------------------------------------------------------------------+
//| Expert set order function                                        |
//+------------------------------------------------------------------+
void SetOrder( const string aSymbol, ulong &ticket, const double price, const double volume, const bool buy_sell )
{
  MqlTradeRequest request = {0};
  MqlTradeResult  result  = {0};
  ticket = 0;
   
//--- Fill structure
  request.magic = 1234567890;
  request.symbol = aSymbol;
  request.volume = volume; 
  request.type_filling = ORDER_FILLING_IOC;
  request.type_time = ORDER_TIME_DAY;
    
  if ( price == 0 )
  {
    request.action = TRADE_ACTION_DEAL;
    request.comment = "Рыночный ордер...";
//---    
    if ( buy_sell )
    {
      request.type = ORDER_TYPE_BUY;
    }
    else
    {
      request.type = ORDER_TYPE_SELL;
    }
  }
  else
  { 
    request.action = TRADE_ACTION_PENDING;
    request.price = price;
    request.comment = "Лимитный ордер...";
//---    
    if (buy_sell)
    {
      request.type = ORDER_TYPE_BUY_LIMIT;
    }
    else
    {
      request.type = ORDER_TYPE_SELL_LIMIT;
    }   
  }  
//--- Send order
  if ( OrderSend( request, result ) )
  {
    if ( result.retcode == TRADE_RETCODE_PLACED ) 
    {
      ticket = result.order;
    }
    else
    {
      Print( "SeOrder: Установка ордера не выполнена! ", aSymbol );
    }
  }
  else
  {
    Print( "SeOrder: Ордер не отправлен! ", aSymbol );
  }
}

 

 Удаление ордера командой OrderSend()

void RemoveOrder( ulong& ord_ticket )
{
  if ( ord_ticket >  0 )
  {
    if ( OrderSelect( ord_ticket ) )
    {
      MqlTradeRequest request = {0};
      MqlTradeResult  result  = {0};
//---  
      request.action = TRADE_ACTION_REMOVE;
      request.order  = ord_ticket;
//---  
      if ( OrderSend( request, result ) )
      {
        if ( result.retcode == TRADE_RETCODE_PLACED )
        { 
          ord_ticket = result.order;
        }
        else
        {
           Print( "RemoveOrder: Удаление старого ордера не выполнено! Билет = ", ord_ticket );
        }  
      }
      else
      {
        Print( "RemoveOrder: Ордер не отослан! Билет = ", ord_ticket );
      }
    }
  }
}

 

 Установка отложенного ордера командой OrderSend()

//+------------------------------------------------------------------+
//| Place order                                                      |
//+------------------------------------------------------------------+
void PlaceOrder( const string aSymbol, ulong& ticket, const double price, const double volume, const bool buy_sell )
{
  MqlTradeRequest request = {0};
  MqlTradeResult  result  = {0};
  ticket = 0;
     
//--- Fill structure
  request.action = TRADE_ACTION_PENDING;
  request.magic  = 1234567890;
  request.symbol = aSymbol;
  request.volume = volume;
  request.price  = price;
    
  if ( buy_sell )
  {
    request.type = ORDER_TYPE_BUY_LIMIT;
  }
  else
  {
    request.type = ORDER_TYPE_SELL_LIMIT;
  } 
  request.comment = "Отложенный ордер...";      
  request.type_filling = ORDER_FILLING_RETURN;
  request.type_time = ORDER_TIME_DAY;
  
//--- Send order
  if ( OrderSend( request, result ) )
  {
    if ( result.retcode == TRADE_RETCODE_PLACED ) 
    {
      ticket = result.order;
    }
    else
    {
      Print( "PlaceOrder: Ордер не установлен!" );
    }
  }
  else
  {
    Print( "PlaceOrder: Ордер не отослан! " );
  }
}

 

 Модификация отложенного ордера  командой OrderSend() 

//+------------------------------------------------------------------+
// Modify order                                                      |
//+------------------------------------------------------------------+
void ModifyOrder( const string aSymbol, const double price, ulong& ticket )
{
  if ( ticket > 0 )
  {
    if ( OrderSelect( ticket ) )
    {
      MqlTradeRequest request = {0};
      MqlTradeResult  result  = {0};
   
      request.action = TRADE_ACTION_MODIFY;
      request.symbol = aSymbol;
      request.order  = ticket;
      request.price  = price;
      request.type_time = ORDER_TIME_DAY;
  
      if ( OrderSend( request, result ) )
      {
        if ( result.retcode == TRADE_RETCODE_PLACED ) 
        {
          ticket = result.order;
        }
        else
        {
          Print( "ModifyOrder: Ордер не модифицирован! Билет = ", ticket );
        }
      }
      else
      {
        Print( "ModifyOrder: Ордер не отослан! Билет ", ticket );
      }
    }
  }
}

 

Установка отложенного ордера командой OrderSendAsync()

При использовании этой команды, билет получаем не в результате этой

функции, а в функции OnTradeTransaction(). В функции  OrderSendAsync() мы

получаем номер запроса на установку ордера:

 

uint req_id;
ulong order_ticket = 0;
void PlaceAsync( const string a_symbol, uint& req_id, const double price, const double volume, const bool buy_sell )
{
  MqlTradeRequest request = {0};
  MqlTradeResult  result  = {0};
  req_id = 0;
     
//--- Fill structure
  request.action = TRADE_ACTION_PENDING;
  request.magic  = 1234567890;
  request.symbol = a_symbol;
  request.volume = volume;
  request.price  = price;
    
  if ( buy_sell )
  {
    request.type = ORDER_TYPE_BUY_LIMIT;
  }
  else
  {
    request.type = ORDER_TYPE_SELL_LIMIT;
  } 
  request.comment = "Отложенный ордер...";      
  request.type_filling = ORDER_FILLING_RETURN;
  request.type_time = ORDER_TIME_DAY;
  
//--- Send order
  if ( OrderSendAsync( request, result ) )
  {
    if ( result.retcode == TRADE_RETCODE_PLACED ) 
    {
      req_id = result.request_id;
    }
    else
    {
      Print( "PlaceAsync: Ордер не установлен! ", a_symbol );
    }
  }
  else
  {
    Print( "PlaceAsync: Ордер на отослан! ", a_symbol );
  }
}

 Получение билета по номеру запроса:

void OnTradeTransaction( const MqlTradeTransaction &trans,
                         const MqlTradeRequest &request,
                         const MqlTradeResult &result )
{
  switch( trans.type )
  {
    case TRADE_TRANSACTION_REQUEST: if ( trans.order_state == ORDER_STATE_STARTED )
                                    {
                                      if ( ( req_id != 0 ) && ( result.request_id == req_id ) )
                                      {
                                        if ( result.retcode == TRADE_RETCODE_PLACED )
                                        {
                                          if ( result.order > 0 )
                                          {
                                            order_ticket = result.order;
                                          }
                                          else
                                          {
                                            Print( "OnTradeTransaction: Не получен билет! Запрос = ", req_id );
                                          }
                                        }
                                      }
                                    }  
                                    break;
                                    
  }
}

 

Обработка ошибок ( кодов возврата) функций OrderSend() и OrderSendAsync()

в реализацию отправки ордера добавляется функция CheckError() Пример:

void ModifyOrder( const string aSymbol, const double price, ulong& ticket )
{
  if ( ticket > 0 )
  {
    if ( OrderSelect( ticket ) )
    {
      MqlTradeRequest request = {0};
      MqlTradeResult  result  = {0};
   
      request.action = TRADE_ACTION_MODIFY;
      request.symbol = aSymbol;
      request.order  = ticket;
      request.price  = price;
      request.type_time = ORDER_TIME_DAY;
  
      if ( OrderSend( request, result ) )
      {
        if ( result.retcode == TRADE_RETCODE_PLACED ) 
        {
          ticket = result.order;
        }
        else
        {
          CheckError( result.retcode, "ModifyOrder: Ордер не модифицирован! Билет = ", ticket );
        }
      }
      else
      {
        CheckError( result.retcode, "ModifyOrder: Ордер не отослан! Билет ", ticket );
      }
    }
  }
}

 Сама функция CheckError() (в примере не все коды возврата)

void CheckError( const uint ret_code, const string err_msg, const ulong a_ticket )
{
  switch( ret_code )
  {
    case TRADE_RETCODE_TRADE_DISABLED:
                                           break;
    case TRADE_RETCODE_MARKET_CLOSED:
                                           break;
    case TRADE_RETCODE_NO_MONEY:
                                           break; 
    case TRADE_RETCODE_PRICE_OFF:
                                           break;   
    case TRADE_RETCODE_TOO_MANY_REQUESTS:
                                           break;
    case TRADE_RETCODE_SERVER_DISABLES_AT: 
                                           break;
    case TRADE_RETCODE_CLIENT_DISABLES_AT: 
                                           break;
    case TRADE_RETCODE_INVALID_PRICE:      
                                           break;
    case TRADE_RETCODE_INVALID:
                                           break;                                                       
                
    default: Print( err_msg, GetRetCode( ret_code ), "; Билет = ", a_ticket );  
             break;            
  }
}

См. продолжение 


 Особенности:

Покупая более ОДНОГО контракта ЛИМИТНЫМ ордером с исполнением ORDER_FILLING_IOC,

ордер в истории может храниться как ORDER_STATE_CANCELED, если ордер залился первым объёмом,

а вторым не успел.

Пример:

 

Покупая 3 контракта ЛИМИТНЫМ ордером с исполнением ORDER_FILLING_IOC,

складывается следующая ситуация:

1. Если мы купили все три контракта, то ордер в истории имеет состояние = ORDER_STATE_FILLED

2. Если мы ничего не купили, то в истории состояние =  ORDER_STATE_CANCELED

3. Если мы купили первых два контракта (28449), а 1 контракт не купили (28450), то в истории состояние =  ORDER_STATE_CANCELED

4. Если мы не купили первых два контракта (28449), а купили 1 (28450), то в истории состояние = ORDER_STATE_PARTIAL 

======= Конец примера =================== 

Количество не эффективных транзакций ( не эффективной транзакцией считается транзакция не приведшая к сделке.

Установка, модификация и удаление ордера) на срочном рынке ФОРТС  ограничено 2000 за полную торговую сессию

с 19-00 текущего дня до 18-45 следующего дня. За превышение - штраф Биржи

http://moex.com/n8725

 

Баги:

1. Если на сервере МТ5 брокера или на бирже происходит сбой, то на команду

удалить(модифицировать) СУЩЕСТВУЮЩИЙ ордер сервер возвращает:

ошибку 10013 =  TRADE_RETCODE_INVALID = Неправильный запрос ( Invalid request )

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

(это не опечатка, а именно такое сообщение) 

В документации какого кода возврата торгового сервера - нет! 

 

Что с того, что какой-то режим не поддерживается? С чего вдруг от этого запрещать себе торговлю?

Особенно если "не поддерживает Stop Limit режим установки ордеров"?  Вот это беда вообще невероятная, не дающая возможности торговать.

© РАЗРУХА В ГОЛОВАХ 

 

В самом начале написано:

ВАЖНО: Чтобы не "растягивать" топик, при возникновении замечаний,

или есть вопросы - создать в этом разделе отдельную тему (здесь отвечать не буду).  

 P/S Для особо "одарённых" :

В этой функции необходимо проверять те параметры, которые

Вы будете использовать в своём советнике. Вот пример: 

....................... 

 

Продолжение:

Часто используемые и полезные функции:

Сама функция CheckError() (в примере не все коды возврата)

......................................................................... 

Расшифровка кодов возврата:

string GetRetCode( const uint code )
{
  string retcode;
  
  switch( code )
  {
    case TRADE_RETCODE_REQUOTE: retcode = "Реквота";
         break;
    case TRADE_RETCODE_REJECT: retcode = "Запрос отвергнут";
         break;
    case TRADE_RETCODE_CANCEL: retcode = "Запрос отменен трейдером";
         break;
    case TRADE_RETCODE_PLACED: retcode = "Ордер размещен";
         break;
    case TRADE_RETCODE_DONE: retcode = "Заявка выполнена";
         break;
    case TRADE_RETCODE_DONE_PARTIAL: retcode = "Заявка выполнена частично";
         break;
    case TRADE_RETCODE_ERROR: retcode = "Ошибка обработки запроса";
         break;
    case TRADE_RETCODE_TIMEOUT: retcode = "Запрос отменен по истечению времени";
         break;
    case TRADE_RETCODE_INVALID: retcode = "Неправильный запрос";
         break;
    case TRADE_RETCODE_INVALID_VOLUME: retcode = "Неправильный объем в запросе";
         break;
    case TRADE_RETCODE_INVALID_PRICE: retcode = "Неправильная цена в запросе";
         break;
    case TRADE_RETCODE_INVALID_STOPS: retcode = "Неправильные стопы в запросе";
         break;
    case TRADE_RETCODE_TRADE_DISABLED: retcode = "Торговля запрещена";
         break;
    case TRADE_RETCODE_MARKET_CLOSED: retcode = "Рынок закрыт";
         break;
    case TRADE_RETCODE_NO_MONEY: retcode = "Нет достаточных денежных средств для выполнения запроса";
         break;
    case TRADE_RETCODE_PRICE_CHANGED: retcode = "Цены изменились";
         break;
    case TRADE_RETCODE_PRICE_OFF: retcode = "Отсутствуют котировки для обработки запроса";
         break;
    case TRADE_RETCODE_INVALID_EXPIRATION: retcode = "Неверная дата истечения ордера в запросе";
         break;
    case TRADE_RETCODE_ORDER_CHANGED: retcode = "Состояние ордера изменилось";
         break;
    case TRADE_RETCODE_TOO_MANY_REQUESTS: retcode = "Слишком частые запросы";
         break;
    case TRADE_RETCODE_NO_CHANGES: retcode = "В запросе нет изменений";
         break;
    case TRADE_RETCODE_SERVER_DISABLES_AT: retcode = "Автотрейдинг запрещен сервером";
         break;
    case TRADE_RETCODE_CLIENT_DISABLES_AT: retcode = "Автотрейдинг запрещен клиентским терминалом";
         break;
    case TRADE_RETCODE_LOCKED: retcode = "Запрос заблокирован для обработки";
         break;
    case TRADE_RETCODE_FROZEN: retcode = "Ордер или позиция заморожены";
         break;
    case TRADE_RETCODE_INVALID_FILL: retcode = "Указан неподдерживаемый тип исполнения ордера по остатку";
         break;
    case TRADE_RETCODE_CONNECTION: retcode = "Нет соединения с торговым сервером";
         break;
    case TRADE_RETCODE_ONLY_REAL: retcode = "Операция разрешена только для реальных счетов";
         break;
    case TRADE_RETCODE_LIMIT_ORDERS: retcode = "Достигнут лимит на количество отложенных ордеров";
         break;
    case TRADE_RETCODE_LIMIT_VOLUME: retcode = "Достигнут лимит на объем ордеров и позиций для данного символа";
         break;
    case TRADE_RETCODE_INVALID_ORDER: retcode = "Неверный или запрещённый тип ордера";
         break;
    case TRADE_RETCODE_POSITION_CLOSED: retcode = "Позиция с указанным POSITION_IDENTIFIER уже закрыта";
         break;
    default: retcode = "Нет кода возврата.";  
         break; 
  }
  return( retcode );
}

  

Рекомендация

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

лучше воспользоваться событием BookEvent

 

Примеры:

Добавление стакана:

(Использовать ТОЛЬКО в OnInit() ) 

  if ( !MarketBookAdd( _Symbol ) )
  {
    MessageBox( "Не добавлен стакан фьючерса " + _Symbol + "!", "Ошибка", MB_OK | MB_ICONHAND );
    return( INIT_FAILED );
  } 

Удаление подписки на стакан:

void OnDeinit( const int reason )
{
  MarketBookRelease( _Symbol );
}

 

 Получение лучшего ASK и BID и их объёмов из стакана цен:

double sell_price, buy_price;
long sell_volume, buy_volume;

//+------------------------------------------------------------------+
//| Expert Get Stakan values function                                |
//+------------------------------------------------------------------+ 
bool GetStakanValues( const string aSymbol, double &sell_price,
                      double &buy_price, long &sell_volume, long &buy_volume )
{
  MqlBookInfo book_price[];
  buy_price  = 0;
  sell_price = DBL_MAX;
  buy_volume = 0;
  sell_volume = 0;
  
//--- Get stakan
  if ( MarketBookGet( aSymbol, book_price ) )//getBook )
  {
    int size = ArraySize( book_price );
//---    
    if ( size > 0 )
    {
      double a_min_price = SymbolInfoDouble( aSymbol, SYMBOL_SESSION_PRICE_LIMIT_MIN );
      double a_max_price = SymbolInfoDouble( aSymbol, SYMBOL_SESSION_PRICE_LIMIT_MAX );
//---     
      for( int i = 0; i < size; i++ )
      {
        if ( book_price[i].type == BOOK_TYPE_SELL )
        {
          if ( book_price[i].price < sell_price )
          {
            sell_price = book_price[i].price;
            sell_volume = book_price[i].volume;  
          }
        }
        else
        if ( book_price[i].type == BOOK_TYPE_BUY ) //First buy - exit
        {
          buy_price = book_price[i].price;
          buy_volume = book_price[i].volume;
          break;
        }
      }
      if ( ( buy_price <= a_max_price ) && ( buy_price >= a_min_price ) &&
           ( sell_price <= a_max_price ) && ( sell_price >= a_min_price ) )
      {
        if ( sell_price == DBL_MAX ) sell_price = 0;
//---        
        if ( ( sell_price > 0 ) && ( buy_price > 0 ) )
        {
          return( true );
        }  
      }
    }
  }
//---
  if ( sell_price == DBL_MAX ) sell_price = 0;
//---   
  return( false); 
}

 Вызов функции:

Проверка if ( a_symbol == _Symbol ) ОБЯЗАТЕЛЬНА, она гарантирует, что изменился именно Ваш стакан цен. 

//+------------------------------------------------------------------+
//| Expert On Book event function                                    |
//+------------------------------------------------------------------+  
void OnBookEvent( const string &a_symbol )
{
  if ( a_symbol == _Symbol )
  {
    if ( GetStakanValues( _Symbol, sell_price, buy_price, sell_volume, buy_volume ) )
    {
      //you code
    }
  }
}
 

СПАСИБО!!!)

 

Особенности:

Формулы расчёта и начисление баллов за неэффектвные и ошибочные

транзакции во вложении. 

P/S Достаточно часто изменяются и правила и баллы :( 

Файлы:
 

Часто используемые и полезные функции: 

Функция SetStDayTime() возвращает время начала торгового дня(на момент запроса).

Функция GetExgangeFee() возвращает комиссию биржи и кол-во сделок за торговый день (на момент запроса):

//+------------------------------------------------------------------+
//|                                                       Tr_fee.mq5 |
//|                                          Copyright 2015, Mikalas |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Mikalas"
#property link      "https://www.mql5.com"
#property version   "1.00"
//
input long   TrPoint   = 1;              //Балл за транзакцию
input long   DealPoint = 40;             //Балл за сделку
//
datetime start_day_time;
//
//+------------------------------------------------------------------+
//| Expert Set start day time function                               |
//+------------------------------------------------------------------+
datetime SetStDayTime()
{
  MqlDateTime  dt_str; 
  TimeTradeServer( dt_str );
//---
  if ( ( dt_str.day_of_week == 0 ) || ( dt_str.day_of_week == 6 ) ) return( datetime( 0 ) );  
//---
  string time_str = IntegerToString( dt_str.year ) + "." + IntegerToString( dt_str.mon ) +
                    "." + IntegerToString( dt_str.day ) + " 19:00:00";
  ulong cur_day = ulong( StringToTime( time_str ) );                     

  if ( ( dt_str.hour >= 19 ) && ( dt_str.hour <= 23 ) )
  {
    return( StringToTime( time_str ) );
  }
  else
  {
    ulong one_day = 24 * 60 * 60;
//---      
    if ( dt_str.day_of_week == 1 )
    {
      cur_day -= one_day * 3;
    }
    else
    {
      cur_day -= one_day;
    }
    return( datetime( cur_day ) );
  }  
  return( datetime( 0 ) );
}
//+------------------------------------------------------------------+
//| Expert calc deals fee function                                   |
//+------------------------------------------------------------------+
double GetExgangeFee( const datetime start_time, long& deals )
{
  double all_fee = 0.0;
  ulong deal_ticket;
  deals = 0;
//---  
  if ( HistorySelect( start_time, TimeTradeServer() ) )
  {
    int deals_total = HistoryDealsTotal();
//---   
    if ( deals_total > 0 )
    {
      for ( uint i = 0; i < uint( deals_total ); i++ )
      {
        deal_ticket = HistoryDealGetTicket( i );
//---        
        if ( deal_ticket > 0 )
        {
          ulong order_ticket = ulong( HistoryDealGetInteger( deal_ticket, DEAL_ORDER ) );
          
          if ( order_ticket > 0 )
          {
            deals++;
            all_fee += HistoryDealGetDouble( deal_ticket, DEAL_COMMISSION );
          }  
        }
      }
      return( MathAbs( all_fee ) );
    }  
  }
  return( 0 );
}
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
  long a_deals;
  start_day_time = SetStDayTime();
//---  
  if ( ulong( start_day_time ) == 0 )
  {
    MessageBox( "Не установлено время начала торгового дня!", "Ошибка", MB_OK | MB_ICONHAND );
    return( INIT_FAILED );
  } 
  Print( "Exgange Fee = ", GetExgangeFee( start_day_time, a_deals ), "; Deals = ", a_deals );
  return( INIT_SUCCEEDED );
}
 
Михаил:

Часто используемые и полезные функции: 

Функция SetStDayTime() возвращает время начала торгового дня(на момент запроса).

Функция GetExgangeFee() возвращает комиссию биржи и кол-во сделок за торговый день (на момент запроса):

Ну прям беспрецендентный претендент на звание "Индусский Кодер - 2015".

SetStDayTime() решается двумя строчками. Но вам конечно не надо...

 

Михаил, благодарю за ваши функции!

Изобретение мною некоторых велосипедов отменяется )

 
Михаил:

Очень надо.

И как же?

Надо работать с числовым представлением времени.

datetime a=TimeTradeServer(); 

Время начала дня:

datetime r=(a/86400)*86400

Время в 19:00 сегодня:

datetime r=(a/86400)*86400+19*3600;

Если время в 19:00 сегодня больше текущего, значит нужны вчерашние 19:00:

if(r>a)r-=86400;

Тут, если надо пропустить выходные, проверяем день недели, если воскресенье,  вычитаем 86400*2, если суббота, вычитаем 86400 (чтобы получить пятницу).

Как-то так.  

Потом, для отображения, если надо, переводим в строку:  

TimeToStr(r)
 
Михаил:

А высокосный год?

А теперь, воплотите Ваши мысли в конкретный код.

Перепешите мою функцию по своему, и как Вы говорили в ДВЕ строчки! 

А что високосный год? Все будет нормально.

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

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