Проект - "Газонокосилка". Советник "gazonkos".
Опубликовано: 01.01.2007
Механическая торговая система «Газонокосилка» названа, так потому что советник, торгующий по этой системе, должен будет «косить капусту» понемногу, но часто. Поэтому такие параметры как стоплосс и тейкпрофит выбраны небольшими, чтобы сделки могли закрываться при небольших движениях цены. Однако, советник не должен пипсовать и оптимальное для него – это одна, две сделки в день.
Торговые правила системы «Газонокосилка»:
1. Входим на откате ценового движения
2. Выходим по Стоплосс и Тейкпрофит
Таким образом, сначала необходимо определить ценовое движение или импульс (тут может быть множество вариантов). Затем дожидаемся отката цены (так же множество вариантов) и входим в рынок.
Ценовое движение
Определять ценовое движение можно множеством различных способов. Это движение, как правило, можно охарактеризовать несколькими свойствами, такими как силой движения, длительностью и другими.

Однако, для первоначальной версии советника упростим процедуру определения движения (импульса) цены. Как и в советнике «20/200_pips» будем определять изменение цены за некоторый промежуток времени. А, если еще точнее, то будем смотреть разницу между ценами закрытия баров в момент времени t1 и t2 (см. рисунок). Если цена Close за промежуток времени от t1 до t2 увеличилась на величину большую чем delta, то это будем воспринимать, как наличие ценового движения вверх, а если уменьшилась на delta и более – то вниз.
Откат
После сильного движения цены часто происходит ее откат в обратном направлении. Вот этот откат мы и будем ловить в советнике. В первоначальном варианте будем считать откатом движение цены в обратном импульсу направлении на некоторую величину. Например, для длинной позиции будем сравнивать максимальное значение цены за период ожидания отката с текущим значением и, если разница будет больше некоторого значения, имеем откат, а значит и сигнал на покупку.

Время ожидания отката, для начала, ограничим одним баром, на котором получен сигнал об импульсе цены. Таким образом, перейдя в состояние ожидания отката цены, советник будет в течение одного бара ожидать отката, а если его не произойдет, то перейдет в первоначальное состояние и начнет все сначала.
При работе советника на часовом графике, одного бара будет достаточно для определения отката. Конечно, можно и нужно использовать более продвинутые способы определения отката, но об этом будет в последующих статьях по проекту «Газонокосилка».
Вход в позицию осуществляется сразу после того, как советник обнаружит откат ценового движения. Входим по направлению ценового движения, в надежде на то, что цена, после отката, продолжит свое движение.
Выход из позиции происходит по достижении Тейкпрофита или Стоплосса. Таким образом, советнику не нужно сопровождать открытую позицию с целью ее модификации или закрытия.
Советник «gazonkos»
Всю работу торговой системы «Газонокосилка», можно разбить на несколько состояний:
1. Ждем движения цены (импульса)
2. Следим за ценой и ждем отката
3. Входим в позицию
Поэтому советник написан в том же стиле. Это дает возможность составить легко-читаемый код советника, и возможность легко изменять код под свои нужды. Вот его структурная схема:

Советник следует запускать на графиках с периодом H1 (это связано лишь с выбранными способами определения движения цены и ее отката). А тестирование проводить только по модели «все тики», т.к. в данной системе требуется определять откат цены внутри часового бара, что возможно только в модели «все тики» при наличии минутной истории.
Итак, подытожим правила работы системы заложенные в первой версии советника «gazonkos»:
Советник с приходом нового часового бара проверяет, не было ли движения цены (импульса). Если был, то в течение этого часового бара проверяем, не было ли отката цены, если был, то тут же входим в рынок, если отката не было, то переходим в режим ожидания движения цены и все повторяется.
//+------------------------------------------------------------------+ //| gazonkos expert.mq4 | //| 1H EUR/USD | //| Smirnov Pavel | //| www.autoforex.ru | //+------------------------------------------------------------------+ #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)//функция возвращает количество открытых ордеров с magic = MagicValue { int j=0; int i; for (i=0;i<OrdersTotal();i++)//Производим просмотр среди всех открытых ордеров { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))//Выбираем по-порядку ордера { if (OrderMagicNumber()==MagicValue) j++; //Подсчитываем только те у котроых нужный magic } else { Print("gazonkos expert: OrderSelect() в OrdersTotalMagic() вернул ошибку - ",GetLastError()); return(-1); } } return(j);//Возвращаем количество подсчитанных ордеров с magic = MagicValue. } int init() { return(0); } int deinit() { return(0); } int start() { // STATE = 0 Ждем сигнала к началу работы советника ------------------------------------------------------------ if (STATE==0) { bool cantrade=true; if(TimeHour(TimeCurrent())==LastTradeTime) cantrade=false;//запрещаем торговать пока не наступит новый час после последней //открытой сделки (чтобы избежать множественных открываний сделок на одном и том же часовом баре) if(OrdersTotalMagic(magic)>=active_trades) cantrade=false;// проверяем на допустимое количество открытых ордеров if(cantrade) // если не было ни одного запрета на открытие сделок, то переходим к ожиданию сигналов системы на открытие ордеров STATE=1; } // STATE = 1 Ждем импульса (движения) цены ---------------------------------------------------------------------- if (STATE==1) { if((Close[t2]-Close[t1])>delta*Point)// сигнал для входа в длинную позицию { Trade = 1; //идентификатор позиции, для которой получен сигнал на открытие "-1" - короткая позиция, "1"-длинная maxprice=Bid;// запоминаем текущее положение цены (необходимо для определения отката в STATE=2) LastSignalTime=TimeHour(TimeCurrent());//Запоминаем время получения сигнала STATE = 2; // перейти в следующее состояние } if((Close[t1]-Close[t2])>delta*Point)// сигнал для входа в короткую позицию { Trade = -1; // идентификатор позиции, для которой получен сигнал на открытие "-1" - короткая позиция, "1"-длинная minprice=Bid;// запоминаем текущее положение цены (необходимо для определения отката в STATE=2) LastSignalTime=TimeHour(TimeCurrent());//Запоминаем время получения сигнала STATE = 2; // перейти в следующее состояние } } // STATE = 2 - Ждем отката цены -------------------------------------------------------------------------------- if (STATE==2) { if(LastSignalTime!=TimeHour(TimeCurrent()))//Если на баре на котором получен сигнал не произошло отката,то переходим в состояние STATE=0 { STATE=0; return(0); } if(Trade==1)// ожидаем отката для длинной позиции { if(Bid>maxprice) maxprice=Bid;//если цена пошла еще выше, то меняем значение maxprice на текущее значение цены if(Bid<(maxprice-Otkat*Point))// проверяем наличие отката цены после импульса STATE=3;//если произошел откат на величину Otkat, то переходим в состояние открытия длинной позиции } if(Trade==-1)// ожидаем отката для короткой позиции { if(Bid<minprice) minprice=Bid;//если цена пошла еще ниже, то меняем значение minprice на текущее значение цены if(Bid>(minprice+Otkat*Point))// проверяем наличие отката цены после импульса STATE=3;//если произошел откат на величину Otkat, то переходим в состояние открытия короткой позиции } } // STATE = 3 - открываем позиции согласно переменной Trade ("-1" - короткую, "1" - длинную) -------------------- 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 - Максимальное количество одновременно открытых ордеров.
О результатах тестирования советника и, возможно, о его модификациях читайте в следующих статьях.
Продолжение следует ...
Смирнов П.В.