
Реализация автоматического анализа волн Эллиотта на MQL5
Введение
Одним из самых популярных методов анализа рынка является волновой анализ. Однако данный процесс является достаточно сложным, что приводит к использованию дополнительных инструментов. Одним из таких инструментов является автоматический разметчик.
В данной статье рассматривается создание автоматического анализатора волн Эллиотта на языке MQL5. Предполагается, что читатель уже знаком с волновой теорией, а если нет, то необходимо обратиться к соответствующим источникам.
1. Волновой принцип Эллиотта
Волны Эллиотта - теоретическая модель поведения рынка, разработанная Ральфом Нельсон Эллиоттом, согласно которой все движение цен на рынке подчиняется психологии людей и является циклическим процессом смены импульсных волн на коррекционные и наоборот.
Импульсные волны представляют собой последовательность пяти колебаний цены, коррекционные волны - последовательность трех или пяти колебаний цены. Импульсные волны по форме, структуре, а также применимым к ним правилам бывают следующих типов:
1. Импульсы: | |
---|---|
![]() Рисунок 1. Импульс |
|
2. Клинья: | |
![]() Рисунок 2. Клин |
|
3. Диагонали: | |
![]() Рисунок 3. Диагональ |
|
Коррекционные волны различаются на: | |
4. Зигзаги: | |
![]() Рисунок 4. Зигзаг |
|
5. Плоскости: | |
![]() Рисунок 5. Плоскость |
|
6. Двойные зигзаги: | |
![]() Рисунок 6. Двойной зигзаг |
|
7. Тройные зигзаги: | |
![]() Рисунок 7. Тройной зигзаг |
|
8. Двойные тройки: | |
![]() Рисунок 8. Двойная тройка |
|
9. Тройные тройки: | |
![]() Рисунок 9. Тройная тройка |
|
10. Сходящиеся треугольники: | |
![]() Рисунок 10. Сходящийся треугольник |
|
11. Расходящиеся треугольники: | |
![]() Рисунок 11. Расходящийся треугольник |
|
Представленные выше модели волн и правила соответствуют лишь классическому представлению о волновом анализе.
Существует также его современное представление, сформированное при изучении рынка Forex. Найдена, например новая модель наклонного (сдвигающегося) треугольника, выявлены импульсы с треугольником во второй волне и др.
Как видно из рисунков 1-11, каждая импульсная или коррекционная волна состоит из таких же импульсных и коррекционных волн (выделены штриховой линией), но уже меньшей степени. Это так называемая фрактальность (вложенность) волн Эллиотта: волны больших степеней состоят из волн меньших степеней, которые в свою очередь состоят из волн еще меньших степеней и так далее.
На этом можно закончить краткое введение в волновой принцип Эллиотта и перейти к теме автоматической разметки волн.
2. Алгоритм автоматической разметки волн Эллиотта
Как уже, наверное, стало ясно, анализ волн Эллиотта - сложный и многогранный процесс. Поэтому люди с самого начала стали искать и применять инструменты, помогающие его облегчить.
Одним из таких инструментов стал механизм автоматической разметки волн Эллиотта.
Можно выделить два принципа авторазметки:
- Согласно фрактальности волн, анализ ведется "сверху вниз", от больших волн к меньшим;
- Анализ ведется методом прямого перебора возможных вариантов.
Блок-схема алгоритма автоматического анализа волн Эллиотта представлена на рисунке 12.
Рисунок 12. Блок-схема алгоритма автоматического анализа волн Эллиотта
Рассмотрим алгоритм более подробно на примере автоматической разметки Импульса (см. рисунок 13).
На первом этапе, на требуемом интервале времени графика цены с помощью "Зигзага" выделяется необходимое для разметки количество точек. Количество точек зависит от того, какую волну мы хотим анализировать. Так, для анализа Импульса требуется шесть точек - 5 вершин и одна точка начала. Если бы анализировался Зигзаг, то количество требуемых точек было бы уже 4 - 3 вершины и одна точка начала.
Если "Зигзаг" определил шесть точек на графике цены, тогда сразу можно произвести разметку Импульса: первая точка - точка начала волны 1, вторая точка - вершина волны 1, третья точка - вершина волны 2, четвертая точка - вершина волны 3, пятая точка - вершина волны 4, и шестая точка - вершина волны 5.
Однако на рисунке 13 "Зигзаг" определил 8 точек. В этом случае придется перебрать по этим точкам все возможные варианты разметки волны. А их, если нетрудно посчитать, будет пять (выделены разным цветом). И каждый вариант разметки придется проверять на правила.
Рисунок 13. Варианты разметки импульса
После проверки на правила, в случае, если размеченная волна по всем параметрам является Импульсом, таким же образом происходит анализ ее субволн.
То же самое касается анализа всех остальных импульсных и коррекционных волн.
3. Виды волн для автоматической разметки
Как уже было ранее сказано, анализ будет вестись сверху вниз путем подачи программе указания найти на заданном интервале какую-либо волну. Однако на самом большом интервале невозможно определить состояние волны, ее начало и конец. Такую волну будем называть неначатой и незавершенной.
Все волны можно разбить на следующие группы:
- Неначатые волны:
- Волны с неначатой первой волной - 1<-2-3-4-5 (например, Импульс с неначатой волной 1; количество требуемых точек - 5) и 1<-2-3 (например, Зигзаг с неначатой волной A; количество требуемых точек - 3);
- Волны с неначатой второй волной - 2<-3-4-5 (например, Диагональ с неначатой волной 2; количество требуемых точек - 4) и 2<-3 (например, Плоскость с неначатой волной B; количество требуемых точек -2);
- Волны с неначатой третье волной - 3<-4-5 (например, Тройной зигзаг с неначатой волной Y; количество требуемых точек - 3);
- Волны с неначатой четвертой волной - 4<-5 (например, Треугольник с неначатой волной D; количество требуемых точек -2);
- Волны с неначатой пятой волной - 5< (например, Импульс с неначатой волной 5; количество требуемых точек - 1);
- Волны с неначатой третьей волной - 3< (например Двойная тройка с неначатой волной Z; количество требуемых точек - 1);
- Незавершенные волны:
- Волны с незавершенной пятой волной - 1-2-3-4-5> (например, Импульс с незавершенной волной 5; количество требуемых точек - 5);
- Волны с незавершенной четвертой волной - 1-2-3-4> (например, Тройной зигзаг с незавершенной волной XX; количество требуемых точек - 4);
- Волны с незавершенной третьей волной - 1-2-3> (например, Клин с незавершенной волной 3; количество требуемых точек -3);
- Волны с незавершенной второй волной - 1-2> (например, Зигзаг с незавершенной волной B; количество требуемых точек -2);
- Волны с незавершенной первой волной - 1> (например, Плоскость с незавершенной волной A; количество требуемых точек -1);
- Неначатые и незавершенные волны:
- Волны с неначатой первой волной и незавершенной второй волной -1<-2> (например, Зигзаг с неначатой волной A и незавершенной волной B; количество требуемых точек - 1);
- Волны с неначатой второй волной и незавершенной третьей волной - 2<-3> (например, Зигзаг с неначатой волной B и незавершенной волной C; количество требуемых точек - 1);
- Волны с неначатой третьей волной и незавершенной четвертой волной - 3<-4> (например, Импульс с неначатой волной 3 и незавершенной волной 4; количество требуемых точек - 1);
- Волны с неначатой четвертой волной и незавершенной пятой волной - 4<-5> (например, Импульс с неначатой волной 4 и незавершенной волной 5; количество требуемых точек - 1);
- Волны с неначатой первой и незавершенной третьей волной - 1<-2-3> (например, Тройная тройка с неначатой волной W и незавершенной волной Y; количество требуемых точек - 2);
- Волны с неначатой второй волной и незавершенной четвертой волной - 2<-3-4> (например, Клин с неначатой волной 2 и незавершенной волной 4; количество требуемых точек - 2);
- Волны с неначатой третьей волной и незавершенной пятой волной - 3<-4-5> (например, Диагональ с неначатой волной 3 и незавершенной волной 5; количество требуемых точек - 2);
- Волны с неначатой первой и незавершенной четвертой волной - 1<-2-3-4> (например, Тройная тройка с неначатой волной W и незавершенной волной XX; количество требуемых точек - 3);
- Волны с неначатой второй волной и незавершенной пятой волной - 2<-3-4-5> (например, Импульс с неначатой волной 2 и незавершенной волной 5; количество требуемых точек - 3);
- Волны с неначатой первой волной и незавершенной пятой волной -1<-2-3-4-5> (например, Тройной зигзаг с неначатой волной W и незавершенной волной Z; количество требуемых точек - 4);
- Завершенные волны - 1-2-3-4-5 (количество требуемых точек - 6) и 1-2-3 (количество требуемых точек - 4).
Знак "<" после номера волны говорит о том, что она не началась. Знак ">" после номера волны говорит, что она незавершена.
На рисунке 14 можно выделить следующие волны:
- Волну с неначатой первой волной A - A<-B-C;
- Волну с неначатой первой W и незавершенной второй X волной - W<-X>;
- Завершенные волны B и C;
Рисунок 14. Неначатые и незавершенные волны
4. Описание структур данных автоматического анализатора волн Эллиотта
Для написания автоматического анализатора волн Эллиотта нам понадобятся следующие структуры данных:
4.1. Структура описания анализируемых в программе волн:
// Структура описания анализируемых в программе волн struct TWaveDescription { string NameWave; // название волны int NumWave; // количество субволн в волне string Subwaves[6]; // названия возможных субволн в волне };
4.2. Класс для хранения параметров конкретной волны:
// Класс для хранения параметров волны class TWave { public: string Name; // имя волны string Formula; // формула волны (1-2-3-4-5, <1-2-3 и т.п.) int Level; // уровень (степень) волны double ValueVertex[6]; // значения вершин волны int IndexVertex[6]; // индексы вершин волны };
4.3. Класс для хранения значений вершин и индексов вершин зигзага:
// Класс для хранения значений вершин и индексов зигзага class TZigzag:public CObject { public: CArrayInt *IndexVertex; // индексы вершин зигзага CArrayDouble *ValueVertex; // значения вершин зигзага };
4.4. Класс для представления дерева волн:
// Класс для представления дерева волн class TNode:public CObject { public: CArrayObj *Child; // потомки данного узла дерева TWave *Wave; // волна, хранимая в узле дерева string Text; // текст узла дерева TNode *Add(string Text,TWave *Wave=NULL) // функция добавления узла в дерево { TNode *Node=new TNode; Node.Child=new CArrayObj; Node.Text =Text; Node.Wave=Wave; Child.Add(Node); return(Node); } };
4.5. Структура для хранения найденных по зигзагу точек:
// Структура для хранения точек, найденных по зигзагу struct TPoints { double ValuePoints[]; // значения найденных точек int IndexPoints[]; // индексы найденных точек int NumPoints; // количество найденных точек };
4.6. Класс для хранения параметров уже проанализированного участка графика:
// Класс для хранения параметров уже проанализированного участка, соответствующему узлу дереву волн class TNodeInfo:CObject { public: int IndexStart,IndexFinish; // диапазон уже проанализированного участка double ValueStart,ValueFinish; // крайние значения уже проанализированного участка string Subwaves; // название волны или группы волн TNode *Node; // узел, указывающий на проанализированный диапазон графика };
4.7. Класс для хранения маркировки волн перед нанесением на график:
// Класс для хранения маркировки волн перед нанесением на график class TLabel:public CObject { public: double Value; // значение вершины int Level; // уровень волны string Text; // маркировка вершины };
5. Описание функций автоматического анализатора волн Эллиотта
Для написания автоматического анализатора волн Эллиотта нам понадобятся следующие функции:
int Zigzag(int H,int Start,int Finish,CArrayInt *IndexVertex,CArrayDouble *ValueVertex)
Ключевым звеном в автоматическом анализаторе волн Эллиотта является "Зигзаг", по которому и будут строиться волны. При этом расчет "Зигзага" по какому-либо параметру должен быть очень быстрым.
В нашем анализаторе будет использоваться "Зигзаг", взятый из статьи "Как писать быстрые и неперерисовывающиеся зигзаги".
Функция Zigzag рассчитывает "Зигзаг" с параметром H на интервале от Start до Finish и записывает найденные индексы вершин и значения вершин, соответственно, в массивы IndexVertex и ValueVertex, адреса которых передаются в данную функцию.
Функция Zigzag возвращает количество найденных вершин "Зигзага".
Функция перебора "Зигзага" и сохранения его параметров:
void FillZigzagArray(int Start,int Finish)
Как было показано раньше, нам будет нужно находить необходимое количество точек на графике цены для разметки волны. Поэтому потребуется иметь массив вершин "Зигзагов" с разными параметрами, который мы потом и будем перебирать для нахождения этих точек.
Функция FillZigzagArray рассчитывает "Зигзаги" на интервале графика от Start до Finish со всеми возможными значениями параметра H (пока количество вершин "Зигзага" не станет равно или менее двух), сохраняет информацию о найденных вершинах в объектах класса TZigzag и записывает эти объекты в глобальный массив ZigzagArray, объявление которого выглядит следующим образом:
CArrayObj ZigzagArray;
Функция поиска на заданном интервале требуемого количества точек на графике цены:
bool FindPoints(int NumPoints,int IndexStart,int IndexFinish,double ValueStart,double ValueFinish,TPoints &Points)
Функция FindPoints ищет не менее NumPoints точек на графике цены на требуемом диапазоне поиска от IndexStart до IndexFinish с требуемыми значениями первой и последней точек ValueStart и ValueFinish, и сохраняет их (т.е. точки) в структуре Points, ссылка на которую передается в данную функцию.
Функция FindPoints возвращает true, если требуемое количество точек удалось найти, иначе возвращается false.
5.4. NotStartedAndNotFinishedWaves
Функция анализа неначатых и незавершенных волн:
void NotStartedAndNotFinishedWaves(TWave *ParentWave,int NumWave,TNode *Node,string Subwaves,int Level)
Функция NotStartedAndNotFinishedWaves анализирует все волны третьей группы волн - волны неначатые и незавершенные. Функция анализирует NumWave волну (с волновым уровнем Level) волны с названием ParentWave.Name, которая может принимать форму Subwaves волн (форму Зигзага, Плоскости, Двойного зигзага и (или) др.). Анализируемая волна NumWave будет храниться в узле дерева волн, дочернем узлу Node.
Так, например, если ParentWave.Name="Импульс", NumWave=5, Subwaves="Импульс, Диагональ," и Level=2, то можно сказать, что функция NotStartedAndNotFinishedWaves будет анализировать пятую волну Импульса, которая имеет волновой уровень 2 и может принять форму Импульса или Диагонали.
В качестве примера приведем блок-схему алгоритма анализа неначатой и незавершенной волны 1<-2-3> в функции NotStartedAndNotFinishedWaves:
<img alt="Рисунок 15. Блок-схема анализа волны с формулой "1"" title="Рисунок 15. Блок-схема анализа волны с формулой "1"" src="https://c.mql5.com/2/2/fig15__1.gif" style="vertical-align:middle;" height="1746" width="750">
Рисунок 15. Блок-схема анализа волны с формулой "1<-2-3>"
При работе функции NotStartedAndNotFinishedWaves вызываются функции NotStartedWaves, NotFinishedWaves и FinishedWaves.
Функция анализа неначатых волн:
void NotStartedWaves(TWave *ParentWave,int NumWave,TNode *Node,string Subwaves,int Level)
Функция NotStartedWaves анализирует все волны первой группы волн - волны неначатые. Функция анализирует NumWave волну (с волновым уровнем Level) волны с названием ParentWave.Name, которая может принимать форму Subwaves волн. Анализируемая волна NumWave будет храниться в узле дерева волн, дочернем узлу Node.
При работе функции NotStartedWaves вызываются функции NotStartedWaves и FinishedWaves.
Все волны анализируются аналогично блок-схеме на рисунке 15.
Функция анализа незавершенных волн:
void NotFinishedWaves(TWave *ParentWave,int NumWave,TNode *Node,string Subwaves,int Level)
Функция NotFinishedWaves анализирует все волны второй группы волн - волны незавершенные. Функция анализирует NumWave волну (с волновым уровнем Level) волны с названием ParentWave.Name, которая может принимать форму Subwaves волн. Анализируемая волна NumWave будет храниться в узле дерева волн, дочернем узлу Node.
При работе функции NotFinishedWaves вызываются функции NotFinishedWaves и FinishedWaves.
Все волны анализируются аналогично блок-схеме на рисунке 15.
Функция анализа завершенных (законченных) волн:
void FinishedWaves(TWave *ParentWave,int NumWave,TNode *Node,string Subwaves,int Level)
Функция FinishedWaves анализирует все волны четвертой группы волн - волны завершенные. Функция анализирует NumWave волну (с волновым уровнем Level) волны с названием ParentWave.Name, которая может принимать форму Subwaves волн. Анализируемая волна NumWave будет храниться в узле дерева волн, дочернем узлу Node.
При работе функции FinishedWaves вызывается функция FinishedWaves.
Все волны анализируются аналогично блок-схеме на рисунке 15.
5.8. FindWaveInWaveDescription
Функция поиска волны в структуре данных WaveDescription:
int FindWaveInWaveDescription(string NameWave)
Функция FindWaveInWaveDescription по названию волны NameWave, передаваемую в качестве параметра, ищет ее в массиве структур WaveDescription и возвращает номер индекса, соответствующего данной волне.
Массив структур WaveDescription имеет следующий вид:
TWaveDescription WaveDescription[]= { { "Импульс",5, { "", "Импульс,Клин,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,", "Импульс,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,Сходящийся треугольник,Расходящийся треугольник,", "Импульс,Диагональ," } } , { "Клин",5, { "", "Импульс,Клин,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,", "Импульс,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,Сходящийся треугольник,Расходящийся треугольник,", "Импульс,Диагональ," } } , { "Диагональ",5, { "", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,Сходящийся треугольник,Расходящийся треугольник,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,Сходящийся треугольник,Расходящийся треугольник," } } , { "Зигзаг",3, { "", "Импульс,Клин,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,Сходящийся треугольник,Расходящийся треугольник,", "Импульс,Диагональ,", "", "" } } , { "Плоскость",3, { "", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,Сходящийся треугольник,Расходящийся треугольник,", "Импульс,Диагональ,", "", "" } } , { "Двойной зигзаг",3, { "", "Зигзаг,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,Сходящийся треугольник,Расходящийся треугольник,", "Зигзаг,", "", "" } } , { "Тройной зигзаг",5, { "", "Зигзаг,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,", "Зигзаг,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,Сходящийся треугольник,Расходящийся треугольник,", "Зигзаг," } } , { "Двойная тройка",3, { "", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,Сходящийся треугольник,Расходящийся треугольник,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,Сходящийся треугольник,Расходящийся треугольник,", "", "" } } , { "Тройная тройка",5, { "", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,Сходящийся треугольник,Расходящийся треугольник,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,Сходящийся треугольник,Расходящийся треугольник," } } , { "Сходящийся треугольник",5, { "", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,Сходящийся треугольник,Расходящийся треугольник,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,Сходящийся треугольник,Расходящийся треугольник," } } , { "Расходящийся треугольник",5, { "", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,Сходящийся треугольник,Расходящийся треугольник,", "Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,Сходящийся треугольник,Расходящийся треугольник," } } };
Функция FindWaveInWaveDescription применяется в функциях анализа волн NotStartedAndNotFinishedWaves, NotStartedWaves, NotFinishedWaves и FinishedWaves.
Функция, проверяющая, был ли уже проанализирован данный участок графика:
bool Already(TWave *Wave,int NumWave,TNode *Node,string Subwaves)
Так как автоматический анализ волн Эллиотта происходит методом перебора, то может возникнуть ситуация, когда данный участок графика уже был проанализирован на предмет наличия какой-либо волны или группы волн. Чтобы это знать, необходимо сохранять ссылку на узел в дереве волн уже проанализированной волны, а затем только выдавать эту ссылку. Все это происходит в функции Already.
Функция Already ищет в глобальном массиве NodeInfoArray, в котором хранятся объекты класса TNodeInfo, участок графика, соответствующий волне NumWave волны с именем Wave.Name, имеющую форму Subwaves волн, и записывает в Node адрес узла уже размеченного участка графика. Если данного участка нет, то создается и заполняется новый объект класса TNodeInfo и записывается в массив NodeInfoArray.
Функция возвращает true, если участок графика уже анализировался, иначе возвращается false.
Массив NodeInfoArray объявляется следующим образом:
CArrayObj NodeInfoArray;
5.10. Функции проверки волны на правила
Включают в себя функцию VertexAAboveB, WaveAMoreWaveB и собственно WaveRules, из которой и вызываются первые две функции. При проверке следует помнить, что волны бывают неначатые и (или) незавершенные, и, например, у волны с формулой "1<-2-3>" невозможно определить, зашла ли четвертая волна за территорию первой или нет, т.к. четвертой волны еще нет.
Функция проверки волны на правила:
bool WaveRules(TWave *Wave)
Функция WaveRules возвращает true, если волна с названием Wave.Name "правильная", иначе возвращается false. При своей работе функция WaveRules вызывает функции VertexAAboveVertexB и WaveAMoreWaveB.
Функция проверки превышения одной вершины другой вершины:
int VertexAAboveVertexB(int A,int B,bool InternalPoints)
Функция VertexAAboveVertexB возвращает число >=0, если вершина волны A превысила вершину волны B, иначе возвращается -1. Если InternalPoints=true, то учитываются внутренние точки волн (максимальные и (или) минимальные значения волн).
Функция проверки превышения длины одной волны длины другой волны:
int WaveAMoreWaveB(int A,int B)
Функция WaveAMoreWaveB возвращает число >=0, если волна A больше волны B, иначе возвращается -1.
11. Функции очистки памяти
Функция очистки дерева волн с верхним узлом Node:
void ClearTree(TNode *Node)
Функция очистки массива ClearNodeInfoArray:
void ClearNodeInfoArray()
Функция очистки массива ZigzagArray:
void ClearZigzagArray()
5.12. Функции обхода дерева волн и выдачи результатов анализа на график
После завершения автоматического анализа волн Эллиотта у нас имеется дерево волн.
Его пример можно представить как на рисунке ниже:
Рисунок 16. Пример дерева волн
Теперь, чтобы отобразить результаты анализа на графике, необходимо обойти данное дерево. Как видно из рисунка 16, вариантов обхода может быть несколько (т.к. имеется несколько вариантов волн), и каждый вариант обхода ведет за собой разную разметку.
Можно выделить два типа узлов дерева.
Первый тип - узлы с названием волн ("Импульс", "Зигзаг" и т.п.). Второй тип - узлы с номерами волн ("1", "1<" и т.п.). Вся информация о параметрах волны находится в первом типе узлов. Поэтому при посещении данных узлов мы будем извлекать и записывать информацию о волне, чтобы затем отобразить ее на графике.
Для простоты мы будем обходить дерево, посещая только первые варианты волн.
Пример обхода приведен на рисунке 17 и выделен красной линией.
Рисунок 17. Пример обхода дерева волн
Функция обхода дерева волн:
void FillLabelArray(TNode *Node)
Функция FillLabelArray обходит дерево волн с корнем Node, посещая только первые варианты волн в дереве, и заполняет глобальный массив LabelArray, в каждом индексе которого будет храниться ссылка на массив вершин (массив объектов класса TLabel), имеющих данный индекс на графике.
Массив LabelArray определен следующим образом:
CArrayObj *LabelArray[];
Функция вывода результатов анализа на график:
void CreateLabels()
Функция CreateLabels создает графические объекты "Текст", соответствующие меткам волн на графике. Метки волн создаются на основе массива LabelArray.
Функция обновления (корректировки) вершин волн на графике:
void CorrectLabel()
Функция CorrectLabel корректирует метки волн на графике при его прокручивании и (или) его сужении.
6. Реализация функций автоматической разметки волн Эллиотта
//+------------------------------------------------------------------+ //| Функция Zigzag | //+------------------------------------------------------------------+ int Zigzag(int H,int Start,int Finish,CArrayInt *IndexVertex,CArrayDouble *ValueVertex) { bool Up=true; double dH=H*Point(); int j=0; int TempMaxBar = Start; int TempMinBar = Start; double TempMax = rates[Start].high; double TempMin = rates[Start].low; for(int i=Start+1;i<=Finish;i++) { // обработка случая восходящего сегмента if(Up==true) { // проверка, не изменился ли текущий максимум if(rates[i].high>TempMax) { // если да, скорректируем соответствующие переменные TempMax=rates[i].high; TempMaxBar=i; } else if(rates[i].low<TempMax-dH) { // иначе, если пробит отстающий уровень, зафиксируем максимум ValueVertex.Add(TempMax); IndexVertex.Add(TempMaxBar); j++; // скорректируем соответствующие переменные Up=false; TempMin=rates[i].low; TempMinBar=i; } } else { // обработка случая нисходящего сегмента // проверка, не изменился ли текущий минимум if(rates[i].low<TempMin) { // если да, скорректируем соответствующие переменные TempMin=rates[i].low; TempMinBar=i; } else if(rates[i].high>TempMin+dH) { // иначе, если пробит отстающий уровень, зафиксируем минимум ValueVertex.Add(TempMin); IndexVertex.Add(TempMinBar); j++; // скорректируем соответствующие переменные Up=true; TempMax=rates[i].high; TempMaxBar=i; } } } // возвратим количество вершин зигзага return(j); }
CArrayObj ZigzagArray; // объявляем глобальный динамический массив ZigzagArray //+------------------------------------------------------------------+ //| Функция FillZigzagArray | //| перебираются значения параметра H зигзага | //| и заполняется массив ZigzagArray | //+------------------------------------------------------------------+ void FillZigzagArray(int Start,int Finish) { CArrayInt *IndexVertex=new CArrayInt; // создаем динамически массив индексов вершин зигзага CArrayDouble *ValueVertex=new CArrayDouble; // создаем динамический массив значений вершин зигзага TZigzag *Zigzag; // объявляем класс для хранения индексов и значений вершин зигзага int H=1; int j=0; int n=Zigzag(H,Start,Finish,IndexVertex,ValueVertex);//находим вершины зигзага с параметром H=1 if(n>0) { // сохраняем вершины зигзага в массиве ZigzagArray Zigzag=new TZigzag; // создаем объект для хранения найденных индексов и вершин зигзага, // заполняем его и сохраняем в массиве ZigzagArray Zigzag.IndexVertex=IndexVertex; Zigzag.ValueVertex=ValueVertex; ZigzagArray.Add(Zigzag); j++; } H++; // в цикле перебираем параметр H зигзага while(true) { IndexVertex=new CArrayInt; // создаем динамический массив индексов вершин зигзага ValueVertex=new CArrayDouble; // создаем динамический массив значений вершин зигзага n=Zigzag(H,Start,Finish,IndexVertex,ValueVertex); // находим вершины зигзага if(n>0) { Zigzag=ZigzagArray.At(j-1); CArrayInt *PrevIndexVertex=Zigzag.IndexVertex; // получаем массив индексов предыдущего зигзага bool b=false; // в цикле проверяем, есть ли разница между текущим зигзагом и предыдущим зигзагом for(int i=0; i<=n-1;i++) { if(PrevIndexVertex.At(i)!=IndexVertex.At(i)) { // если разница есть, сохраняем вершины зигзага в массиве ZigzagArray Zigzag=new TZigzag; Zigzag.IndexVertex=IndexVertex; Zigzag.ValueVertex=ValueVertex; ZigzagArray.Add(Zigzag); j++; b=true; break; } } if(b==false) { // иначе, если разницы нет, освобождаем память delete IndexVertex; delete ValueVertex; } } // ищем вершины зигзага до тех пор, пока их станет меньше или равно двум if(n<=2) break; H++; } }
//+------------------------------------------------------------------+ //| Функция FindPoints | //| Заполняет массивы ValuePoints и IndexPoints структуры Points | //+------------------------------------------------------------------+ bool FindPoints(int NumPoints,int IndexStart,int IndexFinish,double ValueStart,double ValueFinish,TPoints &Points) { int n=0; // в цикле перебираем массив ZigzagArray for(int i=ZigzagArray.Total()-1; i>=0;i--) { TZigzag *Zigzag=ZigzagArray.At(i); // получаемый i-ый зигзаг в массиве ZigzagArray CArrayInt *IndexVertex=Zigzag.IndexVertex; // получаем массив индексов вершин i-го зигзага CArrayDouble *ValueVertex=Zigzag.ValueVertex; // получаем массив значений вершин i-го зигзага int Index1=-1,Index2=-1; // ищем индекс массива IndexVertex, соответствующий первой точке for(int j=0;j<IndexVertex.Total();j++) { if(IndexVertex.At(j)>=IndexStart) { Index1=j; break; } } // ищем индекс массива IndexVertex, соответствующий последней точке for(int j=IndexVertex.Total()-1;j>=0;j--) { if(IndexVertex.At(j)<=IndexFinish) { Index2=j; break; } } // если нашли первую и последнюю точки if((Index1!=-1) && (Index2!=-1)) { n=Index2-Index1+1; // узнаем, сколько точек нашли } // если нашли требуемое количество точек (равное или большее) if(n>=NumPoints) { // проверяем, чтобы первая и последняя вершины совпадали с требуемыми значениями вершин if(((ValueStart!=0) && (ValueVertex.At(Index1)!=ValueStart)) || ((ValueFinish!=0) && (ValueVertex.At(Index1+n-1)!=ValueFinish)))continue; // заполняем структуру Points, передаваемую в качестве параметров Points.NumPoints=n; ArrayResize(Points.ValuePoints, n); ArrayResize(Points.IndexPoints, n); int k=0; // заполняем массивы ValuePoints и IndexPoints структуры Points for(int j=Index1; j<Index1+n;j++) { Points.ValuePoints[k]=ValueVertex.At(j); Points.IndexPoints[k]=IndexVertex.At(j); k++; } return(true); }; }; return(false); };
6.4. Функция NotStartedAndNotFinishedWaves:
//+------------------------------------------------------------------+ //| Функция NotStartedAndNotFinishedWaves | //+------------------------------------------------------------------+ void NotStartedAndNotFinishedWaves(TWave *ParentWave,int NumWave,TNode *Node,string Subwaves,int Level) { int v1,v2,v3,v4,I; TPoints Points; TNode *ParentNode,*ChildNode; int IndexWave; string NameWave; TWave *Wave; int i=0,pos=0,start=0; // в массив ListNameWave записываем волны, которые будем анализировать string ListNameWave[]; ArrayResize(ListNameWave,ArrayRange(WaveDescription,0)); while(pos!=StringLen(Subwaves)-1) { pos=StringFind(Subwaves,",",start); NameWave=StringSubstr(Subwaves,start,pos-start); ListNameWave[i++]=NameWave; start=pos+1; } int IndexStart=ParentWave.IndexVertex[NumWave-1]; int IndexFinish=ParentWave.IndexVertex[NumWave]; double ValueStart = ParentWave.ValueVertex[NumWave - 1]; double ValueFinish= ParentWave.ValueVertex[NumWave]; // находим не менее двух точек на графике цены и записываем их в структуру Points // если не нашли, то выходим из функции if(FindPoints(2,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)return; // циклы перебора неначатых и незавершенных волн с формулой "1<-2-3>" v1=0; while(v1<=Points.NumPoints-2) { v2=v1+1; while(v2<=Points.NumPoints-1) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, // чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if((WaveDescription[IndexWave].NumWave==5) || (WaveDescription[IndexWave].NumWave==3)) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="1<-2-3>"; Wave.ValueVertex[0] = 0; Wave.ValueVertex[1] = Points.ValuePoints[v1]; Wave.ValueVertex[2] = Points.ValuePoints[v2]; Wave.ValueVertex[3] = 0; Wave.ValueVertex[4] = 0; Wave.ValueVertex[5] = 0; Wave.IndexVertex[0] = IndexStart; Wave.IndexVertex[1] = Points.IndexPoints[v1]; Wave.IndexVertex[2] = Points.IndexPoints[v2]; Wave.IndexVertex[3] = IndexFinish; Wave.IndexVertex[4] = 0; Wave.IndexVertex[5] = 0; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=1; // создаем первую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий первой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем вторую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий второй субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем третью субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий третьей субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v2=v2+2; } v1=v1+2; } // циклы перебора неначатых и незавершенных волн с формулой "2<-3-4>" v2=0; while(v2<=Points.NumPoints-2) { v3=v2+1; while(v3<=Points.NumPoints-1) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==5) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="2<-3-4>"; Wave.ValueVertex[0] = 0; Wave.ValueVertex[1] = 0; Wave.ValueVertex[2] = Points.ValuePoints[v2]; Wave.ValueVertex[3] = Points.ValuePoints[v3]; Wave.ValueVertex[4] = 0; Wave.ValueVertex[5] = 0; Wave.IndexVertex[0] = 0; Wave.IndexVertex[1] = IndexStart; Wave.IndexVertex[2] = Points.IndexPoints[v2]; Wave.IndexVertex[3] = Points.IndexPoints[v3]; Wave.IndexVertex[4] = IndexFinish; Wave.IndexVertex[5] = 0; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=2; // создаем вторую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий второй субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем третью субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий третьей субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; //создаем четвертую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий четвертой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v3=v3+2; } v2=v2+2; } // циклы перебора неначатых и незавершенных волн с формулой "3<-4-5>" v3=0; while(v3<=Points.NumPoints-2) { v4=v3+1; while(v4<=Points.NumPoints-1) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, // чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==5) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="3<-4-5>"; Wave.ValueVertex[0] = 0; Wave.ValueVertex[1] = 0; Wave.ValueVertex[2] = 0; Wave.ValueVertex[3] = Points.ValuePoints[v3]; Wave.ValueVertex[4] = Points.ValuePoints[v4]; Wave.ValueVertex[5] = 0; Wave.IndexVertex[0] = 0; Wave.IndexVertex[1] = 0; Wave.IndexVertex[2] = IndexStart; Wave.IndexVertex[3] = Points.IndexPoints[v3]; Wave.IndexVertex[4] = Points.IndexPoints[v4]; Wave.IndexVertex[5] = IndexFinish; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=3; // создаем третью субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий третьей субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем четвертую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий четвертой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем пятую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий пятой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v4=v4+2; } v3=v3+2; } // находим не менее трех точек на графике цены и записываем их в структуру Points // если не нашли, то выходим из функции if(FindPoints(3,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false) return; // циклы перебора неначатых и незавершенных волн с формулой "1<-2-3-4>" v1=0; while(v1<=Points.NumPoints-3) { v2=v1+1; while(v2<=Points.NumPoints-2) { v3=v2+1; while(v3<=Points.NumPoints-1) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==5) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="1<-2-3-4>"; Wave.ValueVertex[0] = 0; Wave.ValueVertex[1] = Points.ValuePoints[v1]; Wave.ValueVertex[2] = Points.ValuePoints[v2]; Wave.ValueVertex[3] = Points.ValuePoints[v3]; Wave.ValueVertex[4] = 0; Wave.ValueVertex[5] = 0; Wave.IndexVertex[0] = IndexStart; Wave.IndexVertex[1] = Points.IndexPoints[v1]; Wave.IndexVertex[2] = Points.IndexPoints[v2]; Wave.IndexVertex[3] = Points.IndexPoints[v3]; Wave.IndexVertex[4] = IndexFinish; Wave.IndexVertex[5] = 0; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=1; // создаем первую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий первой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем вторую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий второй субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем третью субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий третьей субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем четвертую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий четвертой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } //иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v3=v3+2; } v2=v2+2; } v1=v1+2; } // циклы перебора неначатых и незавершенных волн с формулой "2<-3-4-5>" v2=0; while(v2<=Points.NumPoints-3) { v3=v2+1; while(v3<=Points.NumPoints-2) { v4=v3+1; while(v4<=Points.NumPoints-1) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==5) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="2<-3-4-5>"; Wave.ValueVertex[0] = 0; Wave.ValueVertex[1] = 0; Wave.ValueVertex[2] = Points.ValuePoints[v2]; Wave.ValueVertex[3] = Points.ValuePoints[v3]; Wave.ValueVertex[4] = Points.ValuePoints[v4]; Wave.ValueVertex[5] = 0; Wave.IndexVertex[0] = 0; Wave.IndexVertex[1] = IndexStart; Wave.IndexVertex[2] = Points.IndexPoints[v2]; Wave.IndexVertex[3] = Points.IndexPoints[v3]; Wave.IndexVertex[4] = Points.IndexPoints[v4]; Wave.IndexVertex[5] = IndexFinish; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=2; // создаем вторую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий второй субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем третью субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий третьей субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; //создаем четвертуюю субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); //если участок графика, соответствующий четвертой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем пятую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий пятой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v4=v4+2; } v3=v3+2; } v2=v2+2; } // находим не менее четырех точек на графике цены и записываем их в структуру Points // если не нашли, то выходим из функции if(FindPoints(4,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false) return; // циклы перебора неначатых и незавершенных волн с формулой "1<-2-3-4-5>" v1=0; while(v1<=Points.NumPoints-4) { v2=v1+1; while(v2<=Points.NumPoints-3) { v3=v2+1; while(v3<=Points.NumPoints-2) { v4=v3+1; while(v4<=Points.NumPoints-1) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==5) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="1<-2-3-4-5>"; Wave.ValueVertex[0] = 0; Wave.ValueVertex[1] = Points.ValuePoints[v1]; Wave.ValueVertex[2] = Points.ValuePoints[v2]; Wave.ValueVertex[3] = Points.ValuePoints[v3]; Wave.ValueVertex[4] = Points.ValuePoints[v4]; Wave.ValueVertex[5] = 0; Wave.IndexVertex[0] = IndexStart; Wave.IndexVertex[1] = Points.IndexPoints[v1]; Wave.IndexVertex[2] = Points.IndexPoints[v2]; Wave.IndexVertex[3] = Points.IndexPoints[v3]; Wave.IndexVertex[4] = Points.IndexPoints[v4]; Wave.IndexVertex[5] = IndexFinish; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=1; // создаем первую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий первой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем вторую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий второй субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем третью субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий третьей субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем четвертую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий четвертой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем пятую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий пятой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v4=v4+2; } v3=v3+2; } v2=v2+2; } v1=v1+2; } // находим не менее одной точки на графике цены и записываем ее в структуру Points // если не нашли, то выходим из функции if(FindPoints(1,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)return; // цикл перебора неначатых и незавершенных волн с формулой "1<-2>" v1=0; while(v1<=Points.NumPoints-1) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==5 || WaveDescription[IndexWave].NumWave==3) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="1<-2>"; Wave.ValueVertex[0] = 0; Wave.ValueVertex[1] = Points.ValuePoints[v1]; Wave.ValueVertex[2] = 0; Wave.ValueVertex[3] = 0; Wave.ValueVertex[4] = 0; Wave.ValueVertex[5] = 0; Wave.IndexVertex[0] = IndexStart; Wave.IndexVertex[1] = Points.IndexPoints[v1]; Wave.IndexVertex[2] = IndexFinish; Wave.IndexVertex[3] = 0; Wave.IndexVertex[4] = 0; Wave.IndexVertex[5] = 0; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=1; // создаем первую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий первой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем вторую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий второй субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v1=v1+1; } // цикл перебора неначатых и незавершенных волн с формулой "2<-3>" v2=0; while(v2<=Points.NumPoints-1) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==5 || WaveDescription[IndexWave].NumWave==3) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="2<-3>"; Wave.ValueVertex[0] = 0; Wave.ValueVertex[1] = 0; Wave.ValueVertex[2] = Points.ValuePoints[v2]; Wave.ValueVertex[3] = 0; Wave.ValueVertex[4] = 0; Wave.ValueVertex[5] = 0; Wave.IndexVertex[0] = 0; Wave.IndexVertex[1] = IndexStart; Wave.IndexVertex[2] = Points.IndexPoints[v2]; Wave.IndexVertex[3] = IndexFinish; Wave.IndexVertex[4] = 0; Wave.IndexVertex[5] = 0; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=2; // создаем вторую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий второй субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем третью субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий третьей субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v2=v2+1; } // цикл перебора неначатых и незавершенных волн с формулой "3<-4>" v3=0; while(v3<=Points.NumPoints-1) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==5) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="3<-4>"; Wave.ValueVertex[0] = 0; Wave.ValueVertex[1] = 0; Wave.ValueVertex[2] = 0; Wave.ValueVertex[3] = Points.ValuePoints[v3]; Wave.ValueVertex[4] = 0; Wave.ValueVertex[5] = 0; Wave.IndexVertex[0] = 0; Wave.IndexVertex[1] = 0; Wave.IndexVertex[2] = IndexStart; Wave.IndexVertex[3] = Points.IndexPoints[v3]; Wave.IndexVertex[4] = IndexFinish; Wave.IndexVertex[5] = 0; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=3; // создаем третью субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий третьей субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем четвертую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий четвертой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v3=v3+1; } // цикл перебора неначатых и незавершенных волн с формулой "4<-5>" v4=0; while(v4<=Points.NumPoints-1) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==5) { //создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="4<-5>"; Wave.ValueVertex[0] = 0; Wave.ValueVertex[1] = 0; Wave.ValueVertex[2] = 0; Wave.ValueVertex[3] = 0; Wave.ValueVertex[4] = Points.ValuePoints[v4]; Wave.ValueVertex[5] = 0; Wave.IndexVertex[0] = 0; Wave.IndexVertex[1] = 0; Wave.IndexVertex[2] = 0; Wave.IndexVertex[3] = IndexStart; Wave.IndexVertex[4] = Points.IndexPoints[v4]; Wave.IndexVertex[5] = IndexFinish; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=4; // создаем четвертую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий четвертой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем пятую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий пятой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } //иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v4=v4+1; } }
//+------------------------------------------------------------------+ //| Функция NotStartedWaves | //+------------------------------------------------------------------+ void NotStartedWaves(TWave *ParentWave,int NumWave,TNode *Node,string Subwaves,int Level) { int v1,v2,v3,v4,v5,I; TPoints Points; TNode *ParentNode,*ChildNode; int IndexWave; string NameWave; TWave *Wave; int i=0,Pos=0,Start=0; // в массив ListNameWave записываем волны, которые будем анализировать string ListNameWave[]; ArrayResize(ListNameWave,ArrayRange(WaveDescription,0)); while(Pos!=StringLen(Subwaves)-1) { Pos=StringFind(Subwaves,",",Start); NameWave=StringSubstr(Subwaves,Start,Pos-Start); ListNameWave[i++]=NameWave; Start=Pos+1; } int IndexStart=ParentWave.IndexVertex[NumWave-1]; int IndexFinish=ParentWave.IndexVertex[NumWave]; double ValueStart = ParentWave.ValueVertex[NumWave - 1]; double ValueFinish= ParentWave.ValueVertex[NumWave]; // находим не менее двух точек на графике цены и записываем их в структуру Points // если не нашли, то выходим из функции if(FindPoints(2,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)return; // циклы перебора неначатых волн с формулой "4<-5" v5=Points.NumPoints-1; v4=v5-1; while(v4>=0) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==5) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="4<-5"; Wave.ValueVertex[0] = 0; Wave.ValueVertex[1] = 0; Wave.ValueVertex[2] = 0; Wave.ValueVertex[3] = 0; Wave.ValueVertex[4] = Points.ValuePoints[v4]; Wave.ValueVertex[5] = Points.ValuePoints[v5]; Wave.IndexVertex[0] = 0; Wave.IndexVertex[1] = 0; Wave.IndexVertex[2] = 0; Wave.IndexVertex[3] = IndexStart; Wave.IndexVertex[4] = Points.IndexPoints[v4]; Wave.IndexVertex[5] = Points.IndexPoints[v5]; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=4; // создаем четвертую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий четвертой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем пятую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий пятой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v4=v4-2; } // циклы перебора неначатых волн с формулой "2<-3" v3=Points.NumPoints-1; v2=v3-1; while(v2>=0) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==3) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="2<-3"; Wave.ValueVertex[0] = 0; Wave.ValueVertex[1] = 0; Wave.ValueVertex[2] = Points.ValuePoints[v2]; Wave.ValueVertex[3] = Points.ValuePoints[v3]; Wave.ValueVertex[4] = 0; Wave.ValueVertex[5] = 0; Wave.IndexVertex[0] = 0; Wave.IndexVertex[1] = IndexStart; Wave.IndexVertex[2] = Points.IndexPoints[v2]; Wave.IndexVertex[3] = Points.IndexPoints[v3]; Wave.IndexVertex[4] = 0; Wave.IndexVertex[5] = 0; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=2; // создаем вторую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий второй субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем третью субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий третьей субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v2=v2-2; } // находим не менее трех точек на графике цены и записываем их в структуру Points // если не нашли, то выходим из функции if(FindPoints(3,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)return; // циклы перебора неначатых волн с формулой "3<-4-5" v5=Points.NumPoints-1; v4=v5-1; while(v4>=1) { v3=v4-1; while(v3>=0) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==5) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="3<-4-5"; Wave.ValueVertex[0] = 0; Wave.ValueVertex[1] = 0; Wave.ValueVertex[2] = 0; Wave.ValueVertex[3] = Points.ValuePoints[v3]; Wave.ValueVertex[4] = Points.ValuePoints[v4]; Wave.ValueVertex[5] = Points.ValuePoints[v5]; Wave.IndexVertex[0] = 0; Wave.IndexVertex[1] = 0; Wave.IndexVertex[2] = IndexStart; Wave.IndexVertex[3] = Points.IndexPoints[v3]; Wave.IndexVertex[4] = Points.IndexPoints[v4]; Wave.IndexVertex[5] = Points.IndexPoints[v5]; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=3; // создаем третью субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий третьей субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем четвертую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий четвертой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем пятую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий пятой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v3=v3-2; } v4=v4-2; } // циклы перебора неначатых волн с формулой "1<-2-3" v3=Points.NumPoints-1; v2=v3-1; while(v2>=1) { v1=v2-1; while(v1>=0) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==3) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="1<-2-3"; Wave.ValueVertex[0] = 0; Wave.ValueVertex[1] = Points.ValuePoints[v1]; Wave.ValueVertex[2] = Points.ValuePoints[v2]; Wave.ValueVertex[3] = Points.ValuePoints[v3]; Wave.ValueVertex[4] = 0; Wave.ValueVertex[5] = 0; Wave.IndexVertex[0] = IndexStart; Wave.IndexVertex[1] = Points.IndexPoints[v1]; Wave.IndexVertex[2] = Points.IndexPoints[v2]; Wave.IndexVertex[3] = Points.IndexPoints[v3]; Wave.IndexVertex[4] = 0; Wave.IndexVertex[5] = 0; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=1; // создаем первую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); //если участок графика, соответствующий первой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем вторую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); //если участок графика, соответствующий второй субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем третью субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий третьей субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v1=v1-2; } v2=v2-2; } // находим не менее четырех точек на графике цены и записываем их в структуру Points // если не нашли, то выходим из функции if(FindPoints(4,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)return; // циклы перебора неначатых волн с формулой "2<-3-4-5" v5=Points.NumPoints-1; v4=v5-1; while(v4>=2) { v3=v4-1; while(v3>=1) { v2=v3-1; while(v2>=0) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==5) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="2<-3-4-5"; Wave.ValueVertex[0] = 0; Wave.ValueVertex[1] = 0; Wave.ValueVertex[2] = Points.ValuePoints[v2]; Wave.ValueVertex[3] = Points.ValuePoints[v3]; Wave.ValueVertex[4] = Points.ValuePoints[v4]; Wave.ValueVertex[5] = Points.ValuePoints[v5]; Wave.IndexVertex[0] = 0; Wave.IndexVertex[1] = IndexStart; Wave.IndexVertex[2] = Points.IndexPoints[v2]; Wave.IndexVertex[3] = Points.IndexPoints[v3]; Wave.IndexVertex[4] = Points.IndexPoints[v4]; Wave.IndexVertex[5] = Points.IndexPoints[v5]; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=2; // создаем вторую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий второй субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем третью субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий третьей субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем четвертую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий четвертой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем пятую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий пятой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v2=v2-2; } v3=v3-2; } v4=v4-2; } // находим не менее пяти точек на графике цены и записываем их в структуру Points // если не нашли, то выходим из функции if(FindPoints(5,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)return; // циклы перебора неначатых волн с формулой "1<-2-3-4-5" v5=Points.NumPoints-1; v4=v5-1; while(v4>=3) { v3=v4-1; while(v3>=2) { v2=v3-1; while(v2>=1) { v1=v2-1; while(v1>=0) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==5) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="1<-2-3-4-5"; Wave.ValueVertex[0] = 0; Wave.ValueVertex[1] = Points.ValuePoints[v1]; Wave.ValueVertex[2] = Points.ValuePoints[v2]; Wave.ValueVertex[3] = Points.ValuePoints[v3]; Wave.ValueVertex[4] = Points.ValuePoints[v4]; Wave.ValueVertex[5] = Points.ValuePoints[v5]; Wave.IndexVertex[0] = IndexStart; Wave.IndexVertex[1] = Points.IndexPoints[v1]; Wave.IndexVertex[2] = Points.IndexPoints[v2]; Wave.IndexVertex[3] = Points.IndexPoints[v3]; Wave.IndexVertex[4] = Points.IndexPoints[v4]; Wave.IndexVertex[5] = Points.IndexPoints[v5]; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=1; // создаем первую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий первой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем вторую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий второй субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем третью субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий третьей субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем четвертую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий четвертой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем пятую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий пятой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v1=v1-2; } v2=v2-2; } v3=v3-2; } v4=v4-2; } }
6.6. Функция NotFinishedWaves:
//+------------------------------------------------------------------+ //| Функция NotFinishedWaves | //+------------------------------------------------------------------+ void NotFinishedWaves(TWave *ParentWave,int NumWave,TNode *Node,string Subwaves,int Level) { int v0,v1,v2,v3,v4,I; TPoints Points; TNode *ParentNode,*ChildNode; int IndexWave; string NameWave; TWave *Wave; int i=0,Pos=0,Start=0; //в массив ListNameWave записываем волны, которые будем анализировать string ListNameWave[]; ArrayResize(ListNameWave,ArrayRange(WaveDescription,0)); while(Pos!=StringLen(Subwaves)-1) { Pos=StringFind(Subwaves,",",Start); NameWave=StringSubstr(Subwaves,Start,Pos-Start); ListNameWave[i++]=NameWave; Start=Pos+1; } int IndexStart=ParentWave.IndexVertex[NumWave-1]; int IndexFinish=ParentWave.IndexVertex[NumWave]; double ValueStart = ParentWave.ValueVertex[NumWave - 1]; double ValueFinish= ParentWave.ValueVertex[NumWave]; // находим не менее двух точек на графике цены и записываем их в структуру Points // если не нашли, то выходим из функции if(FindPoints(2,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)return; // циклы перебора незавершенных волн с формулой "1-2>" v0=0; v1=v0+1; while(v1<=Points.NumPoints-1) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if((WaveDescription[IndexWave].NumWave==5) || (WaveDescription[IndexWave].NumWave==3)) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="1-2>"; Wave.ValueVertex[0] = Points.ValuePoints[v0]; Wave.ValueVertex[1] = Points.ValuePoints[v1]; Wave.ValueVertex[2] = 0; Wave.ValueVertex[3] = 0; Wave.ValueVertex[4] = 0; Wave.ValueVertex[5] = 0; Wave.IndexVertex[0] = Points.IndexPoints[v0]; Wave.IndexVertex[1] = Points.IndexPoints[v1]; Wave.IndexVertex[2] = IndexFinish; Wave.IndexVertex[3] = 0; Wave.IndexVertex[4] = 0; Wave.IndexVertex[5] = 0; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=1; // создаем первую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий первой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем вторую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий второй субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v1=v1+2; } // находим не менее трех точек на графике цены и записываем их в структуру Points // если не нашли, то выходим из функции if(FindPoints(3,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)return; // циклы перебора незавершенных волн с формулой "1-2-3>" v0=0; v1=v0+1; while(v1<=Points.NumPoints-2) { v2=v1+1; while(v2<=Points.NumPoints-1) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if((WaveDescription[IndexWave].NumWave==5) || (WaveDescription[IndexWave].NumWave==3)) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="1-2-3>"; Wave.ValueVertex[0] = Points.ValuePoints[v0]; Wave.ValueVertex[1] = Points.ValuePoints[v1]; Wave.ValueVertex[2] = Points.ValuePoints[v2]; Wave.ValueVertex[3] = 0; Wave.ValueVertex[4] = 0; Wave.ValueVertex[5] = 0; Wave.IndexVertex[0] = Points.IndexPoints[v0]; Wave.IndexVertex[1] = Points.IndexPoints[v1]; Wave.IndexVertex[2] = Points.IndexPoints[v2]; Wave.IndexVertex[3] = IndexFinish; Wave.IndexVertex[4] = 0; Wave.IndexVertex[5] = 0; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=1; // создаем первую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий первой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем вторую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий второй субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем третью субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий третьей субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v2=v2+2; } v1=v1+2; } // находим не менее четырех точек на графике цены и записываем их в структуру Points // если не нашли, то выходим из функции if(FindPoints(4,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false) return; // циклы перебора незавершенных волн с формулой "1-2-3-4>" v0=0; v1=v0+1; while(v1<=Points.NumPoints-3) { v2=v1+1; while(v2<=Points.NumPoints-2) { v3=v2+1; while(v3<=Points.NumPoints-1) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==5) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="1-2-3-4>"; Wave.ValueVertex[0] = Points.ValuePoints[v0]; Wave.ValueVertex[1] = Points.ValuePoints[v1]; Wave.ValueVertex[2] = Points.ValuePoints[v2]; Wave.ValueVertex[3] = Points.ValuePoints[v3]; Wave.ValueVertex[4] = 0; Wave.ValueVertex[5] = 0; Wave.IndexVertex[0] = Points.IndexPoints[v0]; Wave.IndexVertex[1] = Points.IndexPoints[v1]; Wave.IndexVertex[2] = Points.IndexPoints[v2]; Wave.IndexVertex[3] = Points.IndexPoints[v3]; Wave.IndexVertex[4] = IndexFinish; Wave.IndexVertex[5] = 0; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=1; // создаем первую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий первой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем вторую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); //если участок графика, соответствующий второй субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем третью субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий третьей субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем четвертую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий четвертой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v3=v3+2; } v2=v2+2; } v1=v1+2; } // находим не менее пяти точек на графике цены и записываем их в структуру Points // если не нашли, то выходим из функции if(FindPoints(5,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)return; // циклы перебора незавершенных волн с формулой "1-2-3-4-5>" v0=0; v1=v0+1; while(v1<=Points.NumPoints-4) { v2=v1+1; while(v2<=Points.NumPoints-3) { v3=v2+1; while(v3<=Points.NumPoints-2) { v4=v3+1; while(v4<=Points.NumPoints-1) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==5) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="1-2-3-4-5>"; Wave.ValueVertex[0] = Points.ValuePoints[v0]; Wave.ValueVertex[1] = Points.ValuePoints[v1]; Wave.ValueVertex[2] = Points.ValuePoints[v2]; Wave.ValueVertex[3] = Points.ValuePoints[v3]; Wave.ValueVertex[4] = Points.ValuePoints[v4]; Wave.ValueVertex[5] = 0; Wave.IndexVertex[0] = Points.IndexPoints[v0]; Wave.IndexVertex[1] = Points.IndexPoints[v1]; Wave.IndexVertex[2] = Points.IndexPoints[v2]; Wave.IndexVertex[3] = Points.IndexPoints[v3]; Wave.IndexVertex[4] = Points.IndexPoints[v4]; Wave.IndexVertex[5] = IndexFinish; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=1; // создаем первую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий первой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем вторую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий второй субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем третью субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий третьей субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем четвертую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий четвертой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем пятую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий пятой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v4=v4+2; } v3=v3+2; } v2=v2+2; } v1=v1+2; } }
//+------------------------------------------------------------------+ //| Функция FinishedWaves | //+------------------------------------------------------------------+ void FinishedWaves(TWave *ParentWave,int NumWave,TNode *Node,string Subwaves,int Level) { int v0,v1,v2,v3,v4,v5,I; TPoints Points; TNode *ParentNode,*ChildNode; int IndexWave; string NameWave; TWave *Wave; int i=0,Pos=0,Start=0; // в массив ListNameWave записываем волны, которые будем анализировать string ListNameWave[]; ArrayResize(ListNameWave,ArrayRange(WaveDescription,0)); while(Pos!=StringLen(Subwaves)-1) { Pos=StringFind(Subwaves,",",Start); NameWave=StringSubstr(Subwaves,Start,Pos-Start); ListNameWave[i++]=NameWave; Start=Pos+1; } int IndexStart=ParentWave.IndexVertex[NumWave-1]; int IndexFinish=ParentWave.IndexVertex[NumWave]; double ValueStart = ParentWave.ValueVertex[NumWave - 1]; double ValueFinish= ParentWave.ValueVertex[NumWave]; // находим не менее четырех точек на графике цены и записываем их в структуру Points // если не нашли, то выходим из функции if(FindPoints(4,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false) return; // циклы перебора завершенных волн с формулой "1-2-3" v0 = 0; v1 = 1; v3 = Points.NumPoints - 1; while(v1<=v3-2) { v2=v1+1; while(v2<=v3-1) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==3) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave;; Wave.Name=NameWave; Wave.Formula="1-2-3"; Wave.Level=Level; Wave.ValueVertex[0] = Points.ValuePoints[v0]; Wave.ValueVertex[1] = Points.ValuePoints[v1]; Wave.ValueVertex[2] = Points.ValuePoints[v2]; Wave.ValueVertex[3] = Points.ValuePoints[v3]; Wave.ValueVertex[4] = 0; Wave.ValueVertex[5] = 0; Wave.IndexVertex[0] = Points.IndexPoints[v0]; Wave.IndexVertex[1] = Points.IndexPoints[v1]; Wave.IndexVertex[2] = Points.IndexPoints[v2]; Wave.IndexVertex[3] = Points.IndexPoints[v3]; Wave.IndexVertex[4] = 0; Wave.IndexVertex[5] = 0; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=1; // создаем первую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(i)); // если участок графика, соответствующий первой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем вторую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(i)); // если участок графика, соответствующий второй субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем третью субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий третьей субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v2=v2+2; } v1=v1+2; } // находим не менее шести точек на графике цены и записываем их в структуру Points // если не нашли, то выходим из функции if(FindPoints(6,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)return; // циклы перебора завершенных волн с формулой "1-2-3-4-5" v0 = 0; v1 = 1; v5 = Points.NumPoints - 1; while(v1<=v5-4) { v2=v1+1; while(v2<=v5-3) { v3=v2+1; while(v3<=v5-2) { v4=v3+1; while(v4<=v5-1) { int j=0; while(j<=i-1) { // по очереди из ListNameWave извлекаем название волны для анализа NameWave=ListNameWave[j++]; // находим индекс волны в структуре WaveDescription для того, чтобы знать количество ее субволн и их названия IndexWave=FindWaveInWaveDescription(NameWave); if(WaveDescription[IndexWave].NumWave==5) { // создаем объект класса TWave и заполняем его поля - параметры анализируемой волны Wave=new TWave; Wave.Name=NameWave; Wave.Level=Level; Wave.Formula="1-2-3-4-5"; Wave.ValueVertex[0] = Points.ValuePoints[v0]; Wave.ValueVertex[1] = Points.ValuePoints[v1]; Wave.ValueVertex[2] = Points.ValuePoints[v2]; Wave.ValueVertex[3] = Points.ValuePoints[v3]; Wave.ValueVertex[4] = Points.ValuePoints[v4]; Wave.ValueVertex[5] = Points.ValuePoints[v5]; Wave.IndexVertex[0] = Points.IndexPoints[v0]; Wave.IndexVertex[1] = Points.IndexPoints[v1]; Wave.IndexVertex[2] = Points.IndexPoints[v2]; Wave.IndexVertex[3] = Points.IndexPoints[v3]; Wave.IndexVertex[4] = Points.IndexPoints[v4]; Wave.IndexVertex[5] = Points.IndexPoints[v5]; // проверяем волну на правила if(WaveRules(Wave)==true) { // если волна прошла проверку на правила, добавляем ее в дерево волн ParentNode=Node.Add(NameWave,Wave); I=1; // создаем первую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий первой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем вторую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий второй субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем третью субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий третьей субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем четвертую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий четвертой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); I++; // создаем пятую субволну в дереве волн ChildNode=ParentNode.Add(IntegerToString(I)); // если участок графика, соответствующий пятой субволне еще не анализировался, то анализируем его if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false) FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+1); } // иначе, если волна не прошла на правила, освобождаем память else delete Wave; } } v4=v4+2; } v3=v3+2; } v2=v2+2; } v1=v1+2; } }
6.8. Функция FindWaveInWaveDescription:
//+------------------------------------------------------------------+ //| Функция FindWaveInWaveDescription | //+------------------------------------------------------------------+ int FindWaveInWaveDescription(string NameWave) { for(int i=0;i<ArrayRange(WaveDescription,0);i++) if(WaveDescription[i].NameWave==NameWave)return(i); return(-1); }
//+------------------------------------------------------------------+ //| Функция Already | //+------------------------------------------------------------------+ bool Already(TWave *Wave,int NumWave,TNode *Node,string Subwaves) { // получаем требуемые параметры волны или группы волн int IndexStart=Wave.IndexVertex[NumWave-1]; int IndexFinish=Wave.IndexVertex[NumWave]; double ValueStart = Wave.ValueVertex[NumWave - 1]; double ValueFinish= Wave.ValueVertex[NumWave]; // в цикле перебираем массив NodeInfoArray для поиска уже размеченного участка графика for(int i=NodeInfoArray.Total()-1; i>=0;i--) { TNodeInfo *NodeInfo=NodeInfoArray.At(i); // если требуемый участок уже ранее размечался if(NodeInfo.Subwaves==Subwaves && (NodeInfo.ValueStart==ValueStart) && (NodeInfo.ValueFinish==ValueFinish) && (NodeInfo.IndexStart==IndexStart) && (NodeInfo.IndexFinish==IndexFinish)) { // добавляем дочерние узлы найденного узла в дочерние узлы нового узла for(int j=0;j<NodeInfo.Node.Child.Total();j++) Node.Child.Add(NodeInfo.Node.Child.At(j)); return(true); // выходим из функции } } // если участок ранее не размечался, то записываем данные о нем в массив NodeInfoArray TNodeInfo *NodeInfo=new TNodeInfo; NodeInfo.IndexStart=IndexStart; NodeInfo.IndexFinish=IndexFinish; NodeInfo.ValueStart=ValueStart; NodeInfo.ValueFinish=ValueFinish; NodeInfo.Subwaves=Subwaves; NodeInfo.Node=Node; NodeInfoArray.Add(NodeInfo); return(false); }
int IndexVertex[6]; // индексы вершин волны double ValueVertex[6],Maximum[6],Minimum[6]; // значения вершин волны, а также максимальные и минимальные значения волны string Trend; // направление тренда - "Up" или "Down" string Formula; // формула волны - "1<2-3>" или "1-2-3>" и т.п. int FixedVertex[6]; // информация о вершинах волны, зафиксированы они или нет //+------------------------------------------------------------------+ //| Функция WaveRules | //+------------------------------------------------------------------+ bool WaveRules(TWave *Wave) { Formula=Wave.Formula; bool Result=false; // заполняем массив IndexVertex и ValueVertex - индексы вершин и значения вершин волны for(int i=0;i<=5;i++) { IndexVertex[i]=Wave.IndexVertex[i]; ValueVertex[i]=Wave.ValueVertex[i]; FixedVertex[i]=-1; } // заполняем массив FixedVertex, значения которого указывают, является ли вершина фиксированной или нет int Pos1=StringFind(Formula,"<"); string Str; if(Pos1>0) { Str=ShortToString(StringGetCharacter(Formula,Pos1-1)); FixedVertex[StringToInteger(Str)]=1; FixedVertex[StringToInteger(Str)-1]=0; Pos1=StringToInteger(Str)+1; } else Pos1=0; int Pos2=StringFind(Formula,">"); if(Pos2>0) { Str=ShortToString(StringGetCharacter(Formula,Pos2-1)); FixedVertex[StringToInteger(Str)]=0; Pos2=StringToInteger(Str)-1; } else { Pos2=StringLen(Formula); Str=ShortToString(StringGetCharacter(Formula,Pos2-1)); Pos2=StringToInteger(Str); } for(int i=Pos1;i<=Pos2;i++) FixedVertex[i]=1; double High[],Low[]; ArrayResize(High,ArrayRange(rates,0)); ArrayResize(Low,ArrayRange(rates,0)); // находим максимумы и минимумы волн for(int i=1; i<=5; i++) { Maximum[i]=rates[IndexVertex[i]].high; Minimum[i]=rates[IndexVertex[i-1]].low; for(int j=IndexVertex[i-1];j<=IndexVertex[i];j++) { if(rates[j].high>Maximum[i])Maximum[i]=rates[j].high; if(rates[j].low<Minimum[i])Minimum[i]=rates[j].low; } } // узнаем тренд if((FixedVertex[0]==1 && ValueVertex[0]==rates[IndexVertex[0]].low) || (FixedVertex[1]==1 && ValueVertex[1]==rates[IndexVertex[1]].high) || (FixedVertex[2]==1 && ValueVertex[2]==rates[IndexVertex[2]].low) || (FixedVertex[3]==1 && ValueVertex[3]==rates[IndexVertex[3]].high) || (FixedVertex[4]==1 && ValueVertex[4]==rates[IndexVertex[4]].low) || (FixedVertex[5]==1 && ValueVertex[5]==rates[IndexVertex[5]].high)) Trend="Up"; else Trend="Down"; // проверяем требуемую волну на правила if(Wave.Name=="Импульс") { if(VertexAAboveVertexB(1,0,true)>=0 && VertexAAboveVertexB(2,0,true)>=0 && VertexAAboveVertexB(1,2,false)>=0 && VertexAAboveVertexB(3,2,true)>=0 && VertexAAboveVertexB(3,1,false)>=0 && VertexAAboveVertexB(4,1,true)>=0 && VertexAAboveVertexB(3,4,false)>=0 && VertexAAboveVertexB(5,4,true)>=0 && (WaveAMoreWaveB(3,1)>=0 || WaveAMoreWaveB(3,5)>=0)) Result=true; } else if(Wave.Name=="Клин") { if(VertexAAboveVertexB(1,0,true)>=0 && VertexAAboveVertexB(2,0,true)>=0 && VertexAAboveVertexB(1,2,false)>=0 && VertexAAboveVertexB(3,2,true)>=0 && VertexAAboveVertexB(3,1,false)>=0 && VertexAAboveVertexB(4,2,true)>=0 && VertexAAboveVertexB(1,4,false)>=0 && VertexAAboveVertexB(3,4,false)>=0 && VertexAAboveVertexB(5,4,true)>=0&& (WaveAMoreWaveB(3,1)>=0 || WaveAMoreWaveB(3,5)>=0)) Result=true; } else if(Wave.Name=="Диагональ") { if(VertexAAboveVertexB(1,0,true)>=0 && VertexAAboveVertexB(2,0,true)>=0 && VertexAAboveVertexB(1,2,false)>=0 && VertexAAboveVertexB(3,2,true)>=0 && VertexAAboveVertexB(3,1,false)>=0 && VertexAAboveVertexB(4,2,true)>=0 && VertexAAboveVertexB(3,4,false)>=0 && VertexAAboveVertexB(5,4,true)>=0&& (WaveAMoreWaveB(3,1)>=0 || WaveAMoreWaveB(3,5)>=0)) Result=true; } else if(Wave.Name=="Зигзаг") { if(VertexAAboveVertexB(1,0,true)>=0 && VertexAAboveVertexB(2,0,true)>=0 && VertexAAboveVertexB(1,2,false)>=0 && VertexAAboveVertexB(3,2,true)>=0 && VertexAAboveVertexB(3,1,false)>=0) Result=true; } else if(Wave.Name=="Плоскость") { if(VertexAAboveVertexB(1,0,false)>=0 && VertexAAboveVertexB(1,2,false)>=0 && VertexAAboveVertexB(3,2,true)>=0) Result=true; } else if(Wave.Name=="Двойной зигзаг") { if(VertexAAboveVertexB(1,0,true)>=0 && VertexAAboveVertexB(2,0,true)>=0 && VertexAAboveVertexB(1,2,false)>=0 && VertexAAboveVertexB(3,2,true)>=0 && VertexAAboveVertexB(3,1,false)>=0) Result=true; } else if(Wave.Name=="Двойная тройка") { if(VertexAAboveVertexB(1,0,true)>=0 && VertexAAboveVertexB(1,2,false)>=0 && VertexAAboveVertexB(3,2,false)>=0) Result=true; } else if(Wave.Name=="Тройной зигзаг") { if(VertexAAboveVertexB(1,0,true)>=0 && VertexAAboveVertexB(2,0,true)>=0 && VertexAAboveVertexB(1,2,false)>=0 && VertexAAboveVertexB(3,2,true)>=0 && VertexAAboveVertexB(3,1,false)>=0 && VertexAAboveVertexB(5,3,false) && VertexAAboveVertexB(3,4,false)>=0 && VertexAAboveVertexB(5,4,true)>=0) Result=true; } else if(Wave.Name=="Тройная тройка") { if(VertexAAboveVertexB(1,0,true)>=0 && VertexAAboveVertexB(1,2,false)>=0 && VertexAAboveVertexB(3,2,false)>=0 && VertexAAboveVertexB(3,4,false)>=0 && VertexAAboveVertexB(5,4,false)>=0) Result=true; } else if(Wave.Name=="Сходящийся треугольник") { if(VertexAAboveVertexB(1,0,false)>=0 && VertexAAboveVertexB(1,2,false)>=0 && VertexAAboveVertexB(3,2,false)>= 0&& VertexAAboveVertexB(3,4,false)>=0 && VertexAAboveVertexB(5,4,false)>=0 && WaveAMoreWaveB(2,3)>=0 && WaveAMoreWaveB(3,4)>=0 && WaveAMoreWaveB(4,5)>=0) Result=true; } else if(Wave.Name=="Расходящийся треугольник") { if(VertexAAboveVertexB(1,0,false)>=0 && VertexAAboveVertexB(1,2,false)>=0 && VertexAAboveVertexB(3,2,false)>= 0&& VertexAAboveVertexB(3,4,false)>=0 && VertexAAboveVertexB(5,4,false)>=0 && WaveAMoreWaveB(3,2)>=0 && WaveAMoreWaveB(3,2)>=0) Result=true; } return(Result); }
6.11. Функция VertexAAboveVertexB:
//+-------------------------------------------------------------------------------------+ //| Функция VertexAAboveVertexB проверяет, является ли вершина A выше вершины B, | //| передаваемые в качестве параметров данной функции | //| данную проверку можно совершить только если вершина A и B - фиксированные, | //| либо вершина A - нефиксированная и четная, а вершина B - фиксированная, | //| либо вершина A - фиксированная, а вершина B - нефиксированная и нечетная, | //| либо вершина A - нефиксированная и четная, и вершина B - нефиксированная и нечетная | //+-------------------------------------------------------------------------------------+ int VertexAAboveVertexB(int A,int B,bool InternalPoints) { double VA=0,VB=0,VC=0; int IA=0,IB=0; int Result=0; if(A>=B) { IA = A; IB = B; } else if(A<B) { IA = B; IB = A; } // если должны учитываться внутренние точки волны if(InternalPoints==true) { if((Trend=="Up") && ((IA%2==0) || ((IA-IB==1) && (IB%2==0)))) { VA=Minimum[IA]; IA=IA-IA%2; } else if((Trend=="Down") && ((IA%2==0) || ((IA-IB==1) && (IB%2==0)))) { VA=Maximum[IA]; IA=IA-IA%2; } else if((Trend=="Up") && ((IA%2==1) || ((IA-IB==1) && (IB%2==1)))) { VA=Maximum[IA]; IA=IA -(1-IA%2); } else if((Trend=="Down") && (IA%2==1) || ((IA-IB==1) && (IB%2==1))) { VA=Minimum[IA]; IA=IA -(1-IA%2); } VB=ValueVertex[IB]; } else { VA = ValueVertex[IA]; VB = ValueVertex[IB]; } if(A>B) { A = IA; B = IB; } else if(A<B) { A = IB; B = IA; VC = VA; VA = VB; VB = VC; } if(((FixedVertex[A]==1) && (FixedVertex[B]==1)) || ((FixedVertex[A] == 0) &&(A % 2 == 0) && (FixedVertex[B] == 1)) || ((FixedVertex[A] == 1) && (FixedVertex[B] == 0) && (B %2 == 1)) || ((FixedVertex[A] == 0) & (A %2 == 0) && (FixedVertex[B] == 0) && (B % 2== 1))) { if(((Trend=="Up") && (VA>=VB)) || ((Trend=="Down") && (VA<=VB))) Result=1; else Result=-1; } return(Result); }
//+-----------------------------------------------------------------------+ //| Функция WaveAMoreWaveB проверяет, является ли волна A больше волны B, | //| передаваемые в качестве параметров данной функции | //| данную проверку можно совершить только если волна A - завершенная, | //| а волна B - завершенная или незавершенная или неначатая | //+-----------------------------------------------------------------------+ int WaveAMoreWaveB(int A,int B) { int Result=0; double LengthWaveA=0,LengthWaveB=0; if(FixedVertex[A]==1 && FixedVertex[A-1]==1 && (FixedVertex[B]==1 || FixedVertex[B-1]==1)) { LengthWaveA=MathAbs(ValueVertex[A]-ValueVertex[A-1]); if(FixedVertex[B]==1 && FixedVertex[B-1]==1) LengthWaveB=MathAbs(ValueVertex[B]-ValueVertex[B-1]); else if(FixedVertex[B]==1 && FixedVertex[B-1]==0) { if(Trend=="Up") LengthWaveB=MathAbs(ValueVertex[B]-Minimum[B]); else LengthWaveB=MathAbs(ValueVertex[B]-Maximum[B]); } else if(FixedVertex[B]==0 && FixedVertex[B-1]==1) { if(Trend=="Up")LengthWaveB=MathAbs(ValueVertex[B-1]-Minimum[B-1]); else LengthWaveB=MathAbs(ValueVertex[B-1]-Maximum[B-1]); } if(LengthWaveA>LengthWaveB) Result=1; else Result=-1; } return(Result); }
//+------------------------------------------------------------------+ //| Функция очистки дерева волн с верхним узлом Node | //+------------------------------------------------------------------+ void ClearTree(TNode *Node) { if(CheckPointer(Node)!=POINTER_INVALID) { for(int i=0; i<Node.Child.Total();i++) ClearTree(Node.Child.At(i)); delete Node.Child; if(CheckPointer(Node.Wave)!=POINTER_INVALID)delete Node.Wave; delete Node; } }
6.14. Функция ClearNodeInfoArray:
//+------------------------------------------------------------------+ //| Функция очистки массива NodeInfoArray | //+------------------------------------------------------------------+ void ClearNodeInfoArray() { for(int i=NodeInfoArray.Total()-1; i>=0;i--) { TNodeInfo *NodeInfo=NodeInfoArray.At(i); if(CheckPointer(NodeInfo.Node)!=POINTER_INVALID)delete NodeInfo.Node; delete NodeInfo; } NodeInfoArray.Clear(); }
6.15. Функция ClearZigzagArray:
//+------------------------------------------------------------------+ //| Функция очистки массива ZigzagArray | //+------------------------------------------------------------------+ void ClearZigzagArray() { for(int i=0;i<ZigzagArray.Total();i++) { TZigzag *Zigzag=ZigzagArray.At(i); delete Zigzag.IndexVertex; delete Zigzag.ValueVertex; delete Zigzag; } ZigzagArray.Clear(); }
6.16. Функция FillLabelArray:
CArrayObj *LabelArray[]; int LevelMax=0; //+------------------------------------------------------------------+ //| Функция FillLabelArray | //+------------------------------------------------------------------+ void FillLabelArray(TNode *Node) { if(Node.Child.Total()>0) { // выделяем первый узел TNode *ChildNode=Node.Child.At(0); // получаем структуру, в которой хранится информация о волне TWave *Wave=ChildNode.Wave; string Text; // если есть первая вершина if(Wave.ValueVertex[1]>0) { // маркируем вершину в зависимости от волны if(Wave.Name=="Импульс" || Wave.Name=="Клин" || Wave.Name=="Диагональ") Text="1"; else if(Wave.Name=="Зигзаг" || Wave.Name=="Плоскость" || Wave.Name=="Расходящийся треугольник" || Wave.Name=="Сходящийся треугольник") Text="A"; else if(Wave.Name=="Двойной зигзаг" || Wave.Name=="Двойная тройка" || Wave.Name=="Тройной зигзаг" || Wave.Name=="Тройная тройка") Text="W"; // получаем массив вершин ArrayObj, которые имеют индекс Wave.IndexVertex[1] на графике цены CArrayObj *ArrayObj=LabelArray[Wave.IndexVertex[1]]; if(CheckPointer(ArrayObj)==POINTER_INVALID) { ArrayObj=new CArrayObj; LabelArray[Wave.IndexVertex[1]]=ArrayObj; } // записываем информацию о вершине с индексом Wave.IndexVertex[1] в массива ArrayObj TLabel *Label=new TLabel; Label.Text=Text; Label.Level=Wave.Level; if(Wave.Level>LevelMax)LevelMax=Wave.Level; Label.Value=Wave.ValueVertex[1]; ArrayObj.Add(Label); } if(Wave.ValueVertex[2]>0) { if(Wave.Name=="Импульс" || Wave.Name=="Клин" || Wave.Name=="Диагональ") Text="2"; else if(Wave.Name=="Зигзаг" || Wave.Name=="Плоскость" || Wave.Name=="Расходящийся треугольник" || Wave.Name=="Сходящийся треугольник") Text="B"; else if(Wave.Name=="Двойной зигзаг" || Wave.Name=="Двойная тройка" || Wave.Name=="Тройной зигзаг" || Wave.Name=="Тройная тройка") Text="X"; CArrayObj *ArrayObj=LabelArray[Wave.IndexVertex[2]]; if(CheckPointer(ArrayObj)==POINTER_INVALID) { ArrayObj=new CArrayObj; LabelArray[Wave.IndexVertex[2]]=ArrayObj; } TLabel *Label=new TLabel; Label.Text=Text; Label.Level=Wave.Level; if(Wave.Level>LevelMax)LevelMax=Wave.Level; Label.Value=Wave.ValueVertex[2]; ArrayObj.Add(Label); } if(Wave.ValueVertex[3]>0) { if(Wave.Name=="Импульс" || Wave.Name=="Клин" || Wave.Name=="Диагональ") Text="3"; else if(Wave.Name=="Зигзаг" || Wave.Name=="Плоскость" || Wave.Name=="Расходящийся треугольник" || Wave.Name=="Сходящийся треугольник") Text="C"; else if(Wave.Name=="Двойной зигзаг" || Wave.Name=="Двойная тройка" || Wave.Name=="Тройной зигзаг" || Wave.Name=="Тройная тройка") Text="Y"; CArrayObj *ArrayObj=LabelArray[Wave.IndexVertex[3]]; if(CheckPointer(ArrayObj)==POINTER_INVALID) { ArrayObj=new CArrayObj; LabelArray[Wave.IndexVertex[3]]=ArrayObj; } TLabel *Label=new TLabel; Label.Text=Text; Label.Level=Wave.Level; if(Wave.Level>LevelMax)LevelMax=Wave.Level; Label.Value=Wave.ValueVertex[3]; ArrayObj.Add(Label); } if(Wave.ValueVertex[4]>0) { if(Wave.Name=="Импульс" || Wave.Name=="Клин" || Wave.Name=="Диагональ") Text="4"; else if(Wave.Name=="Расходящийся треугольник" || Wave.Name=="Сходящийся треугольник") Text="D"; else if(Wave.Name=="Тройной зигзаг" || Wave.Name=="Тройная тройка") Text="XX"; CArrayObj *ArrayObj=LabelArray[Wave.IndexVertex[4]]; if(CheckPointer(ArrayObj)==POINTER_INVALID) { ArrayObj=new CArrayObj; LabelArray[Wave.IndexVertex[4]]=ArrayObj; } TLabel *Label=new TLabel; Label.Text=Text; Label.Level=Wave.Level; if(Wave.Level>LevelMax)LevelMax=Wave.Level; Label.Value=Wave.ValueVertex[4]; ArrayObj.Add(Label); } if(Wave.ValueVertex[5]>0) { if(Wave.Name=="Импульс" || Wave.Name=="Клин" || Wave.Name=="Диагональ") Text="5"; else if(Wave.Name=="Расходящийся треугольник" || Wave.Name=="Сходящийся треугольник") Text="E"; else if(Wave.Name=="Тройной зигзаг" || Wave.Name=="Тройная тройка") Text="Z"; CArrayObj *ArrayObj=LabelArray[Wave.IndexVertex[5]]; if(CheckPointer(ArrayObj)==POINTER_INVALID) { ArrayObj=new CArrayObj; LabelArray[Wave.IndexVertex[5]]=ArrayObj; } TLabel *Label=new TLabel; Label.Text=Text; Label.Level=Wave.Level; if(Wave.Level>LevelMax)LevelMax=Wave.Level; Label.Value=Wave.ValueVertex[5]; ArrayObj.Add(Label); } // посещаем дочерние узлы текущего узла for(int j=0;j<ChildNode.Child.Total();j++) FillLabelArray(ChildNode.Child.At(j)); } }
6.17. Функция CreateLabels:
double PriceInPixels; CArrayObj ObjTextArray; // объявляем массив, в котором будут храниться графические объекты "Текст" //+------------------------------------------------------------------+ //| Функция CreateLabels | //+------------------------------------------------------------------+ void CreateLabels() { double PriceMax =ChartGetDouble(0,CHART_PRICE_MAX,0); double PriceMin = ChartGetDouble(0,CHART_PRICE_MIN); int WindowHeight=ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS); PriceInPixels=(PriceMax-PriceMin)/WindowHeight; int n=0; // перебираем массив LabelArray for(int i=0;i<ArrayRange(LabelArray,0);i++) { // если имеются вершины с одинаковым индексом i if(CheckPointer(LabelArray[i])!=POINTER_INVALID) { // получаем вершины с одинаковым индексом i CArrayObj *ArrayObj=LabelArray[i]; // перебираем вершины и отображаем на графике for(int j=ArrayObj.Total()-1;j>=0;j--) { TLabel *Label=ArrayObj.At(j); int Level=LevelMax-Label.Level; string Text=Label.Text; double Value=Label.Value; color Color; int Size=8; if((Level/3)%2==0) { if(Text=="1") Text="i"; else if(Text == "2") Text = "ii"; else if(Text == "3") Text = "iii"; else if(Text == "4") Text = "iv"; else if(Text == "5") Text = "v"; else if(Text == "A") Text = "a"; else if(Text == "B") Text = "b"; else if(Text == "C") Text = "c"; else if(Text == "D") Text = "d"; else if(Text == "E") Text = "e"; else if(Text == "W") Text = "w"; else if(Text=="X") Text="x"; else if(Text == "XX") Text = "xx"; else if(Text == "Y") Text = "y"; else if(Text == "Z") Text = "z"; } if(Level%3==2) { Color=Green; Text="["+Text+"]"; } if(Level%3==1) { Color=Blue; Text="("+Text+")"; } if(Level%3==0) Color=Red; int Anchor; if(Value==rates[i].high) { for(int k=ArrayObj.Total()-j-1;k>=0;k--) Value=Value+15*PriceInPixels; Anchor=ANCHOR_UPPER; } else if(Value==rates[i].low) { for(int k=ArrayObj.Total()-j-1;k>=0;k--) Value=Value-15*PriceInPixels; Anchor=ANCHOR_LOWER; } CChartObjectText *ObjText=new CChartObjectText; ObjText.Create(0,"wave"+IntegerToString(n),0,rates[i].time,Value); ObjText.Description(Text); ObjText.Color(Color); ObjText.SetInteger(OBJPROP_ANCHOR,Anchor); ObjText.FontSize(8); ObjText.Selectable(true); ObjTextArray.Add(ObjText); n++; } } } ChartRedraw(); }
6.18. Функция CorrectLabel:
//+------------------------------------------------------------------+ //| Функция CorrectLabel | //+------------------------------------------------------------------+ void CorrectLabel() { double PriceMax=ChartGetDouble(0,CHART_PRICE_MAX,0); double PriceMin = ChartGetDouble(0,CHART_PRICE_MIN); int WindowHeight=ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS); double CurrentPriceInPixels=(PriceMax-PriceMin)/WindowHeight; // перебираем все текстовые объекты (вершины волн) и изменяем их величину цены for(int i=0;i<ObjTextArray.Total();i++) { CChartObjectText *ObjText=ObjTextArray.At(i); double PriceValue=ObjText.Price(0); datetime PriceTime=ObjText.Time(0); int j; for(j=0;j<ArrayRange(rates,0);j++) { if(rates[j].time==PriceTime) break; } double OffsetInPixels; if(rates[j].low>=PriceValue) { OffsetInPixels=(rates[j].low-PriceValue)/PriceInPixels; ObjText.Price(0,rates[j].low-OffsetInPixels*CurrentPriceInPixels); } else if(rates[j].high<=PriceValue) { OffsetInPixels=(PriceValue-rates[j].high)/PriceInPixels; ObjText.Price(0,rates[j].high+OffsetInPixels*CurrentPriceInPixels); } } PriceInPixels=CurrentPriceInPixels; }
7. Функции инициализации, деинициализации и обработки событий
В функции OnInit происходит создание кнопок управления автоматического анализатора волн Эллиотта.
Создаются кнопки:
- "Начать анализ" - происходит автоматический анализ волн,
- "Показать результаты" - происходит вывод меток волн на график,
- "Очистить график" - происходит очистка памяти и удаление меток волн с графика,
- "Скорректировать метки" - происходит корректировка меток волн на графике.
Обработка нажатия на эти кнопки происходит в функции обработки событий OnChartEvent.
В функции OnDeinit удаляются все графические объекты с графика, включая кнопки управления, а также удаляются все объекты, используемые в программе.
#include <Object.mqh> #include <Arrays\List.mqh> #include <Arrays\ArrayObj.mqh> #include <Arrays\ArrayInt.mqh> #include <Arrays\ArrayDouble.mqh> #include <Arrays\ArrayString.mqh> #include <ChartObjects\ChartObjectsTxtControls.mqh> #include <Elliott wave\Data structures.mqh> #include <Elliott wave\Analysis functions.mqh> #include <Elliott wave\Rules functions.mqh> CChartObjectButton *ButtonStart,*ButtonShow,*ButtonClear,*ButtonCorrect; int State; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { State=0; //создаем кнопки управления ButtonStart=new CChartObjectButton; ButtonStart.Create(0,"Начать анализ",0,0,0,150,20); ButtonStart.Description("Начать анализ"); ButtonShow=new CChartObjectButton; ButtonShow.Create(0,"Показать результаты",0,150,0,150,20); ButtonShow.Description("Показать результаты"); ButtonClear=new CChartObjectButton; ButtonClear.Create(0,"Очистить график",0,300,0,150,20); ButtonClear.Description("Очистить график"); ButtonCorrect=new CChartObjectButton; ButtonCorrect.Create(0,"Скорректировать метки",0,450,0,150,20); ButtonCorrect.Description("Скорректировать метки"); ChartRedraw(); return(0); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //очищаем дерево волн ClearTree(FirstNode); //очищаем массив NodeInfoArray ClearNodeInfoArray(); //очищаем массив ZigzagArray ClearZigzagArray(); //очищаем массив LabelArray for(int i=0;i<ArrayRange(LabelArray,0);i++) { CArrayObj *ArrayObj=LabelArray[i]; if(CheckPointer(ArrayObj)!=POINTER_INVALID) { for(int j=0;j<ArrayObj.Total();j++) { TLabel *Label=ArrayObj.At(j); delete Label; } ArrayObj.Clear(); delete ArrayObj; } } //удаляем все графические элементы с графика for(int i=ObjTextArray.Total()-1;i>=0;i--) { CChartObjectText *ObjText=ObjTextArray.At(i); delete ObjText; } ObjTextArray.Clear(); delete ButtonStart; delete ButtonShow; delete ButtonClear; delete ButtonCorrect; ChartRedraw(); } MqlRates rates[]; TNode *FirstNode; //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(id==CHARTEVENT_OBJECT_CLICK && sparam=="Начать анализ" && State!=0) MessageBox("Сначала нажмите кнопку \"Очистить график\""); if(id==CHARTEVENT_OBJECT_CLICK && sparam=="Показать результаты" && State!=1) MessageBox("Сначала нажмите кнопку \"Начать анализ\""); if(id==CHARTEVENT_OBJECT_CLICK && sparam=="Очистить график" && State!=2) MessageBox("Сначала нажмите кнопку \"Показать результаты\""); if(id==CHARTEVENT_OBJECT_CLICK && sparam=="Скорректировать метки" && State!=2) MessageBox("Сначала нажмите кнопку \"Показать результаты\""); //если нажата кнопка "Начать анализ" if(id==CHARTEVENT_OBJECT_CLICK && sparam=="Начать анализ" && State==0) { //заполняем массив rates CopyRates(NULL,0,0,Bars(_Symbol,_Period),rates); //заполняем массив ZigzagArray FillZigzagArray(0,Bars(_Symbol,_Period)-1); //создаем первый узел TWave *Wave=new TWave; Wave.IndexVertex[0] = 0; Wave.IndexVertex[1] = Bars(_Symbol,_Period)-1; Wave.ValueVertex[0] = 0; Wave.ValueVertex[1] = 0; FirstNode=new TNode; FirstNode.Child=new CArrayObj; FirstNode.Wave=Wave; FirstNode.Text="Первый узел"; string NameWaves="Импульс,Клин,Диагональ,Зигзаг,Плоскость,Двойной зигзаг,Тройной зигзаг,Двойная тройка,Тройная тройка,Сходящийся треугольник,Расходящийся треугольник,"; //вызываем функцию поиска неначатых и незавершенных волн NotStartedAndNotFinishedWaves(Wave,1,FirstNode,NameWaves,0); MessageBox("Анализ завершен"); State=1; ButtonStart.State(false); ChartRedraw(); } //если нажата кнопка "Показать результаты" if(id==CHARTEVENT_OBJECT_CLICK && sparam=="Показать результаты" && State==1) { ArrayResize(LabelArray,ArrayRange(rates,0)); //заполняем массив LabelArray FillLabelArray(FirstNode); //показываем маркировку волн на графике CreateLabels(); State=2; ButtonShow.State(false); ChartRedraw(); } //если нажата кнопка "Очистить график" if(id==CHARTEVENT_OBJECT_CLICK && sparam=="Очистить график" && State==2) { //очищаем дерево волн ClearTree(FirstNode); //очищаем массив NodeInfoArray ClearNodeInfoArray(); //очищаем массив ZigzagArray ClearZigzagArray(); //очищаем массив LabelArray for(int i=0;i<ArrayRange(LabelArray,0);i++) { CArrayObj *ArrayObj=LabelArray[i]; if(CheckPointer(ArrayObj)!=POINTER_INVALID) { for(int j=0;j<ArrayObj.Total();j++) { TLabel *Label=ArrayObj.At(j); delete Label; } ArrayObj.Clear(); delete ArrayObj; } } //удаляем разметку с графика for(int i=ObjTextArray.Total()-1;i>=0;i--) { CChartObjectText *ObjText=ObjTextArray.At(i); ObjText.Delete(); } ObjTextArray.Clear(); State=0; ButtonClear.State(false); ChartRedraw(); } if(id==CHARTEVENT_OBJECT_CLICK && sparam=="Скорректировать метки" && State==2) { CorrectLabel(); ButtonCorrect.State(false); ChartRedraw(); } }
На этом мы рассмотрели все функции автоматического анализатора волн Эллиотта.
8. Пути совершенствования программы
Написанная на MQL5 программа автоматической разметки волн Эллиотта обладает рядом недостатков:
- Несовершенная система проверки правил разметки. Так например, при проверке на правила не учитываются соотношения Фибоначчи между волнами, как временные, так и ценовые.
- Наличие неразмеченных областей на графике (пробелов в разметке). Это значит, что по найденным точкам на заданном временном интервале невозможно построить правильную волну. Выходом из данной ситуации является увеличение количества точек для определения какой-либо волны. Например, для нахождения импульса искать не 6, а 8 точек или более.
- По результатам разметки не выводится какая-либо дополнительная информация, например, автоматически не строятся каналы, не вычисляются цели и др.
- Реализация работы с деревом волн в статье не предусмотрена (нельзя выбрать конкретный вариант разметки), поэтому на график выводится только один из множества вариантов разметки (самый первый вариант разметки).
- Вне зависимости от того, что на график выводится только один вариант волн, все остальные варианты находятся в памяти и занимают ее.
- Программа ориентирована на разметку графиков от месячных до дневных, т.к. наблюдается очень медленная работа при большом количестве баров (могут уйти часы для разметки часового графика). Пример разметки месячного графика EURUSD приведен на рисунке 18.
Заключение
В данной статье был рассмотрен алгоритм автоматического анализа волн Эллиотта. Данный алгоритм был реализован на языке MQL5.
Программа обладает рядом недостатков, рассмотренных выше, и дает повод для их дальнейшего устранения. Надеюсь, что данная тема заинтересует поклонников волн Эллиотта, и в скором времени появится много программ, делающих автоматический анализ волн.





- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Перестал работать:
Пишет предупреждение о рекомпиляции. В компиле ошибка мне неизвестная. Посмотрите пожалуйста знающие участники. Спасибо.
Журнал: 2016.07.28 11:27:17.858 MQL5 'Elliott wave.ex5' version is too old, it should be recompiled
При компиле: 'NodeInfo' - conversion is not accessible because of inheritance access Elliott wave.mq5 658 22
Добрый день!
Почему-то не могу скомпилировать.
Спасибо за огромную проделанную работу. Я хочу, чтобы данный алгоритм можно было использовать везде, поэтому сейчас переписываю его на Golang. У меня возник вопрос:
В функции WaveRules на этапе проверки "Расходящихся треугольников" есть следующая строка:
Очевидно, что здесь есть ошибка, т.к. я не могу представить ситуации, когда одно и то же надо проверять 2 раза подряд. Что хотел сказать автор второй проверкой WaveAMoreWaveB(3,2)?
Возможно, нужно сделать проверку лишь один раз, а возможно, во второй проверке нужно будет подставить какие-то другие числа?
Заранее благодарю за ответ.
Ещё прошу заметить, что в функции WaveRules массивы High и Low ни разу не использовались. Скорее всего, они не нужны. Скажите, если я не прав.