Когда вы программируете советника, обычно вы хотите, чтобы он торговал за вас. В этой статье мы рассмотрим, как советник может открывать ордера с помощью функции OrderSend().
OrderSend() — это функция, которая позволяет открывать новые ордера. Она состоит из следующих аргументов:
int OrderSend( string symbol, // символ int cmd, // торговая операция double volume, // количество лотов double price, // цена int slippage, // проскальзывание double stoploss, // стоп-лосс double takeprofit, // тейк-профит string comment=NULL, // комментарий int magic=0, // идентификатор datetime expiration=0, // срок истечения ордера color arrow_color=clrNONE // цвет );
Разберем каждый агрумент подробнее:
- symbol — это торговый инструмент, которым вы хотите торговать, например, EURUSD. Обычно в советнике мы будем использовать функцию Symbol(), которая возвращает имя символа текущего графика.
- cmd — это тип ордера для отправки, который может быть OP_BUY или OP_SELL для рыночных ордеров на покупку и продажу. OP_BUYLIMIT, OP_SELLLIMIT, OP_BUYSTOP, OP_SELLSTOP для лимитных и стоп-ордеров.
- volume — количество лотов или размер позиции. К примеру, 0,1 или 0,01.
- price — цена, по которой ордер должен быть открыт. Для ордера на покупку это будет цена Ask. Для ордера на продажу, это будет цена Bid. Для отложенных ордеров это будет любая действительная цена, которая будет выше или ниже текущей цены.
- slippage — это приемлемая разница между ценой открытия, запрошенной клиентом и фактической ценой на сервере. Например, проскальзывание в 3 пункта позволяет открыть ордер, поданный по цене 1.1980, если цена на сервере отличается не более, чем на 3 пункта (то есть между 1.1983 и 1.1977).
- stoploss — значение стоп-лосса.
- takeprofit — значение тейк-профита. Важно помнить, что ордера стоп-лосс и тейк-профит не могут быть размещены слишком близко к цене открытия, иначе ордер не будет открыт. Также цены стоп-лосса и тейк-профита должны быть округлены к числу десятичных знаков, используемых брокером.
- comment — комментарий к ордеру.
- magic — это число, которое вы можете присвоить ордеру, чтобы его идентифицировать. Например, вы хотите использовать одно и то же число для всех ордеров, открытых вашим советником.
- expiration — это время, в течение которого отложенный ордер остается в силе. По истечении срока экспирации он не будет исполнен.
- arrow_color — это цвет стрелки на графике при отправке ордера.
Функция OrderSend() имеет тип данных int и возвращает номер тикета открытого ордера, если он отправлен успешно, и -1, если отправка ордера не удалась. В этом случае можно использовать функцию GetLastError(), чтобы увидеть причину ошибки.
Посмотрим на простой пример скрипта:
//+------------------------------------------------------------------+ //| Test-1.mq4 | //| Copyright 2019, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Александр Паркер" #property link "https://traderblog.net/" #property version "1.00" #property strict //Определяем базовые данные double StopLoss=30; //Размер стоп-лосса в пунктах. double TakeProfit=50; //Размер тейк-профита в пунктах. double LotSize=0.05; //Размер позиции в лотах. double Slippage=5; //Допустимое проскальзывание в пунктах. double Command=OP_BUY; //Тип ордера. В данном случае ордер на покупку. double CalculateNormalizedDigits() { if(Digits<=3){ return(0.01); } else if(Digits>=4){ return(0.0001); } else return(0); } //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { // Рассчитываем цены для стоп-лосса, тейк-профита. double nDigits=CalculateNormalizedDigits(); double OpenPrice=Ask; double StopLossPrice=Ask-StopLoss*nDigits; double TakeProfitPrice=Ask+TakeProfit*nDigits; //Определяем переменную для хранения результата работы функции OrderSend() int OrderNumber; OrderNumber=OrderSend(Symbol(),Command,LotSize,OpenPrice,Slippage,StopLossPrice,TakeProfitPrice); //Проверяем, исполнился ордер или нет, затем выводим результат. if(OrderNumber>0){ Alert("Ордер ",OrderNumber," открыт"); } else{ Alert("Ордер не открыт. Ошибка - ",GetLastError()); } }
Функция Symbol() возвращает текущий торговый инструмент графика. OP_BUY указывает, что это рыночный ордер на покупку. Ask — это предопределенная переменная в MQL4, в которой хранится самая последняя цена Ask.
Проскальзывание Slippage является целым числом. Если ваш брокер использует 4-значные котировки (2-значные для пар с йеной), 1 пункт будет равен 1 пункту. Однако, если ваш брокер предлагает 3 и 5-значные котировки, в этом случае вам нужно добавить дополнительный ноль.
Запустим скрипт на EURUSD:
Если мы захотим разместить отложенный ордер, цена открытия будет отличаться от текущей рыночной цены. Значения стоп-лосса и тейк-профита должны быть рассчитаны относительно цены открытия отложенного ордера.
В нашем примере мы будем использовать переменную PendingPrice для цены отложенного ордера. Ее можно рассчитать по нашему торговому алгоритму или в качестве внешнего параметра. Для стоп-ордера на покупку PendingPrice должна быть больше текущей цены Ask.
OrderSend(Symbol(),OP_BUYSTOP,LotSize,PendingPrice,Slippage,BuyStopLoss, BuyTakeProfit,"Buy Stop Ордер",MagicNumber,0,Green);
Мы используем OP_BUYSTOP для указания стоп-ордера на покупку и PendingPrice для цены открытия нашего ордера.
Лимитные ордера аналогичны стоп-ордерам, за исключением того, что цена отложенного ордера является обратной относительно текущей цены и типа ордера. Для лимитных ордеров на покупку цена отложенного ордера должна быть меньше текущей цены Bid.
OrderSend(Symbol(),OP_BUYLIMIT,LotSize,PendingPrice,Slippage,BuyStopLoss, BuyTakeProfit,"Buy Limit Ордер",MagicNumber,0,Green);
Мы использовали OP_BUYLIMIT, чтобы разместить лимитный ордер на покупку. В остальном параметры идентичны параметрам для стоп-ордеров.
Рассмотрим пример скрипта, который может помочь вам открыть ордер с большим количеством опций. Двумя основными ограничениями при открытии ордера вручную в MetaTrader являются:
- Ручной расчет размера позиции.
- Невозможность установить магическое число.
Скрипт позволит вам установить процент капитала, которым вы готовы рискнуть, а также рассчитать размер позиции в зависимости от установленного вами стоп-лосса.
#property copyright "Александр Паркер" #property link "https://traderblog.net/" #property version "1.00" #property strict #property show_inputs enum Operation{ buy=OP_BUY, //BUY sell=OP_SELL, //SELL }; extern double Lots=1; //Размер позиции. extern bool UseRiskPercentage=true; //Процент риска для расчета размера позиции. extern double RiskPercentage=2; //Процент доступного баланса торгового счета для риска. input Operation Command=buy; //Тип ордера. extern int TakeProfit=40; //Тейк-профит в пунктах. extern int StopLoss=20; //Стоп-лосс в пунктах. extern int Slippage=2; //Проскальзывание в пунктах. extern int MagicNumber=0; //Магическое число. extern string Cmt=""; //Комментарий. //Нормализуем пункты. double CalculateNormalizedDigits() { if(Digits<=3){ return(0.01); } else if(Digits>=4){ return(0.0001); } else return(0); } //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- //Если стоп-лосс не установлен и используется процент риска, останавливаем скрипт и выводим требуется стоп-лосс. if(StopLoss==0 && UseRiskPercentage){ Print("Необходим стоп-лосс, если вы используете процент риска."); return; } int Cmd=Command; //Нормализуем и рассчитываем размер позиции. double nTickValue=MarketInfo(Symbol(),MODE_TICKVALUE); double nDigits=CalculateNormalizedDigits(); if(Digits==3 || Digits==5){ Slippage=Slippage*10; nTickValue=nTickValue*10; } if(UseRiskPercentage){ Lots=(AccountBalance()*RiskPercentage/100)/(StopLoss*nTickValue); Lots=MathRound(Lots/MarketInfo(Symbol(),MODE_LOTSTEP))*MarketInfo(Symbol(),MODE_LOTSTEP); } //Установливаем цены открытия, стоп-лосса и тейк-профита double OpenPrice=0; double TakeProfitPrice=0; double StopLossPrice=0; if(Cmd==OP_BUY){ OpenPrice=NormalizeDouble(MarketInfo(Symbol(),MODE_ASK),Digits); if(TakeProfit!=0) TakeProfitPrice=NormalizeDouble(OpenPrice+TakeProfit*nDigits,Digits); if(StopLoss!=0) StopLossPrice=NormalizeDouble(OpenPrice-StopLoss*nDigits,Digits); } if(Cmd==OP_SELL){ OpenPrice=NormalizeDouble(MarketInfo(Symbol(),MODE_BID),Digits); if(TakeProfit!=0) TakeProfitPrice=NormalizeDouble(OpenPrice-TakeProfit*nDigits,Digits); if(StopLoss!=0) StopLossPrice=NormalizeDouble(OpenPrice+StopLoss*nDigits,Digits); } //Выводим всю информацию Print("Открываем ордер ",Command," размер ",Lots, " цены открытия ",OpenPrice," проскальзывание ",Slippage," стоп-лосс ",StopLossPrice," тейк-профит ",TakeProfitPrice," комментарий ",Cmt," магическое число ",MagicNumber); //Отправляем ордер. int OrderNumber; OrderNumber=OrderSend(Symbol(),Cmd,Lots,OpenPrice,Slippage,StopLossPrice,TakeProfitPrice,Cmt,MagicNumber); if(OrderNumber>0){ Print("Ордер ",OrderNumber," открыт"); } else{ Print("Ошибка - ",GetLastError()); } }