Skip to content

Latest commit

 

History

History
71 lines (47 loc) · 10.6 KB

File metadata and controls

71 lines (47 loc) · 10.6 KB

Алгоритм распознавания волн Эллиотта (EWMarkup v1)

Общая концепция

EWMarkup v1 — это алгоритм точного (exact) распознавания структур волн Эллиотта на основе ценовых экстремумов (зигзага). В его основе лежит подход динамического программирования (Dynamic Programming) «снизу-вверх» (bottom-up), который концептуально схож с алгоритмом Кока-Янгера-Касами (CYK) для синтаксического анализа формальных грамматик.

Алгоритм принимает на вход последовательность чередующихся ценовых точек (например, собранных с помощью SimpleExtremumFinder) и строит из них дерево вложенных волновых моделей. Главная задача алгоритма — найти такую комбинацию моделей (Импульсы, Зигзаги, Треугольники и т.д.), которая максимально соответствует правилам волновой теории и имеет наивысшую оценку (Score).


1. Входные данные и инициализация состояния

  • Вход: Список экстремумов List<BarPoint> points длины $N+1$, что дает $N$ базовых сегментов (отрезков между двумя соседними экстремумами).
  • Состояние (DP Матрица): Алгоритм использует двумерную матрицу dp[i, j], где каждая ячейка хранит список гипотез (объектов ExactParsedNode), представляющих возможные волновые структуры, начинающиеся в точке i и заканчивающиеся в точке j.
  • Инициализация (длина 1): На первом шаге каждый отдельный сегмент от точки $i$ до $i+1$ (диагональ dp[i, i]) объявляется базовой моноволной (с типом SIMPLE_IMPULSE, счетом Score = 1.0 и длиной 1 волна). Эта моноволна затем «продвигается» (Promote) для участия в формировании более крупных структур.

2. Основной цикл (Сборка "Снизу-Вверх")

Алгоритм итеративно увеличивает длину рассматриваемого участка графика $L$ от 2 до $N$.

Для каждого отрезка $[i, j]$ длины $L$ алгоритм перебирает все возможные точки разбиения $M$ ($i \le M &lt; j$). Затем он берет левую часть dp[i, M] (узлы p) и правую часть dp[M+1, j] (узлы c) и пытается присоединить правую часть как новую подволну к незавершенной левой части.

Проверки при объединении (Комбинаторика)

Прежде чем объединить p и c в новую структуру, проводится ряд жестких проверок:

  1. Проверка незавершенности: Узел p должен нуждаться в новых подволнах (p.WaveCount < p.ExpectedWaves), а узел c должен быть полностью завершенной самостоятельной моделью.
  2. Чередование направлений: Соседние подволны обязаны иметь противоположные направления (lastWave.IsUp != c.IsUp).
  3. Грамматика Эллиотта (Model Compatibility): Функция IsAllowed проверяет, может ли модель узла c выступать в роли $K$-й волны для модели узла p (согласно правилам в ElliottWavePatternHelper). Например, 2-я волна Импульса не может быть Импульсом, она должна быть коррекционной структурой (Зигзаг, Флэт и т.д.).
  4. Геометрические правила (Constraints): В CheckWaveConstraints и CheckFinalConstraints проверяются нерушимые правила волновой теории (hard rules).
    • Пример для Импульса: Волна 2 не перекрывает начало Волны 1. Волна 3 не может быть самой короткой. Волна 4 не заходит на территорию Волны 1 (с учетом исключений для диагоналей).

3. Оптимизация памяти и агрессивное отсечение (Fast Pruning)

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

  • Для каждой ячейки dp[i, j] отслеживается минимальный порог выживания minScore[i, j].
  • Predictive Scoring (Предиктивная оценка): Вместо того чтобы создавать тяжелый объект ExactParsedNode при каждом удачном совпадении правил, алгоритм до создания объекта вычисляет ожидаемый балл (predictedScore) новой комбинации.
  • Если в ячейке уже накоплено максимум допустимых гипотез (500) и predictedScore <= minScore, алгоритм мгновенно пропускает итерацию, экономя память и CPU.
  • Периодическая чистка: Как только размер корзины превышает лимит (например, > 1000 элементов), список принудительно сортируется по Score и урезается до 500 лучших, а minScore обновляется.

4. Оценка гипотез (Scoring System)

Балл (Score) узла вычисляется функцией CalculateScore и является главным критерием выбора "лучшей" разметки. Он состоит из нескольких множителей:

  1. Probability Coefficient (Вес модели): Базовая вероятность модели. Например, Импульсы (IMPULSE) получают значительный множитель (x5.0), чтобы алгоритм отдавал предпочтение чистым трендовым движениям, а не сложным вложенным коррекциям.
  2. Геометрическое среднее подволн: Оценки всех входящих в модель подволн перемножаются, и берется корень степени их количества.
  3. Fibonacci Scoring (Фибоначчи соотношения): Оцениваются длины подволн относительно друг друга.
    • Применяются карты Фибоначчи (GetFiboWeight). Например, 2-я волна импульса соотносится к 1-й, 3-я к 1-й, и т.д.
    • В зависимости от соотношения (0.382, 0.618, 1.618), начисляется повышающий коэффициент, если соотношение идеально, и нейтральный (1.0), если нет.
  4. Чередование (Alternation): Для Импульсов проверяется правило чередования коррекций (волна 2 и волна 4). Если одна из них глубокая (Deep), а вторая мелкая (Shallow), балл дополнительно умножается на 1.2.
  5. Штраф за незавершенность: Если модель еще не достроена (например, сформированы только 3 волны Импульса из 5), её итоговый счет понижается Math.Pow(0.6, missingWaves), чтобы полностью готовые модели имели приоритет перед фрагментарными (при прочих равных).

5. Промоушен (Promotion)

Как только узел p набирает нужное количество подволн (например, 5 для Импульса или 3 для Зигзага), он считается «полным». Вызывается функция Promote:

  1. Проверяется, что общее (net) направление движения цены от старта до конца модели совпадает с флагом IsUp этой модели. Волны не могут двигаться против своего макро-тренда.
  2. Полный узел добавляется в ячейку dp[Start, End] как единая волна 1-го порядка. Теперь на следующих итерациях длины $L$ эта крупная структура может выступать как подволна (например, Волна 1) для еще более старшей модели (супер-структуры).

6. Результат

В конце работы алгоритма ячейка dp[0, N-1] (охватывающая весь график от первой до последней точки) содержит список всех возможных разметок. Алгоритм сортирует их по убыванию Score и возвращает верхние. В индикаторах обычно берется самый первый вариант (OrderByDescending(x => x.Score).First()), который конвертируется в плоский список точек и связей для отрисовки графики (MarkupResult). Для незавершенных моделей (последняя текущая волна) строятся пунктирные проекции будущих целей на основе Fibo-зон.