ФОРТС структура стакана цен на "планке"

 

Коллеги,

как выглядит массив стакана цен на "планке"? У кого то есть практический опыт?

Документация по MQL5: Константы, перечисления и структуры / Торговые константы / Виды заявок в стакане цен
Документация по MQL5: Константы, перечисления и структуры / Торговые константы / Виды заявок в стакане цен
  • www.mql5.com
Для биржевых инструментов доступно окно "Стакан цен", в котором можно посмотреть текущие заявки на покупку и продажу. Для каждой заявки указано желаемое направление торговой операции, требуемый объем и запрашиваемая цена. Для получения информации...
 
Dmi3:

Коллеги,

как выглядит массив стакана цен на "планке"? У кого то есть практический опыт?

Что Вы имеете ввиду на "планке"?

Стакан на ФОРТС агрегирован, т.е цены расположены сверху вниз от большего к меньшему (если смотреть на стакан в терминале).

Глубину стакана (сколько ask и bid) устанавливает брокер и в Открывашке и в БКС по не более 20 записей для ask и bid (максимально может быть по 50 записей QUIK).

В структуре MqlBookInfo[0] - располагается самый большой ask (при его наличии)

//+------------------------------------------------------------------+
//|                                                    Book_test.mq5 |
//|                                      Copyright 2020 prostotrader |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020 prostotrader"
#property link      "https://www.mql5.com"
#property version   "1.00"
bool is_book = false;
MqlBookInfo book_price[];
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Add books
   is_book = MarketBookAdd(Symbol());
   if(is_book = true)
   {
     Print(__FUNCTION__, ": Подписка на стакан добавлена. Символ ", Symbol());
   }
   else
   {
     Print(__FUNCTION__, ": Подписка на стакан не добавлена. Символ ", Symbol());
     return(INIT_FAILED);
   }  
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
    if(is_book = true) MarketBookRelease(Symbol());
    Print(__FUNCTION__, ": Подписка на стакан удалена. Символ ", Symbol());
  }

//+------------------------------------------------------------------+
//| BookEvent function                                               |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
  {
   if(symbol == Symbol()) //Проверка ОБЯЗАТЕЛЬНА!
   {
     if(MarketBookGet(Symbol(), book_price) == true)//getBook
     {
       int size = ArraySize(book_price);
       if(size > 0)
       {
         for(int i = 0; i < size; i++)
         {
           if(book_price[i].type == BOOK_TYPE_SELL) 
           {
             //Get book sell data
           }
           else
           if(book_price[i].type == BOOK_TYPE_BUY) 
           {
             //Get book buy data
           }
         }
       }
     }  
    }
  }
//+------------------------------------------------------------------+

Добавлено

Процедуру OnBookEvent() целесообразно использовать, если Вам необходимо получать не только лучший ask и bid

Документация по MQL5: Константы, перечисления и структуры / Структуры данных / Структура стакана цен
Документация по MQL5: Константы, перечисления и структуры / Структуры данных / Структура стакана цен
  • www.mql5.com
Структура MqlBookInfo является предопределенной, поэтому ее объявление и описание не требуется. Чтобы использовать структуру, достаточно объявить переменную данного типа.
 
А нет-ли возможности получать не полный стакан, а только 3 аска и 3 бида, например. В документации я не нашёл, да и не очень старательно искал.
 
prostotrader:

Что Вы имеете ввиду на "планке"?

Стакан на ФОРТС агрегирован, т.е цены расположены сверху вниз от большего к меньшему (если смотреть на стакан в терминале).

Глубину стакана (сколько ask и bid) устанавливает брокер и в Открывашке и в БКС по не более 20 записей для ask и bid (максимально может быть по 50 записей QUIK).

В структуре MqlBookInfo[0] - располагается самый большой ask (при его наличии)

Добавлено

Процедуру OnBookEvent() целесообразно использовать, если Вам необходимо получать не только лучший ask и bid

Как устроен стакан я знаю.

Еще раз вопрос:

Что происходит в массиве из 40 элементов при отсутствии, например, предложения?

- Первые 20 элементов будут содержать нули?

- Первые 20 элементов будут содержать информацию о bid'ах?

- Весь массив будет состоять не из 40, а из 20 элементов, которые будут  содержать только bid'ы?

Интересует только практический опыт. Как это должно быть теоретически я представляю, хочется подтверждений.

 
Alexey Viktorov:
А нет-ли возможности получать не полный стакан, а только 3 аска и 3 бида, например. В документации я не нашёл, да и не очень старательно искал.

А зачем? Вы получаете целиком массив, а потом делаете с ним все, что захотите.

 
Dmi3:

А зачем? Вы получаете целиком массив, а потом делаете с ним все, что захотите.

Это понятно, но если мне не надо больше 3х, то и копировать их нет необходимости. Разве не так? Не найдя возможности я так и поступил, получил сколько дали и вытащил то что интересует...
 
Dmi3:

Как устроен стакан я знаю.

Еще раз вопрос:

Что происходит в массиве из 40 элементов при отсутствии, например, предложения?

- Первые 20 элементов будут содержать нули?

- Первые 20 элементов будут содержать информацию о bid'ах?

- Весь массив будет состоять не из 40, а из 20 элементов, которые будут  содержать только bid'ы?

Интересует только практический опыт. Как это должно быть теоретически я представляю, хочется подтверждений.

Размер

int size = ArraySize(book_price);

показывает сколько записей в действительности в стакане.

А какие из них ask или bid показывает

if(book_price[i].type == BOOK_TYPE_SELL) 

Если размер size = 0, то стакан пустой.

//+------------------------------------------------------------------+
//|                                                    Book_test.mq5 |
//|                                      Copyright 2020 prostotrader |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020 prostotrader"
#property link      "https://www.mql5.com"
#property version   "1.00"
//
bool is_book = false;
MqlBookInfo book_price[];
int cnt = 0;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Add books
   is_book = MarketBookAdd(Symbol());
   if(is_book = true)
   {
     Print(__FUNCTION__, ": Подписка на стакан добавлена. Символ ", Symbol());
   }
   else
   {
     Print(__FUNCTION__, ": Подписка на стакан не добавлена. Символ ", Symbol());
     return(INIT_FAILED);
   }  
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
    if(is_book = true) MarketBookRelease(Symbol());
    Print(__FUNCTION__, ": Подписка на стакан удалена. Символ ", Symbol());
  }

//+------------------------------------------------------------------+
//| BookEvent function                                               |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
  {
   if(symbol == Symbol())
   {
     cnt++;
     if(cnt >=2) return;
     if(MarketBookGet(Symbol(), book_price) == true)//getBook
     {
       int size = ArraySize(book_price);
       if(size > 0)
       {
         for(int i = 0; i < size; i++)
         {
           if(book_price[i].type == BOOK_TYPE_SELL) 
           {
             Print(__FUNCTION__, ": Получена запись Sell. Цена = ", book_price[i].price, "; Объем = ", book_price[i].volume);
           }
           else
           if(book_price[i].type == BOOK_TYPE_BUY) 
           {
             Print(__FUNCTION__, ": Получена запись Buy. Цена = ", book_price[i].price, "; Объем = ", book_price[i].volume);  
           }
         }
       }
       else Print(__FUNCTION__, ": Стакан ", Symbol(), " пустой!");
     }
     if(MarketBookGet("UCAD-9.20", book_price) == true)//getBook
     {
       int size = ArraySize(book_price);
       if(size > 0)
       {
         for(int i = 0; i < size; i++)
         {
           if(book_price[i].type == BOOK_TYPE_SELL) 
           {
             Print(__FUNCTION__, ": Получена запись Sell. Цена = ", book_price[i].price, "; Объем = ", book_price[i].volume);
           }
           else
           if(book_price[i].type == BOOK_TYPE_BUY) 
           {
             Print(__FUNCTION__, ": Получена запись Buy. Цена = ", book_price[i].price, "; Объем = ", book_price[i].volume);  
           }
         }
       }
       else Print(__FUNCTION__, ": Стакан UCAD-9.20 пустой!");
     }  
    }
  }
//+------------------------------------------------------------------+

2020.05.14 16:33:05.542 Book_test (UCAD-6.20,M1)        OnInit: Подписка на стакан добавлена. Символ UCAD-6.20
2020.05.14 16:33:05.656 Book_test (UCAD-6.20,M1)        OnBookEvent: Получена запись Sell. Цена = 1.412; Объем = 2000
2020.05.14 16:33:05.656 Book_test (UCAD-6.20,M1)        OnBookEvent: Получена запись Sell. Цена = 1.4119; Объем = 1000
2020.05.14 16:33:05.656 Book_test (UCAD-6.20,M1)        OnBookEvent: Получена запись Sell. Цена = 1.4118; Объем = 2500
2020.05.14 16:33:05.656 Book_test (UCAD-6.20,M1)        OnBookEvent: Получена запись Sell. Цена = 1.4116; Объем = 625
2020.05.14 16:33:05.656 Book_test (UCAD-6.20,M1)        OnBookEvent: Получена запись Buy. Цена = 1.4109; Объем = 625
2020.05.14 16:33:05.656 Book_test (UCAD-6.20,M1)        OnBookEvent: Получена запись Buy. Цена = 1.4108; Объем = 1000
2020.05.14 16:33:05.656 Book_test (UCAD-6.20,M1)        OnBookEvent: Получена запись Buy. Цена = 1.4107; Объем = 1000
2020.05.14 16:33:05.656 Book_test (UCAD-6.20,M1)        OnBookEvent: Получена запись Buy. Цена = 1.4106; Объем = 1000
2020.05.14 16:33:05.656 Book_test (UCAD-6.20,M1)        OnBookEvent: Стакан UCAD-9.20 пустой!
2020.05.14 16:33:13.221 Book_test (UCAD-6.20,M1)        OnDeinit: Подписка на стакан удалена. Символ UCAD-6.20
 
Alexey Viktorov:
А нет-ли возможности получать не полный стакан, а только 3 аска и 3 бида, например. В документации я не нашёл, да и не очень старательно искал.


//+------------------------------------------------------------------+
//|                                                    Book_test.mq5 |
//|                                      Copyright 2020 prostotrader |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020 prostotrader"
#property link      "https://www.mql5.com"
#property version   "1.00"
//
#define sell_records 3
#define buy_records 3
struct BOOK_DATA
{
  int total_cnt;
  int sell_cnt;
  int buy_cnt;
  int sell_pos;
  int buy_pos;
  MqlBookInfo b_data[];
  bool is_first;
};
bool is_book = false;
BOOK_DATA book_data;
int cnt = 0;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Add books
   is_book = MarketBookAdd(Symbol());
   if(is_book == true)
   {
     Print(__FUNCTION__, ": Book added. Symbol =  ", Symbol());
   }
   else
   {
     Print(__FUNCTION__, ": No book added. Symbol = ", Symbol());
     return(INIT_FAILED);
   }  
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
    if(is_book == true)
    {
      MarketBookRelease(Symbol());
      Print(__FUNCTION__, ": Book removed. Symbol = ", Symbol());
    }  
  }

//+------------------------------------------------------------------+
//| BookEvent function                                               |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
  {
   if(symbol == Symbol())
   {
     cnt++;
     if(cnt >=2) return;
     if(MarketBookGet(Symbol(), book_data.b_data) == true)
     {
       book_data.sell_cnt = 0;
       book_data.buy_cnt = 0;
       book_data.total_cnt = ArraySize(book_data.b_data);
       if(book_data.total_cnt > 0)
       {
         book_data.is_first = true;
         for(int i = 0; i < book_data.total_cnt; i++)
         {
           if(book_data.b_data[i].type == BOOK_TYPE_SELL)
           {
             book_data.sell_cnt++;
           }
           else
           if(book_data.b_data[i].type == BOOK_TYPE_BUY)
           {
             book_data.buy_cnt++;
             if(book_data.is_first == true)
             {
               book_data.is_first = false;
               if(book_data.sell_cnt > 0)
               {
                 book_data.sell_pos = i-1;
               }
               else book_data.sell_pos = -1;  
             }
             if(book_data.buy_cnt == buy_records)
             {
               book_data.buy_pos = i;
               break;
             }
           }  
         }
//--- Print data ---      
         Print(__FUNCTION__, ": Total records = ", book_data.total_cnt);
         Print(__FUNCTION__, ": Sell records = ", book_data.sell_cnt);
         Print(__FUNCTION__, ": Buy records = ", book_data.total_cnt - book_data.sell_cnt); 
         if((book_data.buy_cnt == buy_records) && (book_data.sell_cnt >= sell_records))
         {
           for(int i = book_data.sell_pos + sell_records - 1; i >= book_data.sell_pos; i--)
           {
             Print(__FUNCTION__, ": Sell record. Price = ", book_data.b_data[i].price, " Volume = ",
                                                            book_data.b_data[i].volume);
           }
           for(int i = book_data.buy_pos; i < (book_data.buy_pos + buy_records); i++)
           {
             Print(__FUNCTION__, ": Buy record. Price = ", book_data.b_data[i].price, " Volume = ", book_data.b_data[i].volume);
           }
         }
         else Print(__FUNCTION__, ": Invalid records range!");  
       }
       else Print(__FUNCTION__, ": Book is enpty. Symbol = ", Symbol());
     }
     else Print(__FUNCTION__, ": Get book failed. Symbol = ", Symbol());
    }
  }
//+------------------------------------------------------------------+

2020.05.14 17:20:34.316 Book_test (GOLD-6.20,M1)        OnInit: Подписка на стакан добавлена. Символ GOLD-6.20
2020.05.14 17:20:34.426 Book_test (GOLD-6.20,M1)        OnBookEvent: Total records = 40
2020.05.14 17:20:34.426 Book_test (GOLD-6.20,M1)        OnBookEvent: Sell records = 20
2020.05.14 17:20:34.426 Book_test (GOLD-6.20,M1)        OnBookEvent: Buy records = 20
2020.05.14 17:20:34.426 Book_test (GOLD-6.20,M1)        OnBookEvent: Sell record. Price = 1737.2 Volume = 500
2020.05.14 17:20:34.426 Book_test (GOLD-6.20,M1)        OnBookEvent: Sell record. Price = 1737.0 Volume = 9
2020.05.14 17:20:34.426 Book_test (GOLD-6.20,M1)        OnBookEvent: Sell record. Price = 1736.4 Volume = 2 //Best ask
2020.05.14 17:20:34.426 Book_test (GOLD-6.20,M1)        OnBookEvent: Buy record. Price = 1736.0 Volume = 4  //Best bid
2020.05.14 17:20:34.426 Book_test (GOLD-6.20,M1)        OnBookEvent: Buy record. Price = 1735.9 Volume = 25
2020.05.14 17:20:34.426 Book_test (GOLD-6.20,M1)        OnBookEvent: Buy record. Price = 1735.8 Volume = 2
2020.05.14 17:20:38.023 Book_test (GOLD-6.20,M1)        OnDeinit: Подписка на стакан удалена. Символ GOLD-6.20

Добавлено

Немного изменил код, чтобы меньше памяти юзалось и быстрее работало.

 
prostotrader:

Размер

показывает сколько записей в действительности в стакане.

А какие из них ask или bid показывает

Если размер size = 0, то стакан пустой.

Спасибо, все логично.

 
prostotrader:

Спасибо, я примерно так и сделал.

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

ФОРТС структура стакана цен на "планке"

Alexey Viktorov, 2020.05.14 08:23

Это понятно, но если мне не надо больше 3х, то и копировать их нет необходимости. Разве не так? Не найдя возможности я так и поступил, получил сколько дали и вытащил то что интересует...

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