Scriptong
07-03-2011, 20:50
Своим существованием различного рода рынки напрямую обязаны наличию у человека необходимости в обмене товаров, которая на рынке приобретает статус "покупки" или "продажи". Акт купли-продажи становится возможным только в том случае, когда существует две стороны - покупатель и продавец. Торговый процесс будет протекать до тех пор, пока на одного предложение продажи существует одно предложение покупки. В момент отсутствия одной из сторон сделки торговый процесс утрачивает равновесие. Если не хватает покупателей, то возникает профицит (излишек товара), приводящий к падению цены, что далеко не всегда приводит к появлению покупателей. Если же не хватает продавцов, то ощущается дефицит (недостача товара). Выход из этой ситуации наиболее часто одинаков - повышение цены. Как и в первом случае, эта мера не является панацеей и вполне может привести к полной распродаже товара, даже по завышенной цене. Таков закон спроса и предложения, который не дает успокоиться рыночной цене.
В результате выходит, что состояние полного покоя - некая абстракция, т.к. рынку покой "может только сниться" (рынку Форекс, видимо, по субботам и воскресеньям). Тем не менее, даже в разгар торгов такая абстракция может существовать некоторое время. Посудите сами: у продавца есть достаточное количество товара, который ему обязательно нужно продать. В то же время, имеется достаточное количество покупателей товара. Какой смысл продавцу повышать цену? Торговый процесс будет протекать стабильно, без смены цены. До поры до времени, конечно. То есть приходим к выводу, что рынок всегда будет стремиться к равновесию, без достижения которого само существование рынка становится бессмысленным.
Предсказание точки равновесия представляется довольно сложным занятием, т.к. для этого нужно точно знать количество требуемого и предлагаемого в будущем товара. Имея дело с рынком Форекс, говорить о количестве вообще не приходится. В распоряжении трейдера есть лишь история изменения цены... Но позвольте, что значит "лишь"? История изменения цены это не так уж и мало. На подобных графиках без труда можно найти зоны покоя - это "области плотной штриховки" (термин А. Элдера). Трейдеры называют их флэтовыми зонами. Путь цены к флэту всегда проходит через ее изменение - рост или падение. По аналогии с законом спроса и предложения, предположим, что рост цены - это компенсация предыдущих падений цены, а падение, в свою очередь, является компенсацией предыдущих ростов. Если эта гипотеза верна, то для предсказания будущего направления движения цены необходимо располагать информацией об имеющемся дисбалансе в количественном росте и падении.
На чем может быть основан расчет дисбаланса? Здесь поможет любимый инструмент большинства трейдеров - средняя скользящая линия, точнее, две линии, пересечение которых образует замкнутые области (см. рис. 1).
http://www.forextrade.ru/media/Image/MQLabs/104_ag/figure1.png
Рис. 1. Замкнутые области между двумя средними скользящими линиями.
В итоге получаем два вида областей: область роста (красная гистограмма) и область падения (синяя гистограмма). Каждая область характеризуется занимаемой площадью, которая и будет нас интересовать. Если суммировать площади однотипных областей за некоторый период, то получим два значения, по соотношению которых можно судить о наличии баланса или дисбаланса в распределении сил, определяющих направление движения цены. Так, если суммарная площадь областей роста цены превышает суммарную площадь областей падения цены, то можно говорить о дисбалансе в пользу роста. Этот дисбаланс необходимо расценивать, как вероятность будущего падения цены, при котором сложившийся перевес роста будет компенсирован нисходящим движением.
Расчет площади каждой области не потребует знаний высшей математики, которая предлагает находить площадь фигуры, образованной двумя кривыми, путем интегрирования функций, соответствующих кривым, на определенном отрезке. В терминале Meta Trader 4 ось абсцисс - это время, исчисляемое в барах (свечах), а бары не имеют какой-либо ширины. Видимое пространство между ними необходимо лишь для обеспечения удобства пользователю и может быть увеличено или уменьшено, что не должно влиять на рассчитываемый размер площади. Поэтому для расчета площади рассматриваемых областей достаточно сложить ценовые разности между скользящими средними линями.
Следующим этапом расчета будет сложение площадей, соответствующих однотипным областям. Для получения правильных значений необходимо обеспечить равные условия для каждого типа области, т.е. взять одинаковое количество соответствующих типов областей (например, 10 одних и 10 других). Нет смысла производить расчеты на основании всей имеющейся истории котировок, т.к., во-первых, глубина истории от одного пользователя к другому может существенно меняться, что не применит сказаться на результатах. Во-вторых, при увеличении глубины выборки соотношение сумм площадей будет стремиться к равновесию (при увеличении количества подбрасываний монетки количество выпадений орла и количество выпадений решки стремится к равным значениям), из которого нельзя получить сколько-нибудь полезную информацию. По завершении расчета остается лишь сопоставить полученные значения. Наиболее удобный способ сопоставления - указание соотношения величин в процентах.
Задачи расчета, сопоставления и отображения вычисленных значений будет решать индикатор Square. Для получения решения задачи требуется указание исходных данных, каковые в данном случае представлены следующим набором:
// == Настроечные параметры индикатора ==================================================
extern int MACDFast = 24; // Период быстрой средней MACD
extern int MACDSlow = 120; // Период медленной средней MACD
extern int MACDPrice = 5; // Цена расчета средней:
// 0 - Close
// 1 - Open
// 2 - High
// 3 - Low
// 4 - Median
// 5 - Typical
// 6 - Weighted Close
extern int MACDMethod = 3; // Метод расчета средней
// 0 - Simple
// 1 - Exponential
// 2 - Smoothed
// 3 - Linear Weighted
extern int SamplingDepth = 10; // Глубина выборки. Должна быть четным
// ..числом более 1
extern int MaxLevel = 80; // Значение соотношения площади роста
// ..и площади падания, при котором..
// ..не рекомендуется открывать..
// ..сделки против соотношения
// == Окончание блока ==================================================================
Первые четыре настроечных параметра имеют префикс MACD, хотя на самом деле все они относятся к обычным средним линиям. Появление префикса MACD в названиях входных параметров объясняется тем фактом, что в процессе расчета разности двух средних линий получается значение другого, не менее известного, индикатора - MACD. В таком представлении параметров явно чувствуется отсутствие еще одного наименования - MACDSignal (период сигнальной линии индикатора MACD). В данном случае указание периода сигнальной линии не требуется, т.к. ее значение в программе не используется.
Значение глубины выборки указывается при помощи параметра SamplingDepth. Значение 10 означает, что для расчета будет взято 5 последних областей каждого типа: 5 положительных и 5 отрицательных. Отсюда следует ограничение, накладываемое на величину выборки: это должно быть четное число (иначе не получится взять равное количество областей каждого типа) не меньшее, чем 2 (1 - нечетное число, а 0, хоть и четное, не дает возможности получить хоть какую-нибудь выборку).
Последний параметр MaxLevel указывает предельно рассматриваемое соотношение площадей роста и падения. Например, при соотношении 60% (площадь роста) и 40% (площадь падения) имеем дисбаланс в сторону роста. В итоге можно говорить о том, что в ближайшее время перевес в пользу роста будет компенсирован, т.е. разовьется нисходящее движение. Если рассматриваемое соотношение было получено, когда быстрая средняя пересекла медленную сверху вниз (классический сигнал открытия короткой сделки), то факт наличия дисбаланса является подтверждением такого сигнала. С другой стороны, во время устойчивых трендов дисбаланс может достигать некоторого критического соотношения. Например, 80% против 20%, как указано в приведенном коде. То есть сумма площадей одной из областей не просто превышает сумму площадей другой области, а доминирует над оппонентом. В таких ситуациях сигналы, противоположные тренду, чаще говорят о начале коррекции, чем о затухании тренда. Поэтому при доминировании одного из типов областей над другим лучше воздержаться от заключения сделок как в одну, так и в другую сторону.
Еще одним назначением параметра MaxLevel является указание момента закрытия текущей сделки. Например, сделка была открыта при соотношении 75% к 25% в направлении преобладающего типа областей. За время существования сделки тренд в сторону преобладания продолжился, и соотношение сумм площадей выросло до критического значения - 80% к 20%. Логичным действием в этом случае является закрытие сделки, т.к. рынок вошел в фазу высокой неопределенности: тренд может продолжиться, а может резко развернуться.
Рассмотрим первую необходимую часть индикатора - функцию расчета сумм площадей роста и падения:
//+-------------------------------------------------------------------------------------+
//| Вычисление площади положительной и отрицательной областей |
//+-------------------------------------------------------------------------------------+
void Square(int k)
{
int cnt = 0; // Счетчик областей роста и падения
Above = 0; // Сумма площадей роста
Below = 0; // Сумма площадей падения
while (cnt < SamplingDepth && k < Bars) // Рассчитываем, пока не достигнем..
{ // ..нужной глубины выборки или..
// ..достигнем конца истории
if (MACD[k] > 0) // Положительные считаем отдельно
Above += MACD[k];
else // Отрицательные отдельно
Below += MACD[k];
if ((MACD[k] > 0 && MACD[k+1] <= 0) || // Если произошел переход от одной..
(MACD[k] < 0 && MACD[k+1] >= 0)) // ..области к другой, то увеличиваем
cnt++; // ..счетчик областей
k++; // Переходим к следующему бару
}
}
Функция Square обладает единственным аргументом - k. Через него передается номер бара, начиная с которого необходимо производить расчет площадей. Сумма площадей роста сохраняется в переменной Above, а сумма площадей падения цены - в переменной Below. Обе переменные являются глобальными, поэтому объявления в пределах функции не требуют. Все, что требуется в данном случае - это обнуление значения переменных, чтобы предыдущие результаты не были учтены в текущем расчете.
Далее следует цикл "пока", счетчиком которого является переменная cnt, хранящая количество учтенных областей роста или падения цены. Цикл может быть прерван по двум причинам: достижение необходимого количества областей роста или падения цены (SamplingDepth) или достижение конца имеющейся истории котировок. Переменная Above увеличивает свое значение, когда быстрая средняя скользящая линия оказывается выше, чем медленная средняя линия. Признаком этого является значение индикаторного буфера MACD, который рассчитывается в функции start, но не отображается на графике. Аналогично переменной Above, при нахождении быстрой средней линии ниже медленной, происходит изменение значения переменной Below, которое уменьшается, т.к. значение буфера MACD при этом является отрицательным.
Счетчик cnt увеличивает свое значение в тех случаях, когда значения MACD на текущем и предыдущем барах имеют разный знак, что говорит о моменте пересечения средних линий, а, следовательно, о смене типа области.
Полученные значения Above и Below нуждаются в отображении на графике, чтобы пользователь смог увидеть их и проанализировать. Эту задачу решает функция ShowInfo:
//+-------------------------------------------------------------------------------------+
//| Отображение объектов-надписей |
//+-------------------------------------------------------------------------------------+
void ShowInfo(datetime time, double price, double koef)
{
// - 1 - == Инициализация текстового значения надписей ==================================
if (Above-Below != 0) // Если соотношение площадей не равно,
{ // ..то выведем полученные соотношения
string UText = DoubleToStr(Above/(Above-Below)*100, 1) + "%";
string DText = DoubleToStr(-Below/(Above-Below)*100, 1) + "%";
}
else // Если соотношение площадей равно, то
{ // ..выведем значения 50% и 50%
UText = "50%";
DText = "50%";
}
// - 1 - == Окончание блока =============================================================
// - 2 - == Отображение верхнего значения ===============================================
string name = prefix + time + "U"; // Формирование уникального имени..
// ..объекта
if (ObjectFind(name) < 0) // Если объект не найден, то..
{
ObjectCreate(name, OBJ_TEXT, 0, time, price+koef/5);// ..создаем его
ObjectSet(name, OBJPROP_COLOR, indicator_color1);// Устанавливаем цвет надписи
ObjectSetText(name, UText, 8); // Заполняем надпись содержимым
}
// - 2 - == Окончание блока =============================================================
// - 3 - == Отображение нижнего значения ================================================
name = prefix + time + "D"; // Формирование уникального имени..
// ..объекта
if (ObjectFind(name) < 0) // Если объект не найден, то..
{
ObjectCreate(name, OBJ_TEXT, 0, time, price-koef/5);// ..создаем его
ObjectSet(name, OBJPROP_COLOR, indicator_color2);// Устанавливаем цвет надписи
ObjectSetText(name, DText, 8); // Заполняем надпись содержимым
}
// - 3 - == Окончание блока =============================================================
}
Аргументов у функции три: time и price - время и цена на графике, где необходимо отобразить информацию, koef - отступ в пунктах от указанной цены, который нужно учесть при отображении каждого из двух значений. Так как значения два, то отображение их с одинаковыми координатами приведет к "каше" на экране. Поэтому для вычисления координаты по вертикали одного значения к заданной цене price добавляется значение koef, а для вычисления координаты другого значения из price вычитается koef.
В первом блоке функции производится подсчет значений соотношений Above и Below, а также преобразование чисел в строку. В строковой переменной UText сохраняется текстовое представление числа, соответствующее части суммы площадей роста от общего числа площадей роста и падения, а в переменной DText - части площадей падения от общего числа площадей. Так как для расчета процентного соотношения требуется выполнить операцию деления, то перед выполнением деления производится проверка равенства знаменателя нулю. Знаменателем в данном случае выступает выражение Above - Below (знак "минус" используется для получения суммы, т.к. переменная Below содержит отрицательное значение). Ноль может быть получен лишь в одном случае, когда значения переменных равны. Равенство переменных означает, что соотношение сумм площадей роста и падения цены равно, т.е. "50% на 50%", как и указывается в конечной части блока 1.
Второй и третий блоки алгоритмически подобны. Их задачей является создание графического объекта - текстовой надписи. Название графического объекта должно быть уникальным и, в то же время, должно легко идентифицироваться индикатором как собственное. Поэтому имя объекта состоит из трех частей. Первая часть одинакова для всех объектов графика. Это значение переменной prefix, которое можно изменять, редактируя файл исходного кода индикатора. В данном случае это строка "iSquare_". Вторая часть имени - время (X-координата) на графике, соответствующее объекту. Время является уникальной характеристикой объекта, кроме одного случая - появление второй надписи на этом же баре, т.к. необходимо отобразить два значения. Для различия между двумя объектами, соответствующими одному и тому же времени, необходима третья часть имени - литера "U" (для верхней надписи) или "D" (для нижней надписи). После определения имени производится проверка существования объекта и, если объект с таким именем не найден, создание объекта с установкой нужного цвета и текста.
Использование рассмотренных функций осуществляется в главной функции индикатора start:
//+-------------------------------------------------------------------------------------+
//| Custom indicator iteration function |
//+-------------------------------------------------------------------------------------+
int start()
{
if (!Activate) return(0);
// - 1 - == Вычисление необходимости обновления данных ==================================
int limit, i; // Переменные цикла
if (LastBar == Time[0]) // Если текущий бар уже был рассчитан, то
limit = 0; // ..пересчитываем только его
else // ..если не был рассчитан, то..
if (LastBar == 0) // ..при первом входе рассчитаем значения
limit = Bars-3; // ..для всех имеющихся баров
else // Если расчет производился на каком-то..
{ // ..другом баре, то..
limit = iBarShift(NULL, 0, LastBar + Period()*60);// ..начнем расчет с первого..
// ..бара после него
if (MACD[limit+1] > 0) // Также не забудем обработать..
Above += MACD[limit+1]; // ..окончательное значение для..
else // ..сформированного бара limit+1,..
Below += MACD[limit+1]; // .. прибавив значение площади роста..
// ..или площади падения
}
LastBar = Time[0]; // Отметим новый бар
// - 1 - == Окончание блока =============================================================
// - 2 - == Отображение индикатора на истории ===========================================
for(i = limit; i >= 0; i--) // По всем непосчитанным барам
{
MACD[i] = iMA(NULL, 0, MACDFast, 0, MACDMethod, MACDPrice, i) - // Вычисление..
iMA(NULL, 0, MACDSlow, 0, MACDMethod, MACDPrice, i);// ..разности..
// ..значений средних скользящих (MACD)
// - 2.1 - == Пересечение снизу вверх (сигнал покупки) ============================
if (MACD[i+1] > 0 && MACD[i+2] <= 0) // Если произошло пересечение снизу вверх
{
double k = iATR(NULL, 0, 14, i); // Подсчитаем среднюю волатильность
Square(i+2); // Рассчитаем площади
if (Above - Below == 0) // При равенстве площадей выведем значок..
GreateUp[i] = Low[i] - k; // .."большой палец вверх". Можно..
else // ..открываться
if (MathAbs(Below/(Above - Below))*100 >= MaxLevel ||// При большом..
Above/(Above - Below)*100 >= MaxLevel)// ..превосходстве одной площади..
Up[i] = Low[i] - k; // ..падения над другой выведем "стрелку..
// ..вверх", заходить нежелательно
else // Если уровень MaxLevel не преодолен,то..
GreateUp[i] = Low[i] - k; // ..выведем значок "большой палец вверх"
ShowInfo(Time[i] + 180*Period(), // Покажем результат соотношения
MathMax(Up[i], GreateUp[i]),
k);
FollowBuy = true; // Необходимо отслеживать площадь роста
FollowSell = false; // Площадь падения отслеживать не нужно
}
// - 2.1 - == Окончание блока =====================================================
// - 2.2 - == Пересечение сверху вниз (сигнал продажи) ============================
if (MACD[i+1] < 0 && MACD[i+2] >= 0) // Если произошло пересечение сверху вниз
{
k = iATR(NULL, 0, 14, i); // Подсчитаем среднюю волатильность
Square(i+2); // Рассчитаем площади
if (Above - Below == 0) // При равенстве площадей выведем значок..
Down[i] = High[i] + k; // .."большой палец вниз". Можно..
else // ..открываться
if (Above/(Above - Below)*100 >= MaxLevel ||// При большом превосходстве..
MathAbs(Below/(Above - Below))*100 >= MaxLevel)// ..одной площади..
Down[i] = High[i] + k; // ..над другой выведем "стрелку вниз",..
// ..заходить нежелательно
else // Если уровень MaxLevel не преодолен,то..
GreateDown[i] = High[i] + k; // ..выведем значок "большой палец вниз"
ShowInfo(Time[i] + 180*Period(), // Покажем результат соотношения
MathMax(Down[i], GreateDown[i]),
k);
FollowSell = true; // Необходимо отслеживать площадь падения
FollowBuy = false; // Площадь роста отслеживать не нужно
}
// - 2.2 - == Окончание блока =====================================================
// - 2.3 - == Слежение за длинной сделкой =========================================
if (FollowBuy) // Если нужно продолжать подсчет сумм..
{ // ..после получения сигнала
k = 0; // Значение MACD текущего бара
if (i == 0) // Если текущий бар нулевой, то занесем..
k = MACD[i]; // ..значение MACD в переменную k
else // Иначе можно увеличивать общую сумму
Above += MACD[i]; // Увеличим площадь роста
if (Above + k - Below == 0) continue; // При делении на ноль выходим
if ((Above+k)/(Above+k-Below)*100 >= MaxLevel)// Если ссоотношение площади роста
{ // .. и площади падения превысило MaxLevel
CloseTrade[i] = High[i] + iATR(NULL, 0, 14, i);// ..отметим на графике этот..
FollowBuy = false; // ..факт и прекратим дальнейшее..
} // ..отслеживание событий
else // Иначе не отмечаем
CloseTrade[i] = 0;
}
// - 2.3 - == Окончание блока =====================================================
// - 2.4 - == Слежение за короткой сделкой ========================================
if (FollowSell) // Если нужно продолжать подсчет сумм..
{ // ..после получения сигнала
k = 0; // Значение MACD текущего бара
if (i == 0) // Если текущий бар нулевой, то занесем..
k = MACD[i]; // ..значение MACD в переменную k
else // Иначе можно увеличивать общую сумму
Below += MACD[i]; // Увеличим площадь падения
if (Above-Below-k == 0) continue; // При делении на ноль выходим
if (MathAbs((Below+k)/(Above-Below-k))*100 >= MaxLevel)// Если ссоотношение..
{ // ..площади падения и площади роста..
// ..превысило MaxLevel
CloseTrade[i] = Low[i] - iATR(NULL, 0, 14, i);// ..отметим на графике этот..
FollowSell = false; // ..факт и прекратим дальнейшее..
} // ..отслеживание событий
else // Иначе не отмечаем
CloseTrade[i] = 0;
}
// - 2.4 - == Окончание блока =====================================================
}
// - 2 - == Окончание блока =============================================================
return(0);
}
Специфика индикатора такова, что оптимизация его вычислений при помощи стандартной функции IndicatorCounted затруднительна. Трудность заключается в том, что значения Above и Below, как видно из кода функции start, формируются накопительным итогом от момента пересечения средних скользящих. При использовании IndicatorCounted потребовалось бы повторное нахождение последнего пересечения средних линий и пересчет значений сумм площадей роста и падения на каждом тике. Реализованный метод расчета (без IndicatorCounted) этого недостатка лишен. Вместо IndicatorCounted используется принцип, хорошо зарекомендовавший себя при использовании в экспертах - определение времени открытия последнего бара, на котором расчет уже производился. Время сохраняется в переменной LastBar. Определение номера бара, с которого нужно производить расчет, занимает код всего первого блока. Если в LastBar сохранено значение, соответствующее текущему бару (бару с индексом 0), то становится понятно, что расчет на текущем баре уже производился и необходимо лишь произвести незначительные изменения для бара с индексом 0. Если значение LastBar не соответствует текущему бару, то в этом случае возможно два варианта. Первый вариант - индикатор только что загружен (значение LastBar равно нулю). Значит, следует произвести расчет значений индикатора по всей доступной истории, т.е., начиная с бара № Bars-3 (для расчета нужно хотя бы два бара слева от расчетного бара). Второй вариант - произошла смена бара. Смена бара может происходить в штатном порядке - бар, индекс которого был 0, приобрел индекс 1, а новый бар появился. А может случиться и так, что на некоторое время пропала связь с сервером брокера, и последний рассматриваемый бар получил индекс более чем 1. Тогда необходимо пересчитать всю историю от последнего посчитанного бара до текущего. Получаем, что неважно, какой номер бара имеется в данном случае - 1 или 10. Главное, чтобы было учтено значение на прошлом баре, а цикл пересчета запущен с первого после обрыва связи бара. Номер бара рассчитывается при помощи функции iBarShift, а учет значения на последнем баре проводится простым прибавлением к значениям переменных Above и Below.
Второй блок функции start - это пересчет истории от бара с индексом limit, рассчитанного в блоке 1, до бара с индексом 0. Индикатор содержит шесть индикаторных буферов, значения четырех из которых видны пользователю, а одного, MACD, не видны. Видимые буфера: Up - "стрелка вверх", GreateUp - "большой палец вверх", Down - "стрелка вниз", GreateDown - "большой палец вниз", CloseTrade - "галочка". Up и Down отображаются на каждом пересечении средних, если не произошло отображения буферов GreateUp и GreateDown. GreateUp и GreateDown отображаются, если соотношение сумм площадей роста и падения не превысило значение MaxLevel, то есть рекомендуется открывать сделку. Если сделку открывать уже поздно (доминирует одна из областей), то отображается обычная "стрелка вверх" или "стрелка вниз". Если после открытия сделки достигается уровень соотношения MaxLevel, то отображается "галочка". Алгоритмически подобными блоками являются пары 2.1 и 2.2, 2.3 и 2.4.
Блоки 2.1 и 2.2 исполняются при обнаружении пересечения средних скользящих линий (2.1 - быстрая пересекла медленную снизу вверх, 2.2 - сверху вниз). В этот момент вызывается функция Square, рассчитывающая значения Above и Below. В зависимости от их соотношения отображается один из буферов, отвечающих за движение вверх (в случае 2.2 - вниз). После этого вызывается функция ShowInfo, выводящая соотношение Above и Below на график, а затем активизируется один из флагов FollowBuy или FollowSell, означающих, что необходимо отслеживать дальнейший рост площади соответствующей области.
Блоки 2.3 и 2.4 отслеживают рост площади соответствующей области с тем, чтобы вывести значок "галочки", означающий прекращение торговли в данном направлении, т.е. достижение критического соотношения, которое больше или равно, чем значение MaxLevel. Присутствие переменной k в каждом блоке нужно для того, чтобы в переменных Above и Below находились значения, соответствующие сформированным барам. Для текущего, нулевого, бара рассчитывается значение переменной k, учитываемое при подсчете текущего соотношения. При достижении соотношения уровня MaxLevel слежение за ростом площади области прекращается.
Результат работы разработанного индикатора показан на рис. 2.
http://www.forextrade.ru/media/Image/MQLabs/104_ag/figure2.png
Рис. 2. Результат работы индикатора Square.
Критический уровень соотношения сумм площадей областей роста и падения цены здесь установлен 70%. Первая сделка на рис. 2 - короткая. Соотношение в пользу падения (67.6% против 32.4%) и критический уровень не достигнут, поэтому сделку можно открывать. Как видно, решение оказалось правильным. Индикатор также подсказал точку выхода, которая оказалась на 120 пунктов ниже точки входа. Затем последовал неправильный совет - открытие длинной сделки (соотношение 64.5% против 35.5% в пользу падения). Возможно, в случаях, когда соотношение не в пользу направления сделки, не стоит открывать сделки. Через три часа после открытия длинной следует сигнал открытия короткой, но он не подтверждается соотношением сумм площадей роста и падения - падение достигло критического уровня. Короткая сделка не открывается. А вот последующая длинная открывается и успешно отрабатывает, если, конечно, к тому моменту была закрыта предыдущая длинная сделка.
О том, как наилучшим образом интерпретировать показания индикатора Square, поговорим во второй части материала. Рассуждения будут основаны на результатах тестирования эксперта, работающего по сходному с индикатором Square принципу.
Индикатор Square (http://www.forextrade.ru/media/Image/MQLabs/104_ag/Square.mq4)
В результате выходит, что состояние полного покоя - некая абстракция, т.к. рынку покой "может только сниться" (рынку Форекс, видимо, по субботам и воскресеньям). Тем не менее, даже в разгар торгов такая абстракция может существовать некоторое время. Посудите сами: у продавца есть достаточное количество товара, который ему обязательно нужно продать. В то же время, имеется достаточное количество покупателей товара. Какой смысл продавцу повышать цену? Торговый процесс будет протекать стабильно, без смены цены. До поры до времени, конечно. То есть приходим к выводу, что рынок всегда будет стремиться к равновесию, без достижения которого само существование рынка становится бессмысленным.
Предсказание точки равновесия представляется довольно сложным занятием, т.к. для этого нужно точно знать количество требуемого и предлагаемого в будущем товара. Имея дело с рынком Форекс, говорить о количестве вообще не приходится. В распоряжении трейдера есть лишь история изменения цены... Но позвольте, что значит "лишь"? История изменения цены это не так уж и мало. На подобных графиках без труда можно найти зоны покоя - это "области плотной штриховки" (термин А. Элдера). Трейдеры называют их флэтовыми зонами. Путь цены к флэту всегда проходит через ее изменение - рост или падение. По аналогии с законом спроса и предложения, предположим, что рост цены - это компенсация предыдущих падений цены, а падение, в свою очередь, является компенсацией предыдущих ростов. Если эта гипотеза верна, то для предсказания будущего направления движения цены необходимо располагать информацией об имеющемся дисбалансе в количественном росте и падении.
На чем может быть основан расчет дисбаланса? Здесь поможет любимый инструмент большинства трейдеров - средняя скользящая линия, точнее, две линии, пересечение которых образует замкнутые области (см. рис. 1).
http://www.forextrade.ru/media/Image/MQLabs/104_ag/figure1.png
Рис. 1. Замкнутые области между двумя средними скользящими линиями.
В итоге получаем два вида областей: область роста (красная гистограмма) и область падения (синяя гистограмма). Каждая область характеризуется занимаемой площадью, которая и будет нас интересовать. Если суммировать площади однотипных областей за некоторый период, то получим два значения, по соотношению которых можно судить о наличии баланса или дисбаланса в распределении сил, определяющих направление движения цены. Так, если суммарная площадь областей роста цены превышает суммарную площадь областей падения цены, то можно говорить о дисбалансе в пользу роста. Этот дисбаланс необходимо расценивать, как вероятность будущего падения цены, при котором сложившийся перевес роста будет компенсирован нисходящим движением.
Расчет площади каждой области не потребует знаний высшей математики, которая предлагает находить площадь фигуры, образованной двумя кривыми, путем интегрирования функций, соответствующих кривым, на определенном отрезке. В терминале Meta Trader 4 ось абсцисс - это время, исчисляемое в барах (свечах), а бары не имеют какой-либо ширины. Видимое пространство между ними необходимо лишь для обеспечения удобства пользователю и может быть увеличено или уменьшено, что не должно влиять на рассчитываемый размер площади. Поэтому для расчета площади рассматриваемых областей достаточно сложить ценовые разности между скользящими средними линями.
Следующим этапом расчета будет сложение площадей, соответствующих однотипным областям. Для получения правильных значений необходимо обеспечить равные условия для каждого типа области, т.е. взять одинаковое количество соответствующих типов областей (например, 10 одних и 10 других). Нет смысла производить расчеты на основании всей имеющейся истории котировок, т.к., во-первых, глубина истории от одного пользователя к другому может существенно меняться, что не применит сказаться на результатах. Во-вторых, при увеличении глубины выборки соотношение сумм площадей будет стремиться к равновесию (при увеличении количества подбрасываний монетки количество выпадений орла и количество выпадений решки стремится к равным значениям), из которого нельзя получить сколько-нибудь полезную информацию. По завершении расчета остается лишь сопоставить полученные значения. Наиболее удобный способ сопоставления - указание соотношения величин в процентах.
Задачи расчета, сопоставления и отображения вычисленных значений будет решать индикатор Square. Для получения решения задачи требуется указание исходных данных, каковые в данном случае представлены следующим набором:
// == Настроечные параметры индикатора ==================================================
extern int MACDFast = 24; // Период быстрой средней MACD
extern int MACDSlow = 120; // Период медленной средней MACD
extern int MACDPrice = 5; // Цена расчета средней:
// 0 - Close
// 1 - Open
// 2 - High
// 3 - Low
// 4 - Median
// 5 - Typical
// 6 - Weighted Close
extern int MACDMethod = 3; // Метод расчета средней
// 0 - Simple
// 1 - Exponential
// 2 - Smoothed
// 3 - Linear Weighted
extern int SamplingDepth = 10; // Глубина выборки. Должна быть четным
// ..числом более 1
extern int MaxLevel = 80; // Значение соотношения площади роста
// ..и площади падания, при котором..
// ..не рекомендуется открывать..
// ..сделки против соотношения
// == Окончание блока ==================================================================
Первые четыре настроечных параметра имеют префикс MACD, хотя на самом деле все они относятся к обычным средним линиям. Появление префикса MACD в названиях входных параметров объясняется тем фактом, что в процессе расчета разности двух средних линий получается значение другого, не менее известного, индикатора - MACD. В таком представлении параметров явно чувствуется отсутствие еще одного наименования - MACDSignal (период сигнальной линии индикатора MACD). В данном случае указание периода сигнальной линии не требуется, т.к. ее значение в программе не используется.
Значение глубины выборки указывается при помощи параметра SamplingDepth. Значение 10 означает, что для расчета будет взято 5 последних областей каждого типа: 5 положительных и 5 отрицательных. Отсюда следует ограничение, накладываемое на величину выборки: это должно быть четное число (иначе не получится взять равное количество областей каждого типа) не меньшее, чем 2 (1 - нечетное число, а 0, хоть и четное, не дает возможности получить хоть какую-нибудь выборку).
Последний параметр MaxLevel указывает предельно рассматриваемое соотношение площадей роста и падения. Например, при соотношении 60% (площадь роста) и 40% (площадь падения) имеем дисбаланс в сторону роста. В итоге можно говорить о том, что в ближайшее время перевес в пользу роста будет компенсирован, т.е. разовьется нисходящее движение. Если рассматриваемое соотношение было получено, когда быстрая средняя пересекла медленную сверху вниз (классический сигнал открытия короткой сделки), то факт наличия дисбаланса является подтверждением такого сигнала. С другой стороны, во время устойчивых трендов дисбаланс может достигать некоторого критического соотношения. Например, 80% против 20%, как указано в приведенном коде. То есть сумма площадей одной из областей не просто превышает сумму площадей другой области, а доминирует над оппонентом. В таких ситуациях сигналы, противоположные тренду, чаще говорят о начале коррекции, чем о затухании тренда. Поэтому при доминировании одного из типов областей над другим лучше воздержаться от заключения сделок как в одну, так и в другую сторону.
Еще одним назначением параметра MaxLevel является указание момента закрытия текущей сделки. Например, сделка была открыта при соотношении 75% к 25% в направлении преобладающего типа областей. За время существования сделки тренд в сторону преобладания продолжился, и соотношение сумм площадей выросло до критического значения - 80% к 20%. Логичным действием в этом случае является закрытие сделки, т.к. рынок вошел в фазу высокой неопределенности: тренд может продолжиться, а может резко развернуться.
Рассмотрим первую необходимую часть индикатора - функцию расчета сумм площадей роста и падения:
//+-------------------------------------------------------------------------------------+
//| Вычисление площади положительной и отрицательной областей |
//+-------------------------------------------------------------------------------------+
void Square(int k)
{
int cnt = 0; // Счетчик областей роста и падения
Above = 0; // Сумма площадей роста
Below = 0; // Сумма площадей падения
while (cnt < SamplingDepth && k < Bars) // Рассчитываем, пока не достигнем..
{ // ..нужной глубины выборки или..
// ..достигнем конца истории
if (MACD[k] > 0) // Положительные считаем отдельно
Above += MACD[k];
else // Отрицательные отдельно
Below += MACD[k];
if ((MACD[k] > 0 && MACD[k+1] <= 0) || // Если произошел переход от одной..
(MACD[k] < 0 && MACD[k+1] >= 0)) // ..области к другой, то увеличиваем
cnt++; // ..счетчик областей
k++; // Переходим к следующему бару
}
}
Функция Square обладает единственным аргументом - k. Через него передается номер бара, начиная с которого необходимо производить расчет площадей. Сумма площадей роста сохраняется в переменной Above, а сумма площадей падения цены - в переменной Below. Обе переменные являются глобальными, поэтому объявления в пределах функции не требуют. Все, что требуется в данном случае - это обнуление значения переменных, чтобы предыдущие результаты не были учтены в текущем расчете.
Далее следует цикл "пока", счетчиком которого является переменная cnt, хранящая количество учтенных областей роста или падения цены. Цикл может быть прерван по двум причинам: достижение необходимого количества областей роста или падения цены (SamplingDepth) или достижение конца имеющейся истории котировок. Переменная Above увеличивает свое значение, когда быстрая средняя скользящая линия оказывается выше, чем медленная средняя линия. Признаком этого является значение индикаторного буфера MACD, который рассчитывается в функции start, но не отображается на графике. Аналогично переменной Above, при нахождении быстрой средней линии ниже медленной, происходит изменение значения переменной Below, которое уменьшается, т.к. значение буфера MACD при этом является отрицательным.
Счетчик cnt увеличивает свое значение в тех случаях, когда значения MACD на текущем и предыдущем барах имеют разный знак, что говорит о моменте пересечения средних линий, а, следовательно, о смене типа области.
Полученные значения Above и Below нуждаются в отображении на графике, чтобы пользователь смог увидеть их и проанализировать. Эту задачу решает функция ShowInfo:
//+-------------------------------------------------------------------------------------+
//| Отображение объектов-надписей |
//+-------------------------------------------------------------------------------------+
void ShowInfo(datetime time, double price, double koef)
{
// - 1 - == Инициализация текстового значения надписей ==================================
if (Above-Below != 0) // Если соотношение площадей не равно,
{ // ..то выведем полученные соотношения
string UText = DoubleToStr(Above/(Above-Below)*100, 1) + "%";
string DText = DoubleToStr(-Below/(Above-Below)*100, 1) + "%";
}
else // Если соотношение площадей равно, то
{ // ..выведем значения 50% и 50%
UText = "50%";
DText = "50%";
}
// - 1 - == Окончание блока =============================================================
// - 2 - == Отображение верхнего значения ===============================================
string name = prefix + time + "U"; // Формирование уникального имени..
// ..объекта
if (ObjectFind(name) < 0) // Если объект не найден, то..
{
ObjectCreate(name, OBJ_TEXT, 0, time, price+koef/5);// ..создаем его
ObjectSet(name, OBJPROP_COLOR, indicator_color1);// Устанавливаем цвет надписи
ObjectSetText(name, UText, 8); // Заполняем надпись содержимым
}
// - 2 - == Окончание блока =============================================================
// - 3 - == Отображение нижнего значения ================================================
name = prefix + time + "D"; // Формирование уникального имени..
// ..объекта
if (ObjectFind(name) < 0) // Если объект не найден, то..
{
ObjectCreate(name, OBJ_TEXT, 0, time, price-koef/5);// ..создаем его
ObjectSet(name, OBJPROP_COLOR, indicator_color2);// Устанавливаем цвет надписи
ObjectSetText(name, DText, 8); // Заполняем надпись содержимым
}
// - 3 - == Окончание блока =============================================================
}
Аргументов у функции три: time и price - время и цена на графике, где необходимо отобразить информацию, koef - отступ в пунктах от указанной цены, который нужно учесть при отображении каждого из двух значений. Так как значения два, то отображение их с одинаковыми координатами приведет к "каше" на экране. Поэтому для вычисления координаты по вертикали одного значения к заданной цене price добавляется значение koef, а для вычисления координаты другого значения из price вычитается koef.
В первом блоке функции производится подсчет значений соотношений Above и Below, а также преобразование чисел в строку. В строковой переменной UText сохраняется текстовое представление числа, соответствующее части суммы площадей роста от общего числа площадей роста и падения, а в переменной DText - части площадей падения от общего числа площадей. Так как для расчета процентного соотношения требуется выполнить операцию деления, то перед выполнением деления производится проверка равенства знаменателя нулю. Знаменателем в данном случае выступает выражение Above - Below (знак "минус" используется для получения суммы, т.к. переменная Below содержит отрицательное значение). Ноль может быть получен лишь в одном случае, когда значения переменных равны. Равенство переменных означает, что соотношение сумм площадей роста и падения цены равно, т.е. "50% на 50%", как и указывается в конечной части блока 1.
Второй и третий блоки алгоритмически подобны. Их задачей является создание графического объекта - текстовой надписи. Название графического объекта должно быть уникальным и, в то же время, должно легко идентифицироваться индикатором как собственное. Поэтому имя объекта состоит из трех частей. Первая часть одинакова для всех объектов графика. Это значение переменной prefix, которое можно изменять, редактируя файл исходного кода индикатора. В данном случае это строка "iSquare_". Вторая часть имени - время (X-координата) на графике, соответствующее объекту. Время является уникальной характеристикой объекта, кроме одного случая - появление второй надписи на этом же баре, т.к. необходимо отобразить два значения. Для различия между двумя объектами, соответствующими одному и тому же времени, необходима третья часть имени - литера "U" (для верхней надписи) или "D" (для нижней надписи). После определения имени производится проверка существования объекта и, если объект с таким именем не найден, создание объекта с установкой нужного цвета и текста.
Использование рассмотренных функций осуществляется в главной функции индикатора start:
//+-------------------------------------------------------------------------------------+
//| Custom indicator iteration function |
//+-------------------------------------------------------------------------------------+
int start()
{
if (!Activate) return(0);
// - 1 - == Вычисление необходимости обновления данных ==================================
int limit, i; // Переменные цикла
if (LastBar == Time[0]) // Если текущий бар уже был рассчитан, то
limit = 0; // ..пересчитываем только его
else // ..если не был рассчитан, то..
if (LastBar == 0) // ..при первом входе рассчитаем значения
limit = Bars-3; // ..для всех имеющихся баров
else // Если расчет производился на каком-то..
{ // ..другом баре, то..
limit = iBarShift(NULL, 0, LastBar + Period()*60);// ..начнем расчет с первого..
// ..бара после него
if (MACD[limit+1] > 0) // Также не забудем обработать..
Above += MACD[limit+1]; // ..окончательное значение для..
else // ..сформированного бара limit+1,..
Below += MACD[limit+1]; // .. прибавив значение площади роста..
// ..или площади падения
}
LastBar = Time[0]; // Отметим новый бар
// - 1 - == Окончание блока =============================================================
// - 2 - == Отображение индикатора на истории ===========================================
for(i = limit; i >= 0; i--) // По всем непосчитанным барам
{
MACD[i] = iMA(NULL, 0, MACDFast, 0, MACDMethod, MACDPrice, i) - // Вычисление..
iMA(NULL, 0, MACDSlow, 0, MACDMethod, MACDPrice, i);// ..разности..
// ..значений средних скользящих (MACD)
// - 2.1 - == Пересечение снизу вверх (сигнал покупки) ============================
if (MACD[i+1] > 0 && MACD[i+2] <= 0) // Если произошло пересечение снизу вверх
{
double k = iATR(NULL, 0, 14, i); // Подсчитаем среднюю волатильность
Square(i+2); // Рассчитаем площади
if (Above - Below == 0) // При равенстве площадей выведем значок..
GreateUp[i] = Low[i] - k; // .."большой палец вверх". Можно..
else // ..открываться
if (MathAbs(Below/(Above - Below))*100 >= MaxLevel ||// При большом..
Above/(Above - Below)*100 >= MaxLevel)// ..превосходстве одной площади..
Up[i] = Low[i] - k; // ..падения над другой выведем "стрелку..
// ..вверх", заходить нежелательно
else // Если уровень MaxLevel не преодолен,то..
GreateUp[i] = Low[i] - k; // ..выведем значок "большой палец вверх"
ShowInfo(Time[i] + 180*Period(), // Покажем результат соотношения
MathMax(Up[i], GreateUp[i]),
k);
FollowBuy = true; // Необходимо отслеживать площадь роста
FollowSell = false; // Площадь падения отслеживать не нужно
}
// - 2.1 - == Окончание блока =====================================================
// - 2.2 - == Пересечение сверху вниз (сигнал продажи) ============================
if (MACD[i+1] < 0 && MACD[i+2] >= 0) // Если произошло пересечение сверху вниз
{
k = iATR(NULL, 0, 14, i); // Подсчитаем среднюю волатильность
Square(i+2); // Рассчитаем площади
if (Above - Below == 0) // При равенстве площадей выведем значок..
Down[i] = High[i] + k; // .."большой палец вниз". Можно..
else // ..открываться
if (Above/(Above - Below)*100 >= MaxLevel ||// При большом превосходстве..
MathAbs(Below/(Above - Below))*100 >= MaxLevel)// ..одной площади..
Down[i] = High[i] + k; // ..над другой выведем "стрелку вниз",..
// ..заходить нежелательно
else // Если уровень MaxLevel не преодолен,то..
GreateDown[i] = High[i] + k; // ..выведем значок "большой палец вниз"
ShowInfo(Time[i] + 180*Period(), // Покажем результат соотношения
MathMax(Down[i], GreateDown[i]),
k);
FollowSell = true; // Необходимо отслеживать площадь падения
FollowBuy = false; // Площадь роста отслеживать не нужно
}
// - 2.2 - == Окончание блока =====================================================
// - 2.3 - == Слежение за длинной сделкой =========================================
if (FollowBuy) // Если нужно продолжать подсчет сумм..
{ // ..после получения сигнала
k = 0; // Значение MACD текущего бара
if (i == 0) // Если текущий бар нулевой, то занесем..
k = MACD[i]; // ..значение MACD в переменную k
else // Иначе можно увеличивать общую сумму
Above += MACD[i]; // Увеличим площадь роста
if (Above + k - Below == 0) continue; // При делении на ноль выходим
if ((Above+k)/(Above+k-Below)*100 >= MaxLevel)// Если ссоотношение площади роста
{ // .. и площади падения превысило MaxLevel
CloseTrade[i] = High[i] + iATR(NULL, 0, 14, i);// ..отметим на графике этот..
FollowBuy = false; // ..факт и прекратим дальнейшее..
} // ..отслеживание событий
else // Иначе не отмечаем
CloseTrade[i] = 0;
}
// - 2.3 - == Окончание блока =====================================================
// - 2.4 - == Слежение за короткой сделкой ========================================
if (FollowSell) // Если нужно продолжать подсчет сумм..
{ // ..после получения сигнала
k = 0; // Значение MACD текущего бара
if (i == 0) // Если текущий бар нулевой, то занесем..
k = MACD[i]; // ..значение MACD в переменную k
else // Иначе можно увеличивать общую сумму
Below += MACD[i]; // Увеличим площадь падения
if (Above-Below-k == 0) continue; // При делении на ноль выходим
if (MathAbs((Below+k)/(Above-Below-k))*100 >= MaxLevel)// Если ссоотношение..
{ // ..площади падения и площади роста..
// ..превысило MaxLevel
CloseTrade[i] = Low[i] - iATR(NULL, 0, 14, i);// ..отметим на графике этот..
FollowSell = false; // ..факт и прекратим дальнейшее..
} // ..отслеживание событий
else // Иначе не отмечаем
CloseTrade[i] = 0;
}
// - 2.4 - == Окончание блока =====================================================
}
// - 2 - == Окончание блока =============================================================
return(0);
}
Специфика индикатора такова, что оптимизация его вычислений при помощи стандартной функции IndicatorCounted затруднительна. Трудность заключается в том, что значения Above и Below, как видно из кода функции start, формируются накопительным итогом от момента пересечения средних скользящих. При использовании IndicatorCounted потребовалось бы повторное нахождение последнего пересечения средних линий и пересчет значений сумм площадей роста и падения на каждом тике. Реализованный метод расчета (без IndicatorCounted) этого недостатка лишен. Вместо IndicatorCounted используется принцип, хорошо зарекомендовавший себя при использовании в экспертах - определение времени открытия последнего бара, на котором расчет уже производился. Время сохраняется в переменной LastBar. Определение номера бара, с которого нужно производить расчет, занимает код всего первого блока. Если в LastBar сохранено значение, соответствующее текущему бару (бару с индексом 0), то становится понятно, что расчет на текущем баре уже производился и необходимо лишь произвести незначительные изменения для бара с индексом 0. Если значение LastBar не соответствует текущему бару, то в этом случае возможно два варианта. Первый вариант - индикатор только что загружен (значение LastBar равно нулю). Значит, следует произвести расчет значений индикатора по всей доступной истории, т.е., начиная с бара № Bars-3 (для расчета нужно хотя бы два бара слева от расчетного бара). Второй вариант - произошла смена бара. Смена бара может происходить в штатном порядке - бар, индекс которого был 0, приобрел индекс 1, а новый бар появился. А может случиться и так, что на некоторое время пропала связь с сервером брокера, и последний рассматриваемый бар получил индекс более чем 1. Тогда необходимо пересчитать всю историю от последнего посчитанного бара до текущего. Получаем, что неважно, какой номер бара имеется в данном случае - 1 или 10. Главное, чтобы было учтено значение на прошлом баре, а цикл пересчета запущен с первого после обрыва связи бара. Номер бара рассчитывается при помощи функции iBarShift, а учет значения на последнем баре проводится простым прибавлением к значениям переменных Above и Below.
Второй блок функции start - это пересчет истории от бара с индексом limit, рассчитанного в блоке 1, до бара с индексом 0. Индикатор содержит шесть индикаторных буферов, значения четырех из которых видны пользователю, а одного, MACD, не видны. Видимые буфера: Up - "стрелка вверх", GreateUp - "большой палец вверх", Down - "стрелка вниз", GreateDown - "большой палец вниз", CloseTrade - "галочка". Up и Down отображаются на каждом пересечении средних, если не произошло отображения буферов GreateUp и GreateDown. GreateUp и GreateDown отображаются, если соотношение сумм площадей роста и падения не превысило значение MaxLevel, то есть рекомендуется открывать сделку. Если сделку открывать уже поздно (доминирует одна из областей), то отображается обычная "стрелка вверх" или "стрелка вниз". Если после открытия сделки достигается уровень соотношения MaxLevel, то отображается "галочка". Алгоритмически подобными блоками являются пары 2.1 и 2.2, 2.3 и 2.4.
Блоки 2.1 и 2.2 исполняются при обнаружении пересечения средних скользящих линий (2.1 - быстрая пересекла медленную снизу вверх, 2.2 - сверху вниз). В этот момент вызывается функция Square, рассчитывающая значения Above и Below. В зависимости от их соотношения отображается один из буферов, отвечающих за движение вверх (в случае 2.2 - вниз). После этого вызывается функция ShowInfo, выводящая соотношение Above и Below на график, а затем активизируется один из флагов FollowBuy или FollowSell, означающих, что необходимо отслеживать дальнейший рост площади соответствующей области.
Блоки 2.3 и 2.4 отслеживают рост площади соответствующей области с тем, чтобы вывести значок "галочки", означающий прекращение торговли в данном направлении, т.е. достижение критического соотношения, которое больше или равно, чем значение MaxLevel. Присутствие переменной k в каждом блоке нужно для того, чтобы в переменных Above и Below находились значения, соответствующие сформированным барам. Для текущего, нулевого, бара рассчитывается значение переменной k, учитываемое при подсчете текущего соотношения. При достижении соотношения уровня MaxLevel слежение за ростом площади области прекращается.
Результат работы разработанного индикатора показан на рис. 2.
http://www.forextrade.ru/media/Image/MQLabs/104_ag/figure2.png
Рис. 2. Результат работы индикатора Square.
Критический уровень соотношения сумм площадей областей роста и падения цены здесь установлен 70%. Первая сделка на рис. 2 - короткая. Соотношение в пользу падения (67.6% против 32.4%) и критический уровень не достигнут, поэтому сделку можно открывать. Как видно, решение оказалось правильным. Индикатор также подсказал точку выхода, которая оказалась на 120 пунктов ниже точки входа. Затем последовал неправильный совет - открытие длинной сделки (соотношение 64.5% против 35.5% в пользу падения). Возможно, в случаях, когда соотношение не в пользу направления сделки, не стоит открывать сделки. Через три часа после открытия длинной следует сигнал открытия короткой, но он не подтверждается соотношением сумм площадей роста и падения - падение достигло критического уровня. Короткая сделка не открывается. А вот последующая длинная открывается и успешно отрабатывает, если, конечно, к тому моменту была закрыта предыдущая длинная сделка.
О том, как наилучшим образом интерпретировать показания индикатора Square, поговорим во второй части материала. Рассуждения будут основаны на результатах тестирования эксперта, работающего по сходному с индикатором Square принципу.
Индикатор Square (http://www.forextrade.ru/media/Image/MQLabs/104_ag/Square.mq4)