Проект - "Газонокосилка". Советник "gazonkos".
Механическая торговая система «Газонокосилка» названа, так потому что советник, торгующий по этой системе, должен будет «косить капусту» понемногу, но часто. Поэтому такие параметры как стоплосс и тейкпрофит выбраны небольшими, чтобы сделки могли закрываться при небольших движениях цены. Однако, советник не должен пипсовать и оптимальное для него – это одна, две сделки в день.
Торговые правила системы «Газонокосилка»:
1. Входим на откате ценового движения
2. Выходим по Стоплосс и Тейкпрофит
Таким образом, сначала необходимо определить ценовое движение или импульс (тут может быть множество вариантов). Затем дожидаемся отката цены (так же множество вариантов) и входим в рынок.
Ценовое движение
Определять ценовое движение можно множеством различных способов. Это движение, как правило, можно охарактеризовать несколькими свойствами, такими как силой движения, длительностью и другими.
Однако, для первоначальной версии советника упростим процедуру определения движения (импульса) цены. Как и в советнике «20/200_pips» будем определять изменение цены за некоторый промежуток времени. А, если еще точнее, то будем смотреть разницу между ценами закрытия баров в момент времени t1 и t2 (см. рисунок). Если цена Close за промежуток времени от t1 до t2 увеличилась на величину большую чем delta, то это будем воспринимать, как наличие ценового движения вверх, а если уменьшилась на delta и более – то вниз.
Откат
После сильного движения цены часто происходит ее откат в обратном направлении. Вот этот откат мы и будем ловить в советнике. В первоначальном варианте будем считать откатом движение цены в обратном импульсу направлении на некоторую величину. Например, для длинной позиции будем сравнивать максимальное значение цены за период ожидания отката с текущим значением и, если разница будет больше некоторого значения, имеем откат, а значит и сигнал на покупку.
Время ожидания отката, для начала, ограничим одним баром, на котором получен сигнал об импульсе цены. Таким образом, перейдя в состояние ожидания отката цены, советник будет в течение одного бара ожидать отката, а если его не произойдет, то перейдет в первоначальное состояние и начнет все сначала.
При работе советника на часовом графике, одного бара будет достаточно для определения отката. Конечно, можно и нужно использовать более продвинутые способы определения отката, но об этом будет в последующих статьях по проекту «Газонокосилка».
Вход в позицию осуществляется сразу после того, как советник обнаружит откат ценового движения. Входим по направлению ценового движения, в надежде на то, что цена, после отката, продолжит свое движение.
Выход из позиции происходит по достижении Тейкпрофита или Стоплосса. Таким образом, советнику не нужно сопровождать открытую позицию с целью ее модификации или закрытия.
Советник «gazonkos»
Всю работу торговой системы «Газонокосилка», можно разбить на несколько состояний:
1. Ждем движения цены (импульса)
2. Следим за ценой и ждем отката
3. Входим в позицию
Поэтому советник написан в том же стиле. Это дает возможность составить легко-читаемый код советника, и возможность легко изменять код под свои нужды. Вот его структурная схема:
Советник следует запускать на графиках с периодом H1 (это связано лишь с выбранными способами определения движения цены и ее отката). А тестирование проводить только по модели «все тики», т.к. в данной системе требуется определять откат цены внутри часового бара, что возможно только в модели «все тики» при наличии минутной истории.
Итак, подытожим правила работы системы заложенные в первой версии советника «gazonkos»:
Советник с приходом нового часового бара проверяет, не было ли движения цены (импульса). Если был, то в течение этого часового бара проверяем, не было ли отката цены, если был, то тут же входим в рынок, если отката не было, то переходим в режим ожидания движения цены и все повторяется.
Вот код советника, так же его можно посмотреть здесь:
#property copyright "Smirnov Pavel"
#property link "www.autoforex.ru"
extern int magic = 12345;
extern int TakeProfit = 16;
extern int Otkat = 16;
extern int StopLoss = 40;
extern int t1=3;
extern int t2=2;
extern int delta=40;
extern double lot = 0.1;
extern int active_trades=1;
int STATE=0;
int Trade=0;
double maxprice=0.0;
double minprice=10000.0;
int ticket;
bool cantrade=true;
int LastTradeTime=0;
int LastSignalTime=0;
int OpenLong(double volume=0.1)
{
int slippage=10;
string comment="gazonkos expert (Long)";
color arrow_color=Blue;
ticket=OrderSend(Symbol(),OP_BUY,volume,Ask,slippage,Ask-StopLoss*Point,
Ask+TakeProfit*Point,comment,magic,0,arrow_color);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
{
Print("Buy order opened : ",OrderOpenPrice());
return(0);
}
}
else
{
Print("Error opening Buy order : ",GetLastError());
return(-1);
}
}
int OpenShort(double volume=0.1)
{
int slippage=10;
string comment="gazonkos expert (Short)";
color arrow_color=Red;
ticket=OrderSend(Symbol(),OP_SELL,volume,Bid,slippage,Bid+StopLoss*Point,
Bid-TakeProfit*Point,comment,magic,0,arrow_color);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
{
Print("Sell order opened : ",OrderOpenPrice());
return(0);
}
}
else
{
Print("Error opening Sell order : ",GetLastError());
return(-1);
}
}
int OrdersTotalMagic(int MagicValue)
{
int j=0;
int i;
for (i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
{
if (OrderMagicNumber()==MagicValue) j++;
}
else
{
Print("gazonkos expert: OrderSelect() в OrdersTotalMagic() вернул ошибку - ",GetLastError());
return(-1);
}
}
return(j);
}
int init()
{
return(0);
}
int deinit()
{
return(0);
}
int start()
{
if (STATE==0)
{
bool cantrade=true;
if(TimeHour(TimeCurrent())==LastTradeTime) cantrade=false;
if(OrdersTotalMagic(magic)>=active_trades) cantrade=false;
if(cantrade)
STATE=1;
}
if (STATE==1)
{
if((Close[t2]-Close[t1])>delta*Point)
{
Trade = 1;
maxprice=Bid;
LastSignalTime=TimeHour(TimeCurrent());
STATE = 2;
}
if((Close[t1]-Close[t2])>delta*Point)
{
Trade = -1;
minprice=Bid;
LastSignalTime=TimeHour(TimeCurrent());
STATE = 2;
}
}
if (STATE==2)
{
if(LastSignalTime!=TimeHour(TimeCurrent()))
{
STATE=0;
return(0);
}
if(Trade==1)
{
if(Bid>maxprice) maxprice=Bid;
if(Bid<(maxprice-Otkat*Point))
STATE=3;
}
if(Trade==-1)
{
if(Bid<minprice) minprice=Bid;
if(Bid>(minprice+Otkat*Point))
STATE=3;
}
}
if(STATE==3)
{
if(Trade==1)
{
OpenLong(lot);
LastTradeTime=TimeHour(TimeCurrent());
STATE=0;
}
if(Trade==-1)
{
OpenShort(lot);
LastTradeTime=TimeHour(TimeCurrent());
STATE=0;
}
}
return(0);
}
|
Код советника хорошо закомментирован и, благодаря блочной структуре, легок для восприятия и понимания принципов работы. Поэтому я не стану углубляться в описании его работы.
Приведу лишь описание входных параметров (внешних переменных) советника по которым можно будет проводить оптимизацию:
magic – магический номер, используя который, советник работает только со своими ордерами.
TakeProfit - Уровень тейкпрофит в пунктах. Он выставляется для всех ордеров при открытии.
Otkat - Величина отката в пунктах. При откате цены на эту величину происходит переход советника в состояние открытия сделки.
StopLoss - уровень стоплосса в пунктах. Как и TakeProfit выставляется при открытии позиции.
t1 – номер бара, который участвует в определении движения цены.
t2 - номер бара, который участвует в определении движения цены.
delta – величина используемая при определении импульса движения цены.
lot - Размер позиции.
active_trades - Максимальное количество одновременно открытых ордеров.
О результатах тестирования советника и, возможно, о его модификациях читайте в следующих статьях.
Продолжение следует ...
Обсуждение системы «Газонокосилка» на форуме.
С Уважением.
Смирнов П.В.