Торговля в ночное время
Что-то все так мне и не получается приступить к рассмотрению способов сортировки глобальных массивов. Сегодня я получил очередное письмо от читателя моего блога с просьбой помочь в реализации ночной торговли на языке MQL4. Данное письмо мне показалось интересным и я написал эксперта, который так интересовал автора письма.
Основная идея эксперта заключается в том, что определенное время (задается параметром StartTime) эксперт выставляет buy limit ордер на BuyLimit_Diff пипсов ниже Bid и sell limit ордер на SellLimit_Diff пипсов выше цены Ask. Дата эксперации ордеров задается в минутах в параметре Expiration. Если один из отложенных ордеров срабатывает, то второй удаляется (т.е. они OCO ордера - One Cancells Other). Stop Loss ордер выставляется на расстоянии BuyLimit_SL и SellLimit_SL пипсов от цены ордера соответственно.
Величина трейлинг стопа задается в параметре TrailingStop.
Исходный код эксперта:
//+-------------------------------------------------------------------------------------------+ //| Night_Trading.mq4 | //| Copyright (c) 2007, Andrey Vedikhin | //| http://www.vedikhin.ru | //| | //| Ver. 1.0 | //| | //| This expert advisor is distributed on an "AS IS" basis, WITHOUT | //| WARRANTY OF ANY KIND, either express or implied. | //| | //| You will use it on your own risk and Andrey Vedikhin will not be | //| liable for any damage, loss or profit of any kind while using or | //| misusing this expert advisor. | //+-------------------------------------------------------------------------------------------+ #property copyright "Copyright (c) 2007, Andrey Vedikhin" #property link "http://www.vedikhin.blog-forex.org" //---- input parameters extern int BuyLimit_SL=17; extern int SellLimit_SL=17; extern int BuyLimit_Diff=15; extern int SellLimit_Diff=19; // время в минутах, сколько отложенные ордера будут действительны extern int Expiration=240; // время, когда размещать отложенные ордера (по времени MetaTrader) extern string StartTime="16:00"; // время, когда нужно закрывать позиции extern string CloseTime="08:00"; extern int TrailingStop=60; extern double Lots=1.0; extern int Slippage=3; int MyMagicNumber = 777; datetime LastTradeTime; int StartHour; int StartMinute; int CloseHour; int CloseMinute; //+------------------------------------------------------------------+ //| expert initialization function | //+------------------------------------------------------------------+ int init() { //---- // установим ряд переменных, чтобы не вычислять их каждый раз StartHour = TimeHour(StrToTime(StartTime)); StartMinute = TimeMinute(StrToTime(StartTime)); CloseHour = TimeHour(StrToTime(CloseTime)); CloseMinute = TimeMinute(StrToTime(CloseTime)); // LastTradeTime - когда в последний раз выставляли отложенные ордера LastTradeTime = 0; int c_hour = TimeHour(TimeCurrent()); int c_minute = TimeMinute(TimeCurrent()); if ((c_hour>StartHour)||((c_hour==StartHour)&&(c_minute>=StartMinute))) LastTradeTime = TimeCurrent(); //---- return(0); } //+------------------------------------------------------------------+ //| expert deinitialization function | //+------------------------------------------------------------------+ int deinit() { //---- //---- return(0); } //+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ int start() { //---- int i; int t; datetime c_time = TimeCurrent(); int c_hour = TimeHour(c_time); int c_minute = TimeMinute(c_time); // Проверим, не пора ли нам выставлять отложенные ордера if (TimeDay(c_time)!=TimeDay(LastTradeTime)) { if ((c_hour>StartHour)||((c_hour==StartHour)&&(c_minute>=StartMinute))) { // выставим buy limit t = OrderSend(Symbol(), OP_BUYLIMIT, Lots, Bid-Point*BuyLimit_Diff, Slippage, Bid-Point*BuyLimit_Diff-BuyLimit_SL*Point, 0, NULL, MyMagicNumber, c_time+60*Expiration, Green); if (t==-1) { Print("Error ", GetLastError(), ": Start()->OrderSend() [Op=OP_BUYLIMIT]"); return(0); } // выставим sell limit if (OrderSend(Symbol(), OP_SELLLIMIT, Lots, Ask+Point*SellLimit_Diff, Slippage, Ask+Point*SellLimit_Diff+SellLimit_SL*Point, 0, NULL, MyMagicNumber, c_time+60*Expiration, Red)==-1) { LastTradeTime = TimeCurrent(); Print("Error ", GetLastError(), ": Start()->OrderSend() [Op=OP_SELLLIMIT]"); if (OrderDelete(t)) Print("Pending order #", t, " has been deleted"); else Print("Error ", GetLastError(), ": Start()->OrderDelete()"); } LastTradeTime = TimeCurrent(); return(0); } } // если один отложенный ордер сработал, то удалим второй t = -1; for (i=0; i<OrdersTotal(); i++) { if (!OrderSelect(i, SELECT_BY_POS)) { Print("Error ", GetLastError(), ": Start()->OrderSelect(", i, ") [OrderTotal()=", OrdersTotal(),"]"); continue; } if (OrderSymbol()!=Symbol()) continue; if (OrderMagicNumber()!=MyMagicNumber) continue; if ((OrderType() == OP_BUYLIMIT)||(OrderType() == OP_SELLLIMIT)) { if (t!=-1) { t = -1; break; } else { t = OrderTicket(); } } } if (t!=-1) { if (OrderDelete(t)) Print("Pending order #", t, " has been deleted [OCO]"); else Print("Error ", GetLastError(), ": Start()->OrderDelete() [OCO]"); } // не пора закрывать позиции? if (((c_hour>CloseHour)||((c_hour==CloseHour)&&(c_minute>=CloseMinute)))&& (TimeDay(c_time)!=TimeDay(LastTradeTime))) { for (i=0; i<OrdersTotal(); i++) { if (!OrderSelect(i, SELECT_BY_POS)) { Print("Error ", GetLastError(), ": Start()->OrderSelect(", i, ") [OrderTotal()=", OrdersTotal(),"]"); continue; } if (OrderSymbol()!=Symbol()) continue; if (OrderMagicNumber()!=MyMagicNumber) continue; if (OrderType() == OP_BUY) { if (!OrderClose(OrderTicket(), OrderLots(), Bid, Slippage)) Print("Error ", GetLastError(), ": Start()->OrderClose() [cannot close", " a buy position]"); return(0); } if (OrderType() == OP_SELL) { if (!OrderClose(OrderTicket(), OrderLots(), Ask, Slippage)) Print("Error ", GetLastError(), ": Start()->OrderClose() [cannot close", " a short position]"); return(0); } } } // управление трейлинг стопом for (i=0; i<OrdersTotal(); i++) { if (!OrderSelect(i, SELECT_BY_POS)) { Print("Error ", GetLastError(), ": Start()->OrderSelect(", i, ") [OrderTotal()=", OrdersTotal(),"]"); continue; } if (OrderSymbol()!=Symbol()) continue; if (OrderMagicNumber()!=MyMagicNumber) continue; double diff; if (OrderType() == OP_BUY) { diff = Bid-Point*TrailingStop-OrderStopLoss(); if (diff>0) { if (!OrderModify(OrderTicket(), OrderOpenPrice(), Bid-Point*TrailingStop, 0,0)) Print("Error ", GetLastError(), ": Start()->OrderModify() [trailing stop]"); else Print("Trailing stop on #", OrderTicket()," [place stop loss at ", Bid-Point*TrailingStop, "]"); } return(0); } if (OrderType() == OP_SELL) { diff = OrderStopLoss()-Ask-Point*TrailingStop; if (diff>0) { if (!OrderModify(OrderTicket(), OrderOpenPrice(), Ask+Point*TrailingStop,0,0)) Print("Error ", GetLastError(), ": Start()->OrderModify() [trailing stop]"); else Print("Trailing stop on #", OrderTicket()," [place stop loss at ", Ask+Point*TrailingStop, "]"); } return(0); } } //---- return(0); } //+------------------------------------------------------------------+
В следующем выпуске я разберу код эксперта "по косточкам" и расскажу о непонятных для Вас функциях.
Все статьи по теме "Пишем советников для MetaTrader 4".
- Механическая торговая система - миф или реальность?
- С чего начать при написании советника:
- Создаем нового советника - Настраиваем параметры. - Язык MetaQuotes Language 4:
Комментарии по теме "Торговля в ночное время"
Здравствуйте Андрей.
Спасибо за ваши старания, ваш блог достаточно интересен, особенно в вопросах программирования на MQL4.
Однако в данном случае есть некоторое противоречие. Дело в том, что вы пытаетесь выставить одновременно два ордера с привязкой к условию «время». В таком случае, если один из ордеров по какой-то причине не будет установлен, то значение переменной LastTradeTime все равно будет установлено как текущее время и повторно условие уже не сработает до завтра. Далее, естественным образом должен будет удалиться и второй ордер, так как он останется один. Вероятно, следовало бы устанавливать текущее значение LastTradeTime только в том случае, если оба ордера были выставлены.
Плюс к этому не плохо было бы использовать глобальные переменные (из другой вашей статьи), на тот случай, если торговля будет осуществляться по нескольким инструментам в одно и то же время. В противном случае, вероятность потерять ордера (или ордеры?) будет увеличиваться.
Возможно, я не прав и цель данной статью в том, чтобы показать, как работают функции времени, а не как торговать по времени. В таком случае, извините
:)
Автор: Mark Piccioli | 17.01.2007 10:14
Благодарю за столь лестные отзывы в адрес моего проекта.
Я абсолютино согласен с Ваши замечанием про LastTradeTime, однако Ваше решение, к сожалению, тоже не лишено недостатков. Если будет выставлен только один ордер, то на следующем тике эксперт снова попытается выставить оба ордера и мы получим в итоге три ордера. Решением может быть предварительный просмотр, не был ли уже какой-то из ордеров выставлен.
По поводу использования критических секций - я абсолютно с Вами согласен. Но цель этой статьи была не написать эксперта, который будет работать безошибочно во всех проблемных ситуациях, а показать как можно реализовать те или иные приемы управления ордерами.
Я подытожу весь предыдущий опыт и напишу идеального (с точки зрения реагирования на проблемные ситуации) эксперта позже. Это будет давно мною обещаемый эксперт по теории хаоса.
Автор: Андрей Ведихин | 23.01.2007 19:31