Торговля в ночное время
Что-то все так мне и не получается приступить к рассмотрению способов сортировки глобальных массивов. Сегодня я получил очередное письмо от читателя моего блога с просьбой помочь в реализации ночной торговли на языке 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