"A
trend is your friend" ("Тренд - твой друг").С этой поговоркой трудно поспорить. Где еще, как не в трендах, делают
состояния? При какихиных обстоятельствах на рынке можно в считанные минуты стать
миллионером или нищим? Ведь любой тренд сопровождается всплеском эмоций, спектр
которых протягивается от безумного страха до неуемной жадности. Поэтому многие
трейдеры относятся к тренду, как к божеству - его и боятся, и ждут одновременно.
Но так как рынок, а тем более его
составляющая, которой является тренд, не терпит эмоций, нужно подойти к
торговле с четким математическим расчетом. Это поможет совершать сделки без
оглядки на эмоциональный фон.
Итак, какой инструмент лучше всего
характеризует тренд? Безусловно, набор средних скользящих. Какой набор средних
скользящих является классическим? "Самым классическим" является набор двух
средних, на основании которых создан индикатор MACD.
Но с другой стороны, две средние на "набор" не тянут. Требуется хотя бы три
средние. И здесь мы располагаем классикой - индикатор из системы Билла Вильямса
Аллигатор.
Но, как любой индикатив, индикатор
Аллигатор имеет свои недостатки, которые приводят к частым ложным сигналам. В
свою очередь, такие сигналы довольно дорого (в буквальном смысле) обходятся
трейдеру. Одним из решений этой проблемы является дополнение системы фильтром.
Им может быть что угодно - еще один индикатор, ограничение работы по времени,
расчет уровней поддержки и сопротивления. В данном случае стоит остановиться на
еще одном трендовом индикаторе. Речь идет о параболике -
Parabolic SAR. Чем он нам поможет? Это мы увидим уже в полном описании
торговой системы.
Первым сигналом начала тренда в системе
выступает именно параболик. Если его точки переместились под цену, то это
воспринимаем как начало восходящего тренда. Следует заметить - только начало.
Это еще не значит, что стоит сразу же открывать длинную позицию. А вот
имеющиеся короткие позиции необходимо закрыть. Для открытия длинной сделки
следует дождаться подтверждения тренда, что нужно ожидать уже от Аллигатора.
Его сигналом к покупке считается нахождение линии губ выше линии зубов, которые,
в свою очередь, находятся выше линии челюстей. При этом точка параболика не
должна быть выше линии челюстей, а цена открытия свечи должна быть выше линии
губ. Это позволит не открывать сделки, когда большая часть тренда уже прошла,
но, в то же время, дает веские основания для идентификации движения в качестве
тренда.
Для совершения коротких сделок, ждем
первого сигнала от параболика. Его точки должны переместиться в область над
ценой, что дает нам сигнал закрытия длинных сделок. Далее ждем, когда линия губ
Аллигатора окажется ниже линии зубов, а линия зубов - ниже линии челюстей. Вновь
проверяем, находятся ли точки параболика над линией челюстей Аллигатора, а цена
открытия свечи - под линией губ. Только при выполнении этих условий можно открывать
короткую сделку.
Описанный принцип проиллюстрирован на рис.
1, где зеленая линия - линия губ Аллигатора, красная - линия зубов, а синяя -
линия челюстей. Черные точки - это параболик. На рис. 1 очень хорошо видно, как
индикаторы фильтруют сигналы друг друга, не позволяя реагировать на поздние или
просто ложные сигналы.
Рис.
1. - Совершение сделок по стратегии "Ловец трендов".
Особых
отличий от "стандартной схемы" в стратегии нет. Поэтому данный советник от
предыдущих будет отличаться лишь сигнальной частью. Сигналов снова выходит пять:
0 - нет сигнала
1 - сигнал покупки
2 - сигнал продажи
3 - сигнал закрытия длинных сделок
4 - сигнал закрытия коротких сделок
В результате, знакомая функция
GetSignal принимает вид:
//+-------------------------------------------------------------------------------------+
//| Расчет значений параболика и Аллигатора с формированием сигналов для позиций |
//+-------------------------------------------------------------------------------------+
void GetSignal()
{
Signal = 0;
// - 1 - == Получение значений индикаторов ==============================================
double SAR = iSAR(Symbol(), 0, SARStep, SARMaximum, 0);
double Jaw = iAlligator(Symbol(), 0, JawPeriod, JawShift, TeethPeriod, TeethShift,
LipsPeriod, LipsShift, AlligatorMethod, AlligatorPrice,
MODE_GATORJAW, 0);
double Teeth = iAlligator(Symbol(), 0, JawPeriod, JawShift, TeethPeriod, TeethShift,
LipsPeriod, LipsShift, AlligatorMethod, AlligatorPrice,
MODE_GATORTEETH, 0);
double Lips = iAlligator(Symbol(), 0, JawPeriod, JawShift, TeethPeriod, TeethShift,
LipsPeriod, LipsShift, AlligatorMethod, AlligatorPrice,
MODE_GATORLIPS, 0);
// - 1 - == Окончание блока =============================================================
// - 2 - == Генерация сигнала ===========================================================
if (SAR < Low[1]) // Параболик под ценой
{
Signal = 3; // Закрытие SELL
if (SAR < Jaw && Open[] > Lips && Jaw < Teeth && Teeth < Lips) // Параболик ниже
// Аллигатора, а цена открытия свечи - выше
Signal = 1; // Открытие BUY
}
if (SAR > High[1]) // Параболик над ценой
{
Signal = 4; // Закрытие BUY
if (SAR > Jaw && Open[] < Lips && Lips < Teeth && Teeth < Jaw) // Параболик выше
// Аллигатора, а цена открытия свечи - ниже
Signal = 2;
}
// - 2 - == Окончание блока =============================================================
}
Бросается в глаза расчет значений индикаторов на нулевом баре
(см. блок 1). Обычно подобное не приветствуется, так как невозможно точно
смоделировать поведение цен "внутри бара". Но все дело в том, что эти значения
будут рассчитываться лишь для момента открытия нового бара. Все последующие
значения, которые можно рассчитать за время формирования бара, учитываться не
будут, так как функция GetSignal будет выполняться
всего один раз на один бар - при его открытии.
Во втором блоке генерация сигналов
"закрытие Sell"и "открытие
Buy"происходит вложено,
как это и предписано стратегией. Если значение параболика ниже минимума
предыдущей свечи, то это в любом случае сигнал "закрытие Sell"
(переменная Signal принимает значение 3).
И в то же время это условие является частью сигнала "открытие
Buy", которое подтверждается, когда параболик
оказывается ниже линии челюстей (переменная Jaw),
а остальные линии Аллигатора выстраиваются в движении наверх (линии
малого периода выше линий большего периода).
Такая же вложенность наблюдается у сигналов "закрытие
Buy"и "открытие
Sell". Если значение
параболика выше максимума предыдущей свечи, то это сигнал "закрытие
Buy" (переменная
Signal принимает значение 4).
Переход сигнала "закрытие Buy" в сигнал "открытие
Sell"происходит, когда
параболик становится выше линии челюстей Аллигатора, а линии Аллигатора
выстраиваются в движении вниз.
Вложенная обработка сигналов находит свое
продолжение и в функции start:
//+-------------------------------------------------------------------------------------+
//| Функция START эксперта |
//+-------------------------------------------------------------------------------------+
int start()
{
// - 1 - == Разрешено ли советнику работать? ===========================================
if (!Activate || FatalError) // Отключается работа советника, если функция
return(); // init завершилась с ошибкой или имела место фатальная ошибка
// - 1 - == Окончание блока ============================================================
// - 2 - == Сбор информации об условиях торговли ========================================
Spread = ND(MarketInfo(Symbol(), MODE_SPREAD)*Point); // текщий спрэд
StopLevel = ND(MarketInfo(Symbol(), MODE_STOPLEVEL)*Point); // текущий уровень стопов
// - 2 - == Окончание блока ============================================================
if (LastBar == Time[])
return();
// - 3 - == Расчет последних трех экстремумов ЗЗ ========================================
GetSignal();
// - 3 - == Окончание блока ============================================================
// - 4 - == Установка ордеров ===========================================================
if (Signal == 1 || Signal == 3) // Открытие BUY или закрытие SELL
{
int Res = CheckOrdersReal(OP_SELL); // Закрытие SELL и проверка существования BUY
if (Res == 0 && Signal == 1)// Открытие BUY только при условии успешного выполнения
{ // функции CheckOrdersReal и наличия сигнала открытия BUY
RefreshRates();
double SL = ND(IF(StopLoss == 0, 0, Ask - StopLoss*Tick));
double TP = ND(IF(TakeProfit == 0, 0, Ask + TakeProfit*Tick));
if (OpenOrderCorrect(OP_BUY, ND(Ask), SL, TP, True) != 0) // открытие позиции
return(); // если не удалось открыть, то попытка переносится на следующий тик
}
if (Res == 1) return();//если не удалось закрыть SELL, то сделаем это на следующем
// тике
}
if (Signal == 2 || Signal == 4) // Открытие SELL или закрытие BUY
{
Res = CheckOrdersReal(OP_BUY); // Закрытие BUY и проверка существования SELL
if (Res == 0 && Signal == 2)//Открытие SELL только при условии успешного выполнения
{ // функции CheckOrdersReal и наличия сигнала открытия SELL
RefreshRates();
SL = ND(IF(StopLoss == 0, 0, Bid + StopLoss*Tick));
TP = ND(IF(TakeProfit == 0, 0, Bid - TakeProfit*Tick));
if (OpenOrderCorrect(OP_SELL, ND(Bid), SL, TP, True) != 0) // открытие позиции
return(); // если не удалось открыть, то попытка переносится на следующий тик
}
if (Res == 1) return();//если не удалось закрыть SELL, то сделаем это на следующем
// тике
}
// - 4 - == Окончание блока ============================================================
LastBar = Time[];
return();
}
В четвертом блоке, где и происходит
непосредственное открытие сделок, первичная реакция происходит на два типа
сигнала - открытия и закрытия. Лишь после успешной отработки функции закрытия (CheckOrdersReal),
в дело вступает проверка наличия сигнала открытия.
Также стоит обратить внимание на принцип отработки новой
свечи. Он, конечно, довольно банальный - сохранение времени открытия самой
последней свечи в переменной LastBar. Но здесь
учитываются случаи, когда советнику не удалось в течение одного тика совершить
операции закрытия старой сделки и открытия новой. Для этого и проверяются
результаты вызова функций OpenOrderCorrect и
CheckOrdersReal. Если хотя бы одна из этих функций
завершилась неудачно, то выполнение до предпоследней строки функции
start так и не дойдет. В итоге в переменной
LastBar останется значение времени открытия предыдущей
свечи, что позволит выполнить все действия по открытию и закрытию сделок.
Основные функции советника описаны и он готов к работе, как в
тестере, так и онлайн. Но перед реальным использованием стоит протестировать
стратегию и увидеть ее слабые места.
Эксперт SARPlusAlligator протестируем
на промежутке 01.01.2008 - 19.09.2009, таймфрейм H1, значения входных параметров
- по умолчанию. Результаты приведены на рис. 2 - 5.
Рис. 2. - График кривой баланса,
получаемый при тестировании советника на валютной паре
EURUSD.
Рис. 3.
- График кривой баланса, получаемый при тестировании советника на валютной паре
USDCHF.
Рис. 4.
- График кривой баланса, получаемый при тестировании советника на валютной паре
GBPUSD.
Рис. 5.
- График кривой баланса, получаемый при тестировании советника на валютной паре
USDJPY.
На этот раз
результаты получились наполовину удачные (или наполовину неудачные - кому как
больше нравится), так как на двух из четырех валютных пар получена прибыль, а на
остальных двух - нет. Рассмотрим статистические характеристики прибыльных пар.
Это GBPUSD и USDJPY.
GBPUSD.Количество сделок 332. Чистая прибыль
4278.48 долларов против
максимальной просадки 859.18, что дает фактор восстановления
4.98. За все время
разработок стратегий в данной рубрике это самый высокий показатель! Если
исходить из начального капитала 10000, то максимальный риск за последние полтора
года составил 8,5%. Но при этом получена прибыль 42,7%. Довольно неплохой
бизнес. Ко всему прочему, характер кривой баланса очень близок к идеальному.
Рост наблюдается равномерный, нет периодов "застоя" или рывков. Поэтому
результаты смело можно относить к отличным.
USDJPY.Количество сделок 363. Чистая прибыль 2057.63
долларов против максимальной просадки 767.65.
Соответственно, фактор восстановления 2.68. Как уже ранее упоминалось, фактор
восстановления больше двух - очень неплохой показатель. Но здесь немного портит
картину вид кривой баланса. В первой половине теста особых изменений баланса не
происходило, затем же произошел двухэтапный рывок вверх, после которого
наблюдается небольшое затишье. Это свидетельствует о непостоянстве выявленной
закономерности, но, с другой стороны, может принести плоды сиюминутно, в отличие
от пары GBPUSD, где прибыль накапливается равномерно.
Такие удачные результаты тестирования по
парам GBPUSD и USDJPY
наводят на мысль о возможном применении стратегии на одной из самых волатильных
валютных пар Forex - GBPJPY, которая чудесным образом
сочетает закономерности обеих пар. Для "чистоты эксперимента" тестирование
произведем с точно такими же параметрами и на точно таком же промежутке (см.
рис. 6)
Рис.
6.
- График кривой баланса, получаемый при тестировании советника на валютной паре
GBPJPY.
Как видим, чуда
не случилось. Результаты взяли крайности от своих "родителей". От
USDJPY взято непостоянство, а от
GBPUSD - хорошая прибыль. Но в итоге это вылилось в такие показатели.
Количество сделок 357. Читая прибыль 6831.94, а максимальная просадка 2665.58
долларов. Фактор восстановления выходит 2.56. Это ниже, чем у обеих родительских
пар. Вид кривой баланса ужасен. Сначала серьезная просадка, потом резкий выход
из нее, а затем вновь топтание на месте. Поэтому работать по описанной стратегии на паре GBPJPY
не рекомендуется.
В последнее время приходит много писем с
просьбой о разработке торговых роботов под приложение
AutoGraf 4 (AG). Поэтому в дополнение к разработанному советнику
SARPlusParabolic предлагаю разработать стратегию
для приложения AutoGraf 4.
Работа стратегий
в AG немного отличается от работы стандартных
советников. Это стоит учитывать как программистам, так и обычным пользователям,
несмотря на то, что язык используется одинаковый - MQL4.
Ключевые отличия
самостоятельной работы эксперта от работы в среде AG
следующие:
В AG нет необходимости задавать
объем сделок, уровень стопа и уровень профита во внешних параметрах
эксперта. Они могут быть изменены "на лету" в любое время при помощи
соответствующих значков панели инструментови
эксперт получает их на каждом новом тике. Например, для изменения объема
сделки, нужно перетащить мышкой значение под надписью
"Lots" вверх, после чего появится шкала выбора размера
объема сделки. Поэтому внешних параметров у экспертов для
AG обычно не делают. Их, конечно, можно сделать, но изменять их
необходимо при запуске самого AG в параметрах
AT_1 - AT_31.
Все позиции и ордера, устанавливаемые экспертом из-под
AG, должны иметь в поле комментария подпись "AG_AT",
что дает возможность AG правильно идентифицировать ордера.
В коде основной функции эксперта (которая называется не
start, а AG_AT) для
окончания работы функции нужно применять оператор
return(1), вместо привычного return(0).
Обычный return(0) означает отключение эксперта.
В AG реализован принцип выдачи
служебных сообщений в окно индикатора AG_ind.
Поэтому вместо использования функции Comment,
необходимо использовать выдачу сообщений через массив
Message.
Существует еще масса других отличий, но они больше связаны
именно с возможностями AG и не относятся к самому
процессу перепрограммирования эксперта.
В результате, замена функции start
в случае реализации стратегии под AG будет выглядеть
так:
int AG_AT(int Parol_AT, double Order[][], string Object[], double Instrument[][][][],
int Ddraw_Object[][], double& Tuning[], double& Manager[][], string& Message[])
{
if (FatalError) return();
string Comm = "AG_AT"; // Комментарий (рекомендуется "AG_AT")
// - 1 - == Получение настроек AutoGraf =================================================
Lots = NormalizeDouble(Tuning[1],2); // Значение лотов
StopLoss = NormalizeDouble(Tuning[4],); // StopLoss (пунктов)
TakeProfit = NormalizeDouble(Tuning[5],); // TakeProfit (пунктов)
// - 1 - == Окончание блока =============================================================
// - 2 - == Сбор информации об условиях торговли ========================================
Tick = MarketInfo(Symbol(), MODE_TICKSIZE); // минимальный тик
Spread = ND(MarketInfo(Symbol(), MODE_SPREAD)*Point); // текщий спрэд
StopLevel = ND(MarketInfo(Symbol(), MODE_STOPLEVEL)*Point); // текущий уровень стопов
// - 2 - == Окончание блока ============================================================
if (LastBar == Time[])
return(1);
// - 3 - == Расчет последних трех экстремумов ЗЗ ========================================
GetSignal();
// - 3 - == Окончание блока ============================================================
// - 4 - == Установка ордеров ===========================================================
if (Signal == 1 || Signal == 3) // Открытие BUY или закрытие SELL
{
int Res = CheckOrdersReal(OP_SELL); // Закрытие SELL и проверка существования BUY
if (Res == 0 && Signal == 1)// Открытие BUY только при условии успешного выполнения
{ // функции CheckOrdersReal и наличия сигнала открытия BUY
RefreshRates();
double SL = ND(IF(StopLoss == 0, 0, Ask - StopLoss*Tick));
double TP = ND(IF(TakeProfit == 0, 0, Ask + TakeProfit*Tick));
if (OpenOrderCorrect(Message, OP_BUY, ND(Ask), SL, TP, True) != 0) // открытие
return(1); // если не удалось открыть, то попытка переносится на следующий тик
}
if (Res == 1) return(1);//если не удалось закрыть SELL, то сделаем это на следующем
// тике
}
if (Signal == 2 || Signal == 4) // Открытие SELL или закрытие BUY
{
Res = CheckOrdersReal(OP_BUY); // Закрытие BUY и проверка существования SELL
if (Res == 0 && Signal == 2)//Открытие SELL только при условии успешного выполнения
{ // функции CheckOrdersReal и наличия сигнала открытия SELL
RefreshRates();
SL = ND(IF(StopLoss == 0, 0, Bid + StopLoss*Tick));
TP = ND(IF(TakeProfit == 0, 0, Bid - TakeProfit*Tick));
if (OpenOrderCorrect(Message, OP_SELL, ND(Bid), SL, TP, True) != 0) // открытие
return(1); // если не удалось открыть, то попытка переносится на следующий тик
}
if (Res == 1) return(1);//если не удалось закрыть SELL, то сделаем это на следующем
// тике
}
// - 4 - == Окончание блока ============================================================
LastBar = Time[];
return(1);
}
По сути, ничего не изменилось. Лишь в вызовах функций,
выдающих сообщения, добавилась передача массива Message,
а параметры Lots, TakeProfit и
StopLoss теперь берутся из значений
AG. Остальные функции остаются такими же.
Для подключения стратегии к AG
нужно произвести следующие действия:
Скопировать файл AG_AT.ex4 в
папку MT4\experts\libraries
Запустить AutoGraf
Выставить правильные значения Lots,
StopLoss (SL) и TakeProfit (TP). Напомню, в
стратегии не используются стопы и профиты. Поэтому для получения
идентичного эффекта необходимо выставить SL = 0 и
TP = 0.
Передвинуть объект AT в верхнее
положение, что приведет к активации эксперта.
Все! Стратегия подключена и работает.
Файл AG_AT.mq4 приведен здесь для
возможности перекомпиляции эксперта AG_AT в случае выхода нового билда
(build) МТ4 (не путатьс
выходом нового терминала МТ5), так как под каждый новый билд все эксперты и
индикаторы желательно перекомпилировать заново.
Использование полученного
советника рекомендуется только в полуавтоматическом режиме под присмотром
трейдера и после всестороннего изучения слабых и сильных сторон стратегии.
Комментарии
Отправить комментарий