Маржинальные требования

Наиболее востребованная для трейдера информация о финансовом инструменте — это размер денежных средств, необходимых для открытия позиции. Не зная того, сколько денег необходимо для покупки или продажи заданного количества лотов, в эксперте нельзя реализовать систему управления капиталом и контролировать состояние счета.

Поскольку MetaTrader 5 используется для торговли различными инструментами (валюты, товары, акции, облигации, опционы, фьючерсы) принципы расчета залога существенно различаются. В документации приведены подробности, в частности, для Forex и фьючерсов, а также биржи.

Несколько свойств MQL5 API позволяют определить разновидность рынка и способ расчета маржи для конкретного инструмента.

Забегая вперед, скажем, что для заданного сочетания таких параметров как тип торговой операции, инструмент, объем и цена, MQL5 позволяет вычислить маржу с помощью функции OrderCalcMargin — это наиболее простой способ, но он имеет существенное ограничение: функция не учитывает текущие открытые позиции и отложенные ордера. Тем самым, в частности, игнорируются возможные поправки на перекрывающиеся объемы, когда на счете разрешены встречные позиции.

Таким образом, чтобы получить детализацию текущих занятых под залог средств счета в разбивке по открытым позициям и ордерам, от MQL-программы может потребоваться анализ нижеприведенных свойств и вычисления по формулам. Кроме того, функция OrderCalcMargin запрещена для использования в индикаторах. Заранее оценить свободную маржу после совершения предполагаемой сделки можно с помощью OrderCheck.

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

Описание

SYMBOL_TRADE_CALC_MODE

Способ вычисления залога и прибыли (см. ENUM_SYMBOL_CALC_MODE)

SYMBOL_MARGIN_HEDGED_USE_LEG

Логический флаг включения (true) или отключения (false) режима расчета хеджированной маржи по наибольшей из перекрытых позиций (покупки и продажи)

SYMBOL_MARGIN_INITIAL

Начальная маржа для биржевого инструмента

SYMBOL_MARGIN_MAINTENANCE

Поддерживающая маржа для биржевого инструмента

SYMBOL_MARGIN_HEDGED

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

Первые два свойства входят в перечисление ENUM_SYMBOL_INFO_INTEGER, а последние три — в ENUM_SYMBOL_INFO_DOUBLE, и их можно прочитать, соответственно, функциями SymbolInfoInteger и SymbolInfoDouble.

Конкретные формулы расчета маржи зависят от свойства SYMBOL_TRADE_CALC_MODE и приведены в таблице ниже. Более полную информацию можно найти в документации MQL5.

Обратите внимание, что начальная и поддерживающая маржа не используются для инструментов Forex и для них эти свойства всегда равны 0.

Начальная маржа обозначает размер необходимых залоговых средств в маржинальной валюте для открытия позиции объемом в один лот. Она используется при проверке достаточности средств клиента перед входом в рынок. Для получения окончательного размера взимаемой маржи в зависимости от типа и направления ордера следует проверить коэффициенты маржи с помощью функции SymbolInfoMarginRate — таким образом брокер может задать индивидуальное "плечо" или дисконт для каждого инструмента.

Поддерживающая маржа указывает минимальное значение средств в маржинальной валюте инструмента для поддержания открытой позиции в один лот. Она используется при проверке достаточности средств клиента при изменении состояния счета (торговых условий). Если уровень средств упадет ниже суммы поддерживающей маржи всех позиций, брокер начнет их принудительно закрывать.

Если свойство с поддерживающей маржой равно 0, то используется начальная маржа. Как и в случае начальной маржи, для получения окончательного размера взимаемой маржи в зависимости от типа и направления следует проверить коэффициенты маржи с помощью функции SymbolInfoMarginRate.

Перекрытые позиции, то есть разнонаправленные позиции по одному и тому же символу, могут существовать только на торговом счету с хеджированием. Очевидно, что и расчет хеджированной маржи вместе со свойствами SYMBOL_MARGIN_HEDGED_USE_LEG, SYMBOL_MARGIN_HEDGED имеют смысл только на таких счетах. Хеджированная маржа применяется для перекрытого объема

Брокер может выбрать для каждого инструмента один из двух существующих способов расчета маржи для перекрытых позиций:

  • Базовый расчет применяется, когда режим расчета по наибольшей стороне отключен, то есть свойство SYMBOL_MARGIN_HEDGED_USE_LEG равно false. В этом случае маржа складывается из 3 компонентов: залог за неперекрытый объем существующей позиции, залог за перекрытый объем (если есть встречные позиции и свойство SYMBOL_MARGIN_HEDGED ненулевое), залог для отложенных ордеров. Если при этом для инструмента задана первоначальная маржа (свойство SYMBOL_MARGIN_INITIAL ненулевое), то хеджированная маржа указывается как абсолютное значение (в деньгах). Если первоначальная маржа не задана (равна 0), то в SYMBOL_MARGIN_HEDGED указывается размер контракта, который будет использован при расчете маржи по формуле, соответствующей типу торгового инструмента (SYMBOL_TRADE_CALC_MODE).
  • Расчет по наибольшей позиции применяется, когда свойство SYMBOL_MARGIN_HEDGED_USE_LEG равно true. При этом значение SYMBOL_MARGIN_HEDGED не учитывается. Вместо этого вычисляется объем всех коротких и всех длинных позиций по инструменту, для каждой стороны рассчитывается средневзвешенная цена открытия. Далее по формулам, соответствующим типу инструмента (SYMBOL_TRADE_CALC_MODE), рассчитывается маржа для короткой и для длинной стороны. В качестве итогового значения используется наибольшее.

В следующей таблице приведены элементы ENUM_SYMBOL_CALC_MODE и соответствующие им способы расчета маржи. Это же свойство (SYMBOL_TRADE_CALC_MODE) отвечает и за расчет прибыли/убытка позиции, но мы рассмотрим этот аспект позднее, в главе про торговые функции MQL5.

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

Формула

SYMBOL_CALC_MODE_FOREX

Forex

Lots * ContractSize * MarginRate / Leverage

SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE

Forex без "плеча"

Lots * ContractSize * MarginRate

SYMBOL_CALC_MODE_CFD

CFD

Lots * ContractSize * MarketPrice * MarginRate

SYMBOL_CALC_MODE_CFDLEVERAGE

CFD с "плечом"

Lots * ContractSize * MarketPrice * MarginRate / Leverage

SYMBOL_CALC_MODE_CFDINDEX

CFD на индексы

Lots * ContractSize * MarketPrice * TickPrice / TickSize * MarginRate

SYMBOL_CALC_MODE_EXCH_STOCKS

Ценные бумаги на бирже

Lots * ContractSize * LastPrice * MarginRate

SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX

Ценные бумаги на MOEX

Lots * ContractSize * LastPrice * MarginRate

SYMBOL_CALC_MODE_FUTURES

Фьючерсы

Lots * InitialMargin * MarginRate

SYMBOL_CALC_MODE_EXCH_FUTURES

Фьючерсы на бирже

Lots * InitialMargin * MarginRate               или
Lots * MaintenanceMargin * MarginRate

SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS

Фьючерсы на FORTS

Lots * InitialMargin * MarginRate               или
Lots * MaintenanceMargin * MarginRate

SYMBOL_CALC_MODE_EXCH_BONDS

Облигации на бирже

Lots * ContractSize * FaceValue * OpenPrice / 100

SYMBOL_CALC_MODE_EXCH_BONDS_MOEX

Облигации на MOEX

Lots * ContractSize * FaceValue * OpenPrice / 100

SYMBOL_CALC_MODE_SERV_COLLATERAL

Неторгуемый актив (маржа неприменима)

В формулах использованы следующие обозначения:

  • Lots — объем позиции или ордера в лотах (долях контракта);
  • ContractSize — размер контракта (одного лота, SYMBOL_TRADE_CONTRACT_SIZE);
  • Leverage — "плечо" торгового счета (ACCOUNT_LEVERAGE);
  • InitialMargin — начальная маржа (SYMBOL_MARGIN_INITIAL);
  • MaintenanceMargin — поддерживающая маржа (SYMBOL_MARGIN_MAINTENANCE);
  • TickPrice — стоимость тика (SYMBOL_TRADE_TICK_VALUE);
  • TickSize — размер тика (SYMBOL_TRADE_TICK_SIZE);
  • MarketPrice — последняя известная цена Bid/Ask в зависимости от типа сделки;
  • LastPrice — последняя известная цена Last;
  • OpenPrice — средневзвешенная цена позиции или открытия ордера;
  • FaceValue — номинальная цена облигации;
  • MarginRate — коэффициент маржи согласно функции SymbolInfoMarginRate, может также иметь 2 разных значения: для начальной и поддерживающей маржи.

Альтернативная реализация вычислений по формулам для большинства типов символов приведена в файле MarginProfitMeter.mqh (см. раздел Оценка прибыли торговой операции). Её можно применить и в индикаторах.

Сделаем пару замечаний по некоторым режимам.

В вышеприведенной таблице лишь в трех формулах для фьючерсов применена начальная маржа (SYMBOL_MARGIN_INITIAL). Однако если это свойство имеет ненулевое значение в спецификации любого другого символа, то именно оно определяет маржу.

Некоторые биржы могут налагать собственную специфику на корректировку маржи, как, например, система дисконтов для FORTS (SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS). Подробности — в документации MQL5 и у вашего брокера.

При режиме SYMBOL_CALC_MODE_SERV_COLLATERAL стоимость инструмента учитывается в Активах (Assets), которые суммируются с собственными средствами (Equity). Тем самым открытые позиции по такому инструменту увеличивают размер свободных средств (Free Margin) и служат дополнительным обеспечением под открытые позиции по торгуемым инструментам. Рыночная стоимость открытой позиции рассчитывается на основании объема, размера контракта, текущей цены рынка и коэффициента ликвидности: Lots * ContractSize * MarketPrice * LiqudityRate (последнее значение можно получить как свойство SYMBOL_TRADE_LIQUIDITY_RATE).

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

#include <MQL5Book/SymbolFilter.mqh>
   
input bool UseMarketWatch = false;
input bool ShowPerSymbolDetails = false;
input bool ExcludeZeroInitMargin = false;
input bool ExcludeZeroMainMargin = false;
input bool ExcludeZeroHedgeMargin = false;

По умолчанию информация запрашивается для всех доступных символов. Для ограничения контекста только обзором рынка следует установить UseMarketWatch в true.

Параметр ShowPerSymbolDetails позволяет включить вывод подробной информации о каждом символе (по умолчанию параметр равен false, и выводится только статистика).

Последние 3 параметра предназначены для фильтрации символов по условиям нулевых значений маржи (начальной, поддерживающей и хеджирующей, соответственно).

Для сбора и удобного отображения в журнале полного набора свойств по каждому символу (когда включен режим ShowPerSymbolDetails) в коде определена структура MarginSettings.

struct MarginSettings
{
   string name;
   ENUM_SYMBOL_CALC_MODE calcMode;
   bool hedgeLeg;
   double initial;
   double maintenance;
   double hedged;
};

Поскольку часть свойств является целочисленной (SYMBOL_TRADE_CALC_MODE, SYMBOL_MARGIN_HEDGED_USE_LEG), а часть — вещественной (SYMBOL_MARGIN_INITIAL, SYMBOL_MARGIN_MAINTENANCE, SYMBOL_MARGIN_HEDGED), запрашивать их объектом-фильтром придется по отдельности.

Теперь обратимся непосредственно к рабочему коду в OnStart. Здесь как обычно определим объект фильтра (f), выходные массивы для имен символов (symbols) и значений запрашиваемых свойств (flags, values). Помимо них добавим массив структур MarginSettings.

void OnStart()
{
   SymbolFilter f;                // объект фильтра
   string symbols[];              // массив для имен
   long flags[][2];               // массив для целочисленных векторов
   double values[][3];            // массив для вещественных векторов
   MarginSettings margins[];      // составной выходной массив
   ...

Для подсчета статистики введен массив-карта stats с ключом типа ENUM_SYMBOL_CALC_MODE и целым int-значением — количеством, сколько раз встретился каждый способ. Также все случаи нулевой маржи и включенного режима расчета по большей "стороне" должны фиксироваться в соответствующих переменных-счетчиках.

   MapArray<ENUM_SYMBOL_CALC_MODE,intstats// счетчики для каждого способа/режима
   int hedgeLeg = 0;                          // и прочие счетчики
   int zeroInit = 0;                          // ...
   int zeroMaintenance = 0;
   int zeroHedged = 0;
   ...

Далее укажем интересующие нас свойства, связанные с маржой, которые будут считываться из настроек символов. Сперва целочисленные в массиве ints и затем вещественные в массиве doubles.

   ENUM_SYMBOL_INFO_INTEGER ints[] =
   {
      SYMBOL_TRADE_CALC_MODE,
      SYMBOL_MARGIN_HEDGED_USE_LEG
   };
   
   ENUM_SYMBOL_INFO_DOUBLE doubles[] =
   {
      SYMBOL_MARGIN_INITIAL,
      SYMBOL_MARGIN_MAINTENANCE,
      SYMBOL_MARGIN_HEDGED
   };
   ...

В зависимости от входных параметров настроим условия фильтрации.

   if(ExcludeZeroInitMarginf.let(SYMBOL_MARGIN_INITIAL0SymbolFilter::IS::GREATER);
   if(ExcludeZeroMainMarginf.let(SYMBOL_MARGIN_MAINTENANCE0SymbolFilter::IS::GREATER);
   if(ExcludeZeroHedgeMarginf.let(SYMBOL_MARGIN_HEDGED0SymbolFilter::IS::GREATER);
   ...

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

   f.select(UseMarketWatchintssymbolsflags);
   const int n = ArraySize(symbols);
   ArrayResize(symbols0n);
   f.select(UseMarketWatchdoublessymbolsvalues);
   ...

Массив с символами приходится обнулять после первого применения фильтра, чтобы имена не задваивались. Несмотря на 2 раздельных запроса, порядок элементов во всех выходных массивах (ints и doubles) одинаковый, поскольку условия фильтрации не меняются.

Если пользователем включен подробный лог, выделяем память под массив структур margins.

   if(ShowPerSymbolDetailsArrayResize(marginsn);

Наконец, вычисляем статистику, перебирая все элементы полученных массивов, и опционально заполняем массив структур.

   for(int i = 0i < n; ++i)
   {
      stats.inc((ENUM_SYMBOL_CALC_MODE)flags[i].value[0]);
      hedgeLeg += (int)flags[i].value[1];
      if(values[i].value[0] == 0zeroInit++;
      if(values[i].value[1] == 0zeroMaintenance++;
      if(values[i].value[2] == 0zeroHedged++;
      
      if(ShowPerSymbolDetails)
      {
         margins[i].name = symbols[i];
         margins[i].calcMode = (ENUM_SYMBOL_CALC_MODE)flags[i][0];
         margins[i].hedgeLeg = (bool)flags[i][1];
         margins[i].initial = values[i][0];
         margins[i].maintenance = values[i][1];
         margins[i].hedged = values[i][2];
      }
   }
   ...

Остается лишь вывести статистику в журнал.

   PrintFormat("===== Margin calculation modes for %s symbols %s=====",
      (UseMarketWatch ? "Market Watch" : "all available"),
      (ExcludeZeroInitMargin || ExcludeZeroMainMargin || ExcludeZeroHedgeMargin
         ? "(with conditions) " : ""));
   PrintFormat("Total symbols: %d"n);
   PrintFormat("Hedge leg used in: %d"hedgeLeg);
   PrintFormat("Zero margin counts: initial=%d, maintenance=%d, hedged=%d",
      zeroInitzeroMaintenancezeroHedged);
   
   Print("Stats per calculation mode:");
   stats.print();
   ...

Поскольку элементы перечисления ENUM_SYMBOL_CALC_MODE выводятся как целые числа (что не очень информативно), мы также отображаем "легенду", где для каждого значения указано название (из EnumToString).

   Print("Legend: key=calculation mode, value=count");
   for(int i = 0i < stats.getSize(); ++i)
   {
      PrintFormat("%d -> %s"stats.getKey(i), EnumToString(stats.getKey(i)));
   }
   ...

Если требуется подробная информация по отобранным символам, выводим массив структур margins.

   if(ShowPerSymbolDetails)
   {
      Print("Settings per symbol:");
      ArrayPrint(margins);
   }
}

Запустим скрипт пару раз с разными настройками. Для начала — с настройками по умолчанию.

===== Margin calculation modes for all available symbols =====
Total symbols: 131
Hedge leg used in: 14
Zero margin counts: initial=123, maintenance=130, hedged=32
Stats per calculation mode:
    [key] [value]
[0]     0     101
[1]     4      16
[2]     1       1
[3]     2      11
[4]     5       2
Legend: key=calculation mode, value=count
0 -> SYMBOL_CALC_MODE_FOREX
4 -> SYMBOL_CALC_MODE_CFDLEVERAGE
1 -> SYMBOL_CALC_MODE_FUTURES
2 -> SYMBOL_CALC_MODE_CFD
5 -> SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE

Для второго прогона установим ShowPerSymbolDetails и ExcludeZeroInitMargin в true. Тем самым запрашивается подробная информация о всех символах, в которых задано ненулевое значения начальной маржи.

===== Margin calculation modes for all available symbols (with conditions) =====
Total symbols: 8
Hedge leg used in: 0
Zero margin counts: initial=0, maintenance=7, hedged=0
Stats per calculation mode:
    [key] [value]
[0]     0       5
[1]     1       1
[2]     5       2
Legend: key=calculation mode, value=count
0 -> SYMBOL_CALC_MODE_FOREX
1 -> SYMBOL_CALC_MODE_FUTURES
5 -> SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE
Settings per symbol:
      [name] [calcMode] [hedgeLeg]    [initial] [maintenance]    [hedged]
[0] "XAUEUR"          0      false    100.00000       0.00000    50.00000
[1] "XAUAUD"          0      false    100.00000       0.00000   100.00000
[2] "XAGEUR"          0      false   1000.00000       0.00000  1000.00000
[3] "USDGEL"          0      false 100000.00000  100000.00000 50000.00000
[4] "SP500m"          1      false   6600.00000       0.00000  6600.00000
[5] "XBRUSD"          5      false    100.00000       0.00000    50.00000
[6] "XNGUSD"          0      false  10000.00000       0.00000 10000.00000
[7] "XTIUSD"          5      false    100.00000       0.00000    50.00000