Одной из
непреложных истин успешной торговли на срочном рынке является соблюдение
определенных норм риска. Об этом знает каждый трейдер, это первое, что он
скажет, если разбудить его ночью и спросить, как правильно работать на
Forex.
Но в том то
и дело, что просто знать далеко недостаточно. Определяющим является умение
удержаться в рамках этого правила. Например, большинство автолюбителей тоже
знают основные правила дорожного движения. Но такое знание не является помехой в
периодических мелких нарушениях. И действительно, зачем выполнять требование
знака "STOP", если обзор на
перекрестке отличный, а в пределах полукилометра нет ни одной машины
(а заодно и сотрудников ГАИ/ГИПДД)?
Выходит, что
зачастую всяческие правила и законы мешают нам быть более гибкими в решении той
или иной задачи. Но в трейдинге у нас никогда нет "отличного обзора на
перекрестке", а множество "помех справа" является настолько замаскированным, что
очень трудно разобраться, с какой стороны ждать неприятностей. Именно поэтому в
торговле все время приходится излишне перестраховываться, подспудно осознавая,
что по законам Мерфи все беды случаются во время нашей малейшей расслабленности.
Если же посмотреть на это с другой стороны, то выполнение норм риска дает
немалый бонус. Речь идет о тех частых случаях, когда открытая сделка находится в
убыточной зоне. В этот момент трейдер не будет ощущать страха потери денег, так
как возможные убытки будут небольшими по сравнению с полным размером капитала.
Да, прибыль в этом случае тоже не достигнет астрономических величин, но лучше уж
"синица в руках, чем журавль в небе".
Приверженцам
именно такого, малорискового, подхода к торговле и посвящается данная стратегия.
Азартным или, как сейчас модно говорить, "агрессивным" трейдерам все
нижеизложенное с большой степенью вероятности принесет колоссальные убытки.
На первый взгляд стратегия является банальной и очень простой, но это так только
с точки зрения самой техники открытия и закрытия сделок. Именно техническая
простота позволяет получить конкурентное преимущество на рынке, что бы там не
говорили о сложности торговых процессов. С теоретической же стороны все
действительно не так уж и просто.
Теория
заключается в том, что еще из школьного курса физики нам известен тот факт, что
любой нестационарный процесс всегда стремится к равновесному состоянию.
Например, ветреная погода объясняется тем, что в одном регионе давление
повышенное, а в другом пониженное. Ветер гонит воздушные массы из области
высокого давления в область низкого давления, пытаясь уравновесить давление. Это
аналог тренда на рынке. Безветренная погода свидетельствует об одинаковом
давлении в близлежащих географических районах. На такое состояние говорят:
"погода устоялась". Это аналог флэта на рынке. Таким образом, что бы не
происходило с погодой, какие бы катаклизмы на нас не обрушивались, рано или
поздно все вернется к равновесному состоянию. Это не означает, что вернется к
"тому, как было", уровень может стать совсем другим, но равновесие будет
достигнуто.
Равновесное состояние рынка определить достаточно легко. Это колебание цены
около средней цены, взятой за некоторый период, то есть вокруг средней скользящей.
Выходит, что самым лучшим моментом для открытия сделки будет именно такой
случай. Если пойти дальше, то можно придти к выводу, что это же состояние будет
наиболее рациональным моментом закрытия сделки, ведь все движения закончились и
можно не бояться, что мы упустим еще один виток тренда.
В
результате мы определили, что сигналом открытия сделки будет являться
пересечение цены и средней скользящей. До боли знакомо, не правда ли? Но
вкладывали ли вы раньше в такой сигнал хоть какой-нибудь физический смысл?
Пойдем дальше. На данный момент определен только сигнал открытия сделки, но еще
ничего не было сказано о направлении - "вверх или вниз". Но и здесь нам не
понадобятся дополнительные инструменты, так как у нас есть направление средней
скользящей. Она может быть нисходящая или восходящая. Даже в случае равенства
значений средней на двух барах подряд, можно взять более ранние значения,
которые не равны между собой.
Поэтому направление будет всегда.
Графически
описанная стратегия представлена на рис. 1.
Рис. 1 - Пересечение цены и средней скользящей.
Как видно из
рисунка, сделки совершаются довольно редко и удерживаются продолжительное время.
Первый сигнал открытия длинной позиции был подан после того, как цена уже
показала небольшое восходящее движение, которое заставило среднюю скользящую
изменить направление на восходящее. Затем рынок вернулся к уровню средней, чем и
дал возможность открытия сделки по выгодной цене. После этого движение набрало
силу и мощным импульсом достигло цены 1.3710. Здесь все и прекратилось.
Неминуемое тяготение к равновесию дало о себе знать, и цена вернулась к 1.34,
встретившись там со своим средним значением. Но направление средней скользящей
все еще восходящее и в принципе можно было бы добавиться к имеющейся позиции,
заработав дополнительные 200 пунктов. Исходя же из правила уменьшения риска,
делать такое крайне нежелательно.
Попытавшись еще
раз пойти вверх, цена в итоге развернулась и очередным импульсом достигла
отметки 1.31, но даже здесь сделку закрывать не стоит, памятуя о правиле
возврата к средней. Видя, что направление средней скользящей изменилось на
нисходящее, планируем закрытие сделки с первым же пересечением, которое и
происходит в районе 1.33. На этом уровне открывается противоположная сделка.
Да, цена пугает очередным выбросом вверх, но это не мешает дождаться следующего
возврата "на круги своя" с тем, чтобы закрыть небольшую прибыль и открыть
противоположную сделку.
Таким вот образом
совершаются все остальные сделки по данной стратегии, которая рассчитана именно
на долгосрочные тренды. Но даже долговременное нахождение рынка в узком флэте не
очень вредит стратегии, так как все входы и выходы совершаются на усредненном
уровне, который в этом случае меняется очень мало.
Перейдем к
воплощению идеи в коде. Первым делом напишем сигнальную часть системы:
//+-------------------------------------------------------------------------------------+
//| Расчет уровней для каждого направления торговли |
//+-------------------------------------------------------------------------------------+
void GetSignal()
{
// - 1 - ============================= Инициализация переменных =========================
BuyLevel = ; SellLevel = ;
double MA1 = , MA2 = ;
int i = 1;
// - 1 - ================================== Окончание блока =============================
// - 2 - =========== Поиск последнего изменения направления средней скользящей ==========
while (MA1 - MA2 == && i < Bars)
{
MA1 = iMA(Symbol(), , MAPeriod, , MAMethod, MAPrice, i);
MA2 = iMA(Symbol(), , MAPeriod, , MAMethod, MAPrice, i+1);
i++;
}
// - 2 - ================================== Окончание блока =============================
// - 3 - =========== Генерация сигнала по средней и расчет цены открытия ================
if (MA1 > MA2) // Восходящее движение средней
BuyLevel = iMA(Symbol(), , MAPeriod, , MAMethod, MAPrice, 1);
if (MA1 < MA2) // Нисходящее движение средней
SellLevel = iMA(Symbol(), , MAPeriod, , MAMethod, MAPrice, 1);
// - 3 - ================================== Окончание блока =============================
}
В первом
блоке инициализируем значения уровня открытия длинной сделки (BuyLevel)и уровня открытия короткой сделки (SellLevel)нулем, что в дальнейшем будет обозначать отсутствие сигнала. МА1 и МА2
нужны для хранения значения средних на текущем (ближайший закрытый бар) и
предыдущем (предшествующий бар ближайшему закрытому бару) барах.Переменная i - счетчик баров для цикла,
работающего во втором блоке.
Второй блок содержит цикл, который
находит два ближайших значения средней скользящей, не равных между собой. Это
решение учитывает возможность применения периодов средней скользящей линии
довольно высокого порядка (100 и более), когда разница между двумя соседними
значениями линии настолько мала, что точности вещественных
чисел MQL4 в
пятнадцать знаков после запятой может быть недостаточно.
Третий блок уже решает, какой из
сигналов следует подать. Сигнал BUY будет подан, если
средняя скользящая определена как восходящая. Ценой открытия сделки (BuyLevel)
будетопределено ближайшее сформированное значение
средней. Аналогично, сигнал SELL будет активирован в
случае идентификации нисходящего направления средней скользящей. И точно также в
качестве цены открытия сделки будет установлено значение средней скользящей
линии на ближайшем баре.
В общем, особых трудностей с
понятием логики работы функции GetSignal возникнуть не
должно.
Совсем другое дело функция
CheckOrders:
//+-------------------------------------------------------------------------------------+
//| Нахождение всех своих ордеров и позиций. |
//| Перемещение стопов на новый уровень, перемещение ордеров на новую цену |
//+-------------------------------------------------------------------------------------+
bool CheckOrders()
{
BuyPending = False; // Флаг наличия отложенного ордера BUY (BuyStop или BuyLimit)
SellPending = False; // Флаг наличия отложенного ордера SELL (SellStop или SellLimit)
HighBuy = ; // Цена открытия самого последнего BUY
LowSell = ; // Цена открытия самого последнего SELL
Buys = ; Sells = ; // Счетчики кол-ва своих ордеров и позиций
// - 1 - ============================ Отсеиваем свои ордера и позиции ===================
for (int i = ; i < OrdersTotal(); i++)
if (OrderSelect(i, SELECT_BY_POS))
if (OrderSymbol() == Symbol() && MathFloor(OrderMagicNumber()/100) == MagicNumber)
// - 1 - ================================ Окончание блока ===============================
{
// - 2 - =============== Принятие решений о модификации ордеров или позиций =============
double Price = ; // Цена открытия для отложенного ордера. Если != 0, то меняем
double TP = ; // Уровень профита для позиций. Если != 0, то меняем
double SL = ; // Уровень стопа для позиций. Если != 0, то меняем
bool Delete = False; // Если True, то ордер нужно удалить
switch (OrderType())
{
case OP_BUY:
Buys++;
HighBuy = MathMax(OrderOpenPrice(), HighBuy);
if (SellLevel != ) // Существует сигнал для входа в короткую
{
if (SellLevel > Bid)// Цена входа выше текущей, проверяем уровень профита
if (MathAbs(SellLevel - OrderTakeProfit()) >= Tick)
if (SellLevel - Bid > StopLevel)
TP = SellLevel;
if (SellLevel < Bid) // Цена входа ниже текущей, проверяем уровень стопа
if (MathAbs(SellLevel - OrderStopLoss()) >= Tick)
if (Bid - SellLevel > StopLevel)
SL = SellLevel;
}
break;
case OP_SELL:
Sells++;
if (OrderOpenPrice() < LowSell || LowSell == )
LowSell = OrderOpenPrice();
if (BuyLevel != ) // Существует сигнал для входа в длинную
{
if (BuyLevel < Bid) // Цена входа ниже текущей, проверяем уровень профита
if (MathAbs(BuyLevel + Spread - OrderTakeProfit()) >= Tick)
if (Bid - BuyLevel > StopLevel)
TP = BuyLevel + Spread;
if (BuyLevel > Bid) // Цена входа выше текущей, проверяем уровень стопа
if (MathAbs(BuyLevel + Spread - OrderStopLoss()) >= Tick)
if (BuyLevel - Ask > StopLevel)
SL = BuyLevel + Spread;
}
break;
case OP_BUYSTOP:
Buys++;
BuyPending = True;
if (BuyLevel != && BuyLevel > Ask)//Еще существует сигнал открытия длинной
{ // и он выше текущей цены
if (MathAbs(BuyLevel + Spread - OrderOpenPrice()) >= Tick)
if (BuyLevel - Bid > StopLevel && BuyLevel - Bid > FreezeLevel)
Price = BuyLevel + Spread;
}
else
if (OrderOpenPrice() - Ask > FreezeLevel) // Если ордер не заморожен, то
Delete = True; // удаляем
break;
case OP_SELLSTOP:
Sells++;
SellPending = True;
if (SellLevel != && SellLevel < Bid)// Существует сигнал открытия короткой
{ // и он ниже текущей цены
if (MathAbs(SellLevel - OrderOpenPrice()) >= Tick)
if (Bid - SellLevel > StopLevel && Bid - SellLevel > FreezeLevel)
Price = SellLevel;
}
else
if (Bid - OrderOpenPrice() > FreezeLevel) // Если ордер не заморожен, то
Delete = True; // удаляем
break;
case OP_BUYLIMIT:
Buys++;
BuyPending = True;
if (BuyLevel != && BuyLevel < Ask)//Еще существует сигнал открытия длинной
{ // и он ниже текущей цены
if (MathAbs(BuyLevel + Spread - OrderOpenPrice()) >= Tick)
if (Bid - BuyLevel > StopLevel && Bid - BuyLevel > FreezeLevel)
Price = BuyLevel + Spread;
}
else
if (Ask - OrderOpenPrice() > FreezeLevel) // Если ордер не заморожен, то
Delete = True; // удаляем
break;
case OP_SELLLIMIT:
Sells++;
SellPending = True;
if (SellLevel != && SellLevel > Bid)// Существует сигнал открытия короткой
{ // и он выше текущей цены
if (MathAbs(SellLevel - OrderOpenPrice()) >= Tick)
if (SellLevel - Bid > StopLevel && SellLevel - Bid > FreezeLevel)
Price = SellLevel;
}
else
if (OrderOpenPrice() - Bid > FreezeLevel) // Если ордер не заморожен, то
Delete = True; // удаляем
break;
}
// - 2 - ================================ Окончание блока ===============================
// - 3 - =============== Исполнение решений по модификации ордеров и позиций ============
if (Price != || TP != || SL != )// Если нужно изменить хотя бы один параметр
{
// - 3.1 - ==== Не все параметры нуждаются в изменении =======================
if (Price == )
Price = OrderOpenPrice();
if (TP == )
TP = OrderTakeProfit();
if (SL == )
SL = OrderStopLoss();
// - 3.1 - =================== Окончание блока ===============================
// - 3.2 - ================== Непосредственно модификация ====================
if (WaitForTradeContext())
if (!OrderModify(OrderTicket(), NP(Price), NP(SL), NP(TP), ))
{
Print("Ордер #", OrderTicket(), ", Price = ", Price, ", SL = ", SL,
", TP = ", TP);
return(False);
}
// - 3.2 - =================== Окончание блока ===============================
RefreshRates();
}
// - 3 - ================================ Окончание блока ===============================
// - 4 - =============== Исполнение решения по удалению ордеров =========================
if (Delete) // Если установлен флаг удаления, то удаляем ордер
{
if (WaitForTradeContext())
OrderDelete(OrderTicket());
return(False); // вне зависимости от результата выходим, чтобы вернуться для
// пересчета ордеров на следующем тике
}
// - 4 - ================================ Окончание блока ===============================
}
return(True); // Все проверки завершились удачно, можно работать дальше
}
Назначением функции является поиск ордеров и позиций,
относящихся к эксперту, а также проверка и изменение уровней стопов, профитов
позиций и цен открытия отложенных ордеров.
Первый блок практически стандартный. Единственное его
отклонение - кумулятивность поля MagicNumber. В
советнике реализован принцип разделения позиций по
MagicNumber, что приводит к уникальности каждого ордера или позиции.
Единственное сходство между ними - одинаковые старшие разряды поля. Для этого
при открытии позиции магик рассчитывается как 100*MagicNumber+<порядковый
номер позиции в серии>. То есть, если после открытия
первой позиции разрешить эксперту добавлять на каждом новом сигнале по еще одной
позиции, то вторая сделка будет открыта с порядковым номером 2. Каждая новая
позиция увеличивает этот номер на единицу. Поэтому для определения
принадлежности найденного ордера/позиции к эксперту необходимо разделить магик
ордера/позиции на 100 без остатка. Если полученное число равно
параметру
MagicNumber, значит, ордер "свой".
Второй блок, хоть и самый большой, состоит из шести
однотипных частей. Каждая часть соответствует одному из типов ордеров. Например,
если найдена позиция BUY, то счетчик длинных позиций
Buys прирастает на единицу, а переменная HighBuy,
в которой, в конце концов, должна оказаться цена открытия самого высокого
BUY, принимает наибольшее из двух предложенных
значений. Затем, если активен сигнал открытия короткой позиции, определяется,
какой параметр (стоп или профит) должен быть равен цене открытия короткой
позиции SellLevel. Если SellLevel
выше текущей цены, то сравнивать нужно уровень профита. Если же
SellLevel ниже текущей цены, то сравнивать нужно
уровень стопа. В обоих случаях неравенство параметра нужному значению приводит к
переопределению переменной TP или
SL содержимым переменной SellLevel, что
автоматически приведет к изменению соответствующего уровня (это уже производится
в третьем блоке).
Аналогичным образом, если обнаружена позиция
SELL, то растет счетчик коротких позиций
Sells, а переменная LowSell
находится в поисках самой нижней позиции Sell. Точно
также при активном сигнале открытия длинной позиции проверяется равенство уровня
профита или стопа значению BuyLevel. При необходимости
проведения изменений переменная TP или
SL принимает ненулевое значение.
При обнаружении одного из отложенных ордеров растет
соответствующий счетчик ордеров (Sells или
Buys)и проверяется
правильность цены открытия отложенного ордера. Если ордер
BuyStop или BuyLimit, то цена открытия должна
быть равна BuyLevel, если же
SellStop или SellLimit, то
SellLevel. В случае обнаружения несоответствия типа ордера и типа сигнала (не
тот сигнал или уровень BuyLevel/SellLevel находится
по другую сторону от текущей цены), ордер нужно удалить. Для этого существует
флаг Delete, возведенное состояние которого (значение
True) сигнализирует о необходимости удаления ордера.
В третьем блоке производится исполнение одного из
"приговоров". Если хотя бы одно из значений переменных Price,
TP или SL не равно нулю, то производится
модификация ордера/позиции. Чтобы не изменить другие параметры ордера, которые в
таком изменении не нуждаются, оставшиеся "нулевые" переменные приводим к
соответствующим значениям: Price - к
OrderOpenPrice, TP - к TakeProfit,
SL - к OrderStopLoss. После этого можно
приступать непосредственно к модификации ордера/позиции. Неудачное завершение
операции модификации приводит к экстренному выходу из функции
CheckOrders с тем, чтобы вернуться сюда на следующем тике для повторения
попытки.
Другой "приговор" - удаление ордера - совершается в
четвертом блоке. Здесь все проще, чем в третьем. При активном флаге
Delete будет произведено удаление ордера и выход из
функции CheckOrders. Делается это с целью пересчета
всех имеющихся ордеров и позиций советника на следующем тике.
Функции GetSignal и
CheckOrders объединяются по смыслу в функции 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); // текущий уровень стопов
FreezeLevel = ND(MarketInfo(Symbol(), MODE_FREEZELEVEL)*Point); // уровень заморозки
// - 2 - === Окончание блока ============================================================
// - 3 - ================== Расчет уровней открытия длинных и кортких позиций ===========
if (LastBar == Time[])
return();
if (LastSignal != Time[])
{
GetSignal();
LastSignal = Time[];
}
// - 3 - ================================ Окончание блока ==============================
// - 4 - =========== Изменение стопов позиций и цены открытия отложенных ордеров ========
if (!CheckOrders())
return();
// - 4 - ========================== Окончание блока =====================================
// - 5 - ================================ Установка ордеров =============================
int Type = -1;
double Price = ;
int Orders = ;
// - 5.1 - ===================== Установка BUY-ордеров ==============================
if (Buys < MaxDeals) // Текущее количество BUY-позиций меньше разрешенного
if (BuyLevel!= && !BuyPending)//Сигнал открытия длинной позиции, а ордеров Buy нет
if (BuyLevel + Spread > HighBuy + OffPips*Tick) // Предыдущая BUY-позиция далеко
{
if (BuyLevel - Bid > StopLevel) // Уровень входа выше текущей цены
Type = OP_BUYSTOP; // Установим BuyStop
if (Bid - BuyLevel > StopLevel) // Уровень входа ниже текущей цены
Type = OP_BUYLIMIT; // Установим BuyLimit
Price = NP(BuyLevel + Spread);
Orders = Buys+1;
}
// - 5.1 - ===================== Окончание блока ====================================
// - 5.2 - ===================== Установка SELL-ордеров =============================
if (Sells < MaxDeals) // Текущее количество SELL-позиций меньше разрешенного
if (SellLevel!= && !SellPending)//Сигнал открытия короткой позиции, а Sell орд нет
if (SellLevel < LowSell - OffPips*Tick || // Предыдущая SELL-позиция далеко
LowSell == )
{
if (SellLevel - Bid > StopLevel) // Уровень входа выше текущей цены
Type = OP_SELLLIMIT; // Установим SellLimit
if (Bid - SellLevel > StopLevel) // Уровень входа ниже текущей цены
Type = OP_SELLSTOP; // Установим SellStop
Price = NP(SellLevel);
Orders = Sells+1;
}
// - 5.2 - ===================== Окончание блока ====================================
// - 5.3 - ===================== Непосредственно установка ==========================
if (Type > )
if (OpenOrderCorrect(Type, Lots, Price, , , 100*MagicNumber+Orders) > )
return(False);
// - 5.3 - ========================== Окончание блока ===============================
// - 5 - ================================ Окончание блока ==============================
LastBar = Time[];
return();
}
Третий блок как раз вызывает
функцию расчета сигнала GetSignal один раз за бар.
Здесь же контролируется исполнение тела советника с тем, чтобы не производились
многоразовые проверки в течение одного и того же бара. Так, если все, что нужно
было сделать в течение нового бара, сделано, то новых действий до начала
следующего бара не будет.
Четвертый блок вызывает функцию
CheckOrders, проверяя необходимость проведения изменений в структуре
ордеров и позиций. Если хотя бы одна из операций в
CheckOrders завершилась неудачно, то выполнение start
экстренно завершается, что приводит к новому ее запуску на следующем
тике.
Пятый блок имеет схожую структуру со вторым блоком
функции CheckOrders. Вначале определяются переменные
Type, Price и Orders. Type
отвечает за тип ордера, который необходимо установить. Отрицательное значение
Type свидетельствует о том, что ордер устанавливать не
нужно. Price определяет цену открытия ордера, а
Orders - новый порядковый номер ордера в серии.
Блок 5.1 рассматривает возможность установки ордеров
BuyStop или BuyLimit.
Сначала количество существующих BUY-позиций
Buys сравнивается с максимально допустимым количеством
ордеров MaxDeals. Это внешний параметр эксперта,
который доступен пользователю для изменения. Если поставить его значение больше
1, то на каждом новом сигнале после открытия первой позиции будет открываться
еще одна позиция. Но, конечно же, это произойдет не более
MaxDeals раз. Далее проверяется наличие сигнала BUY
(BuyLevel != 0) и отсутствие отложенных ордеров BUY-типа
(!BuyPending). Если условие выполнено, то происходит переход к последнему
условию - достаточно ли расстояние в пунктах от предыдущей торговой позиции.
Достаточность расстояния определяется самим пользователем при помощи значения
параметра эксперта OffPips. Если новый уровень
открытия находится к последней позиции ближе, чем OffPips
пунктов, то ордер установлен не будет. Дополнительной проверкой перед
установкой ордера является определение типа ордера. Проверяется расположение
уровня BuyLevel относительно текущей цены. Если
BuyLevel выше - будет установлен
BuyStop, если ниже - BuyLimit.
Блок 5.2 рассматривает возможность
установки ордеров SellStop или
SellLimit. Все происходит по образу и подобию блока 5.2.
Блок 5.3, основываясь на значении Type,
Price и Orders, устанавливает нужный ордер.
Если установка завершается неудачно, то вновь произойдет экстренный выход из
функции start.
Вот такими тремя основными
функциями описывается работа предложенной "простой" стратегии. Для подтверждения
или опровержения предположений, выдвинутых в начале материала, необходимо
проверить работу советника. Этого можно достигнуть тестированием эксперта,
которое проведем на таймфрейме Н1, диапазоне тестирования 01.01.2007 -
22.01.2010 с входными параметрами по умолчанию. В качестве периода средней
скользящей линии выбрано значение 144 (см. рис. 2 - 5).
Рис. 2. - График кривой баланса,
получаемый при тестировании советника на валютной паре
EURUSD.
Несмотря на довольно
уверенный характер кривой баланса, показанный на валютной паре
EURUSD, соотношение чистой прибыли и максимальной просадке еле
превзошло единицу 3101.57/2595.38 = 1.2. Но некоторая часть этой просадки
является отражением нахождения позиций в убыточной зоне, то есть до реального
закрытия сделки. Если же высчитать просадку по закрытым сделкам, то это число
уменьшится где-то до 2000. Впрочем, и это значение является большим.
Рис.
3.
- График кривой баланса, получаемый при тестировании
советника на валютной паре
USDCHF.
Примерно такой же график кривой баланса можно наблюдать уUSDCHF.Но, в отличие от евро, франк может похвастаться более умеренной просадкой
- 1257.64 доллара, в то время как чистая прибыль показана не намного меньшей -
2928.54 доллара. В итоге фактор восстановления получается даже больше двух -
2.33. Стоит отметить, что очень небольшим оказалось значение средней убыточной
сделки - всего лишь 27 долларов. Но в данном случае убытки берут количеством -
на одну прибыльную сделку в среднем приходится три убыточные.
Рис.
4.
- График кривой баланса, получаемый при тестировании
советника на валютной паре
GBPUSD.
Единственная валютная пара,
которой нельзя занести стратегию в актив - GBPUSD.
Несмотря на итоговый плюс - 287.5 долларов, все остальные показатели очень
"плохие". К тому же, более чем доходчиво обо всем говорит вид кривой баланса.
Рис. 5.
- График кривой баланса, получаемый при тестировании советника на валютной паре
USDJPY.
Примерно на равных с франком стратегия себя чувствует
на валютной пареUSDJPY.
Чистая прибыль 2949.38 доллара при максимальной просадке 1387.73 доллара, что
дает фактор восстановления 2.13, тоже неплохо. Уверенный рост кривой баланса на
двух третях графика также говорит в пользу применения стратегии.
Исходя из полученных результатов, для работы по данной
стратегии объемом 0.1 лот минимальный депозит должен составлять 3600 долларов на
валютной паре USDCHF (тройной запас прочности)
с планируемой доходностью порядка 35% годовых.
Доработка стратегии для
использования в AutoGraf 4.0
Для
предоставления возможности работы с данной стратегией пользователям AutoGraf 4.0
доработаем эксперт, разделив его на файлы AG_AT.mq4 и
AG_MADirection.mq4. Все входные параметры эксперта
перенесем во входные параметры AutoGraf. Параметрам
MAPeriod, MAPrice и MAMethod
будут соответствовать параметры AT_1 - AT_3. Параметр
MaxDeals можно будет менять, изменяя параметр
AT_4. Единственный параметр, для которого нашлось
место в инструментальной панели AutoGraf, это
OffPips. Он будет соответствовать дистанции
Ds.
Для запуска советника из-под
AutoGraf 4.0совершите такие шаги:
Для получения похожих
с тестами результатов работы выставьте объем открываемой позиции (Lots)0.1, дистанцию Offpips 100 (Ds =
10), значения
AT_1 = 144, AT_2 = 0, AT_3 = 0 и
AT_4 = 1.
Выберите стратегию №3. Для этого передвиньте вверх значок
So и среди названий стратегий найдитезначок
S3, который также потяните вверх.
Запустит
е функцию автоматической торговли, передвинув
значок AT в верхнее положение.
Использование полученного
советника рекомендуется только в полуавтоматическом режиме под присмотром
трейдера и после всестороннего изучения слабых и сильных сторон стратегии.
Комментарии
Отправить комментарий