English 中文 Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Индикаторы малой, промежуточной и основной тенденции

Индикаторы малой, промежуточной и основной тенденции

MetaTrader 5Трейдинг | 21 марта 2011, 11:56
12 414 28
Dmitriy Skub
Dmitriy Skub

Введение

В предисловии к своей книге "Модель, Цена и Время. Применение теории Ганна в системах торговли" Джеймс Хьержик пишет: "Мой опыт в бизнесе, связанном с торговлей на рынке товарных фьючерсов, показал мне, что слишком часто трейдеры в своем анализе начинают чрезмерно пристращаться к чему-то одному: модели, цене, либо ко времени.

Наиболее общие ошибки создаются системами вокруг времени входа и цены выхода, или цены входа и момента выхода. В дополнение к этому, есть еще трейдеры, которые часто практикуют модель при входе или выходе в условиях снизившихся цен, либо для очень короткого временного промежутка. Эти наблюдения предоставили еще одно свидетельство того, что сочетание всех трех методов необходимо для успеха на рыночном пространстве."

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


График малой тенденции

Внешний вид графика малой тенденции показан на рис.1. Рассмотрим кратко правила построения графика малой тенденции:

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

График малой тенденции

рис.1 График малой тенденции

При изменении направления движения графика образуются так называемые второстепенные вершины и основания. На рис.1 второстепенные основания отмечены левыми ценовыми метками красного цвета, а второстепенные вершины отмечены правыми ценовыми метками зеленого цвета.

Если, при восходящем движении, направление движения изменилось на нисходящее, но не пробило последнее по времени основание, то имеем корректирующее движение. В противном случае, произошла смена направления движения. Аналогично, при нисходящем движении.

Таким образом, цена двигается между основаниями и вершинами. Такие движения называются колебаниями. При этом, могут образовываться корректирующие движения.

Вот, вкратце, правила построения линии индикатора малой тенденции. Более подробное описание можно прочитать в первой части книги. График этого индикатора напоминает график популярного индикатора зиг-заг. Но, в отличие от него, не перерисовывается после закрытия очередного бара и не имеет никаких внешних настраиваемых параметров, влияющих на построение линий.


Индикатор малой тенденции - GannMicroTrend

Разработаем индикатор, который будет отображать график малой тенденции. Внешний вид должен быть таким, как на рис.1. Добавим, также, вывод на экран положения последних по времени вершины и основания. Данный индикатор находится в приложенном к статье файле GannMicroTrend.mq5.

Для вывода этой информации используем библиотеку, описанную в статье "Взгляни на рынок через готовые классы". Для этого в начале текста нашего индикатора добавим директиву включения файла:

#include  <TextDisplay.mqh>

Предполагается, что указанный выше файл находится в директории Include.

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

Для этого добавим внешние задаваемые параметры:

input int     MaxBars = 1000;
input bool    IsSaveTrendParams = true;
//---------------------------------------------------------------------
input bool    ShowInfo = true;
input int     UpDownInfoShift = 1;
input int     LeftRightInfoShift = 1;
input color   TitlesColor = LightCyan;
input color   TopFieldsColor = Green;
input color   LowFieldsColor = Brown;
//---------------------------------------------------------------------
input color   UpTrendColor = LightGreen;
input color   DnTrendColor = LightPink;
input int     LineWidth = 4;
//---------------------------------------------------------------------
input color   UpStopLossColor = Green;
input color   DnStopLossColor = Brown;
input int     StopLossWidth = 1;

Назначение этих параметров приведено в следующей таблице:

Название параметра
 Назначение параметра

MaxBars

 Максимальное число баров истории, на которое отрисовывается индикатор. Если 0, то обсчитываются и отрисовываются все доступные бары истории.

IsSaveTrendParams

 Если истина, то сохраняются в глобальных переменных параметры текущего тренда и параметры последних по времени вершины и основания.

ShowInfo

 Если истина, то в окне графика отображаются координаты последних по времени вершины и основания.

UpDownInfoShift

 Сдвиг по вертикали сверху вниз места вывода информации.

LeftRightInfoShift

 Сдвиг по горизонтали слева направо места вывода информации.

TitlesColor

 Цвет заголовков при выводе информации.

TopFieldsColor

 Цвет текста при выводе параметров последней по времени вершины.

LowFieldsColor

 Цвет текста при выводе параметров последней по времени основания.

UpTrendColor

 Цвет отрисовки линии восходящего движения.

DnTrendColor

 Цвет отрисовки линии нисходящего движения.

LineWidth

 Толщина трендовых линий.

UpStopLossColor

 Цвет правых ценовых меток, обозначающих вершины.

DnStopLossColor

 Цвет левых ценовых меток, обозначающих основания.

StopLossWidth

 Размер ценовых меток, обозначающих вершины и основания.


Строить линию тренда будем с помощью графических объектов типа CChartObjectTrend из набора стандартных классов. Второстепенные вершины будем отмечать левыми ценовыми метками - объектами типа CChartObjectArrowLeftPrice, а второстепенные основания - объектами типа CChartObjectArrowRightPrice. Все эти объекты содержатся в стандартных классах, поставляемых вместе с терминалом МТ5.

Поскольку в дальнейшем нам может понадобится манипуляция трендовыми линиями, а также вершинами/основаниями, то мы будем хранить их список в объектах типа CList, также из набора стандартных классов. Для этого добавим в начале индикатора директивы включения заголовочных файлов:

#include  <Arrays\List.mqh>
#include  <ChartObjects\ChartObjectsLines.mqh>
#include  <ChartObjects\ChartObjectsArrows.mqh>

Далее добавим сами объекты-списки:

CList*  trend_list_Ptr = NULL;  // список трендовых линий
CList*  up_list_Ptr = NULL;     // список вершин
CList*  dn_list_Ptr = NULL;     // список оснований


Теперь у нас есть все необходимые элементы для построения индикатора. Обработчик события инициализации индикатора имеет следующий вид:

int  OnInit()
{
  trend_list_Ptr = new CList();
  if(CheckPointer(trend_list_Ptr) != POINTER_DYNAMIC)
  {
    Print("Ошибка создания объекта CList #1");
    return(-1);
  }

  up_list_Ptr = new CList();
  if(CheckPointer(up_list_Ptr) != POINTER_DYNAMIC)
  {
    Print("Ошибка создания объекта CList #2");
    return(-1);
  }

  dn_list_Ptr = new CList();
  if(CheckPointer(dn_list_Ptr) != POINTER_DYNAMIC)
  {
    Print("Ошибка создания объекта CList #3");
    return(-1);
  }

  if(InitGraphObjects() != 0)
  {
    Print("Ошибка создания объекта TableDisplay");
    return(-1);
  }

  return(0);
}

Здесь создаются указатели на объекты-списки, затем проверяется успешность создания. Если указатель не валидный, то выводится сообщение об ошибке и на этом работа индикатора завершается. Место возникновения ошибки можно определить по номеру со значком #. Далее инициализируется таблица для вывода параметров последних по времени вершины и основания. Это делается в коде функции InitGraphObjects.


Основная часть нашего индикатора - обработчик события о необходимости провести расчет. Это функция OnCalculate. Рассмотрим ее по частям. Первая часть - проверка необходимости пересчета всей отображаемой части индикатора. Такая необходимость возникает, например, при первом старте индикатора на графике, при загрузке обновленной истории на график, при изменении тайм-фрейма. Во всех этих случаях значение аргумента prev_calculated равно нулю.

Это проверяется следующим образом:

int    index, start = prev_calculated - 1;

if(prev_calculated == 0)
{
  if(CheckPointer(trend_list_Ptr) != POINTER_INVALID)
  {
    trend_list_Ptr.Clear();
  }
  if(CheckPointer(up_list_Ptr) != POINTER_INVALID)
  {
    up_list_Ptr.Clear();
  }
  if(CheckPointer(dn_list_Ptr) != POINTER_INVALID)
  {
    dn_list_Ptr.Clear();
  }

//  Определим номер бара начала расчета:
  if(MaxBars > 0 && rates_total > MaxBars)
  {
    start = rates_total - MaxBars;
  }
  else
  {
    start = 0;
  }
  time_prev = 0;
  trend_prev = 0;
}

Если возникает необходимость пересчитать весь индикатор, то мы очищаем список трендовых линий и списки вершин/оснований. При этом, эти графические объекты также удаляются и с графика. Затем определяем номер бара, с которого надо начинать расчет индикатора - переменную start. Если задано значение внешней переменной MaxBars большее нуля и оно меньше числа баров на графике rates_total, то стартовый бар для расчета будет равен:

    start = rates_total - MaxBars;

Напомним, что нумерация баров тайм-серий начинается с нуля (самый старый бар).

Если же значение внешней переменной MaxBars равно нулю (что означает - расчитывать индикатор на всех барах графика) или больше числа баров на графике, то надо пересчитать все значения индикатора на всех барах графика, т.е. start равен нулю.


Далее идет цикл расчета трендовой линии и положений второстепенных вершин/оснований. Анализ значений максимальной и минимальной цены баров, в соответствии с приведенными выше правилами, достаточно несложный и не требует дополнительных пояснений (см. исходный текст в файле GannMicroTrend.mq5).

Для отрисовки участков трендовой линии используется следующая простая функция:

//---------------------------------------------------------------------
//  Отрисовка отрезка:
//---------------------------------------------------------------------
void  CreateCut(datetime _dt1, double _prc1, datetime _dt2, double _prc2, color _clr, int _wd)
{
  string  name = GetUniqName(prefix + " ");
  CChartObjectTrend*  trend_obj = new CChartObjectTrend();
  if(CheckPointer(trend_obj) != POINTER_INVALID)
  {
    trend_obj.Create(0, name, 0, _dt1, _prc1, _dt2, _prc2);
    trend_obj.Color(_clr);
    trend_obj.Width(_wd);
    trend_list_Ptr.Add(trend_obj);
  }
}

Здесь используется функция для получения уникального, в пределах графика, имени GetUniqName, подробно описанная в статье "Взгляни на рынок через готовые классы". В случае успешного создания графического объекта трендовая линия, задаются его параметры (цвет и толщина линии) и этот объект добавляется в список линий через вызов метода CList::Add.

Для отрисовки положения второстепенных вершин/оснований используются функции CreateUpStopLoss/CreateDnStopLoss соответственно. Они построены аналогично функции CreateCut и добавляют созданные объекты в свои списки.

После того как цикл расчета закончен, на экран выводятся параметры последних по времени основания и вершины. Здесь мы используем созданные на предыдущем этапе списки. Эти списки у нас получаются уже отсортированными по времени в сторону возрастания и вызовом метода CList::GetLastNode мы и получаем последний по времени объект для вершины или основания.

Результат работы описанного индикатора представлен на следующем рисунке:

Индикатор малой тенденции

рис.2 Индикатор малой тенденции



График промежуточной тенденции

График промежуточной тенденции отражает движения рынка, очерчиваемые двумя барами (двух-баровыми движениями). Внешний вид графика промежуточной тенденции показан на рис.2. Рассмотрим краткие правила построения графика промежуточной тенденции:

  • при восходящем движении (когда максимум следующего бара выше максимума предыдущего двух-барового движения и минимум следующего бара также выше минимума предыдущего двух-барового движения), мы соединяем следующий максимум бара с предыдущим максимумом двух-барового движения и получаем линию восходящего движения промежуточной тенденции;
  • при нисходящем движении (когда минимум следующего бара ниже минимума предыдущего двух-барового движения и максимум следующего бара также ниже минимума предыдущего двух-барового движения), мы соединяем следующий минимум бара с предыдущим минимумом двух-барового движения и получаем линию нисходящего движения промежуточной тенденции;
  • если, при восходящем движении, максимум очередного бара не превысил максимум предыдущего двух-барового движения и, при этом, минимум очередного бара меньше минимума предыдущего двух-барового движения, то направление движения изменилось на нисходящее;
  • если, при восходящем движении, максимум очередного бара не превысил максимум предыдущего двух-барового движения и, при этом, минимум очередного бара меньше минимума предыдущего двух-барового движения, то направление движения изменилось на нисходящее;
  • если, при любом движении, минимум очередного бара больше минимума предыдущего двух-барового движения и, при этом, максимум очередного бара меньше максимума предыдущего двух-барового движения, то этот бар называется внутренним (см. рис.2) и в построении графика не участвует;
  • если, при любом движении, максимум очередного бара больше максимума предыдущего бара и, при этом, минимум очередного бара меньше минимума предыдущего бара, то этот бар называется внешним (см. рис.2). В зависимости от направления бара (повышающийся или понижающийся), строится соответствующий сегмент графика.



График промежуточной тенденции

рис.3 График промежуточной тенденции

Единственный показатель разворота промежуточной тенденции наверх - это пересечение уровня промежуточной вершины. Точно так же единственный показатель разворота вниз - это пересечение уровня промежуточного основания.

Если промежуточная тенденция идет вверх, а рынок образует промежуточное колебание вниз, но не аннулирует предыдущее основание промежуточного колебания, то это - коррекция. И если промежуточная тенденция идет вниз, а рынок образует промежуточное колебание наверх, но не аннулирует предыдущую вершину промежуточного колебания, это тоже коррекция.


Индикатор промежуточной тенденции - GannMiddleTrend

Разработаем индикатор, который будет отображать график промежуточной тенденции. Внешний вид должен быть таким, как на рис.2. Кроме того, должны отображаться на экране положения последних по времени вершины и основания. Данный индикатор находится в приложенном к статье файле GannMiddleTrend.mq5.

В данном индикаторе, для отрисовки элементов графика мы будем использовать индикаторный буфер и тип рисования DRAW_COLOR_SECTION. Это нам понадобится в дальнейшем при разработке эксперта. Для доступа к данным индикатора из эксперта используем индикаторный буфер.

Параметры отображения индикатора на экране задаем следующими директивами:

#property indicator_buffers    2
#property indicator_plots      1
#property indicator_type1      DRAW_COLOR_SECTION
#property indicator_color1     LightGreen, LightPink
#property indicator_width1     4

Здесь задается последовательно:

  • число индикаторных буферов (их всего два - буфер данных и буфер индекса цвета);
  • число отображаемых графиков на экране;
  • тип отрисовки графика индикатора (будем отрисовывать с помощью цветных секций);
  • цвета, которые можно задавать в буфере индекса цвета;
  • толщина линий графика индикатора;


В функции инициализации OnInit мы привязываем выделенные для индикатора буферы и задаем некоторые другие параметры индикатора. Это делает следующий фрагмент кода:

SetIndexBuffer(0, DataBuffer, INDICATOR_DATA);
SetIndexBuffer(1, ColorBuffer, INDICATOR_COLOR_INDEX);

IndicatorSetInteger(INDICATOR_DIGITS, Digits( ));
IndicatorSetString(INDICATOR_SHORTNAME, "GannMiddleTrend");
PlotIndexSetString(0, PLOT_LABEL, "GannMiddleTrend");
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);

Здесь задается последовательно:

  • буфер для использования в индикаторе в качестве буфера данных (для отрисовки на экране);
  • буфер для задания цвета участков графика индикатора;
  • число цифр после запятой при отображении значений индикатора на экране;
  • короткое имя индикатора при отображении на экране;
  • имя графической серии (буфера данных) при отображении на экране;
  • величина, соответствующая пустому значению на экране (без отрисовки);


Индикатор аналогичен по структуре и внешним параметрам индикатору малой тенденции GannMicroTrend. Разница заключается только в том, что здесь используется непосредственное задание значений в индикаторном буфере и буфере цвета вместо использования графических объектов. Поэтому останавливаться на деталях реализации мы не будем. Результат работы индикатора представлен на следующем рисунке:

Индикатор промежуточной тенденции

рис.4 Индикатор промежуточной тенденции

Как видно, он совпадает с нарисованным вручную на рис.3.


График основной тенденции

График основной тенденции отражает движения рынка, очерчиваемые тремя барами (трех-баровыми движениями). Внешний вид графика основной тенденции показан на рис.5. Рассмотрим краткие правила построения графика основной тенденции:

  • при восходящем движении (когда максимум следующего бара выше максимума предыдущего трех-барового движения и минимум следующего бара также выше минимума предыдущего трех-барового движения), мы соединяем следующий максимум бара с предыдущим максимумом трех-барового движения и получаем линию восходящего движения основной тенденции;
  • при нисходящем движении (когда минимум следующего бара ниже минимума предыдущего трех-барового движения и максимум следующего бара также ниже минимума предыдущего трех-барового движения), мы соединяем следующий минимум бара с предыдущим минимумом трех-барового движения и получаем линию нисходящего движения основной тенденции;
  • если, при восходящем движении, максимум очередного бара не превысил максимум предыдущего трех-барового движения и, при этом, минимум очередного бара меньше минимума предыдущего трех-барового движения, то направление движения изменилось на нисходящее;
  • если, при восходящем движении, максимум очередного бара не превысил максимум предыдущего трех-барового движения и, при этом, минимум очередного бара меньше минимума предыдущего трех-барового движения, то направление движения изменилось на нисходящее;
  • если, при любом движении, минимум очередного бара больше минимума предыдущего трех-барового движения и, при этом, максимум очередного бара меньше максимума предыдущего трех-барового движения, то этот бар называется внутренним (см. рис.5) и в построении графика не участвует;
  • если, при любом движении, максимум очередного бара больше максимума предыдущего бара и, при этом, минимум очередного бара меньше минимума предыдущего бара, то этот бар называется внешним (см. рис.5). В зависимости от направления бара (повышающийся или понижающийся), строится соответствующий сегмент графика.

График основной тенденции

рис.5 График основной тенденции

Единственный показатель разворота основной тенденции наверх - это пересечение уровня главной вершины. Точно так же единственный показатель разворота вниз - это пересечение уровня главногооснования.

Если основная тенденция идет вверх, а рынок образует колебание вниз, но не аннулирует предыдущее основание колебания, то это - коррекция. И если основная тенденция идет вниз, а рынок образует колебание наверх, но не аннулирует предыдущую вершину колебания, это тоже коррекция.


Индикатор основной тенденции - GannMainTrend

Разработаем индикатор, который будет отображать график основной тенденции. Внешний вид должен быть таким, как на рис.5. Кроме того, должны отображаться на экране положения последних по времени вершины и основания. Данный индикатор находится в приложенном к статье файле GannMainTrend.mq5.

Индикатор полностью аналогичен по структуре и внешним параметрам индикатору промежуточной тенденции GannMiddleTrend, поэтому останавливаться на деталях реализации мы не будем. Результат работы индикатора представлен на следующем рисунке:

Индикатор основной тенденции

рис.6 Индикатор основной тенденции


Торговля по графику колебаний

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

В книге Джеймса Хьержика предлагается следующая стратегия:

  • выявляются участки с длительным движением вниз (вверх);
  • после образования вялого, движущегося в горизонтальном направлении рынка, размешается ордер на покупку над вершиной (продажу под основанием)последнего колебания;
  • защитный стоп размещается чуть ниже основания (чуть выше вершины) последнего колебания;
  • после открытия позиции, стоп перемещается вслед за ценой под образующиеся основания (вершины) новых колебаний;

Проиллюстрируем это рисунком:

Торговля по графику колебаний

рис.7 Торговля по графику колебаний

На экстремально высоких ценовых уровнях рекомендуется рассматривать возможность продаж, а на экстремально низких ценовых уровнях - покупок. На рис.7 представлен график промежуточной тенденции. Выявлять участки с длительным движением мы будем по графику основной тенденции. Выявлять участки "вялого" рынка будем по графику промежуточной тенденции. Сопровождать позицию будем также по графику промежуточной тенденции.

Вот как выглядит тот же участок на графике основной тенденции:

Участок на графике основной тенденции

рис.8 Участок на графике основной тенденции

Длительное движение вниз (колебание) идет между главной вершиной 1.36913 и главным основанием 1.18758. Это движение занимает 1815.5 четырех-значных пунктов. Затем идет участок "вялого" рынка с почти горизонтальным трендом от 1.24664 до 1.21495 (см. рис.7). Это движение занимает 316.9 пунктов. После этого цена пробивает уровень промежуточной вершины последнего колебания на графике промежуточной тенденции и идет вверх.

Мы ставим начальный стоп чуть ниже промежуточного основания последнего колебания 1.21495 и сопровождаем позицию по графику промежуточной тенденции. В результате этого трейда мы получили профит примерно 1.31186 - 1.23966 = 722.0 пункта.


Получение торговых сигналов для использования в "Мастере MQL5"

Прежде чем разрабатывать код для реализации нашей торговой системы, представим схематично весь ход торгов. Рассмотрим следующий рисунок:

Отработка позиции BUY

рис.9 Отработка позиции BUY

Отработка позиции BUY состоит из следующих действий:

  • Определяем по графику основной тенденции длительное нисходящее движение (участок A-B на рис.9). Длительность и величину движения задаем параметрами dT и dP, соответственно. Значения этих параметров должны быть определены исходя из изучения истории данного инструмента.
  • После образования главного основания на графике основной тенденции (точка B на рис.9), ждем образования точек C и D на графике промежуточной тенденции. Эти точки, совместно с точкой B, образуют промежуточные колебания B-C и C-D. Если длительность и величина этих колебаний не превышает заданных значений, то считаем, что образовался горизонтальный тренд (или "вялый" рынок).
  • Ждем пробоя уровня промежуточной вершины C (или последней по времени промежуточной вершины, которая образуется после C). После пробоя, ставим стоп чуть ниже уровня промежуточного основания в точке D (или последнего по времени промежуточного основания, которое образуется после C).
  • Сопровождаем позицию по мере продолжения восходящего движения, перемещая стоп под образующиеся промежуточные основания (чуть ниже точек F и L).
  • В зависимости от режима управления капиталом, можно добавляться к объему позиции в точках пробоя образующихся промежуточных вершин (точки G и M).
Отработка позиции SELL состоит из зеркально отраженных действий.


Итак, для создания эксперта нам необходимы следующие составные части: модуль, отвечающий за генерацию сигнала BUY/SELL; модуль трейлинга стопа открытой позиции; возможно и модуль, отвечающий за "пирамидинг" позиции.

При написании этой части использовались статьи: Как написать свой модуль торговых сигналов, Как написать свой модуль сопровождения открытых позиций и Как написать свой модуль управления капиталом и риском.


Разработка модуля, отвечающего за генерацию торговых сигналов состоит из следующих частей:

  • Добавление директивы препроцессора для включения стандартного mqh-файла, содержащего базовые классы для генерации эксперта. Это делается следующим образом:
#include <Expert\ExpertSignal.mqh>
Вставляем эту директиву в начале нашего модуля генерации торгового сигнала.


  • Добавление специальных строк в виде комментариев, которые говорят редактору MetaEditor, что данный файл должен использоваться при генерации эксперта:
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Сигнал по колебаниям на графиках средней и основной        |
//| тенденций по Ганну                                               |
//| Type=Signal                                                      |
//| Name=TGannBreakSignal                                            |
//| Class=TGannBreakSignal                                           |
//| Page=                                                            |
//| Parameter=MinMainSwingContinuance,int,5                          |
//| Parameter=MinMainSwingSize,double,300.0                          |
//| Parameter=MinMiddleSwingContinuance,int,3                        |
//| Parameter=MaxMiddleSwingSize,double,200.0                        |
//| Parameter=OpenPriceSpace,double,5.0                              |
//| Parameter=StopLossSpace,double,5.0                               |
//+------------------------------------------------------------------+
// wizard description end

Здесь мы видим параметр Title, который задает название модуля, появляющееся в списке MetaEditor'a при генерации эксперта (см. описание ниже). Важный параметр - Type, который как раз и определяет, что данный модуль является модулем генерации сигнала. Также, присутствуют внешние параметры и их значения "по умолчанию".

Все эти строки добавляются сразу после директивы включения стандартного файла ExpertSignal.mqh.


  • Описание класса, потомка базового класса, описанного в файле ExpertSignal.mqh. Данный класс должен реализовывать некоторую функциональность, отсутствующую в базовом классе CExpertSignal. Описание нашего класса имеет следующий вид (некоторые не существенные части здесь не показаны):
class TGannBreakSignal : public CExpertSignal
{
private:
  int     min_main_swing_continuance;        // минимальная длительность колебания на графике основной тенденции
  double  min_main_swing_size_points;        // минимальный размер колебания на графике основной тенденции
  int     min_middle_swing_continuance;      // минимальная длительность горизонтального колебания на графике промежуточной тенденции
  double  max_middle_swing_size_points;      // максимальный размер колебания на графике промежуточной тенденции
  double  open_price_space;                  // зазор от вершины/основания колебания при открытии позиции
  double  stop_loss_space;                   // зазор от вершины/основания колебания при установке стоп-лосса

private:
  datetime  main_swing_lf_datetime;          // время для левой точки колебания на графике основной тенденции
  double    main_swing_lf_price;             // цена для левой точки колебания на графике основной тенденции
  datetime  main_swing_rt_datetime;          // время для правой точки колебания на графике основной тенденции
  double    main_swing_rt_price;             // цена для правой точки колебания на графике основной тенденции
  int       main_swing_continuance;          // длительность колебания на графике основной тенденции
  double    main_swing_size_points;          // размер колебания на графике основной тенденции

private:
  datetime  middle_swing_lf_datetime;        // время для левой точки колебания на графике промежуточной тенденции
  double    middle_swing_lf_price;           // цена для левой точки колебания на графике промежуточной тенденции
  datetime  middle_swing_rt_datetime;        // время для правой точки колебания на графике промежуточной тенденции
  double    middle_swing_rt_price;           // цена для правой точки колебания графике промежуточной тенденции
  int       middle_swing_continuance;        // длительность горизонтального колебания на графике промежуточной тенденции
  double    middle_swing_size_points;        // размер колебания на графике промежуточной тенденции

public:
  int     GetMainSwingContinuance();        // получить значение длительности колебания на графике основной тенденции
  double  GetMainSwingSizePoints();         // получить значение размера колебания в 4х-значных пунктах на графике основной тенденции
  int     GetMiddleSwingContinuance();      // получить значение длительности колебания на графике промежуточной тенденции
  double  GetMiddleSwingSizePoints();       // получить значение размера колебания в 4х-значных пунктах на графике промежуточной тенденции

//    Переопределяемые методы базового класса:
  virtual bool  ValidationSettings();
  virtual bool  CheckOpenLong(double& price, double& sl, double& tp, datetime& expiration);
  virtual bool  CheckOpenShort(double& price, double& sl, double& tp, datetime& expiration);
  virtual bool  InitIndicators(CIndicators* indicators);

//    Вспомогательные методы:
protected:
  int   GetMainSwing();                     // получение параметров колебания на графике основной тенденции
  int   GetMiddleSwing();                   // получение параметров колебания на графике промежуточной тенденции
};


Назначение членов-данных понятно из комментариев. Рассмотрим некоторые методы класса. Прежде всего, надо переопределить методы базового класса. Первый метод используется для проверки корректности заданных внешних параметров советника:

//---------------------------------------------------------------------
//  Проверка корректности заданных параметров:
//---------------------------------------------------------------------
bool  TGannBreakSignal::ValidationSettings()
{
  if(min_main_swing_continuance <= 0)
  {
    Print(Wrong Parameter: min_main_swing_continuance = ", min_main_swing_continuance);
    return( false);
  }
  if(min_main_swing_size_points <= 0.0)
  {
    Print("Wrong Parameter: min_main_swing_size_points = ", DoubleToString(min_main_swing_size_points, 1));
    return(false);
  }
  if(min_middle_swing_continuance <= 0)
  {
    Print("Wrong Parameter: min_middle_swing_continuance = ", min_middle_swing_continuance);
    return(false);
  }
  if(max_middle_swing_size_points <= 0.0)
  {
    Print("Wrong Parameter: max_middle_swing_size_points = ", DoubleToString(max_middle_swing_size_points, 1));
    return(false);
  }

  return(true);
}

Здесь проводится простейшая проверка внешних задаваемых параметров на корректность. Понятно, что размер колебания в пунктах и его длительность в барах не может быть меньшей или равной нулю. В случае некорректного задания внешних параметров, метод возвращает false.


Дапее, рассмотрим методы генерации сигналов на открытие позиций. Проверка необходимости открытия длинной позиции производится следующим, унаследованным из базового класса, методом:

bool  TGannBreakSignal::CheckOpenLong(double& _price, double& _sl, double& _tp, datetime& _expiration)
{
  if GetMainSwing() == -1)
  {
    return(false);
  }

  if(GetMiddleSwing() == -1)
  {
    return(false);
  }

//  Если основное колебание вверх, то условий для открытия длинной позиции нет:
  if(main_swing_rt_price >= main_swing_lf_price)
  {
    return(false);
  }

//  Если промежуточное "вялое" колебание еще не сформировалось, то условий для открытия длинной позиции нет:
  if(middle_swing_rt_price >= middle_swing_lf_price)
  {
    return(false);
  }

//  Проверим параметры колебания на графике основной тенденции:
  if(main_swing_continuance < min_main_swing_continuance || main_swing_size_points < min_main_swing_size_points)
  {
    return(false);
  }

//  Проверим параметры колебания на графике промежуточной тенденции:
  if(middle_swing_continuance < min_middle_swing_continuance || middle_swing_size_points > max_middle_swing_size_points)
  {
    return(false);
  }

  double  unit = PriceLevelUnit();

//  Если цена пересекла вершину "вялого" промежуточного колебания, то открываемся:
  double  delta = this.m_symbol.Bid() - (middle_swing_lf_price + open_price_space * unit);
  if((delta >= 0.0) && (delta < (10.0 * unit)))
  {
    _price = 0.0;
    _sl = m_symbol.NormalizePrice(middle_swing_rt_price - stop_loss_space * unit);
    _tp = 0.0;

    return(true);
  }

  return(false);
}

Сначало вызываются два метода для получения параметров последних по времени колебаний для графиков основной и промежуточной тенденций - TGannBreakSignal::GetMainSwing и TGannBreakSignal::GetMiddleSwing. Если эти методы завершились успешно, то можно анализировать параметры колебаний.

Поскольку, мы проверяем наличие сигнала на открытие длинной позиции, то основное колебание должно быть вниз. Мы сравниваем положение точек А и В (см. рис.9) - если точка В ниже по цене, чем точка А, то ценовое колебание было вниз.

Далее проверяется существование точек С и D (см. рис.9). Причем, точка D должна быть ниже точки С по цене. Если это условие выполняется, то проверяются параметры колебаний основной и промежуточной тенденций. Проверяется длительность движения и величина движения.

Если все предыдущие проверки прошли успешно, то выполняется последняя проверка - пересекла ли цена вершину промежуточного колебания. Если пересекла, то заполняется значение стопа и возврат результата true.


Проверка необходимости открытия короткой позиции производится вызовом метода TGannBreakSignal::CheckOpenShort, который выполняет проверки, аналогичные методу TGannBreakSignal::CheckOpenLong, но в зеркальном отражении по оси цен.


Итак, мы рассмотрели структуру и основные методы модуля, отвечающего за генерацию торговых сигналов. Описанный модуль приложен к данной статье в виде файла GannTrendSignal.mqh.


Второй модуль, который нам понадобится - модуль трейлинга стопа открытой позиции. Данный модуль также разрабатывается на основе стандартных классов и состоит из следующих частей:

  • Добавление директивы препроцессора для включения стандартного mqh-файла, содержащего базовые классы для генерации кода сопровождения позиции. Это делается следующим образом:
#include <Expert\ExpertTrailing.mqh>

Вставляем эту директиву в начале нашего модуля сопровождения позиции.


  • Добавление специальных строк в виде комментариев, которые говорят редактору MetaEditor, что данный файл должен использоваться при генерации сопровождения позиции в эксперте:
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=По основаниям/вершинам на графике промежуточной тенденции  |
//| Type=Trailing                                                    |
//| Name=MiddleTrend                                                 |
//| Class=MiddleTrendTrailing                                        |
//| Page=                                                            |
//| Parameter=StopLossSpace,double,5.0                              |
//+------------------------------------------------------------------+
// wizard description end

Здесь параметр Type задан равным значению "Trailing", - это говорит о том, что данный модуль должен использоваться для сопровождения позиции (трэйлинга). Также, присутствуют внешние параметры и их значения "по умолчанию".

Все эти строки добавляются сразу после директивы включения стандартного файла ExpertTrailing.mqh.


  • Описание класса, потомка базового класса, описанного в файле ExpertTrailing.mqh. Данный класс должен реализовывать некоторую функциональность, отсутствующую в базовом классе CExpertTrailing. Описание нашего класса имеет следующий вид (некоторые не существенные части здесь не показаны):
class MiddleTrendTrailing : public CExpertTrailing
{
private:
  datetime  middle_swing_lf_datetime; // время для левой точки колебания на графике промежуточной тенденции
  double    middle_swing_lf_price;    // цена для левой точки колебания на графике промежуточной тенденции
  datetime  middle_swing_rt_datetime; // время для правой точки колебания на графике промежуточной тенденции
  double    middle_swing_rt_price;    // цена для правой точки колебания графике промежуточной тенденции
  double    stop_loss_space;          // зазор от вершины/основания колебания при установке стоп-лосса

private:
  int    GetMiddleSwing();          // получение параметров колебания на графике промежуточной тенденции

public:
//  Параметры настройки:
  void  StopLossSpace(double _space);

public:
//  Переопределяемые методы базового класса:
  virtual bool  ValidationSettings();
  virtual bool  InitIndicators(CIndicators* indicators);
  virtual bool  CheckTrailingStopLong(CPositionInfo* position, double& sl, double& tp);
  virtual bool  CheckTrailingStopShort(CPositionInfo* position, double& sl,double& tp);
};

Основные методы, переопределяемые в нашем классе - MiddleTrendTrailing::CheckTrailingStopLong и MiddleTrendTrailing::CheckTrailingStopShort. Эти два метода проверяют необходимость модификации стоп-лосса для длинной и короткой позиции, соответственно.

Рассмотрим метод MiddleTrendTrailing::CheckTrailingStopLong подробней:

bool  MiddleTrendTrailing::CheckTrailingStopLong(CPositionInfo* _position, double& _sl, double& _tp)
{
  if(_position == NULL)
  {
    return(false);
  }

  if(GetMiddleSwing() == -1)
  {
    return(false);
  }

  double  sl_req_price = m_symbol.NormalizePrice(MathMin(middle_swing_lf_price, middle_swing_rt_price) - stop_loss_space * m_adjusted_point);

  if(_position.StopLoss() >= sl_req_price)
  {
    return(false);
  }

  _tp = EMPTY_VALUE;
  _sl = sl_req_price;

  return(true);
}

Сначало вызываются метод для получения параметров последнего по времени колебания для графика промежуточной тенденций - TGannBreakSignal::GetMiddleSwing. Если этот метод завершился успешно (возвратил нулевое значение), то можно анализировать параметры колебания.

Далее, мы вычисляем уровень цены для размещения стоп-лосса, исходя из полученных параметров колебания. Если вычисленный уровень стоп-лосса меньше текущего (для длиннной позиции), то мы заполняем параметр метода _sl новым значением sl_req_price и возвращаем true. В противном случае, возвращаем false, - это говорит о том, что уровень стоп-лосса не требует модификации.

Метод проверки необходимости модификации стоп-лосса для короткой позиции построен аналогично.


Итак, мы рассмотрели структуру и основные методы модуля, отвечающего за сопровождение открытой позиции (трэйлинг). Описанный модуль приложен к данной статье в виде файла GannTrailing.mqh.


Генерация эксперта на основе торговых сигналов

Генерация эксперта по готовому шаблону с помощью "Мастера MQL5" достаточно несложная задача. Она состоит из последовательности шагов:

  • Шаг 1

С помощью команд главного меню MetaEditor'а Файл/Создать мы вызываем мастер генерации эксперта. На экране возникает окно диалога следующего вида:

Вызов диалога генерации эксперта

рис.10 Вызов диалога генерации эксперта

Выбираем "радио-кнопку" с надписью "Советник (сгенерировать)" и нажимаем кнопку "Далее" - переходим к следующему шагу генерации эксперта.


  • Шаг 2

На этом шаге задаются общие параметры советника - название, "магический" номер и др. Появляется следующее окно диалога:

Задание общих параметров советника

рис.11 Задание общих параметров советника

Установим значение параметра EveryTick в true - нам нужна работа советника по каждому тику, "магический" номер можно оставить без изменения. Нажимаем кнопку "Далее" и переходим к следующему шагу генерации.


  • Шаг 3

На этом шаге задаются параметры сигналов для советника. Сначала выбирается конкретный тип сигнала из списка:

Выбор типа сигнала

рис.12 Выбор типа сигнала

Выбираем название нашего сигнала, написанного ранее, и на экране появляется окно диалога следующего вида:

Задание параметров сигнала

рис.13 Задание параметров сигнала

Здесь мы можем подкорректировать необходимые нам значения параметров "по умолчанию". Снова нажимаем кнопку "Далее" и переходим к следующему шагу.


  • Шаг 4

На этом шаге выбирается тип трэйлинга для сопровождения открытой позиции. Можно выбрать любой из предлагаемого списка, но мы выберем разработанный ранее трэйлинг-стоп:

Выбор типа трэйлинга позиции

рис.14 Выбор типа трэйлинга позиции

Получаем следующее окно диалога:

Задание параметров трэйлинга

рис.15 Задание параметров трэйлинга

Здесь можно подкорректировать значения "по умолчанию" для задаваемых внешних параметров. Нажимаем кнопку "Далее" и переходим к следующему шагу.


  • Шаг 5

Задание параметров управления капиталом

рис.16 Задание параметров управления капиталом

Здесь можно выбрать параметры управления капиталом (способ вычисления рабочего лота). Оставим как есть - торговля с фиксированным торговым объемом. Нажатие на кнопку "Готово" и мы получаем готовый сгенерированный эксперт с заданным названием, алгоритмом открытия позиции, трэйлингом и правилами управления капиталом.

Протестируем сгенерированный эксперт, чтобы убедиться в его работоспособности:

рис. 17 Тест сгенерированного эксперта

рис. 17 Тест сгенерированного эксперта

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


Заключение

Мы рассмотрели, фактически, только первую часть теории Ганна и ее применение в системах торговли и анализа рынков - модель. Представляется, что наилучшие результаты ее применения могут быть достигнуты на тех временных периодах, где деление графика на бары соответствует естественной организации торговли.

Для рынков акций - это торговля с использованием дневных, недельных и месячных интервалов. Для валютного рынка - торговля с использованием сессионных интервалов. Для товарных рынков - торговля с использованием, кроме дневных, недельных, месячных интервалов, еще и сезонных колебаний рынка.


После заключения

Решил провести небольшое дополнительное исследование, не относящееся напрямую к теме статьи, но затрагивающее идеи Ганна. А именно, задаться вопросом: действительно ли цена при своем движении отмечает так называемые "круглые" уровни? Т.е. уровни цен, оканчивающиеся цифрами 50 и 100 для евро-валют и акций (для японской йены "круглые" уровни цены оканчиваются цифрами 40).

Для этого построим лепестковую диаграмму распределения вершин/оснований по последним цифрам после запятой. Для пяти-значных котировок это последние три цифры после запятой (последняя цифра - десятые доли пункта). Будем использовать график промежуточной тенденции для дневных баров.

По круговой оси будем откладывать последние цифры в цене от нуля до пятидесяти (десятые доли пункта округляем), а по вертикальной оси - число вершин/оснований, образовавшихся на данных уровнях. Построим отдельно для вершин, оснований и суммарную диаграмму.

Вот что получилось для некоторых основных валютных пар на интервале с 2000г. по 2011г. и дневном тайм-фрейме:






Как интерпретировать полученные результаты? Во-первых, перекосы в диаграммах есть. Т.е., не все значения цены равновероятны для образования вершин/оснований. Во-вторых, эти значения не совпадают точно с "круглыми" значениями - что, в общем-то, и ожидалось. Можно ли это использовать для торговли, сложно сказать. Здесь требуется более серьезное исследование. Возможно, более интересные результаты, с практической точки зрения, можно получить на фондовом рынке.

По крайней мере, это  - еще один инструмент для анализа истории и не самый плохой.

Прикрепленные файлы |
gannmicrotrend.mq5 (17.08 KB)
gannmiddletrend.mq5 (17.22 KB)
gannmaintrend.mq5 (17.39 KB)
ganntrendsignal.mqh (22.58 KB)
ganntrailing.mqh (9.65 KB)
textdisplay.mqh (15.43 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (28)
Victor Kirillin
Victor Kirillin | 5 сент. 2012 в 12:06
mln141:

Так и не нашел ответа, что же делать с сообщением:

                                      2012.09.05 13:51:54    Core 1    2012.01.01 00:00:00   CExpertBase::SetOtherSeries: changing of timeseries is forbidden



Будьте добры, поподробнее в Сервисдеск. Желательно с исходниками (тайну вкладов гарантирую).
Victor Kirillin
Victor Kirillin | 5 сент. 2012 в 12:53
mln141:

Так и не нашел ответа, что же делать с сообщением:

                                      2012.09.05 13:51:54    Core 1    2012.01.01 00:00:00   CExpertBase::SetOtherSeries: changing of timeseries is forbidden



Наводящий вопрос: Для создания эксперта Вы используете "запчасти" из стандартной поставки, или есть сто-то самодельное?
mln141
mln141 | 5 сент. 2012 в 13:06
uncleVic:
Наводящий вопрос: Для создания эксперта Вы используете "запчасти" из стандартной поставки, или есть сто-то самодельное?
Все стандартное. Подробности выслал в личку.
dren
dren | 17 февр. 2014 в 18:09

Вопрос gj создание советчика. Не могли бы скинуть файлы на почту или в личку? Проблема при создании, не высвечиваются сигналы и magicnumber

rossor
rossor | 10 июн. 2014 в 10:30

Классный индикатор. Дмитрий, Браво!

Раньше строил эти индюки вручную, но с Вашим индикатором этот труд стал многократно производительней . Просмотрел и сравнил свои ручные чарты на разных инструментах  с данными индикаторов - всё один в один. К сожалению, их востребованность сейчас неоправданно ниже, чем могла бы быть. В силу непонимания методов Ганна средой независимых трейдеров.

Когда меня спрашивают, с чего нужно начать изучение методов Ганна, я рекомендую начинать с методов описанных в книге Хьержик. Не потому, что это "начала", а потому что это "основа". На этой основе строятся все более экзотические и обнародованные методы Ганна, за вычетом его астрологических подходов. Можно окончить дорогостоящие курсы Ламберта-Ганна или Дэвида Бартона или выучить приёмы Патрика Микулы, можно даже понять их построения, но это не даст адекватного понимания подходов Ганна и не даст ожидаемой высокой результативности.

Его основы (не методические, но сущностные) в следующем:

  • Торговать не следует непрерывно, торговать нужно тогда когда , как минимум, можешь определить точку входа и точку выхода (цена и время входа в позицию + цена и время выхода);
  • Для определения точек входа/выхода на разных рынках для разных инструментов, на основании постоянных наблюдений за рынками, создавались разнообразные и иногда весьма оригинальные инструменты;
  • В разное время на одном и том же рынке проявляли эффективность разные инструменты. Если инструмент работал эффективно некоторое время под него создавались адекватные шаблоны упрощающие вычисления, типа разнообразных чётных и нечётных квадратов 9, 12 и тд. Внесистемное отдельное использование тех же квадратов, гексагонов и прочее-бессмысленно;
  • Базой любых вычислений, изучений и работы по любому инструменту оставалось изучение разных трендов, построение индикаторов тенденции и систематизация вершин и оснований, так как прошлые экстремумы определяют и будущие. Близко к тому что делал Ганн в работе по тренду представил в своей книге Хьержик;

Дмитрий сумел извлечь квинтэссенцию из книги Хьержика и сделать удачный индикатор тенденции.

Можно посмотреть на вопрос шире: если мы правильно определяем тенденцию, то дальше дело выучки и техники как безубыточно оприходовать этот тренд. Про бестрендовые рынки мы сейчас не говорим-это отдельная песня. Для практической работы достаточно использовать индикатор малой и промежуточной тенденции, оставляя индикатор главной тенденции для долгосрочных исследований. Можно использовать их вместо косвенных индикаторов тенденции типа ADX или DMI.

Статистические распределения вероятностей в MQL5 Статистические распределения вероятностей в MQL5
В статье рассмотрены распределения вероятностей (нормальное, логнормальное, биномиальное, логистическое, экспоненциальное, распределения Коши, Стьюдента, Лапласа, Пуассона, гиперболическое секанс распределение, бета и гамма-распределения) случайных величин, используемые в прикладной статистике. Предложены классы для работы с данными распределениями.
Уменьшаем расход памяти на вспомогательные индикаторы Уменьшаем расход памяти на вспомогательные индикаторы
Если индикатор для своих расчетов задействует значения множества других индикаторов, то такая система расходует много памяти. В статье рассмотрены несколько способов снижения расхода памяти при использовании вспомогательных индикаторов. Сэкономленная память позволит вам увеличить число одновременно используемых в терминале валютных пар, индикаторов и стратегий, что повысит надежность вашего торгового портфеля. Вот так простая забота о технических ресурсах вашего компьютера способна превратиться в материальные ресурсы на вашем депозите.
Основы тестирования в MetaTrader 5 Основы тестирования в MetaTrader 5
В чем различия между тремя режимами тестирования в MetaTrader 5 и на что обратить внимание? Как происходит тестирование эксперта, торгующего одновременно на нескольких инструментах? Когда и как вычисляются значения индикаторов при тестировании и как обрабатываются события? Как синхронизировать бары с разных инструментов при тестировании в режиме "Только цены открытия"? Статья призвана дать ответы на эти и многие другие вопросы.
Трассировка, отладка и структурный анализ кода Трассировка, отладка и структурный анализ кода
Весь комплекс задач создания структуры работающего кода и его трассировки можно решить без особых сложностей. Эта возможность появилась в MetaTrader 5 благодаря новому свойству языка MQL5 - автоматическое создание переменных сложного типа данных (структуры и классы) и их уничтожение при выходе из локальной области видимости. В статье описана методика и предоставлен готовый инструмент.