Торговый робот,
реализующий принципы стратегии
"Летучая мышь",
в рамках проекта MQLabs был создан в феврале 2010.
Возврат к стратегии спустя полгода и ее развитие стали возможны, благодаря идее,
выдвинутой на
форуме MQLabs. В полной
мере предложенный вариант стратегии не реализован, но некоторые полезные идеи из
него удалось почерпнуть.
В дальнейшем будет подразумеваться, что
читатель знаком с торговыми правилами стратегии "Летучая мышь". Поэтому
настоятельно рекомендуется ознакомиться с первой частью материала.
Оригинальная стратегия "Летучая мышь",
наряду с первичной позицией, оперирует двумя дополнительными ордерами, открытыми
в направлении первичной позиции, а также рассчитывает уровень общего профита для
всех сделок. Открытие и закрытие сделок только при пробитии линии поддержки или
сопротивления без использования уровня профита и дополнительных отложенных
ордеров не позволяли создать прибыльную торговую систему.
В настоящий момент решение найдено
благодаря использованию индикатора ZigZag, который
дает подтверждение сигнала открытия сделки. В результате от системы "Летучая
мышь" используется только принцип открытия первичной позиции - пересечение
линии поддержки или сопротивления. Это будет лишь первый сигнал, по получению
которого ничего не происходит. Для открытия позиции необходимо подтверждение от
ZigZag'a, а именно: формирование экстремума в
противоположную сторону от направления первого сигнала. При открытии
сделка снабжается уровнем стоп-приказа, который устанавливается и перемещается в
соответствии с правилами "Летучей мыши". А вот уровня профита у сделки нет. Это
позволяет получить максимальную прибыль при затяжном тренде, но дает малую
прибыль или даже убытки при краткосрочных движениях цены.
Опытный трейдер должен заметить, что
последний экстремум ZigZag'a - величина не постоянная
и может многократно изменять свое положение. Как же определить, что экстремум
больше не будет перемещаться? Никак. Если бы существовал четкий ответ на этот
вопрос, то такая тактика сама по себе стала бы наиболее успешной стратегией в
мире. От индикатора ZigZag в данном случае требуется
только момент появления нового экстремума. Это ни в коем случае не означает
сиюминутную смену направления движения цены, а выступает некоторым сигналом о
"пресыщении" текущего движения. Страховкой от дальнейшего движения цены в
направлении экстремума является уровень стоп-приказа сделки, установленный в
соответствии с показаниями индикатора ATR_the_Bat (см.
рис. 1).
Рис. 1. - Сигнал покупки и
подтверждение.
К моменту пробития ценой линии
сопротивления (жирная линия красного цвета) последний экстремум
ZigZag'a - это максимум. А для подтверждения покупки
необходим минимум. Поэтому на следующей, после пробития линии сопротивления,
свече длинная позиция не открывается. Необходимо дождаться формирования минимума
ZigZag'a. Это событие происходит через шесть часов
после пробития линии сопротивления. В итоге сделка открывается по меньшей цене,
чем уровень линии сопротивления. К тому же, размер Stop Loss
в пунктах очень мал, что позволяет безболезненно совершить
несколько убыточных сделок подряд.
В случае пробития линии поддержки
необходимо дождаться формирования максимума ZigZag'a.
Только после этого можно заключать сделку на продажу.
Подтверждение совершения сделки при помощи
индикатора ZigZag позволяет не только совершить сделку
по лучшей (относительно уровня пробития линии) цене, но и отфильтровать ложные
пробития линий поддержки и сопротивления при затяжном тренде.
Реализация описанных правил торговли
представлена в виде эксперта NightBatAndZZ. По
сравнению с экспертом
NightBat, из него исключены параметры Lots1,
FiboTarget1, Fibo2, Lots2, FiboTarget2 и Fibo3, Lots3,
FiboTarget3, т.к. установка дополнительных отложенных ордеров в данном
случае не используется. Вместо них введены параметры Lots
и PercentOfDepo, при помощи которых можно
указывать объем сделок эксперта. При ненулевом параметре Lots
устанавливается равный объем всех сделок, а при нулевом значении
Lots объем каждой сделки рассчитывается в процентах от
имеющихся на счете свободных средств (Free margin).
Величина процентов указывается в параметре PercentOfDepo.
Также советник
располагает временем функционирования, которое пользователь может указать с
точностью до часа. Когда текущий час будет равен значению, указанному в
параметре BeginHour (время серверное),
то эксперт может совершать открытие сделок до тех пор, пока не наступит час,
соответствующий значению параметра EndHour. После
этого открытие сделок при наличии сигналов открытия не производится, а имеющаяся
открытая сделка существует в соответствии со всеми условиями стратегии, пока не
будет закрыта по уровню стопа.
Для указания параметров индикатора
ZigZag,советник
NightBat содержит три входных параметра: ExtDepth, ExtDeviation
и ExtBackStep, полностью соответствующие входным
параметрам индикатора.
Рассмотрение основных функций
эксперта по обычаю начнем с GetSignal. Большая часть
функции, по сравнению с экспертом NighBat, не
претерпела изменений. Добавился лишь один блок - номер 5:
Определение существования экстремума производится на
текущем (бар №0) и ближайшем сформированном (бар №1) барах. Смысл такой двойной
проверки в том, что данные индикатора ZigZag эксперт
получает один раз в течение одного бара. Чаще всего это происходит при открытии
бара. Если цена открытия нулевой свечи выходит за пределы теней предыдущей
свечи, то экстремум ZigZag'a переместится на нулевую
свечу, а на первой свече будет значение 0. Если же цена открытия не вышла за
пределы теней предыдущей свечи, то экстремум останется на первой свече. Т.е. нет
четкого правила, с какой свечи нужно снимать новое значение индикатора
ZigZag.
Два последних аргумента при вызове функции
iCustom определяют буфер индикатора и номер свечи, с
которой снимается значение индикатора. Буфер №1 - это буфер максимумов, а буфер
№2 - буфер минимумов. Нулевое значение буфера свидетельствует об отсутствии
экстремума на запрашиваемой свече.
Сначала опрашивается текущая свеча. Если экстремум на ней
присутствует, то значение ZZHigh0 или
ZZLow0 не будет равно нулю. При нахождении максимума
переменная LastZZ принимает значение -1, что
подтверждает открытие короткой сделки. При нахождении минимума переменная
LastZZ принимает значение 1,
что подтверждает открытие длинной сделки.
Если экстремум на нулевой свече обнаружен не был, то
производится получение значений ZigZag'a на первой
свече по тому же алгоритму. Отсутствие экстремума на первой свече приводит к
сохранению значения переменной LastZZ. Для того чтобы
переменная LAstZZ всегда содержала правильное
значение, согласующееся с последним экстремумом ZigZag'a,
при старте эксперта производится подобная процедура (третий блок функции
init):
// - 3 - ===================== Нахождение последнего экстремума ZigZag ==================
double ZZHigh = 0, ZZLow = 0; // По умолчанию экстремума ZZ нет
int i = 0; // Поиск начинается с текущего бара
// - 3.1 - ============================= Цикл поиска экстремума ======================
while (ZZHigh == 0 && ZZLow == 0 && i < Bars) // Поиск, пока не будет найден экстремум
{ // или не будет достигнут конец исторических данных
ZZHigh = iCustom(NULL, 0, "ZigZag", ExtDepth, ExtDeviation, ExtBackStep, 1, i);
ZZLow = iCustom(NULL, 0, "ZigZag", ExtDepth, ExtDeviation, ExtBackStep, 2, i);
i++;
}
// - 3.1 - ============================= Окончание блока =============================
// - 3.2 - ====================== Достигнут ли успех в поиске экстремума =============
if (i == Bars)
{
Comment("Слишком мало исторических данных для текущих настроек ZigZag. "+
"Советник отключен!");
Print("Слишком мало исторических данных для текущих настроек ZigZag. "+
"Советник отключен!");
return(0);
}
// - 3.2 - ============================= Окончание блока =============================
// - 3.3 - =================== Определение типа найденного экстремума ================
if (ZZHigh != 0) // Найден верхний экстремум ZZ
LastZZ = -1; // Ожидается движение вниз
if (ZZLow != 0) // Найден нижний экстремум ZZ
LastZZ = 1; // Ожидается движение вверх
// - 3.3 - ============================= Окончание блока =============================
// - 3 - ================================= Окончание блока ==============================
Начиная с нулевой свечи,
опрашиваются значения ZigZag'a до тех пор, пока не
будет встречено отличное от нуля значения минимума или максимума. Еще одним
фактором окончания цикла опроса значений индикатора является достижение конца
исторических данных. В этом случае вступает в работу вложенный блок 3.2,
выдающий соответствующее сообщение и прерывающий работу эксперта.
Если экстремум ZigZag'a все же
был найден, то в блоке 3.3 определяется тип экстремума - максимум или минимум.
Таким образом, всегда можно быть уверенным, что переменная
LastZZ содержит правильное значение.
Обработка значений, определенных во время работы функции
GetSignal, производится в функции
CheckOrders:
//+-------------------------------------------------------------------------------------+
//| Анализ расположения ордеров и позиций (перемещение стопов, цен открытия) |
//+-------------------------------------------------------------------------------------+
bool CheckOrders()
{
// - 1 - ==================== Активен сигнал открытия длинных позиций ===================
if (SellLevel > 0) // Существует поддержка (ATR_the_Bat ниже цены)
{
// - 1.1 - ============== Если существует сделка Sell, то закрываем =================
if (SellType == OP_SELL) // Тип позиции - Sell
if (!CloseOrder(SellTicket)) // Попытка закрытия позиции
return(false); // Если закрыть позицию не удалось, то вернем False (ошибка)
// - 1.1 - ============================= Окончание блока ============================
// - 1.2 - ============ Если существует сделка Buy, то подтягиваем стоп =============
if (BuyType == OP_BUY) // Тип позиции - Buy
if (OrderSelect(BuyTicket, SELECT_BY_TICKET) && OrderCloseTime() == 0) // Ордер
// успешно выбран и не находится в списке закрытых
if (MathAbs(OrderStopLoss() - (SellLevel - Tick)) >= Tick) // Стоп необходимо
// изменить
if (Bid - SellLevel + Tick > StopLevel) // Уровень нового стопа располагается
// достаточно далеко от текущей цены
if (!OrderModify(BuyTicket, 0, NP(SellLevel - Tick), // Попытка изменения
OrderTakeProfit(), 0)) // уровня стоп-приказа
return(False); // Если модификация не удалась, то вернем ошибку
// - 1.2 - ============================= Окончание блока ============================
// - 1.3 - ============ Открытие позиции BUY, если ZZ дал подтверждение =============
if (LastZZ == 1) // Последний экстремум ZZ - нижний
if (Hour() >= BeginHour && Hour() < EndHour) // Попадаем ли в рабочее время?
if (BuyType < 0) // Если ордера Buy нет, то открываем
if (OpenOrderCorrect(OP_BUY, GetLots(), NP(Ask), NP(SellLevel - Tick), 0) != 0)
return(False); // Если открыть сделку не удалось, то вернем ошибку
// - 1.3 - ============================= Окончание блока ============================
}
// - 1 - ================================ Окончание блока ===============================
// - 2 - =================== Активен сигнал открытия коротких позиций ===================
if (BuyLevel > 0) // Существует сопротивление (ATR_the_Bat выше цены)
{
// - 2.1 - =============== Если существует сделка Buy, то закрываем =================
if (BuyType == OP_BUY) // Тип позиции - Buy
if (!CloseOrder(BuyTicket)) // Попытка закрытия позиции
return(false); // Если закрыть позицию не удалось, то вернем False (ошибка)
// - 2.1 - ============================= Окончание блока ============================
// - 2.2 - ============ Если существует сделка Sell, то подтягиваем стоп ============
if (SellType == OP_SELL) // Тип позиции - Sell
if (OrderSelect(SellTicket, SELECT_BY_TICKET) && OrderCloseTime() == 0) // Ордер
// успешно выбран и не находится в списке закрытых
if (MathAbs(OrderStopLoss() - (BuyLevel + Spread + Tick)) >= Tick) // Стоп
// необходимо изменить
if (BuyLevel + Spread + Tick - Ask > StopLevel) // Уровень нового стопа
// располагается достаточно далеко от текущей цены
if (!OrderModify(SellTicket, 0, NP(BuyLevel + Spread + Tick), // Попытка
OrderTakeProfit(), 0)) // изменения уровня стоп-приказа
return(False); // Если модификация не удалась, то вернем ошибку
// - 2.2 - ============================= Окончание блока ============================
// - 2.3 - ============ Открытие позиции Sell, если ZZ дал подтверждение ============
if (LastZZ == -1) // Последний экстремум ZZ - верхний
if (Hour() >= BeginHour && Hour() < EndHour) // Попадаем ли в рабочее время?
if (SellType < 0) // Если ордера Sell нет, то открываем
if (OpenOrderCorrect(OP_SELL, GetLots(), NP(Bid), // Попытка открытия сделки
NP(BuyLevel + Spread + Tick), 0) != 0)
return(False); // Если открыть сделку не удалось, то вернем ошибку
// - 2.3 - ============================= Окончание блока ============================
}
// - 2 - ================================ Окончание блока ===============================
return(True);
}
Функция разделена на два
равноценных блока. В первом блоке обрабатывается случай существования линии
поддержки (SellLevel > 0),
что является первым сигналом для открытия длинной позиции. В этом случае первым
действием является проверка существования короткой сделки, что может случиться
только при прерывании работы эксперта на продолжительное время. При нахождении
ордера Sell, производится его принудительное закрытие.
После этого проверяется существование длинной позиции. В
случае обнаружения ордера Buy проводится проверка
правильности значения уровня стоп-приказа. Его значение должно быть на один тик
меньше, чем значение переменной SellLevel. При отличии
значений производится изменение уровня стоп-приказа ордера.
Вложенный блок 1.3 выполняет открытие позиции, если
имеется подтверждение открытия длинной сделки (значение
LastZZ равно 1), текущее время является рабочим
(больше или равно BeginHour и меньше, чем
EndHour) и ордер
Buy не существует (BuyType < 0).
Если сделку открыть не удалось, то функция CheckOrders
вернет значение False, что заставит эксперт
вызвать функцию на текущей свече, как минимум, еще один раз.
Подобный алгоритм имеет блок 2. Он исполняется, когда
существует линия сопротивления (BuyLevel > 0).
В этом случае первым действием является проверка существования длинной
позиции. Второе действие - проверка существования короткой позиции и перемещение
уровня ее стопа, при необходимости. Последнее действие - открытие короткой
сделки, если есть подтверждение открытия сделки от ZigZag'a,
время рабочее, а ордер Sell найден не был.
Тестирование советника
Для тестирования стратегии был выбран таймфрейм Н1. При
использовании другого таймфрейма результаты будут резко отличаться, т.к. эксперт
использует в работе только выбранный период графика.
Для получения репрезентативной
выборки потребовалось использовать данные за последние два с половиной года: 01.01.2008 -
01.09.2010.
Каждой валютной паре был подобран индивидуальный
набор значений входных параметров. Различия наблюдались по трем параметрам:
ATRPeriod, Factor и ExtDepth.
Все остальные параметры имеют значения, установленные по умолчанию.
Результаты тестирования можно наблюдать на рис. 2 - 5.
Рис. 2. Результаты тестирования эксперта
NighBatAndZZ на валютной паре EURUSD.
EURUSD. Значения изменяемых параметров:
ATRPeriod = 2, Factor = 7, ExtDepth
= 26. Вид кривой баланса, откровенно говоря, "некрасивый": два
относительно пологих участка и один, круто поднимающийся вверх. Именно этот
участок и определил общий результат тестирования. В оправдание такому результату можно
сказать, что участок роста не так уж и мал - около трети продолжительности
теста. Ко всему прочему, пологие участки отличаются стабильностью и не ведут к
потере накопленного. В этом плане кривую баланса можно назвать стабильной, но ее
рост - крайне нестабильным. То есть можно говорить о том, что показанный результат
- для терпеливых. Ждать серьезного роста баланса при работе эксперта, скорее
всего, придется долго.
Чистая прибыль показана для евро очень большая - 7559 долларов при максимальной
просадке 1145 долларов. В итоге фактор восстановления показывает рекордную
величину - 6.61.
При желании использования стратегии на валютной паре EURUSD
необходимо располагать депозитом не меньше 3435 долларов в расчете на
объем сделок 0.1 лот. В этом случае ожидаемая годовая доходность может достичь
значения 82.5%.
Рис. 3. Результаты тестирования эксперта NighBatAndZZ на валютной
паре USDCHF.
USDCHF.Значения изменяемых параметров:
ATRPeriod = 7, Factor = 4,
ExtDepth = 18. Вид кривой баланса подобен предыдущему рассмотренному, но
в данном случае более очевидным является участок роста, который занимает десятую
часть всего времени тестирования. Это факт считается подтверждением высокой
нестабильности стратегии, чего хватает для рекомендации не использовать
стратегию на валютной паре USDCHF. При всем этом
статистические результаты интересные: 3249 долларов чистая прибыль и 1028
долларов максимальная просадка.
Рис.
4. Результаты тестирования эксперта NighBatAndZZ на валютной паре GBPUSD.
GBPUSD.
Значения изменяемых параметров:
ATRPeriod =12, Factor =
3,
ExtDepth = 30.Кривая баланса из всех
рассмотренных к данному моменту наиболее стабильная со стабильным ростом.
"Подпорчена" лишь первая четверть тестирования. Далее идут достаточно ровные
взлеты и падения, которые являются приемлемыми в реальной торговле. Чистая
прибыль 6479 долларов против 1577 долларов максимальной просадки. Фактор
восстановления не самый высокий - 4.11.
Стратегию вполне возможно использовать для реальной работы на валютной паре
GBPUSD. При этом размер депозита должен
рассчитываться, исходя из 4800 долларов на каждые 0.1 лота. Ожидаемая прибыль в
этом случае не более 50% годовых.
Рис. 5. Результаты тестирования эксперта
NighBatAndZZ на валютной паре USDJPY.
USDJPY.Значения изменяемых параметров:
ATRPeriod =2, Factor =
3,
ExtDepth = 3.Вид кривой баланса
очень близок к идеалу. Здесь все хорошо: и равномерный рост, и отсутствие
глубоких падений. Поводом для дополнительного оптимизма является продолжение роста на
заключительном этапе тестирования. Еще более приятными можно назвать
статистические данные: чистая прибыль 5426 долларов против максимальной просадки
778 долларов. Фактор восстановления наибольший среди рассмотренных результатов -
6.97. Также стоит отметить размер средней убыточной сделки - 31.34 доллара. В то
же время средняя прибыльная сделка составляет 73.41 доллара.
Однозначно можно заявить о том, что такие результаты как раз для применения в
реальной торговле, конечно, при условии соблюдений правил управления капиталом.
Минимальный депозит для торговли на валютной паре USDJPY
необходимо формировать из расчета 2400 долларов на каждые 0.1 лота. В
этом случае ожидаемая доходность составит 84.8% годовых.
Если начать с 2400 долларов и использовать для каждой сделки 4% от свободных
средств (Lots = 0, PercentOfDepo = 4),
то можно получить более интересный результат (см. рис. 6):
чистая прибыль 13 697 долларов при максимальной просадке 3 252 доллара,
относительная просадка 26%.
Рис. 6. Использование правил управления капиталом как средство увеличения
прибыли.
Доработка стратегии для
использования в AutoGraf 4.0
Преобразование советника в стратегию для
использования в среде
AutoGraf 4.0предполагает
перемещение входных параметров эксперта в список входных параметров
AutoGraf. Подобное изменение "не грозит"двум параметрам: Lots и
PercentOfDepo. Регулировать объем сделок в виде фиксированного значения
или в виде части от свободных средств можно при помощи панели настроек
приложения в любой момент функционирования стратегии. Для этого
необходимо изменить значение, находящееся под надписью Lot
или под значком "%".
Запуск
стратегии "Летучая мышь - 2" в среде AutoGraf 4.0
состоит из следующих шагов:
Получить файл по ссылке
Файлы стратегий для AutoGraf 4.0 и распаковать полученный архив
в папку MT4\experts\libraries (с перезаписью
файлов AG_AT.ex4 и AG_AT.mq4).
Запустить AutoGraf.
Для работы стратегии в ключе приведенных
результатов
в окне настроек AutoGraf (закладка "Входные
параметры") установить нужные значения параметров AT_1
-
AT_8. Полное повторение результатов при
этом не гарантируется.
Выбрать
стратегию №5. Для этого необходимо передвинуть вверх значок
So и среди названий стратегий найти значок S5, который также потянуть вверх.
Запустить функцию
автоматической торговли, передвинув значок AT в верхнее положение.
Использование полученного советника
рекомендуется только в полуавтоматическом режиме под присмотром трейдера и после
всестороннего изучения слабых и сильных сторон стратегии.
Комментарии
Отправить комментарий