|
8. Закрытие и удаление ордеров
Теперь мы можем рассмотреть механизм удаления и закрытия рыночных
ордеров в МТ4. Мы знаем, что функцией OrderSelect(номер_в_списке, SELECT_BY_POS) мы
выбираем ордер, для которого потом получаем параметры. Функции OrderClose() и OrderDelete() требуют обязательный параметр –
номер тикета ордера, который мы получим с помощью OrderTicket(). Предположим, что нам необходимо
быстро закрыть все открытые ордера и удалить все отложенные.
Создадим для этого новый скрипт StopTrade.mq4 . Самый простой способ
будет опять таки пройти в цикле for() по
списку ордеров и в зависимости от типа ордера закрыть или удалить
каждый из них. Тип ордера мы получим функцией OrderType(). Если для удаления отложенного ордера
достаточно знать номер тикета, то закрытие ордера требует указания
правильной цены, по которой мы будем закрывать ордера типа OP_BUY или OP_SELL. Так
как в терминале может быть открыто множество ордеров по разным
инструментам, а исполняться скрипт будет на графике одного из них,
то нам нужна возможность получения значений Ask и Bid для любого
символа. Для этого служит функция MarketInfo() . Выражение MarketInfo(“GBPUSD”, MODE_ASK) означает цену Ask для символа GBPUSD.
Значение символа получаем из OrderSymbol().
Для подсказки я сделал таблицу списка ордеров, где выделенная строка
для ордера на 8-ой позиции в списке ордеров (подсвечена желтым
фоном) означает выбор этого ордера функцией OrderSelect(), а снизу разместил названия функций,
с помощью которых можно получить необходимые параметры ордера. На
рисунке выделена функция OrderTicket() для
получения номера тикета для выбранного ордера.
Мы имеем все необходимые данные для написания скрипта.
Но самой первой операцией в нашем скрипте будет проверка типа счета,
на котором он исполняется. Мы пишем этот скрипт как учебный, и
поэтому необходимо защититься от случайного использования его на
реальном счете. Для проверки типа счета используем функцию isDemo(), которая возвращает true для демо-счета, в противном случае false.
Восклицательный знак (!)
применяется для логических выражений и производит «переворот» :
выражение !true превращается в false, а !false
превращается в true. Выражение !isDemo() на демосчете вернет значение false ( true превратится в
false), а на реальном счету выдаст true. В этом случае скрипт досрочно завершит
работу, предварительно выдав предупреждение «На реальном счете
работа запрещена». Желательно всегда использовать такую защиту во
всех скриптах(совершающих торговые операции) и советниках, чтобы
избежать неприятных сюрпризов. В цикле при переборе ордеров нам
нужно будет проверять тип ордера, всего бывает 6 типов ордеров – 2
открытых (Buy или Sell) и 4 отложенных. Buy мы будем закрывать по
цене Bid, а Sell по цене Ask для того символа, по которому открыт
ордер. Оставшиеся 4 типа отложенных ордера хотелось бы удалять
одинаковым способом, не разбирая – buylimit или sellstop ордер перед
нами. Если мы посмотрим справку, то увидим что константы 0 и 1
означают открытые ордера, а отложенные ордера имеют OrderType()>1(2,3,4 и 5).
Теперь мы можем для ордеров с OrderType()>1 применять удаление OrderDelete(), а два остальных типа ордера
закрывать с помощью OrderClose(). Но писать
множество операций сравнения if(OrderType
равно n) после OrderSelect()
немного некрасиво, сделаем изящней. (Выражение a==b
делает сравнение a и b, и если они равны – возвращает true.) Для таких случаев, когда проверяется
равенство выражения ограниченному количеству значений, хорошо
подходит оператор switch() (переключатель).
Получился такой вариант:
Осталось прописать закрытие и удаление. С удалением
просто- пишем OrderDelete(ticket), где
ticket=OrderTicket(). Для закрытия открытых
ордеров получим текущие цены закрытия с помощью MarketInfo(OrderSymbol(), …). Размер закрываемой
позиции мы получим из OrderLots(),
проскальзывание (slippage) я задал равным 3, цвет рисуемой стрелки
закрытия я установил красным (Red). Если вы не помните, какие
параметры и в каком порядке необходимо передавать функции, то нажав
сочетание клавиш, можно получить подсказку. На рисунке я установил
курсов между скобками в OrderClose():
Теперь скрипт практически готов, осталось только
решить – в каком порядке закрывать и удалять ордера – с конца списка
или с его начала. В этом месте обычно делают вторую распространенную
ошибку.
Список ордеров в терминале является динамическим, в то
время как проход в цикле for() будет
статическим – если было сказано пройти от 0(нуля) до total-1
(количество ордеров в списке до начала удаления ордеров минус один)
, то так и будет. Если ордеров было 10, и мы начнем с начала списка
(с нулевого ордера по списку) , то после прохода от 0 до 4, в списке
ордеров останется 5 ордеров, и размещаться они будут опять на
позициях от 0 до 5. И проход в цикле от 5 до 9 будет выдавать
холостые выстрелы, оставшиеся ордера не будут закрыты или удалены.
Правильным будет удаление с конца списка, тогда не будет эффекта
обвала. На рисунке показан порядок удаления ордеров с конца списка,
размер списка после каждого удаления/закрытия будет уменьшаться, при
этом ни один ордер не будет пропущен.
После прохода до нулевой позиции ордеров в терминале
не останется. Окончательный вариант скрипта будет такой:
Напоследок, зададим горячую клавишу для нашего
скрипта. Например, нажатие Alt+A , будет вызывать на
исполнение наш скрипт на активном графике. Нажмем правой кнопкой
мышки на любом скрипте(индикаторе, советнике) и выберем «Установить
горячую клавишу».
Два раза кликнем напротив нашего скрипта в столбце
«Управление» и выберем из списка Alt. Затем зададим клавишу
(например А).
Скрипт готов к боевому применению на демо-счете.
Запускаем его горячими клавишами на графике USDCHF (это я сделал
специально, так как ордеров на этом инструменте в данный момент нет)
и за 25 секунд закрывается 14 открытых ордеров и удаляется один
отложенный – неплохой результат по скорости.
Перед исполнением скрипта были следующие ордера:
Сам скрипт StopTrade можно взять здесь
Rosh
|