Учимся писать советник. Скользящие средние. Часть 6.

В этот раз мы видоизменим функцию открытия ордеров с простого анализа предыдущей свечи на что-то более техническое. Вначале я решил поэкспериментировать и ввел метод «Орла и Решки» (сколько уже таких экспериментов было безуспешно проведено), использовал 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 минутках с начала текущего года.

strategy-tester-fg15

И не забываем про конкурс поиска ошибок в исходном коде советника "Forex Grail".!

Предыдущая часть 5: Система Мартингейла.

Следующая часть 7: Выстраивание колен.

Комментирование и размещение ссылок запрещено.

Комментарии закрыты.