Добро пожаловать на вторую часть серии уроков по созданию Вашего первого советника.
В предыдущем уроке мы добавили в код, который нам сгенерировал помощник, свою часть. Сегодня мы разберём полученную программу строчку за строчкой.
Вы готовы? Начнём!
Замечание: Наш советник предназначен для обучения и не будет (не нацелен на) извлекать прибыль.
Код, который у нас уже есть:
Код:
//+------------------------------------------------------------------+
//| My_First_EA.mq4 |
//| Kirill |
//| StockProgrammer@mail.ru |
//+------------------------------------------------------------------+
#property copyright "Kirill"
#property link "StockProgrammer@mail.ru"
//---- input parameters
extern double TakeProfit=350.0;
extern double Lots=0.1;
extern double TrailingStop=35.0;
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+
int init()
{
//----
//----
return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
//----
return(0);
}
int Crossed (double line1 , double line2)
{
static int last_direction = 0;
static int current_dirction = 0;
if(line1>line2)current_dirction = 1; //up
if(line1<line2)current_dirction = 2; //down
if(current_dirction != last_direction) //changed
{
last_direction = current_dirction;
return (last_direction);
}
else
{
return (0);
}
}
//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
//----
int cnt, ticket, total;
double shortEma, longEma;
if(Bars<100)
{
Print("bars less than 100");
return(0);
}
if(TakeProfit<10)
{
Print("TakeProfit less than 10");
return(0); // check TakeProfit
}
shortEma = iMA(NULL,0,8,0,MODE_EMA,PRICE_CLOSE,0);
longEma = iMA(NULL,0,13,0,MODE_EMA,PRICE_CLOSE,0);
int isCrossed = Crossed (shortEma,longEma);
total = OrdersTotal();
if(total < 1)
{
if(isCrossed == 1)
{
ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point, "My EA",12345,0,Green);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
Print("BUY order opened : ",OrderOpenPrice());
}
else Print("Error opening BUY order : ",GetLastError());
return(0);
}
if(isCrossed == 2)
{
ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,
Bid-TakeProfit*Point,"My EA",12345,0,Red);
if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
Print("SELL order opened : ",OrderOpenPrice());
}
else Print("Error opening SELL order : ",GetLastError());
return(0);
}
return(0);
}
for(cnt=0;cnt<total;cnt++)
{
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
if(OrderType()<=OP_SELL && OrderSymbol()==Symbol())
{
if(OrderType()==OP_BUY) // long position is opened
{
// should it be closed?
if(isCrossed == 2)
{
OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet); // close position
return(0); // exit
}
// check for trailing stop
if(TrailingStop>0)
{
if(Bid-OrderOpenPrice()>Point*TrailingStop)
{
if(OrderStopLoss()<Bid-Point*TrailingStop)
{
OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green);
return(0);
}
}
}
}
else // go to short position
{
// should it be closed?
if(isCrossed == 1)
{
OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet); // close position
return(0); // exit
}
// check for trailing stop
if(TrailingStop>0)
{
if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
{
if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
{
OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Red);
return(0);
}
}
}
}
}
}
return(0);
}
//+------------------------------------------------------------------+
Идея ТС нашего эксперта.
Прежде чем, разбирать код, рассмотрим, как устроена ТС, на которой основан наш эксперт. Любой эксперт должен решать, когда входить в рынок, и когда из него выходить. Основная идея при написании советников - определить каковы условия входов и выходов.
Наш советник прост и проста его идея. Рассмотрим её.
Используются две средние типа EMA (Exponential Moving Average): EMA 8 (быстрая) и EMA 13 (медленная).
Открытие позиций:
Наш советник будет открывать позиции при пересечении средних. Причём направление пересечения определяет в какую сторону будет открыта позиция.
Если быстрая EMA после пересечения окажется выше медленной EMA, то откроется сделка BUY (long).
Если быстрая EMA после пересечения окажется ниже медленной EMA, то откроется сделка SELL (short).
Одновременно может быть открыта только одна сделка.
Закрытие позиций:
Наш советник будет закрывать позиции при обратном пересечении средних.
Также позиция будет закрываться автоматически при достижении уровня стоп-лосс или тейк-профит.
Модификация позиций:
помимо открытия и закрытия позиций эксперт имеет возможность модификации уже открытых позиций. Эту возможночть мы будем использовать для реализации треилинг-стопа. Про треилинг-стоп мы поговорим позже в данном уроке, а сейчас продолжим разбор:
Код:
//---- input parameters
extern double TakeProfit=350.0;
extern double Lots=0.1;
extern double TrailingStop=35.0;
Код:
int Crossed (double line1 , double line2)
{
static int last_direction = 0;
static int current_dirction = 0;
if(line1>line2)current_dirction = 1; //up
if(line1<line2)current_dirction = 2; //down
if(current_dirction != last_direction) //changed
{
last_direction = current_dirction;
return (last_direction);
}
else
{
return (0);
}
}
Как я уже говорил, идея эксперта заключается в слежении за двумя средними и их пересечениями. Для достижения этой цели мы создаем функцию Crossed.
Функция Crossed принимает на вход две переменные типа double и возвращает переменную типа integer. Первый параметр - это тек. значение первой линии (в нашем случае - быстрой EMA). Второй параметр - это тек. значение второй линии (в нашем случае - медленной EMA).
При каждом вызове функция сохраняет информацию о взаиморасположении этих линий в статических переменных (cтатические переменные хранятся в постоянной области памяти программы, их значения не теряются при выходе из функции). При этом функция сравнивает тек. взаиморасположение линий с их взаиморасположением при предыдущем вызове.
- Функция возвращает 0, если взаиморасположение линий не изменилось.
- Функция возвращает 1, если взаиморасположение линий изменилось, и первая линия оказалась над второй.
- Функция возвращает 2, если взаиморасположение линий изменилось, и первая линия оказалась под второй.
Замечание: Вы можете использовать эту функцию в своих последующих советниках для слежения за пересечениями любых двух линий.
Посмотрим - как мы написали эту функцию?
Код:
int Crossed (double line1 , double line2)
Расположение кода функции значения не имеет. Я его поставил гад функцией start(), Вы можете поставить его где угодно.
Код:
static int last_direction = 0;
static int current_dirction = 0;
Код:
if(current_dirction != last_direction) //changed
Код:
last_direction = current_dirction;
return (last_direction);
Код:
else
{
return (0);
}
Наша программа будет вызывать эту функцию из функции start(), чтобы выполнять правильные действия.
В следующей части урока мы узнаем, как это реализовано, и познакомимся с очень важными торговыми функциями.
Удачи!