
В этот раз мы видоизменим функцию открытия ордеров с простого анализа предыдущей свечи на что-то более техническое. Вначале я решил поэкспериментировать и ввел метод «Орла и Решки» (сколько уже таких экспериментов было безуспешно проведено), использовал MathSrand() и MathRand(), но в итоге решил воспользоваться примером из учебника с использованием технического индикатора скользящего среднего.
Более подробно по способу использования этого индикатора вы можете прочитать в учебнике , мы же просто адаптируем его к нашему эксперту.
Некоторые изменения и дополнения в заголовке советника.
//| Forex-Grail.1.5.mq4 | //| http://hometrade.ru | /* 1.5 Вводим условия открытия и закрытия по техническому индикатору Moving Average на основе учебного примера */
Переключатель UsePreviousResult позволяет нам открывать новую сделку в том же направлении, что и предыдущая профитная сделка. Если же последняя сделка была убыточной, то открываемся в противоположном направлении. Естественно, если вы хотите использовать новый индикатор не только для новых сделок, но и для последующих, то оставьте UsePreviousResult = false.
Периоды Moving Average как и расстояние между ними оставлены без изменений, можно их оптимизировать под ваш рабочий период.
Структура ORDERS введена для ознакомления, для наших целей получения профита последнего закрытого ордера можно было бы обойтись и простой переменной, но нужно понемногу осваивать и более сложные вещи.
//-- 1.5 -- //Если последний ордер закрылся в профит, то в том же направлении откроемся, в противном случае перевернемся. Если UsePreviousResult = false - всё по сигналам extern bool UsePreviousResult = false; extern int Period_MA_1=11; // Период МА 1 extern int Period_MA_2=31; // Период МА 2 extern double Rastvor =28.0; // Расстояние между МА struct ORDERS { int Index; // Индекс в истории OrderSelect int OrderTicket; // OrderTicket string OrderSymbol; // OrderSymbol int OrderType; // OrderType double OrderOpenPrice; // OrderOpenPrice datetime OrderOpenTime; // OrderOpenTime double OrderLots; // OrderLots double OrderStopLoss; // OrderStopLoss double OrderTakeProfit; // OrderTakeProfit double OrderProfit; // OrderProfit double OrderClosePrice; // OrderClosePrice datetime OrderCloseTime; // OrderCloseTime double OrderCommission; // OrderCommission double OrderSwap; // OrderSwap int OrderMagicNumber;// OrderMagicNumber datetime OrderExpiration; // OrderExpiration string OrderComment; // OrderComment }; ORDERS Orders[1]; //массив ORDERS для одного последнего ордера //-- 1.5 --
В специальной функции OnTick() раньше других наших функций поставим новую функцию Closing(), в которой будут проверяться условия на закрытие ордеров и само это закрытие.
void OnTick() { ShowSpread(); //получим спред и отобразим его Closing(); //-- 1.5 -- закрытие позиций в первую очередь. Потом проверка баланса, а затем открытие новых ордеров ...
Претерпела изменение пользовательская функция Traiding(). Вначале проверяем, установлен ли флаг UsePreviousResult, если да, то в своей функции GetTicketLastClosePos() найдем последний закрытый ордер. Если такой ордер есть, то в случае его профитности, следующий ордер будет в том же направлении. В противном случае инвертируем его знак.
Ну а если UsePreviousResult=ложь, или закрытых ордеров нет, то открываться будем по сигналу, выдаваемому в нашей новой функции TradeDirection().
Следует отметить, что переключатель InvertEnter в случае использования сигналов iMA теряет свой смысл, мы тем самым отвергаем технический анализ. Но если в будущем в TradeDirection() будет другой алгоритм открытия позиции, он может опять пригодиться как и в истории со свечами. Хотя и сейчас никто не мешает вам поэкспериментировать с этим флагом смены направления торговли.
void Traiding() { int direction=0,ticket; if (TradesCount()>0) return; //уже есть открытые ордера // куда будем открываться при отсутствии ордеров if (UsePreviousResult && GetTicketLastClosePos(Symbol(),MagicNumber)) //если есть закрытый ордер, узнаем прибыльный ли он и в каком направлении { int type= Orders[0].OrderType; double take= Orders[0].OrderProfit; if (take>0) { Alert("открываемся туда же type=",type," take=",take); direction=type; //если последний ордер был в плюсе, откроемся в ту же сторону } else { direction=InvertPosition(type); //вы противном случае перевернемся Alert("открываемся в противоположную type=",type," take=",take); } } else //ордеров в истории еще нет или не установлен UsePreviousResult, откроемся по сигналу { direction = TradeDirection(); //-- 1.5 -- if (InvertEnter) direction=InvertPosition(direction); //переменим позицию если задано } if (direction==-1) return; //нет торговых сигналов на открытие позиции ///--1.5-- ...
В нашей новой функции определения направления торговли я не стал убирать предыдущие сигналы, просто закомментировал их. Как выше писал, за подробностями по средним iMA обращайтесь к учебному пособию по программировании на MetaQuotes Language 4 (MQL4).
//--1.5-- int TradeDirection() { //-- 1.4.1 куда будем открываться при отсутствии ордеров /* if (Open[1]<Close[1]) { direction=OP_BUY; } else { direction=OP_SELL; } */ /* return MathRand() % 2; //либо 0 либо 1 */ int direct=-1; double MA_1_t, //Текущее значение МА_1 MA_2_t; //Текущее значение МА_2 // Предварительная обработка if(Bars < Period_MA_2) // Недостаточно баров для анализа { Alert("Недостаточно баров в окне. Эксперт не дает сигналов на вход."); return direct; } // Торговые критерии MA_1_t=iMA(NULL,0,Period_MA_1,0,MODE_LWMA,PRICE_TYPICAL,0); // МА_1 MA_2_t=iMA(NULL,0,Period_MA_2,0,MODE_LWMA,PRICE_TYPICAL,0); // МА_2 if (MA_1_t > MA_2_t + Rastvor*Point) // Если разница между МА 1 и 2 большая { direct=OP_BUY ; // Критерий открытия ордера Buy } if (MA_1_t < MA_2_t - Rastvor*Point) // Если разница между МА 1 и 2 большая { direct=OP_SELL ; // Критерий открытия ордера Sell } return direct; }
В функции Closing() мы проходим по всем открытым торговым ордерам и проверяем, нужно ли их закрывать
//Проверяем условия на закрытие позиций, закрытие позиций void Closing() { //пробежимся по открытым ордерам и для каждого проверим условия закрытия, при необходимости закроем for(int trade=0;trade<OrdersTotal();trade++) //пройдем по всем ордерам { if (OrderSelect(trade, SELECT_BY_POS, MODE_TRADES)==true) //смотрим только те что в рынке { if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue; //не наш ордер, пропускаем if (ClosingCondition()) { MyOrderClose(); //моя обертка над функцией закрытия ордера предварительно выбранного в OrderSelect } } } }
В функции ClosingCondition() мы также используем индикатор скользящие средние для выдачи сигналов на закрытие позиции.
//Проверяем условия закрытия с рынка выбранного в OrderSelect ордера bool ClosingCondition() { int close=false; double MA_1_t, //Текущее значение МА_1 MA_2_t; //Текущее значение МА_2 int type=OrderType(); //тип текущего ордера // Предварительная обработка if(Bars < Period_MA_2) // Недостаточно баров для анализа { Alert("Недостаточно баров в окне. Эксперт не дает сигналов на выход."); return false; } // Торговые критерии MA_1_t=iMA(NULL,0,Period_MA_1,0,MODE_LWMA,PRICE_TYPICAL,0); // МА_1 MA_2_t=iMA(NULL,0,Period_MA_2,0,MODE_LWMA,PRICE_TYPICAL,0); // МА_2 if (MA_1_t > MA_2_t + Rastvor*Point) // Если разница между МА 1 и 2 большая { if (type==OP_SELL) return true; // Критерий закрытия ордера Sell } if (MA_1_t < MA_2_t - Rastvor*Point) // Если разница между МА 1 и 2 большая { if (type==OP_BUY) return true; // Критерий закрытия ордера Buy } return close; } //---1.5 --
MyOrderClose() - это моя обертка-заготовка вокруг стандартной функции OrderClose. Перед её вызовом нужно предварительно выбрать текущий ордер с помощью функции OrderSelect()!
//--1.5-- //закрываем предварительно выбранный функцией OrderSelect ордер bool MyOrderClose() { double price; int ticket=OrderTicket(); int type=OrderType(); double lots=OrderLots(); RefreshRates(); //На всякий случай обновим котировки if (type==OP_BUY) price=Bid; else price=Ask; if(OrderClose(ticket,lots,price,SlipPage)) { return true; } else { Print("Ошибка OrderClose:",GetLastError()," ticket=",ticket," lots=",lots," price=",price); return false; } } //--1.5--
Ну вот на сегодня и все. Вот один из репортов тестирования данной модификации советника на паре Евро/Доллар на 5 минутках с начала текущего года.
И не забываем про конкурс поиска ошибок в исходном коде советника "Forex Grail".!
Предыдущая часть 5: Система Мартингейла.
Следующая часть 7: Выстраивание колен.