Спреды и отступы приказов от текущей цены

Для многих торговых стратегий, в особенности тех, что основываются на краткосрочных операциях, важна информация о спреде и дистанции от текущей цены, допускающей установку или модификацию ордеров. Все эти свойства являются частью перечисления ENUM_SYMBOL_INFO_INTEGER и доступны через функцию SymbolInfoInteger.

Идентификатор

Описание

SYMBOL_SPREAD

Размер спреда (в пунктах)

SYMBOL_SPREAD_FLOAT

Логический признак плавающего спреда

SYMBOL_TRADE_STOPS_LEVEL

Минимальный разрешенный отступ (в пунктах) от текущей цены для установки уровней Stop Loss, Take Profit и отложенных ордеров

SYMBOL_TRADE_FREEZE_LEVEL

Дистанция от текущей цены (в пунктах) для заморозки ордеров и позиций

В вышеприведенной таблице под текущей ценой понимается цена Ask или Bid, в зависимости от сути выполняемой операции.

Так защитные уровни Stop Loss и Take Profit предписывают закрытие позиции, которое выполняется операцией противоположного направления к открытию. Поэтому для покупок, открываемых по цене Ask, защитные уровни указывают Bid, а для продаж, открываемых по Bid, защитные уровни указывают Ask. При установке отложенных ордеров, тип цены открытия выбирается стандартным образом: покупка (Buy Stop, Buy Limit, Buy Stop Limit) — по Ask, продажа (Sell Stop, Sell Limit, Sell Stop Limit) — по Bid. Именно с учетом таких типов цен в разрезе упомянутых торговых операций происходит отсчет дистанции в пунктах для свойств SYMBOL_TRADE_STOPS_LEVEL и SYMBOL_TRADE_FREEZE_LEVEL.

Свойство SYMBOL_TRADE_STOPS_LEVEL, если оно ненулевое, запрещает такую модификацию уровней Stop Loss, Take Profit у открытой позиции, чтобы любой из них оказался от текущей цены на более близком расстоянии, чем указанное. Аналогично, нельзя перенести цену открытия отложенного ордера ближе, чем SYMBOL_TRADE_STOPS_LEVEL пунктов от текущей цены.

Свойство SYMBOL_TRADE_FREEZE_LEVEL, если оно ненулевое, ограничивает любые торговые операции по отложенному ордеру или открытой позиции в заданной окрестности текущей цены. Для отложенного ордера заморозка наступает, когда заданная цена открытия оказывается на дистанции меньше SYMBOL_TRADE_FREEZE_LEVEL пунктов от текущей цены (опять же тип текущей цены — Ask или Bid — зависит от покупки или продажи, соответственно). Для позиции под заморозку попадают уровни Stop Loss и Take Profit, оказавшиеся рядом с текущей ценой, а потому для них отсчет ведется для "обратных" типов цен.

Если свойство SYMBOL_SPREAD_FLOAT равно true, свойство SYMBOL_SPREAD не является частью спецификации символа, а содержит актуальный спред, динамически меняющийся при каждом вызове согласно рыночным обстоятельствам. Его также можно найти как разницу между ценами Ask и Bid в структуре MqlTick, вызвав SymbolInfoTick.

Проанализировать указанные свойства позволит скрипт SymbolFilterSpread.mq5. В нем определено пользовательское перечисление ENUM_SYMBOL_INFO_INTEGER_PART, в которое включены лишь интересующие нас в данном контексте свойства из ENUM_SYMBOL_INFO_INTEGER.

enum ENUM_SYMBOL_INFO_INTEGER_PART
{
   SPREAD_FIXED = SYMBOL_SPREAD,
   SPREAD_FLOAT = SYMBOL_SPREAD_FLOAT,
   STOPS_LEVEL = SYMBOL_TRADE_STOPS_LEVEL,
   FREEZE_LEVEL = SYMBOL_TRADE_FREEZE_LEVEL
};

С помощью нового перечисления определен входной параметр Property, который задает, какое именно свойство из 4-х будет анализироваться. Параметры UseMarketWatch и ShowPerSymbolDetails уже известным образом управляют процессом, как и в предыдущих тестовых скриптах.

input bool UseMarketWatch = true;
input ENUM_SYMBOL_INFO_INTEGER_PART Property = SPREAD_FIXED;
input bool ShowPerSymbolDetails = true;

Для удобного отображения информации по каждому символу (имя и значение свойства в каждой строке) с помощью функции ArrayPrint определена вспомогательная структура SymbolDistance (используется, только когда ShowPerSymbolDetails равно true).

struct SymbolDistance
{
   string name;
   int value;
};

В обработчике OnStart описываем необходимые объекты и массивы.

void OnStart()
{
   SymbolFilter f;                // объект фильтра
   string symbols[];              // приемный массив для имен
   long values[];                 // приемный массив для значений
   SymbolDistance distances[];    // массив для печати
   MapArray<long,intstats;      // счетчики конкретных значений выбранного свойства
   ...

Затем применяем фильтр и заполняем приемные массивы значениями указанного свойства Property, с сортировкой.

   f.select(UseMarketWatch, (ENUM_SYMBOL_INFO_INTEGER)Propertysymbolsvaluestrue);
   const int n = ArraySize(symbols);
   if(ShowPerSymbolDetailsArrayResize(distancesn);
   ...

В цикле считаем статистику и заполняем структуры SymbolDistance, если необходимо.

   for(int i = 0i < n; ++i)
   {
      stats.inc(values[i]);
      if(ShowPerSymbolDetails)
      {
         distances[i].name = symbols[i];
         distances[i].value = (int)values[i];
      }
   }
   ...

Наконец выводим результаты в журнал.

   PrintFormat("===== Distances for %s symbols =====",
      (UseMarketWatch ? "Market Watch" : "all available"));
   PrintFormat("Total symbols: %d"n);
   
   PrintFormat("Stats per %s:"EnumToString((ENUM_SYMBOL_INFO_INTEGER)Property));
   stats.print();
   
   if(ShowPerSymbolDetails)
   {
      Print("Details per symbol:");
      ArrayPrint(distances);
   }
}

Вот что можно получить при запуске скрипта с настройками по умолчанию, что соответствует анализу спредов.

===== Distances for Market Watch symbols =====
Total symbols: 13
Stats per SYMBOL_SPREAD:
    [key] [value]
[0]     0       2
[1]     2       3
[2]     3       1
[3]     6       1
[4]     7       1
[5]     9       1
[6]   151       1
[7]   319       1
[8]  3356       1
[9]  3400       1
Details per symbol:
       [name] [value]
[ 0] "USDJPY"       0
[ 1] "EURUSD"       0
[ 2] "USDCHF"       2
[ 3] "USDCAD"       2
[ 4] "GBPUSD"       2
[ 5] "AUDUSD"       3
[ 6] "XAUUSD"       6
[ 7] "SP500m"       7
[ 8] "NZDUSD"       9
[ 9] "USDCNH"     151
[10] "USDSEK"     319
[11] "BTCUSD"    3356
[12] "USDRUB"    3400

Чтобы понять, являются ли спреды текущими (меняющимися динамически) или фиксированными, запустим скрипт с другими настройками: Property = SPREAD_FLOAT, ShowPerSymbolDetails = false.

===== Distances for Market Watch symbols =====
Total symbols: 13
Stats per SYMBOL_SPREAD_FLOAT:
    [key] [value]
[0]     1      13

Согласно этим данным все символы в обзоре рынка имеют плавающий спред (значение 1 в ключе key — это true в SYMBOL_SPREAD_FLOAT). Поэтому если снова и снова запускать скрипт с настройками по умолчанию, мы будем получать новые значения (при открытом рынке).