- Главное событие экспертов: OnTick
- Основные принципы и понятия: ордер, сделка, позиция
- Типы торговых операций
- Типы ордеров
- Режимы исполнения ордеров по цене и объемам
- Сроки действия отложенных ордеров
- Расчет залога для будущего ордера: OrderCalcMargin
- Оценка прибыли торговой операции: OrderCalcProfit
- Структура торгового запроса MqlTradeRequest
- Структура проверки запроса MqlTradeCheckResult
- Проверка корректности запроса: OrderCheck
- Результат отправки запроса: структура MqlTradeResult
- Отправка торгового запроса: OrderSend и OrderSendAsync
- Совершение покупки или продажи
- Модификация уровней Stop Loss и/или Take Profit позиции
- Трейлинг стоп
- Полное и частичное закрытие позиции
- Полное и частичное закрытие встречных позиций (хедж)
- Установка отложенного ордера
- Модификация отложенного ордера
- Удаление отложенного ордера
- Получение списка действующих ордеров
- Свойства ордеров (действующих и в истории)
- Функции для чтения свойств действующих ордеров
- Отбор ордеров по свойствам
- Получение списка позиций
- Свойства позиций
- Функции для чтения свойств позиций
- Свойства сделок
- Выборка ордеров и сделок из истории
- Функции для чтения свойств ордеров из истории
- Функции для чтения свойств сделок из истории
- Типы торговых транзакций
- Событие OnTradeTransaction
- Синхронные и асинхронные запросы
- Событие OnTrade
- Контроль за изменениями торгового окружения
- Особенности создания мультисимвольных экспертов
- Ограничения и преимущества экспертов
- Создание заготовки эксперта в Мастере MQL
Установка отложенного ордера
В разделе Типы ордеров мы теоретически рассмотрели все поддерживаемые платформой варианты установки отложенных ордеров. С практической точки зрения ордера создаются с помощью функций OrderSend/OrderSendAsync, для которых предварительно заполняется структура запроса MqlTradeRequest по особым правилам. В частности, поле action должно содержать значение TRADE_ACTION_PENDING из перечисления ENUM_TRADE_REQUEST_ACTIONS. С учетом него, следующий перечень полей является обязательным:
- action
- symbol
- volume
- price
- type (значение по умолчанию 0 соответствует ORDER_TYPE_BUY)
- type_filling (значение по умолчанию 0 соответствует ORDER_FILLING_FOK)
- type_time (значение по умолчанию 0 соответствует ORDER_TIME_GTC)
- expiration (значение по умолчанию 0, не важно при ORDER_TIME_GTC)
Если нулевые умолчания отвечают поставленной задаче, некоторые из последних 4-х полей можно при заполнении пропустить.
Поле stoplimit является обязательным только для ордеров типов ORDER_TYPE_BUY_STOP_LIMIT и ORDER_TYPE_SELL_STOP_LIMIT.
Опциональными полями являются:
- sl
- tp
- magic
- comment
Нулевые значения в sl и tp обозначают отсутствие защитных уровней.
Дополним наши структуры в файле MqlTradeSync.mqh методами для проверки значений и заполнения полей. Принцип формирования всех типов ордеров одинаков, поэтому рассмотрим пару частных случаев установки лимитных ордеров на покупку и продажу. Остальные типы буду отличаться только значением поля type. Публичные методы с полным набором обязательных полей, а также защитных уровней, называются согласно типам: buyLimit и sellLimit.
ulong buyLimit(const string name, const double lot, const double p,
|
Поскольку в структуре присутствует поле symbol, при необходимости инициализируемое в конструкторе, существуют аналогичные методы без параметра name: они вызывают приведенные выше методы, передавая symbol первым параметром. Таким образом, чтобы создать ордер с минимальными усилиями, достаточно написать:
MqlTradeRequestSync request; // по умолчанию использует текущий символ графика
|
Общая часть кода по проверке переданных значений, их нормализации, сохранению в полях структуры и созданию отложенного ордера выведена во вспомогательный метод _pending. Он возвращает тикет ордера в случае успеха или 0 в случае проблем.
ulong _pending(const string name, const double lot, const double p,
|
Заполнение поля action и вызов методов setSymbol и setVolumePrices уже знакомы нам по предыдущим торговым операциям.
Многострочный оператор if гарантирует, что готовящаяся операция присутствует среди разрешенных операций по символу, прописанных в свойстве SYMBOL_ORDER_MODE. Целочисленное деление типа type пополам с последующим сдвигом 1 на полученное значение взводит правильный бит в маске разрешенных типов ордеров — это особенность сочетания констант в перечислении ENUM_ORDER_TYPE и свойства SYMBOL_ORDER_MODE. Например, ORDER_TYPE_BUY_STOP и ORDER_TYPE_SELL_STOP имеют значения 4 и 5, которые после деления на 2 дают 2 (с учетом отбрасывания дробной части). Операция 1 << 2 имеет результат 4, равный SYMBOL_ORDER_STOP.
Особенностью отложенных ордеров является обработка срока истечения. Этим занимается метод setExpiration. В нем следует убедиться, что заданный режим истечения ENUM_ORDER_TYPE_TIME duration разрешен для символа, а дата и время until правильно заполнены.
bool setExpiration(ENUM_ORDER_TYPE_TIME duration = ORDER_TIME_GTC, datetime until = 0)
|
Битовая маска разрешенных режимов доступна в свойстве SYMBOL_EXPIRATION_MODE. Сочетание битов в маске и констант ENUM_ORDER_TYPE_TIME таково, что нам достаточно вычислить выражение 1 << duration и наложить его на маску: ненулевое значение служит признаком наличия режима.
Для режимов ORDER_TIME_SPECIFIED и ORDER_TIME_SPECIFIED_DAY поле expiration с конкретным значением datetime не может быть пустым. Причем указанные дата и время не могут быть в прошлом.
Поскольку метод _pending, представленный ранее, отправляет в конце запрос на сервер с помощью OrderSend, наша программа должна убедиться, что ордер с полученным тикетом действительно был создан (это особенно важно для лимитных ордеров, которые могут выводиться во внешнюю торговую систему). Поэтому в методе completed, который используется для "блокирующего" контроля результата, добавим ветвь для операции TRADE_ACTION_PENDING.
bool completed()
|
В структуре MqlTradeResultSync добавим метод placed.
bool placed(const ulong msc = 1000)
|
Его главная задача — дождаться появления ордера с помощью ожидания в функции orderExist: она уже использовалась на первом этапе проверки открытия позиции.
Для тестирования нового функционала реализуем эксперт PendingOrderSend.mq5. Он позволяет выбрать с помощью входных переменных тип отложенного ордера и все его атрибуты, а затем выполнить запрос с подтверждением.
enum ENUM_ORDER_TYPE_PENDING
|
Эксперт будет создавать новый ордер при каждом запуске или смене параметров. Автоматического удаления ордера пока не предусмотрено, потому что мы рассмотрим этот тип операции позднее. В связи с этим не забывайте удалять ордера вручную.
Однократная установка ордера выполняется, как и в некоторых предыдущих примерах, по таймеру (поэтому следует предварительно убедиться, что рынок открыт).
void OnTimer()
|
Функция PlaceOrder принимает все настройки в качестве параметров, отправляет запрос и возвращает признак успеха (ненулевой тикет). Для ордеров всех поддерживаемых типов заранее предустановлены расстояния от текущей цены, рассчитываемые как часть дневного размаха котировок.
ulong PlaceOrder(const ENUM_ORDER_TYPE type,
|
Например, коэффициент -0.5 для ORDER_TYPE_BUY_LIMIT означает, что ордер будет поставлен ниже текущей цены на половину дневного размаха (отбой внутрь диапазона), а +1.0 для ORDER_TYPE_BUY_STOP — что ордер окажется на верхней границе диапазона (на пробой).
Сам дневной размах вычисляется следующим образом.
const double range = iHigh(symbol, PERIOD_D1, 1) - iLow(symbol, PERIOD_D1, 1);
|
Находим значения объема и пункта, которые потребуются ниже.
const double volume = lot == 0 ? SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN) : lot;
|
Ценовой уровень установки ордера рассчитываем в переменной price по приведенным коэффициентам от общего диапазона.
const double price = TU::GetCurrentPrice(type, symbol) + range * coefficients[type]; |
Поле stoplimit должно заполняться только для ордеров *_STOP_LIMIT. Значения для него хранит переменная origin.
const bool stopLimit =
|
При срабатывании ордеров этих двух типов новый отложенный ордер будет ставиться на цену, являющуюся сейчас текущей. Действительно, в данном сценарии цена движется от текущего значения до уровня price, где и происходит активация ордера, а потому "прежняя текущая" цена становится корректным уровнем для отскока, обозначенным лимитным ордером. Ниже мы проиллюстрируем эту ситуацию.
Защитные уровни определяются с привлечением объекта TU::TradeDirection, причем в случае стоп-лимитных ордеров отсчет ведется от origin.
TU::TradeDirection dir(type);
|
Далее описывается структура, и заполняются опциональные поля.
MqlTradeRequestSync request(symbol);
|
Здесь же можно выбрать режим заливки. По умолчанию, MqlTradeRequestSync автоматически выбирает первый из разрешенных режимов ENUM_ORDER_TYPE_FILLING.
В зависимости от выбранного пользователем типа ордера, вызываем тот или иной торговый метод.
ResetLastError();
|
Если тикет получен, дожидаемся его появления в торговом окружении терминала.
if(order != 0)
|
Запустим эксперт на графике EURUSD с настройками по умолчанию и дополнительно выберем дистанцию до защитных уровней 1000 пунктов. В журнале увидим следующие записи (в предположении, что настройки по умолчанию совпадают с разрешениями для EURUSD на вашем счете).
Autodetected daily range: 0.01413
|
На графике это выглядит так.
Отложенный ордер ORDER_TYPE_BUY_STOP
Удалим ордер вручную и поменяем тип ордера на ORDER_TYPE_BUY_STOP_LIMIT. В результате получим более сложную картину.
Отложенный ордер ORDER_TYPE_BUY_STOP_LIMIT
Цена, где расположена верхняя пара штрих-пунктирных линий, является ценой срабатывания ордера, в результате чего будет поставлен ORDER_TYPE_BUY_LIMIT ордер на уровне текущей цены, со значениями Stop Loss и Take Profit, помеченными красными линиями. Уровень Take Profit будущего ордера ORDER_TYPE_BUY_LIMIT практически совпадает с уровнем активации только что созданного предварительного ордера ORDER_TYPE_BUY_STOP_LIMIT.
В качестве дополнительного примера для самостоятельного изучения к книге прилагается эксперт AllPendingsOrderSend.mq5, который устанавливает сразу 6 отложенных ордеров: по одному каждого типа.
Отложенные ордера всех типов
В результате его запуска с настройками по умолчанию вы можете получить такие записи в журнале:
Autodetected daily range: 0.01413
|