- Главное событие экспертов: OnTick
- Основные принципы и понятия: ордер, сделка, позиция
- Типы торговых операций
- Типы ордеров
- Режимы исполнения ордеров по цене и объемам
- Сроки действия отложенных ордеров
- Расчет залога для будущего ордера: OrderCalcMargin
- Оценка прибыли торговой операции: OrderCalcProfit
- Структура торгового запроса MqlTradeRequest
- Структура проверки запроса MqlTradeCheckResult
- Проверка корректности запроса: OrderCheck
- Результат отправки запроса: структура MqlTradeResult
- Отправка торгового запроса: OrderSend и OrderSendAsync
- Совершение покупки или продажи
- Модификация уровней Stop Loss и/или Take Profit позиции
- Трейлинг стоп
- Полное и частичное закрытие позиции
- Полное и частичное закрытие встречных позиций (хедж)
- Установка отложенного ордера
- Модификация отложенного ордера
- Удаление отложенного ордера
- Получение списка действующих ордеров
- Свойства ордеров (действующих и в истории)
- Функции для чтения свойств действующих ордеров
- Отбор ордеров по свойствам
- Получение списка позиций
- Свойства позиций
- Функции для чтения свойств позиций
- Свойства сделок
- Выборка ордеров и сделок из истории
- Функции для чтения свойств ордеров из истории
- Функции для чтения свойств сделок из истории
- Типы торговых транзакций
- Событие OnTradeTransaction
- Синхронные и асинхронные запросы
- Событие OnTrade
- Контроль за изменениями торгового окружения
- Особенности создания мультисимвольных экспертов
- Ограничения и преимущества экспертов
- Создание заготовки эксперта в Мастере MQL
Проверка корректности запроса: OrderCheck
Для выполнения любой торговой операции MQL-программа должна предварительно заполнить необходимыми данными структуру MqlTradeRequest. Перед отправкой на сервер с помощью торговых функций её имеет смысл проверить на формальную корректность и оценить последствия выполнения запроса, в частности, размер залога, который потребуется, и оставшихся свободных средств. Данную проверку выполняет функция OrderCheck.
bool OrderCheck(const MqlTradeRequest &request, MqlTradeCheckResult &result)
В случае нехватки средств или ошибочно заполненных параметров функция возвращает false. Кроме того, функция реагирует отказом и при отключенном разрешении торговать — как в терминале в целом, так и для конкретной программы. Конкретный код ошибки смотрите в поле retcode структуры result.
Успешная проверка структуры request и торгового окружения завершается со статусом true, однако это не гарантирует, что запрашиваемая операция непременно выполнится успешно, если её повторить с помощью функций OrderSend или OrderSendAsync. Между вызовами могут измениться торговые условия или у брокера на сервере применены настройки для конкретной внешней торговой системы, которые невозможно учесть в алгоритме формальной проверки, которую делает OrderCheck.
Для получения описания предполагаемого финансового результата следует анализировать поля структуры result.
В отличие от функции OrderCalcMargin, которая рассчитывает оценку требуемого залога только под одну предполагаемую позицию или ордер, OrderCheck учитывает, хоть и в упрощенном режиме, общее состояние торгового счета. Так, она заполняет поле margin в структуре MqlTradeCheckResult и прочие связанные поля (margin_free, margin_level) совокупными показателями, которые сложатся после выполнение приказа. Например, если уже открыта позиция по какому-либо инструменту на момент вызова OrderCheck и проверяемый запрос наращивает позицию, поле margin отразит сумму залога, включая прежние маржинальные обязательства. Если же новый приказ содержит операцию в противоположном направлении, размер маржи не увеличится (в реальности он должен уменьшится, потому что на неттинговом счете позиция таким образом может вообще закрыться, а на счете с хеджингом — применится хеджирующая маржа для встречных позиций, однако столь точный расчет функция не выполняет).
Прежде всего, OrderCheck пригодится программистам на начальном этапе знакомства с торговым API, чтобы экспериментировать с запросами, не отправляя их на сервер.
Протестируем работу функции OrderCheck с помощью простого неторгующего эксперта CustomOrderCheck.mq5. Мы сделали его именно экспертом, а не скриптом, для удобства пользования — так он будет оставаться на графике после прикрепления с текущими настройками, и их легко редактировать, меняя отдельные входные параметры. Если бы это был скрипт, нам пришлось бы каждый раз начинать заново установку нескольких полей со значений по умолчанию.
Чтобы запустить проверку, установим в OnInit таймер.
void OnInit()
|
А в обработчике таймера будет реализован основной алгоритм, причем в самом начале мы отменяем таймер, поскольку нам нужно, чтобы код выполнился один раз, а затем ждал, пока пользователь поменяет параметры.
void OnTimer()
|
Входные параметры эксперта полностью повторяют набор полей структуры торгового запроса.
input ENUM_TRADE_REQUEST_ACTIONS Action = TRADE_ACTION_DEAL;
|
Многие из них не влияют на проверку и финансовые показатели, но оставлены, чтобы можно было в этом убедиться.
По умолчанию состояние переменных соответствует запросу на открытие позиции минимальным лотом текущего инструмента. В частности, параметр Type в отсутствие явной инициализации получит значение 0, которое равно элементу ORDER_TYPE_BUY структуры ENUM_ORDER_TYPE. В параметре Action мы задали явную инициализацию, потому что 0 не соответствует ни одному элементу перечисления ENUM_TRADE_REQUEST_ACTIONS (первый элемент TRADE_ACTION_DEAL равен 1).
void OnTimer()
|
Заполняем структуру. В реальных роботах обычно требуется присвоить только несколько полей, но поскольку этот тест носит универсальный характер, мы должны обеспечить передачу любых параметров, которые введет пользователь.
request.action = Action;
|
Обратите внимание, что здесь мы пока не делаем нормализацию цен и лотов, хотя в реальной программе она требуется. Тем самым данный тест дает возможность ввести "неровные" значения и убедиться, что они приводят к ошибке. В последующих примерах нормализация уже будет включена.
Затем вызываем OrderCheck и выводим в журнал структуры request и result. Из последней нас интересует, на самом деле, только поле retcode, поэтому оно дополнительно печатается с "расшифровкой" в виде текста, макросом TRCSTR (TradeRetcode.mqh). Вы также можете анализировать строковое поле comment, но его формат может меняться, так что оно в большей степени подойдёт для отображения пользователю.
ResetLastError();
|
Вывод структур обеспечивает вспомогательная функция StructPrint, которая основана на ArrayPrint. Из-за этого мы пока получим "сырое" отображение данных — в частности, элементы перечислений представлены числами "как есть". Позднее мы разработаем функцию для более дружественного (понятного для пользователя) вывода структуры MqlTradeRequest (см. TradeUtils.mqh).
Чтобы облегчить анализ результатов, в начале функции OnTimer выведем текущее состояние счета, а в конце для сравнения — вычислим для заданной торговой операции маржу с помощью функции OrderCalcMargin.
void OnTimer()
|
Ниже представлен пример вывода в журнал на "XAUUSD" с настройками по умолчанию.
AccountInfoDouble(ACCOUNT_EQUITY)=15565.22 / ok AccountInfoDouble(ACCOUNT_PROFIT)=0.0 / ok AccountInfoDouble(ACCOUNT_MARGIN)=0.0 / ok AccountInfoDouble(ACCOUNT_MARGIN_FREE)=15565.22 / ok AccountInfoDouble(ACCOUNT_MARGIN_LEVEL)=0.0 / ok OrderCheck(request,result)=true / ok [action] [magic] [order] [symbol] [volume] [price] [stoplimit] [sl] [tp] [deviation] [type] » 1 0 0 "XAUUSD" 0.01 1899.97 0.00 0.00 0.00 0 0 » » [type_filling] [type_time] [expiration] [comment] [position] [position_by] [reserved] » 0 0 1970.01.01 00:00:00 "" 0 0 0 OK_0 [retcode] [balance] [equity] [profit] [margin] [margin_free] [margin_level] [comment] [reserved] 0 15565.22 15565.22 0.00 19.00 15546.22 81922.21 "Done" 0 OrderCalcMargin(Type,symbol,volume,price,margin)=true / ok margin=19.0 / ok |
А вот пример с оценкой предполагаемого увеличения маржи на счете, где уже есть открытая позиция, и мы её собираемся удвоить.
AccountInfoDouble(ACCOUNT_EQUITY)=9999.540000000001 / ok AccountInfoDouble(ACCOUNT_PROFIT)=-0.83 / ok AccountInfoDouble(ACCOUNT_MARGIN)=79.22 / ok AccountInfoDouble(ACCOUNT_MARGIN_FREE)=9920.32 / ok AccountInfoDouble(ACCOUNT_MARGIN_LEVEL)=12622.49431961626 / ok OrderCheck(request,result)=true / ok [action] [magic] [order] [symbol] [volume] [price] [stoplimit] [sl] [tp] [deviation] [type] » 1 0 0 "PLZL.MM" 1.0 12642.0 0.0 0.0 0.0 0 0 » » [type_filling] [type_time] [expiration] [comment] [position] [position_by] [reserved] » 0 0 1970.01.01 00:00:00 "" 0 0 0 OK_0 [retcode] [balance] [equity] [profit] [margin] [margin_free] [margin_level] [comment] [reserved] 0 10000.87 9999.54 -0.83 158.26 9841.28 6318.43 "Done" 0 OrderCalcMargin(Type,symbol,volume,price,margin)=true / ok margin=79.04000000000001 / ok |
Попробуйте менять любые параметры запроса и посмотрите, является ли запрос успешным. Некорректные сочетания параметров будут вызывать коды ошибок из стандартного перечня, но поскольку неверных вариантов гораздо больше, чем зарезервированных (самых распространенных ошибок), функция часто может возвращать обобщенный код TRADE_RETCODE_INVALID (10013). В связи с этим рекомендуется реализовать собственные проверки структуры с большей степенью диагностики.
При отправке реальных запросов на сервер этот же код TRADE_RETCODE_INVALID используется при различных непредвиденных обстоятельствах, например, при попытке повторно изменить ордер, операция изменения которого уже запущена (но еще не завершилась) во внешней торговой системе.