Размер
Использование фильтра Калмана в прогнозе направления цены
Play

Использование фильтра Калмана в прогнозе направления цены

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

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

1. Принцип работы фильтра Калмана

Итак, что же такое фильтр Калмана и почему нам стоит обратить на него внимание? Википедия дает такое определение фильтра:

Фильтр Калмана — эффективный рекурсивный фильтр, оценивающий вектор состояния динамической системы, используя ряд неполных и зашумленных измерений.

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

Работа фильтра разделена на два этапа:

  1. Экстраполяция (предсказание)
  2. Корректировка
1.1. Экстраполяция — предсказание значений системы

В основе первого этапа работы фильтра лежит некая модель анализируемого процесса. По ней строится предсказание состояния системы на один шаг вперед.

  • x k — экстраполированное значение динамической системы на k-том шаге,
  • F k — матрица модели зависимости текущего состояния системы от предыдущего,
  • x^ k-1 — предыдущее состояние системы (значение фильтра на предыдущем шаге),
  • B k — матрица влияния управляющего воздействия на систему,
  • u k — управляющее воздействие на систему.

Под управляющим воздействием можно воспринимать, например, новостной фактор. Но на практике, как правило, управляющее воздействие неизвестно и упускается, а его воздействие относится к шумам.

Затем предсказывается ошибка ковариации системы:

  • P k — экстраполированная ковариационная матрица вектора состояния нашей динамической системы,
  • F k — матрица модели зависимости текущего состояния системы от предыдущего,
  • P^ k-1 — скорректированная на предыдущем шаге ковариационная матрица вектора состояния,
  • Q k — ковариационная матрица шума процесса.
1.2. Корректировка значений системы

Второй этап работы фильтра начинается с измерения фактического состояния системы z k . Здесь фактически измеренное значение состояние системы указывается с учетом действительного состояния системы и погрешности измерений. В нашем случае под погрешностью измерений имеются в виду воздействия шумов на динамическую систему.

К настоящему моменту в нашем распоряжении есть две разные величины, которые представляют состояние одного динамического процесса. Это экстраполированное значение динамической системы, которое мы рассчитали на первом этапе, и фактически измеренное значение. Каждая из этих величин с определенной долей вероятности характеризует истинное состояние нашего процесса, которое, таким образом, находится где-то между ними двумя. Следовательно, наша цель — определить, в какой степени мы доверяем тому или иному значению. Для этого и проводятся итерации второго этапа фильтра Калмана.

Исходя из имеющихся данных, определяем отклонение фактического состояния системы от экстраполированного значения.

  • y k — отклонение фактического состояния системы на k-том шаге от экстраполированного,
  • z k — фактическое состояние системы на k-том шаге,
  • H k — матрица измерений, которая отображает зависимость фактического состояния системы от рассчитанных данных (на практике часто принимает единичное значение),
  • x k — экстраполированное значение динамической системы на k-том шаге.

Следующим шагом рассчитывается ковариационная матрица для вектора ошибки:

  • S k — ковариационная матрица вектора ошибки на k-том шаге,
  • H k — матрица измерений, которая отображает зависимость фактического состояния системы от рассчитанных данных,
  • P k — экстраполированная ковариационная матрица вектора состояния нашей динамической системы,
  • R k — ковариационная матрица шума измерений.

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

  • K k — матрица коэффициентов усиления Калмана,
  • P k — экстраполированная ковариационная матрица вектора состояния нашей динамической системы,
  • H k — матрица измерений, которая отображает зависимость фактического состояния системы от рассчитанных данных,
  • S k — ковариационная матрица вектора ошибки на k-том шаге.

Теперь по уже полученным коэффициентам Калмана корректируем значение состояния нашей системы и ковариационную матрицу оценки вектора состояния.

  • x^ k и x^ k-1 — скорректированные значения на k-том и k-1 шаге,
  • K k — матрица коэффициентов усиления Калмана,
  • y k — отклонение фактического состояния системы на k-том шаге от экстраполированного.
  • P^ k — скорректированная ковариационная матрица вектора состояния нашей динамической системы,
  • I — матрица идентичности,
  • K k — матрица коэффициентов усиления Калмана,
  • H k — матрица измерений, которая отображает зависимость фактического состояния системы от рассчитанных данных,
  • P k — экстраполированная ковариационная матрица вектора состояния нашей динамической системы.

Обобщить все вышесказанное можно нижеприведенной схемой

2. Практическая реализация фильтра Калмана

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

2.1. Инициализация исходных данных

Прежде чем начать писать код, определимся с исходными данными.

Как уже говорилось выше, в основе фильтра Калмана — модель динамического процесса, по которой предсказывается следующее состояние этого процесса. Изначально этот фильтр был предложен для работы с линейными системами, в которых текущее состояние системы легко задается через коэффициент к предыдущему. Нам сложнее: мы имеем дело с не линейной динамической системой, где коэффициент изменяется пошагово. Более того, у нас нет ни малейшего представления о зависимости между двумя соседними состояниями системы. Задача, казалось бы, неразрешимая. Но давайте немного схитрим и воспользуемся авторегрессионными моделями, о которых уже рассказывалось в статьях [1],[2],[3].

Итак, начнем. Для начала объявим класс CKalman, а в нем — необходимые переменные

В функции инициализации класса присвоим начальные значения переменным.

Для построения авторегрессионной модели я воспользовался алгоритмом из статьи [1]. Для этого добавим в класс две private функции.

Функция LevinsonRecursion перенесена без изменений, а функцию Autoregression я слегка модифицировал, поэтому давайте рассмотрим ее подробней. В начале функции мы проверяем наличие необходимой для анализа истории, и если ее недостаточно, возвращается false.

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

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

Сумму полученных коэффициентов авторегрессии приводим к "1" и устанавливаем флаг проведенного расчета в состояние true.

Далее инициализируем необходимые для фильтра переменные. В качестве ковариации шума измерений возьмем среднеквадратичное отклонений значений close за анализируемый период.

Для определения значения ковариации шума процесса сначала рассчитаем массив значений авторегрессионной модели и возьмем среднеквадратичное отклонение значений модели.

Фактические коэффициенты зависимости текущего состояния системы от предыдущего скопируем в массив cda_F, чтобы потом использовать их при расчете новых коэффициентов.

Для начального значения нашей системы возьмем среднее арифметическое из 10 последних значений.

2.2. Предсказание движения цены

После того, как мы получили все исходные данные для работы фильтра, можно приступить к его практической реализации. Первый этап работы фильтра Калмана, как уже упоминалось выше, — экстраполяция состояния системы на один шаг вперед. Создадим public функцию Forecast, в которой будут реализованы функции 1.1. и 1.2.

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

Затем рассчитываем коэффициент зависимости текущего состояния системы от предыдущего и сохраняем его в "0" ячейку массива cda_F, значения которого предварительно сдвигаем на одну ячейку.

После этого пересчитываем состояние системы и вероятность ошибки.

В конце функция возвращает прогнозное состояние системы. В нашем случае это прогнозируемая цена закрытия нового бара.

2.3. Корректировка состояния системы

На следующем этапе, после получения фактического значения закрытия бара, проведем корректировку состояния системы. Для этого создадим public функцию Correction. В ее параметрах будем передавать фактически полученное значение состояния системы, т.е. цену закрытия последнего бара.

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

3. Демонстрация работы фильтра Калмана на практике

Испытаем работу нашего класса по фильтру Калмана на практике. Для этого на базе класса создадим небольшой индикатор. На открытии новой свечи он будет вызывать функцию корректировки состояния системы, а затем — функцию предсказания для прогноза цены закрытия текущего бара. Не пугайтесь перестановки вызова функций класса, ведь мы будем вызывать функцию корректировки состояния для предыдущего (закрытого) бара и прогноз цены закрытия для текущего (только что открытого бара), цена закрытия которого нам неизвестна.

В индикаторе будут 2 буфера. В первый будут выводиться прогнозные значения состояния системы, во второй — скорректированные. Я намеренно создал два буфера, чтобы индикатор не перерисовывался и можно было увидеть масштабы корректировки системы на втором этапе работы фильтра. Код индикатора несложный, он приведен во вложении. Здесь же я приведу результаты его работы.

На представленном графике отображаются три ломаные линии:

  • Черная — фактическая цена закрытия баров;
  • Красная — прогнозная цена закрытия;
  • Синяя — скорректированное фильтром Калмана состояние системы.

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

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

4. Создаем модуль торговых сигналов для генератора экспертов MQL5

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

Для тестирования этой стратегии создадим модуль торговых сигналов для генератора экспертов MQL5. О методике создания модулей торговых сигналов уже не раз рассказывалось в статьях на этом сайте [1], [4], [5]. Я же вкратце расскажу о моментах, касающихся нашей стратегии.

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

В функции инициализации класса присвоим значения по умолчанию переменным и инициализируем класс фильтра Калмана.

Вычислять состояния системы фильтром будем в private функции CalculateIndicators. В начале функции мы проверим, не рассчитывались ли значения фильтра на текущем баре. В случае, если значения уже пересчитаны, выходим из функции.

Затем проверяем последнее состояние системы. Если оно не определено, сбрасываем флаг расчета авторегрессионной модели в классе CKalman, чтобы при последующем обращении к классу модель была пересчитана заново.

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

Затем пересчитываем значения состояния системы для всех непросчитанных баров.

После пересчета проверяем состояние системы и сохраняем время последнего вызова функции. В случае успешного завершения операций функция возвращает true.

Функции принятия решений (LongCondition и ShortCondition) имеют полностью идентичную структуру с зеркальным условием открытия сделки. Код функций рассмотрим на примере функции ShortCondition.

Сначала запускаем функцию пересчета значений фильтра. В случае неудачи пересчета значений фильтра выходим из функции и возвращаем 0.

При удачном пересчете значений фильтра сравниваем предсказанную и скорректированную величины. Если предсказанная величина больше скорректированной, то функция возвращает весовое значение. В противном случае возвращается "0".

Модуль построен по принципу "перевертыша", поэтому мы в нем не прописываем функции закрытия позиций.

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

5. Тестирование советника

Подробное описание создания советника с использованием модуля торговых сигналов описано в статье [1], этот шаг пропустим. Отмечу только, что для тестирования качества сигналов советник был создан только на одном, выше созданном торговом модуле со статическим лотом и без использования трейлинг-стопа.

Тестирование советника проводилось на исторических данных за август 2017 года по EURUSD на таймфрейме Н1. Для расчета авторегрессионной модели использовались исторические данные на 3000 барах, что составляет почти 6 месяцев. Тестирование проводилось без установки стоп-лоссов и тейк-профитов, что позволило увидеть влияние только сигналов фильтра Калмана на торговлю.

Результаты тестирования показали 49.33% прибыльных сделок. При этом прибыль максимальной и средней прибыльной сделки превышает соответствующие показатели убыточных сделок. В целом это дало прибыль за тестируемый период, профит-фактор составил 1.56. Скриншоты тестирования приведены ниже.

При детальном рассмотрении сделок на ценовом графике обращают на себя внимание 2 узких места этой тактики:

  • серии неудачных сделок во флэтовых движениях;
  • поздний выход из открытой позиции.

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

Заключение

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

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

📎📎📎📎📎📎📎📎📎📎