PDA

View Full Version : Точка бифуркации



Scriptong
18-01-2011, 20:54
Бифуркация (медицина) - разделение трубчатого органа
(сосуда или бронха) на 2 ветви одинакового калибра,
отходящие в стороны под одинаковыми углами

Сложность предвидения поведения рыночных цен понятна большинству опытных трейдеров. У новичков, в свою очередь, подобное понимание разбивается о незыблемую стену простого изречения: "у рынка есть только два направления - вверх и вниз". Получается, что если сразу не было угадано верное направление, то можно развернуть сделку и, покрыв убыток, взять причитающуюся прибыль. Парадокс заключается в том, что данное изречение истинно. Рынок действительно движется только в двух направлениях, а "движение вбок" является лишь одной из составных частей роста или падения. Таким образом, в любой момент времени изменение цены может быть охарактеризовано как повышение или понижение.
Причиной изменения цен всегда является неравномерное распределение средств между участниками рынка. Его можно сравнить с таким же сложным, но более понятным любому человеку, процессом, как перемещение воздушных масс. Воздух движется из зоны высокого давления в область низкого давления, стремясь уравновесить давление в обеих областях. То есть целью всего процесса является равновесие. В этом компоненте рынок очень схож с ветром - он тоже стремится к равновесию. Однако достижение равновесия вовсе не является гарантией последующего затишья, и через некоторое время ветер вновь поднимается. Причем, его направление может быть как таким же, как до затишья, так и противоположным. В такие моменты можно говорить о наличии двух равновероятных событий - ветер (рынок) подует в одну (будет расти) или в другую (будет падать) стороны. То есть, применительно к ценовым изменениям, подобные ситуации приводят к формированию точек бифуркации.
По какому критерию можно судить об образовании точки бифуркации? Единого критерия не существует. В идеале любая цена в любой момент времени может быть признана точкой бифуркации. Если же подходить к этому вопросу с позиции технических индикаторов, то равновесием рынка необходимо считать области "среднего положения индикаторов". Например, для Stochastic - это момент пересечения линий, для RSI - пробитие уровня 30 или 70, для фракталов - момент пробития фрактала. Особенно актуально приведенное утверждение для средних скользящих линий. Считается, что наиболее вероятным направлением дальнейшего движения рынка после пересечения средних линий является направление быстрой линии. Опытным трейдерам, не склонным к самообману, известно, что на самом деле ни о какой повышенной вероятности в данном случае речь не идет. В момент пересечения средних вероятность падения или роста рынка оказывается как никогда близкой к соотношению 50/50.
Исходя из вышесказанного, можно сделать вывод о том, что в точках бифуркации вообще нельзя принимать торговые решения. Если иметь в виду определенные направления торговли (вверх или вниз), то это так. Если же говорить о тактике торговли, то именно точки бифуркации представляют собой идеальный момент для осуществления торговли по методу новичков - получить прибыль за счет переворота в случае неудачно выбранного начального направления.
Для реализации упомянутого "метода новичков" необходимо выделить свечи, которые образовали точку бифуркации. Такие свечи образуют бокс, границы которого являются уровнями поддержки и сопротивления. Пробитие уровня поддержки означает последующее падение цены, а пробитие уровня сопротивления - рост цены (см. рис. 1).

http://www.forextrade.ru/media/Image/MQLabs/97_ag/figure1.png
Рис. 1. Точки бифуркации, найденные при помощи пересечения средних.

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

Уровень прибыли ордеров (профит) будем рассчитывать, исходя из высоты бокса. Размер профита первичного ордера может отличаться от размера профита компенсирующего ордера, как в большую, так и в меньшую сторону. Решение о размерах профитов пользователь может выносить сам. На начальном этапе в этом ему поможет индикатор BifurcationBox, при помощи параметров которого можно изменять периоды средних скользящих (FastPeriod и SlowPeriod) и размер целей (профита), рассчитанных в единицах высоты бокса, для первичного ордера (DirectTarget) и для компенсирующего ордера (ReverseTarget). Внешний вид индикатора приведен на рис. 2.

http://www.forextrade.ru/media/Image/MQLabs/97_ag/figure2.png
Рис. 2. Индикатор BifurcationBox.

Красные боксы означают, что по классической теории пересечения средних скользящих линий ожидается падение цены. В таких случаях первичным ордером считается Sell Stop, а компенсирующим - Buy Stop. Синий бокс свидетельствует об ожидании роста цены. Теперь первичным будет считаться ордер Buy Stop, а компенсирующим - Sell Stop.
На основании индикатора BifurcationBox можно перейти к разработке эксперта BifurcationBox_Expert, который будет осуществлять торговлю по приведенным выше правилам. Задачу определения боксов и их границ в советнике решает функция GetSignal:

//+-------------------------------------------------------------------------------------+
//| Генерация сигналов покупки и продажи |
//+-------------------------------------------------------------------------------------+
void GetSignal(int num)
{
// - 1 - ==================== Определение значений средних скользящих ===================
double MAFast1 = iMA(NULL, 0, FastPeriod, 0, MAMethod, MAPrice, num);
double MASlow1 = iMA(NULL, 0, SlowPeriod, 0, MAMethod, MAPrice, num);
double MAFast2 = iMA(NULL, 0, FastPeriod, 0, MAMethod, MAPrice, num+1);
double MASlow2 = iMA(NULL, 0, SlowPeriod, 0, MAMethod, MAPrice, num+1);
// - 1 - ========================== Окончание блока =====================================

// - 2 - =========================== Генерация бокса покупки ============================
if (MAFast1 > MASlow1 && MAFast2 < MASlow2)
{
LastBox = 1;
LastBoxTime = Time[num-1];
Minimum = MathMin(Low[num], Low[num+1]);
Maximum = MathMax(High[num], High[num+1]);
UpTarget = Maximum + (Maximum - Minimum)*DirectTarget;
DownTarget = Minimum - (Maximum - Minimum)*ReverseTarget;
}
// - 2 - ============================= Окончание блока ==================================

// - 3 - =========================== Генерация бокса продажи ============================
if (MAFast1 < MASlow1 && MAFast2 > MASlow2)
{
LastBox = -1;
LastBoxTime = Time[num-1];
Minimum = MathMin(Low[num], Low[num+1]);
Maximum = MathMax(High[num], High[num+1]);
UpTarget = Maximum + (Maximum - Minimum)*ReverseTarget;
DownTarget = Minimum - (Maximum - Minimum)*DirectTarget;
}
// - 3 - ========================== Окончание блока =====================================
}
Первый блок выполняет тривиальную задачу - определение значений быстрой и медленной средних скользящих линий на двух последних барах.

Второй и третий блоки схожи по функционалу. Каждый из них отслеживает момент пересечения линий. Второй блок ожидает, когда быстрая линия пересечет медленную снизу вверх, а третий - сверху вниз. Далее переменная LastBox принимает соответствующее значение (1 или -1), что характеризует тип пересечения. Время фиксации пересечения сохраняется в переменной LastBoxTime. С ее помощью в дальнейшем станет возможным определение нового сигнала. Переменные Minimum и Maximum получают значения минимальной и максимальной цены бокса, который соответствует найденному пересечению. Переменная Minimum указывает уровень поддержки, а переменная Maximum - уровень сопротивления.

Располагая значениями уровней поддержки и сопротивления, можно рассчитать цели для каждого из исходов (пробитие одного из уровней). Если быстрая средняя пересекла медленную снизу вверх, то повышение цены считается основным направлением. Поэтому верхняя цель (UpTarget) рассчитывается, исходя из значения настроечного параметра эксперта DirectTarget (размер прибыли для сделки, открываемой в основном направлении движения; указывается пользователем). Нижняя цель (DownTarget) в этом случае рассчитывается при помощи значения ReverseTarget (размер прибыли для сделки, открытой в противоположном основному направлении движения; указывается пользователем). Если быстрая средняя пересекла медленную сверху вниз, то основным направлением считается падение цены. В итоге по значению DirectTarget рассчитывается нижняя цель (DownTarget), а по значению ReverseTarget рассчитывается верхняя цель (UpTarget).

Учет ордеров в эксперте производится при помощи знакомой функции FindOrders, которая в данном случае немного отличается от стандартной:

//+-------------------------------------------------------------------------------------+
//| Функция поиска своих ордеров |
//+-------------------------------------------------------------------------------------+
void FindOrders()
{
// - 1 - ====================== Инициализация переменных перед поиском ==================
MasterTicket = -1; // До выполнения считаем, что ни..
MasterType = -1; // ..одного ордера нет
SlaveTicket = -1; // До выполнения считаем, что ни..
SlaveType = -1; // ..одного ордера нет
ArrayInitialize(OtherTicket, -1);
ArrayInitialize(OtherType, -1);
OtherCnt = 0; // Счетчик "других" ордеров
int total = OrdersTotal() - 1;
// - 1 - ================================== Окончание блока =============================

// - 2 - ================================ Произведение поиска ===========================
for (int i = total; i >= 0; i--) // Используется весь список ордеров
if (OrderSelect(i, SELECT_BY_POS)) // Убедимся, что ордер выбран
if (MathFloor(OrderMagicNumber()/10) == MagicNumber && // Ордер открыт экспертом,
OrderSymbol() == Symbol()) // ..который прикреплен к текущей..
{ // ..валютной паре
if (OrderOpenTime() < LastBoxTime) // Если ордер открыт до..
{ // ..возникновения последнего бокса,..
// ..то относим ордер к "другим"
OtherTicket[OtherCnt] = OrderTicket();
OtherType[OtherCnt] = OrderType();
OtherCnt++;
}
else // Иначе разделяем ордера на..
{ // ..первичный и компенсирующий
int ID = MathMod(OrderMagicNumber(), 10);// Получение идентификатора ордера

if (ID == 0) // Найдена первичная сделка
{
MasterTicket = OrderTicket();
MasterType = OrderType();
}
if (ID == 1) // Найден компенсирующий ордер
{
SlaveTicket = OrderTicket();
SlaveType = OrderType();
}
}
}
// - 2 - ================================== Окончание блока =============================
}
Ордера, открытые экспертом, имеют несколько классификаций. Одна из классификаций - это деление по принадлежности ордера сигналу. Ордера, открытые по последнему найденному боксу, относятся к "новым" ордерам и описываются переменными MasterTicket, MasterType, SlaveTicket и SlaveType. Ордера, открытые экспертом по более ранним сигналам, относятся к "другим" ордерам, что нашло отражение в названии переменных, их описывающих. Такие переменные в своем названии содержат символы "Other". Например, тикеты "других" ордеров записываются в массив OtherTicket, типы - в массив OtherType. Подсчет количества "других" ордеров производится при помощи счетчика OtherCnt. Отличие "новых" ордеров от "других" производится по времени их открытия. "Новые" имеют время открытия большее или равное, чем значение переменной LastBoxTime, а "старые" - меньшее.
Другой классификацией является деление ордеров на первичные и компенсирующие (вторичные). Первичными считаются ордера, открытые в направлении основного ценового движения, а компенсирующими - те, которые открыты в противоположном направлении. Первичные ордера описываются переменными MasterTicket и MasterType, а компенсирующие - SlaveTicket и SlaveType. Отличить первичные ордера от компенсирующих можно по значению поля MagicNumber, которое формируется как идентификатор эксперта, умноженный на 10, с прибавлением 0 или 1. Значение 0 соответствует первичному ордеру, а 1 - компенсирующему.
Связывание действий эксперта производится в функции start:

//+-------------------------------------------------------------------------------------+
//| Функция start эксперта |
//+-------------------------------------------------------------------------------------+
int start()
{
// - 1 - ========================== Можно ли работать эксперту? =========================
if (!Activate || FatalError) return(0);
// - 1 - ============================= Окончание блока ==================================

// - 2 - ========================== Контроль режима исполнения эксперта =================
if (!IsTesting())
{
Tick = MarketInfo(Symbol(), MODE_TICKSIZE); // минимальный тик
Spread = ND(MarketInfo(Symbol(), MODE_SPREAD)*Point);// текущий спрэд
StopLevel = ND(MarketInfo(Symbol(), MODE_STOPLEVEL)*Point);//текущий уровень стопов
FreezeLevel = ND(MarketInfo(Symbol(), MODE_FREEZELEVEL)*Point);// уровень заморозки
}
// - 2 - ============================= Окончание блока ==================================

// - 3 - ========================== Расчет сигналов открытия и закрытия =================
if (LastSignal != Time[0]) // На текущем баре сигнал еще не был..
{ // ..расчитан
GetSignal(1); // Расчет сигнала
LastSignal = Time[0]; // Сигнал на текущем баре был расчитан
}
// - 3 - ============================= Окончание блока ==================================

// - 4 - ================== Выполнение операций при обнаружении нового бокса ============
FindOrders(); //Сбор информации об имеющихся ордерах
if (LastBoxTime > PrevBoxTime) // Изменился бокс
{
if (!DeleteOtherPendings()) return(0); // Удаление старых отложенных ордеров
FindOrders(); //Сбор информации об имеющихся ордерах
if (!CheckOtherStops()) return(0); // Проверка стопов старых позиций
FindOrders(); //Сбор информации об имеющихся ордерах
if (!Trade()) return(0); // Установка новых отложенных ордеров
PrevBoxTime = LastBoxTime; // Все боксы обработаны
}
// - 4 - ============================= Окончание блока ==================================
else
// - 5 - ====== Выполнение операций на каждом тике, если новый бокс не обнаружен ========
{
if (MasterType < 2) // Первичный ордер сработал или его..
// ..вовсе нет
if (!DeleteOrder(SlaveTicket)) return(0); // Удаление компенсирующего ордера
FindOrders(); //Сбор информации об имеющихся ордерах
if (SlaveTicket < 0) // Компенсирующий ордер отсутствует
DeleteOrder(MasterTicket); // Удаление первичного ордера
}
// - 5 - ============================= Окончание блока ==================================
return(0);
}
Первые три блока являются стандартными и не требуют отдельного описания. Интерес представляют блоки 4 и 5.

Работа эксперта условно разделяется на два типа исполнения: выполнение действий при обнаружении нового бокса (новое пересечение средних линий) и выполнение действий, если новый бокс не обнаружен. Факт наличия нового бокса определяется по значению переменной LastBoxTime, задействованной в теле функции GetSignal. Сигналом появления нового бокса является неравенство значений LastBoxTime и PrevBoxTime. Значение переменной PrevBoxTime становится равным значению LastBoxTime, когда все необходимые действия при обнаружении нового бокса выполнены. "Необходимыми действиями" в этом случае являются: удаление отложенных ордеров, открытых по предыдущему сигналу (функция DeleteOtherPendings), изменение уровней стоп-приказов сделок, открытых по предыдущим сигналам (функция CheckOtherStops), и установка новых отложенных ордеров (функция Trade). Получение ошибки во время выполнения одной из перечисленных функций приводит к мгновенному прерыванию работы функции start, что запускает повторное исполнение всего набора действий при получении новой котировки. В случае успешного завершения работы функций DeleteOtherPendings, CheckOtherStops и Trade переменная PrevBoxTime принимает значение переменной LastBoxTime и блок 4 до нахождения следующего бокса не выполняется.

Блок 5 выполняется во всех случаях, когда не требуется выполнение блока 4, т.е. когда последний найденный бокс был полностью обработан. Здесь отслеживается необходимость удаления первичного или компенсирующего ордеров. Вспомним, что по условиям стратегии первичный ордер должен быть удален, когда компенсирующий ордер достиг профита, т.е. его нет (SlaveTicket < 0), а компенсирующий ордер должен быть удален, когда сработал первичный ордер (MasterType < 2, т.е. тип первичного Buy - 0 или Sell - 1).

Функции DeleteOtherPendings и DeleteOrder в силу своей простоты не нуждаются в отдельном рассмотрении. Функция CheckOtherStops подобна DeleteOtherPendings, но при обнаружении сделки вызывает более серьезную функцию CheckStop, передавая ей тикет найденной позиции:

//+-------------------------------------------------------------------------------------+
//| Проверка стопа указанной позиции |
//+-------------------------------------------------------------------------------------+
bool CheckStop(int ticket)
{
if (OrderSelect(ticket, SELECT_BY_TICKET) && // Существует ордер с заданным..
OrderCloseTime() == 0) // .. тикетом и ордер не закрыт
if (WaitForTradeContext()) // Свободен ли торговый поток?
{
RefreshRates();
double sl = 0;
// - 1 - ==================== Проверка длинной сделки ==========================
if (OrderType() == OP_BUY &&
MathAbs(OrderStopLoss() - Minimum + Tick) >= Tick)
{
sl = Minimum - Tick;
if (Bid - sl <= StopLevel)
return(false);
}
// - 1 - ========================== Окончание блока ============================

// - 2 - ==================== Проверка короткой сделки =========================
if (OrderType() == OP_SELL &&
MathAbs(OrderStopLoss() - Maximum - Spread - Tick) >= Tick)
{
sl = Maximum + Spread + Tick;
if (sl - Ask <= StopLevel)
return(false);
}
// - 2 - ========================== Окончание блока ============================

// - 3 - ==================== Модификация стоп-приказа =========================
if (sl > 0 && MathAbs(OrderStopLoss() - sl) >= Tick)
if (!OrderModify(OrderTicket(), 0, NP(sl), OrderTakeProfit(), 0))
return(false);
// - 3 - ========================== Окончание блока ============================
}
return(True); // Модификация прошла успешно
}
Первым действием функции является выбор ордера по полученному тикету ticket с проверкой существования сделки. Далее, в зависимости от типа позиции, производится проверка правильности уровня стоп-приказа. Если сделка длинная, то стоп-приказ сравнивается со значением переменной Minimum (минимальная цена последнего найденного бокса). Если же сделка короткая, то стоп-приказ сравнивается со значением переменной Maximum (максимальная цена последнего найденного бокса). Если уровень стоп-приказа требует изменения, то производится проверка возможности перемещения на новый уровень, чтобы новый стоп-приказ не оказался слишком близким к текущей цене.
После прохождения проверок в блоках 1 и 2, выполнение передается блоку 3, который выполняется, если рассчитано новое значение стоп-приказа (sl > 0) и оно не равно старому уровню стопа. В случае успешной модификации возвращается значение true, при ошибке будет возвращено значение false.
Установка новых отложенных ордеров при формировании бокса производится с помощью функции Trade:

//+-------------------------------------------------------------------------------------+
//| Открытие позиций |
//+-------------------------------------------------------------------------------------+
bool Trade()
{
if (LastBox == 0) return(true); // Бокс не найден. Выходим
// - 1 - ==================== Установка первичного ордера ===============================
if (MasterType < 0) // Первичный ордер не установлен
{
if (LastBox > 0) // Первичный будет вверху
{
int type = OP_BUYSTOP; // Поэтому его тип - Buy Stop
double price = NP(Maximum + Spread + Tick);// Цена открытия ордера - максимум
double sl = NP(Minimum - Tick); // Стоп-приказ за минимумом бокса
double tp = NP(UpTarget); // Профит - верхняя цель
}
else // Первичный ордер будет внизу
{
type = OP_SELLSTOP; // Поэтому его тип - Sell Stop
price = NP(Minimum - Tick); // Цена открытия ордера - минимум
sl = NP(Maximum + Spread + Tick); // Стоп-приказ за максимумом бокса
tp = NP(DownTarget + Spread); // Профит - нижняя цель
}

if (OpenOrderCorrect(type, DirectLots, price, sl, tp, 0) != 0) // Если ордер не..
return(false); // ..установлен, то вернем ошибку
}
// - 1 - ============================= Окончание блока ==================================

// - 2 - ==================== Открытие короткой позиции =================================
if (SlaveType < 0) // Компенсирующий ордер не установлен
{
if (LastBox < 0) // Компенсирующий будет вверху
{
type = OP_BUYSTOP; // Поэтому его тип - Buy Stop
price = NP(Maximum + Spread + Tick); // Цена открытия ордера - максимум
sl = NP(Minimum - Tick); // Стоп-приказ за минимумом бокса
tp = NP(UpTarget); // Профит - верхняя цель
}
else // Компенсирующий ордер будет внизу
{
type = OP_SELLSTOP; // Поэтому его тип - Sell Stop
price = NP(Minimum - Tick); // Цена открытия ордера - минимум
sl = NP(Maximum + Spread + Tick); // Стоп-приказ за максимумом бокса
tp = NP(DownTarget + Spread); // Профит - нижняя цель
}

if (OpenOrderCorrect(type, ReverseLots, price, sl, tp, 1) != 0) // Если ордер не..
return(false); // ..установлен, то вернем ошибку
}
// - 2 - ============================= Окончание блока ==================================

return(True); // Все операции завершены
}
Функция выполняется только при ненулевом значении переменной LastBox (0 означает отсутствие бокса). Успешным исполнением считается установка двух отложенных ордеров - первичного и компенсирующего. При получении ошибки во время установки одного или другого ордера, функция завершается аварийно и повторяется по приходу следующей котировки.

Сначала устанавливается первичный ордер - переменные MasterTicket и MasterType. Если основное направление движения цены - рост (LastBox = 1), то первичным ордером будет Buy Stop с соответствующей ценой открытия, уровнем стоп-приказа и профита. При определении падения цены, как основного направления движения (LastBox = -1), первичным ордером будет Sell Stop. Объемом первичного ордера является значение настроечного параметра эксперта DirectLots.

После успешной установки первичного ордера производится установка компенсирующего ордера - переменные SlaveTicket и SlaveType. Тип ордера в данном случае определяется с точностью до наоборот, по отношению к первичному. При LastBox = 1 тип компенсирующего ордера будет Sell Stop, а при LastBox = -1 - Buy Stop. Объем компенсирующего ордера указывается при помощи настроечного параметра эксперта ReverseLots.

Тестирование советника
Тестирование советника BifurcationBox, как обычно, произведем на наиболее популярных валютных парах - мажорах: EURUSD, USDCHF, GBPUSD и USDJPY. Не станут сюрпризами таймфрейм и исторический участок тестирования: Н1 и 01.01.2009 - 15.01.2011 соответственно. Каждой из валютных пар был подобран наиболее оптимальный набор настроечных параметров. От пары к паре изменения касались пяти из восьми значимых параметров: DirectLots, FastPeriod, SlowPeriod, DirectTarget и ReverseTarget. Результаты тестирования показаны на рис. 3-6.

http://www.forextrade.ru/media/Image/MQLabs/97_ag/EURUSD.gif
Рис. 3. Результаты тестирования эксперта BifurcationBox на валютной паре EURUSD.

EURUSD. Значения настроечных параметров: DirectLots = 0.2, Fastperiod = 5, SlowPeriod = 32, DirectTarget = 1.0, ReverseTarget = 0.618. Кривая баланса не вселяет особой уверенности, изобилуя длительными периодами просадки. Прибыль же набирается скачками. Немного лучше выглядит статистика тестирования стратегии: чистая прибыль 5 631 доллар при максимальной просадке 1 505 долларов. Фактор восстановления 3.74.

http://www.forextrade.ru/media/Image/MQLabs/97_ag/USDCHF.gif
Рис. 4. Результаты тестирования эксперта BifurcationBox на валютной паре USDCHF.

USDCHF. Значения настроечных параметров: DirectLots = 0.3, Fastperiod = 14, SlowPeriod = 31, DirectTarget = 2.118, ReverseTarget = 3.418. Вид кривой баланса свидетельствует о неспособности стратегии приносить прибыль в течение длительного промежутка времени. Первая половина тестирования прошла под знаком убытков, а вторая - под знаком прибыли. Конечно, хорошо, что в итоге прибыльная часть перевесила убыточную. Но, как говорится, "осадок остался". Подтверждают такой осадок статистические показатели: чистая прибыль 2 175 долларов при максимальной просадке 3 817 долларов, что дает фактор восстановления (ФВ) 0.57 - даже ниже единицы. С таким ФВ об использовании стратегии на валютной паре USDCHF можно забыть.

http://www.forextrade.ru/media/Image/MQLabs/97_ag/GBPUSD.gif
Рис. 5. Результаты тестирования эксперта BifurcationBox на валютной паре GBPUSD.

GBPUSD. Значения настроечных параметров: DirectLots = 0.14, Fastperiod = 5, SlowPeriod = 26, DirectTarget = 2.718, ReverseTarget = 1.518. Кривая баланса, несмотря на резкие взлеты и падения, смотрится увереннее своих предшественников. Особенно обнадеживает тот факт, что эта уверенность сохраняется на протяжении всего участка тестирования. Чистая прибыль 5 976 долларов, максимальная просадка 1 892 доллара. Фактор восстановления 3.16. В совокупности с видом кривой баланса этот результат стоит признать лучшим в сравнении с результатом, показанным стратегией на валютной паре EURUSD.

http://www.forextrade.ru/media/Image/MQLabs/97_ag/USDJPY.gif
Рис. 6. Результаты тестирования эксперта BifurcationBox на валютной паре USDJPY.

USDJPY. Значения настроечных параметров: DirectLots = 0.13, Fastperiod = 21, SlowPeriod = 37, DirectTarget = 2.318, ReverseTarget = 3.818. Полученная кривая имеет вид, очень близкий к идеальному виду - уверенность и стабильность сохраняется на всем участке тестирования. Чистая прибыль 4 209 долларов при максимальной просадке 548 долларов. Фактор восстановления 7.68, что является очень хорошим результатом.

Доработка стратегии для использования в AutoGraf 4.0
Преобразование эксперта BifurcationBox в стратегию "Точка бифуркации", которая может исполняться в среде AutoGraf 4.0, включает в себя этап установки соответствия между входными параметрами эксперта и настроечными параметрами AutoGraf. Небольшим препятствием является тот факт, что стратегия оперирует двумя параметрами, указывающими объем сделки: объем сделки, которая открывается в направлении сигнала (DirectLots), и объем сделки, которая открывается в противоположном от сигнала направлении (ReverseLots). Как известно, AutoGraf располагает лишь одним параметром Lot, позволяющим изменять объем сделок во время исполнения стратегии. Поэтому такую привилегию (изменение объема "на лету") можно оказать только одному из параметров. В данном случае это будет ReverseLots. Для указания объема "прямых" сделок необходимо будет использовать настроечный параметр AT_1.
Соответствие остальных параметров эксперта и настроечных параметров стратегии выглядит следующим образом: FastPeriod - AT_2, SlowPeriod - AT_3, MAMethod - AT_4, MAPrice - AT_5, DirectTarget - AT_6, ReverseTarget - AT_7.
Запуск стратегии "Точка бифуркации" в среде AutoGraf 4.0 состоит из следующих шагов:

Получить файл по ссылке Файлы стратегий для AutoGraf 4.0 (http://www.forextrade.ru/media/Image/MQLabs/97_ag/AG_BifurcationBox.zip) и распаковать полученный архив в папку MT4\experts\libraries (с перезаписью файлов AG_AT.ex4 и AG_AT.mq4).
Запустить AutoGraf (прикрепить индикатор AG_ind, а затем эксперт AG_exp).
Для работы стратегии в ключе приведенных результатов в окне настроек AutoGraf (закладка "Входные параметры") установить нужные значения параметров AT_1 - AT_7. Полное повторение результатов при этом не гарантируется.
Выбрать стратегию №5. Для этого необходимо передвинуть вверх значок So и среди названий стратегий найти значок S5, который также потянуть вверх.
Запустить функцию автоматической торговли, передвинув значок AT в верхнее положение.


Индикатор BifurcationBox (http://www.forextrade.ru/media/Image/MQLabs/97_ag/BifurcationBox.mq4)
Советник BifurcationBox (http://www.forextrade.ru/media/Image/MQLabs/97_ag/BifurcationBox_Expert.mq4)
Файлы стратегий для AutoGraf 4.0 (http://www.forextrade.ru/media/Image/MQLabs/97_ag/AG_BifurcationBox.zip)
Развернутые результаты тестирования эксперта (http://www.forextrade.ru/media/Image/MQLabs/97_ag/Test.zip)

Использование полученного советника рекомендуется только в полуавтоматическом режиме под присмотром трейдера и после всестороннего изучения слабых и сильных сторон стратегии.

Teodor
21-01-2011, 18:18
USDJPY. Выставил в точности такие же параметры и запутил скачанного советника. Прибыль в районе 230 долларов. Если начать с января 2010, то убыток в 24 доллара. Я что-то не понимаю?

Спасибо за ответ после статьи. Тестирование по всем тикам. Со спредом не совсем понятно - что значит спрэд минимальный, данные что не исторические? Качество 90%.
Прикрепил отчет.

Scriptong
22-01-2011, 08:05
USDJPY. Выставил в точности такие же параметры и запутил скачанного советника. Прибыль в районе 230 долларов. Если начать с января 2010, то убыток в 24 доллара. Я что-то не понимаю?

Спасибо за ответ после статьи. Тестирование по всем тикам. Со спредом не совсем понятно - что значит спрэд минимальный, данные что не исторические? Качество 90%.
Прикрепил отчет.

Первое, что бросается в глаза - другой брокер. Для тестирования я использую сервер Admiral Markets. Уже на этом этапе возможны расхождения, т.к. торговые условия от брокера к брокеру меняются. Если сравнить первую похожую закрытую сделку моего отчета и вашего (2009.01.20 18:13 - у вас и 2009.01.20 17:13 - у меня), то сразу получаем серьезное расхождение: у вас итог 1.46 доллара, у меня - 14.61 (т.е. у вас в 10 раз меньше). Отсюда можно сделать вывод, что ваш спрэд в пять раз больше (5*2 = 10). Это первая причина различных итогов.

Вторая причина, как я и предполагал, заключается в недостаточно закачанной вами истории. Сравните следующие участки тестирования: 2010.03.15 - 2010.04.06, 2010.05.10 - 2010.07.14, 2010.07.26 - 2010.08.05. В вашем отчете сделок в эти периоды просто нет. У меня они есть. Это говорит о том, что история котировок за указанные исторические периоды у вас отсутствует. Из тестирования в общей сложности выпало четыре месяца. В итоге вы не досчитались 50 сделок. Для исправления ситуации закачайте полную историю, приведенную в одной из моих статей -Объем сделки и вероятность ее успешности (http://www.forextrade.ru/mqlabs/16.09.2010-mqlabs-obem-sdelki-i-veroyatnost-ee-uspeshnosti), раздел Тестирование.

Teodor
22-01-2011, 12:12
Большое спасибо за потраченное время.
Из-за различия брокеров, у нас разные размеры лотов - у Вас 0.1 Lot соответствует 1 USD для 1pip, а у меня 0.1 USD.
Так что мои прибыли/убытки можно умножить на 10. Тогда, правда, минус в 2010 станет больше...

А почему у Вас в отчете по USDJPY чистая прибыль 3820.53, а в статье 4 209?

Прочитал статью. Конечно, здорово, что есть файлы с данными. Но есть такая проблема, что это не исторические данные того брокера которым я пользуюсь (и, насколько я понимаю, не Вашего, раз Вы решили не использовать исторические данные из терминала). То есть размер спрэдов и вообще сдвиг котировок при торговле в реальном времени может отличатся от полученных при тестах на этих данных.
А те данные в статье откуда? Можно, скажем, скачать обновление?
Был бы признателен, если бы Вы мне объяснили, как при тестировании определяется спрэд - по реальным историческим данным брокера, или берется какое-то случайное (/стандартное) значение для каждого брокера?

И еще вопрос - у Вас все подсчитывается на новом баре ( if (LastSignal != Time[0]) или if (LastBar == Time[0]) return(0); в предыдущих версиях), а почему? Ведь можно все считать по тикам? Просто у меня при таком тестировании (других стратегий) постоянно возникает ошибка несоответствия данных по time-frame-ам: test generator: unmatched data error, а если закомментировать эту строчку - то не возникает, но результаты конечно совсем другие.

Scriptong
22-01-2011, 18:04
Большое спасибо за потраченное время.
Из-за различия брокеров, у нас разные размеры лотов - у Вас 0.1 Lot соответствует 1 USD для 1pip, а у меня 0.1 USD.
Так что мои прибыли/убытки можно умножить на 10. Тогда, правда, минус в 2010 станет больше...

Тогда понятно.



А почему у Вас в отчете по USDJPY чистая прибыль 3820.53, а в статье 4 209?


Видимо, в архив попал отчет с более раннего тестирования. Я ориентировался на следующий файл (см. аттач).



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


Да, данные были дополнены из истории, которую предоставляет MT5. Начальные данные были сформированы в МТ4 путем обращения к HC (F2). Так что полученной истории можно доверять.



Был бы признателен, если бы Вы мне объяснили, как при тестировании определяется спрэд - по реальным историческим данным брокера, или берется какое-то случайное (/стандартное) значение для каждого брокера?


Берутся текущие торговые условия (спрэд, стоплевел и т.д.). Поэтому тестирование в различное время суток при прочих равных условиях может давать различные результаты.



И еще вопрос - у Вас все подсчитывается на новом баре ( if (LastSignal != Time[0]) или if (LastBar == Time[0]) return(0); в предыдущих версиях), а почему? Ведь можно все считать по тикам? Просто у меня при таком тестировании (других стратегий) постоянно возникает ошибка несоответствия данных по time-frame-ам: test generator: unmatched data error, а если закомментировать эту строчку - то не возникает, но результаты конечно совсем другие.

Данную строку из советника убирать нельзя, т.к. это будет совсем другой советник.