Учимся писать советник. Трал. Часть 2.

В то время как два моих тренировочных центовых счета теряют вполне реальные, пусть и небольшие деньги из-за каких-то недоработок или просто невезения, я решил ввести еще одно усовершенствование в наш суперский форексный грааль. Ну а разбором полетов сложившихся просадок займусь позже. Сегодня мы реализуем трейлинг стоп прибыльных позиций.

Но для начала небольшая модификация условий входа. В первой версии советника мы пробовали торговать как в направлении предыдущей свечи, так и в противоход. Чтобы каждый раз не модифицировать код и перекомпилировать советник, введем внешнюю переменную InvertEnter и в зависимости от этого будем менять сигнал на противоположный, если например сейчас флет, то ставим InvertEnter = истина и длинная позиция будет открываться после черной свечи, а не белой.
Вот как выглядит заголовок советника сейчас

...
 //внешние переменные
 extern int SlipPage = 3; //Проскальзывание
 extern int StopLoss = 20; //Стоп-лосс
 extern int TakeProfit = 20; //Тейк-профит
 extern int MagicNumber = 333; //Magic номер
 extern double StartLot = 0.1; // Размер лота для начала торгов
 extern double MaxLot = 1; //Максимально допустимый лот
 extern bool InvertEnter = false; //Вход в противоположную сторону от сигнала
 extern string startTrailingStop = "--- начало TrailingStop, трейлим столько пипс----";
 extern bool Trailing = false; //Использовать трейлинг стоп
 extern int TrailingStopStart=20; //Минимальный профит для трейлинга
 extern int TrailingStopStep=10; //Шаг трейлинга
 extern string endTrailingStop = "--- конец TrailingStop ----";
 //внутренние переменные
 double MINLOT,MAXLOT; //то что дилер нам дает
 bool HaveMoney=true; //запрещение на открытие новых торговых ордеров если например нет денег
 bool AlreadyNotMoneyAlert=false; //если уже сообщали что торговать не на что, то больше не будем
 ...

В функцию OnInit() добавили пару строк для трейлинга.

...
if (Digits == 5 || Digits == 3)
{
TakeProfit *= 10;
StopLoss *= 10;
TrailingStopStart*=10;
TrailingStopStep*=10;
}
...

Так как мы будем отслеживать профитные сделки, то выходить из специальной функции OnTick() из-за нехватки денег уже нельзя, ведь существующие открытые ордера могут при удачном сопровождении пополнить наш баланс. Вынесем эту проверку в отдельную функцию и заодно назначим переменным понятные названия для будущих поколений.

....
void OnTick()
{
HaveMoney=CheckMoney(); //есть деньги?
if (HaveMoney) Traiding(); //торговые операции если достаточно средств
if (Trailing) TrailingPositions();//если задано, то трейлим позиции, даже если нет денег на счету
}
....

Вот эта функция проверки свободной маржи. Кстати, можно задать например ограничение потери депозита в 90% и тут же это проверять.

...
//проверка на наличие денег на счет для торговли. Если нет денег - запретим торговать. Можно еще ввести ограничение на минимальный остаток баланса
bool CheckMoney()
{
double margin= MarketInfo(NULL, MODE_MARGINREQUIRED);
if ( AccountFreeMargin() < margin)
{
if (!AlreadyNotMoneyAlert) //уже сообщали что не хватает денег. Не будем долбить постоянно
{
Alert ("Денег нет! AccountFreeMargin= ",AccountFreeMargin()," margin= ",margin);
AlreadyNotMoneyAlert=true;
}

return false;
}
AlreadyNotMoneyAlert=false;
return true;
}
...

В функцию Traiding() добавим проверку переменой на переворот

...
// куда будем открываться при отсутствии ордеров
if (Open[1]<Close[1])
{
direction=OP_BUY;
}
else
{
direction=OP_SELL;
}

if (InvertEnter) direction=InvertPosition(direction); //переменим позицию если задано
...

А вот сама реализация изменения команды с лонг на шорт и наоборот. Для лимитных ордеров пока ничего не делаем.

....
//переворот позиции бай на селл и наоборот
int InvertPosition(int operat)
{
if (operat==OP_BUY) return OP_SELL;
else if (operat==OP_SELL) return OP_BUY;
else
{
Print ("Нераспознанная позиция для функции InvertPosition:", operat);
return -1;
}
}
....

Ну и наконец самая важная часть текущей модификации адвизора Форекс-Грааль: трейлинг-стоп прибыльных сделок с заданными параметрами. Надеюсь, комментарии в коде помогут понять его принцип действия.

...
//Трейлим ордера соответствующего символа.Трейлин стоп, ограничение убытков и рост профита, аналог стандартного терминального
void TrailingPositions()
{
double takeProfit,stopLoss;

for(int trade=0;trade<OrdersTotal();trade++) { if (OrderSelect(trade, SELECT_BY_POS, MODE_TRADES)) { if (OrderSymbol()!=Symbol() || OrderMagicNumber() != MagicNumber) continue; //это не наш ордер if(OrderType()==OP_BUY) // это наша открытая позиция лонг { takeProfit=OrderTakeProfit(); //текущий тейкпрофит if(NormalizeDouble(Bid-OrderOpenPrice(),Digits)>NormalizeDouble(TrailingStopStart*Point,Digits)) //цена Bid превысила минимально желательный профит
{
stopLoss=NormalizeDouble(Bid-TrailingStopStart*Point, Digits); //новый стоп-лосс будет на месте минимально желательного профита
if(OrderStopLoss() {
if (takeProfit<NormalizeDouble((stopLoss+TrailingStopStep*Point),Digits)) takeProfit=NormalizeDouble((stopLoss+TrailingStopStep*Point),Digits); //если существующий тейк ниже чем новый стоплос+трейлингстоп, то передвинем и его вверх //Это для проверки, можно удалить Print("Корректируем уровни стопа и профита для длинной позиции ",OrderTicket()," Bid=",Bid," новый/старый стоп ",stopLoss,"/",OrderStopLoss()," новый/старый профит ",takeProfit,"/",OrderTakeProfit()); MyOrderModify(OrderTicket(),OrderOpenPrice(),stopLoss,takeProfit,0,Green); } } } else if (OrderType()==OP_SELL) // это наша открытая позиция шорт { takeProfit=OrderTakeProfit(); //текущий тейкпрофит if(NormalizeDouble((OrderOpenPrice()-Ask),Digits)>NormalizeDouble((TrailingStopStart*Point),Digits)) // цена Ask ушла более чем на TrailingStopStart от цены открытия
{
stopLoss=NormalizeDouble((Ask+TrailingStopStart*Point),Digits); //новый стоп лосс
if((NormalizeDouble(OrderStopLoss(),Digits)>NormalizeDouble((Ask+TrailingStopStart*Point),Digits)) || (OrderStopLoss()==0)) //если прежний стоплосс выше чем наш желаемый минимальный профит, или он нулевой, то передвинем
{
if (takeProfit>NormalizeDouble((stopLoss-TrailingStopStep*Point),Digits)) takeProfit=NormalizeDouble((stopLoss-TrailingStopStep*Point),Digits); //если существующий тейк выше чем новый стоплос-трейлингстоп, то передвинем и его вниз

//Это для проверки, можно удалить Print("Корректируем уровни стопа и профита для короткой позиции ",OrderTicket()," Bid=",Bid," новый/старый стоп ",stopLoss,"/",OrderStopLoss()," новый/старый профит ",takeProfit,"/",OrderTakeProfit());
MyOrderModify(OrderTicket(),OrderOpenPrice(),stopLoss,takeProfit,0,Red);
}
}
}
}
}

return;
}
...

В функции трала TrailingPositions() мы использовали для модификации ордера собственную функцию MyOrderModify, которая пока является почти полным аналогом стандартной OrderModify. В дальнейшем в ней, как и в MyOrderSend, желательно сделать проверку и корректировку на разнообразные ошибки исполнения.

...
//Реализация модификации ордера
bool MyOrderModify(int ticket,double price,double stoploss,double takeprofit,datetime expiration,color arrow_color)
{
if(OrderModify(ticket,price,stoploss,takeprofit,expiration,arrow_color))
{
return true;
}
else
{
Print("Ошибка OrderModify:",GetLastError()," ticket=",ticket);
return false;
}
}
...

Заключительным шагом будет изменение номера версии советника, чтобы сохранить для потомков этапы большого пути создания торгового грааля 🙂

...
//+------------------------------------------------------------------+
//| Forex-Grail.1.1.mq4 |
//| Copyright 2016, HomeTrade.ru |
//| https://hometrade.ru |
//+------------------------------------------------------------------+
/*
Учимся писать советник.
Версия 1.0 - основные функции
1.1 Переменная InvertEnter, скользящий TrailigPositions(), Проверка денег для торговли
*/
#define VERSION "1.10"
#property version VERSION
#property copyright "Copyright 2016, HomeTrade.ru"
#property link "https://hometrade.ru"
....

Скомпилируем версию Forex-Grail.1.1.ex4 и прогоним в тестере. Ошибок в журнале нет, стопы трал передвигает корретно. Правда, до грааля похоже еще очень далеко. Но мы ведь начали только вчера…

grail-trail-1.1

Первая часть разработки советника описана в этой статье | Продолжение разработки

Вы можете оставить комментарий, или ссылку на Ваш сайт.

Оставить комментарий

Вы должны быть авторизованы, чтобы разместить комментарий.