Получение списка позиций

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

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

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

Узнать общее количество открытых позиций на счете (по всем финансовым инструментам) позволяет функция PositionsTotal.

int PositionsTotal()

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

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

Выяснить символ позиции по её номеру позволяет функция PositionGetSymbol.

string PositionGetSymbol(int index)

Индекс должен быть в пределах от 0 до N-1, где N — значение, полученное предварительным вызовом PositionsTotal. Порядок следования позиций не регламентирован.

Если позиция не найдена, то вернется пустая строка, а код ошибки будет доступен в _LastError.

Примеры использования этих двух функций встречались в нескольких тестовых экспертах (TrailingStop.mq5, TradeCloseBy.mq5 и других) в функциях с говорящими названиями GetMyPosition/GetMyPositions.

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

Для получения тикета позиции по её номеру предназначена функция PositionGetTicket.

ulong PositionGetTicket(int index)

Дополнительно функция выделяет позицию в торговом окружении терминала, что позволяет затем читать её свойства с помощью группы специальных PositionGet-функций. Иными словами, по аналогии с ордерами, терминал поддерживает для каждой MQL-программ внутренний кеш для хранения свойств одной позиции. Для выделения позиции, помимо PositionGetTicket, существует две функции: PositionSelect и PositionSelectByTicket — они рассмотрены ниже.

В случае ошибки функция PositionGetTicket вернет 0.

Тикет следует отличать от другого свойства — идентификатора, который присваивается каждой позиции и никогда не меняется. Именно идентификаторы используются для увязки позиций с ордерами и сделками, но об этом мы поговорим чуть позже.
 
Тикеты же нужны для выполнения запросов с участием позиций: именно тикеты задаются в полях position и position_by структуры MqlTradeRequest. Кроме того, сохранив тикет в переменной, программа сможет впоследствии выделить конкретную позицию с помощью функции PositionSelectByTicket (см. ниже) и работать с ней, не прибегая к повторному перебору позиций в цикле.

При перевороте позиции на неттинговом счете POSITION_TICKET изменяется на тикет ордера, инициировавшего эту операцию. Однако такую позицию можно по-прежнему отследить с помощью идентификатора. В режиме хеджинга переворот позиции не поддерживается.

bool PositionSelect(const string symbol)

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

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

Возвращаемый результат сигнализирует успешное (true) или неудачное (false) выполнение функции.

Тот факт, что свойства выделенной позиции кешируются означает, что самой позиции может уже не быть или она может быть изменена, если программа считывает её свойства через некоторое время. Рекомендуется вызывать функцию PositionSelect непосредственно перед обращением к данным.

bool PositionSelectByTicket(ulong ticket)

Функция выбирает открытую позицию для дальнейшей работы по указанному тикету.

Примеры использования функций мы рассмотрим позднее, в процессе изучения свойств и связанных с ними PositionGet-функций.

При построении алгоритмов с использованием функций PositionsTotal, OrdersTotal и аналогичных следует учитывать асинхронные принципы работы терминала. Мы уже касались этой темы в ходе написания классов MqlTradeSync.mqh и реализовали ожидание результатов выполнения исходящих торговых запросов. Однако это ожидание не всегда возможно выполнить на клиентской стороне. В частности, если мы установим отложенный ордер, то его превращение в рыночный и последующее исполнение будет происходить на сервере. В этот момент ордер может перестать числиться среди активных (OrdersTotal вернет 0), но позиция еще не отобразится (PositionsTotal также равен 0). Поэтому MQL-программа, имеющая условие на постановку ордера в отсутствии позиции, может ошибочно инициировать новый ордер, в результате чего позиция, в конечном счете, задвоится.

Чтобы решить эту проблему, MQL-программа должна анализировать торговое окружение более глубоко, нежели просто одномоментно проверять количество ордеров и позиций. Например, можно хранить слепок последнего корректного состояния торгового окружения и не допускать, чтобы какие-либо сущности исчезали без того или иного подтверждения. Только после этого можно формировать новый слепок. Так, ордер может удалиться только совместно с изменением позиции (создание, закрытие) или переводом в историю со статусом отмены. Одно из возможных решений предложено в виде класса TradeGuard в файле TradeGuard.mqh. Демонстрационный скрипт — TradeGuardExample.mq5 — также поставляется вместе с книгой. Данный пример оставлен для самостоятельного изучения.