English
preview
Фильтр Калмана для возвратных стратегий на рынке Форекс

Фильтр Калмана для возвратных стратегий на рынке Форекс

MetaTrader 5Примеры | 21 мая 2025, 10:53
448 4
Zhuo Kai Chen
Zhuo Kai Chen

Введение

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



Фильтр Калмана

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

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

Некоторые распространенные способы использования фильтра Калмана в алготрейдинге:

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

Формула расчета значения фильтра Калмана выглядит следующим образом:

Формула Калмана

Для объяснения сложной формулы простым способом обратимся к наглядному примеру.

Визуализация Калмана

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

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

  2. Уточнение: когда появляются новые ценовые данные (измеренные цены), фильтр Калмана сравнивает их с прогнозируемой ценой. Затем он вычисляет так называемый калмановский коэффициент усиления (Kalman Gain, фиолетовая линия), чтобы решить, какой вес придать новому измерению по отношению к прогнозу. Если измерение очень зашумлено, фильтр больше доверяет своему прогнозу. 

  3. Оценка: фильтр обновляет прогнозируемую цену, вводя новое измерение. Обновленная цена (она показана синей Зоной оценки) имеет меньшую неопределенность по сравнению с прогнозом. Зона сужается по мере того, как фильтр уточняет оценку. 

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

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

Вот несколько примеров влияния дисперсии на сглаженность кривой:

различия в сглаженности

В целом, дисперсия процесса (Q) представляет, насколько сильно модель ожидает, что с течением времени истинное состояние изменится, а дисперсия измерения (R) отражает уверенность в наблюдаемых данных. Более высокое значение Q делает фильтр более восприимчивым к внезапным изменениям, но повышает волатильность. Более высокое значение R сглаживает прогнозы, больше доверяя прошлым оценкам, за счет отложенных корректировок. Низкое значение Q и среднее значение R производят стабильные прогнозы, а высокое значение Q и низкое значение R повышают не только реактивность фильтра, но и его зашумленность.


Программирование стратегии

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

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

  • Покупайте, когда последняя цена закрытия будет ниже нижней полосы.
  • Продавайте, когда последняя цена закрытия будет выше верхней полосы.
  • Закрывайте позицию, как только цена пересечет среднюю полосу.
  • Торгуйте только одной позицией за раз во избежание чрезмерного расширения объема торговли.
  • Установите стоп-лосс на расстоянии 1% от цены, чтобы избежать риска «тяжелого» хвоста (fat tail risk), характерного для возвратных стратегий.

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

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

#include <Trade/Trade.mqh>
CTrade trade;
//+------------------------------------------------------------------+
//| Buy Function                                                     |
//+------------------------------------------------------------------+
void executeBuy(string symbol) {
       double ask = SymbolInfoDouble(symbol, SYMBOL_ASK);
       double lots=0.01;
       double sl = ask*(1-0.01);
       trade.Buy(lots,symbol,ask,sl);
}

//+------------------------------------------------------------------+
//| Sell Function                                                    |
//+------------------------------------------------------------------+
void executeSell(string symbol) {      
       double bid = SymbolInfoDouble(symbol, SYMBOL_BID);
       double lots=0.01;
       double sl = bid*(1+0.01);
       trade.Sell(lots,symbol,bid,sl);     
}

Затем инициализируем глобальные переменные и инициализатор здесь. Это инициализирует магическое число для советника, а также дескриптор полос Боллинджера, которые мы используем позднее.

input int Magic = 0;
input int bbPeriod = 100;
input double d = 2.0;

int barsTotal = 0;
int handleMa;

//+------------------------------------------------------------------+
//| Initialization                                                   |
//+------------------------------------------------------------------+
int OnInit()
{   handleBb = iBands(_Symbol,PERIOD_CURRENT,bbPeriod,0,d,PRICE_CLOSE);  
    trade.SetExpertMagicNumber(Magic);
    return INIT_SUCCEEDED;
}

Наконец, в фнукции OnTick() используем его для обеспечения обработки торговой логики на каждом баре, а не на каждом тике:

int bars = iBars(_Symbol,PERIOD_CURRENT);
  
if (barsTotal!= bars){
   barsTotal = bars;

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

double bbLower[], bbUpper[], bbMiddle[];
CopyBuffer(handleBb,UPPER_BAND,1,1,bbUpper);
CopyBuffer(handleBb,LOWER_BAND,1,1,bbLower);
CopyBuffer(handleBb,0,1,1,bbMiddle);

Такая проверка перебирает все текущие открытые позиции на торговом счете, чтобы узнать, открыл ли позицию данный конкретный советник. Если уже есть позиция, открытая этим советником, устанавливаем значение переменной NotInPosition на false. Каждую открытую позицию, которая вернулась к средней полосе, закрываем.

bool NotInPosition = true;
for(int i = 0; i<PositionsTotal(); i++){
    ulong pos = PositionGetTicket(i);
    string symboll = PositionGetSymbol(i);
    if(PositionGetInteger(POSITION_MAGIC) == Magic&&symboll== _Symbol){
       NotInPosition = false;
       if((PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY&&price>bbMiddle[0])
       ||(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL&&price<bbMiddle[0]))trade.PositionClose(pos);  
  }
}  

Окончательная торговая логика будет реализована следующим образом:

if(price<bbLower[0]&&NotInPosition) executeBuy(_Symbol);
if(price>bbUpper[0]&&NotInPosition) executeSell(_Symbol);

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

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

пример сделки

Затем вернемся в MetaEditor и запрограммируем фильтры режимов.

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

int handleMa;
handleMa = iMA(_Symbol,PERIOD_CURRENT,maPeriod,0,MODE_EMA,PRICE_CLOSE);
 
double ma[];
CopyBuffer(handleMa,0,1,1,ma);
    
if(price<bbLower[0]&&price>ma[0]&&NotInPosition) executeBuy(_Symbol);
if(price>bbUpper[0]&&price<ma[0]&&NotInPosition) executeSell(_Symbol);

 После этого запрограммируем функцию для получения значения фильтра Калмана:

//+------------------------------------------------------------------+
//| Kalman Filter Function                                           |
//+------------------------------------------------------------------+
double KalmanFilter(double price,double measurement_variance,double process_variance)
{
    // Prediction step (state does not change)
    double predicted_state = prev_state;
    double predicted_covariance = prev_covariance + process_variance;

    // Kalman gain calculation
    double kalman_gain = predicted_covariance / (predicted_covariance + measurement_variance);

    // Update step (incorporate new price observation)
    double updated_state = predicted_state + kalman_gain * (price - predicted_state);
    double updated_covariance = (1 - kalman_gain) * predicted_covariance;

    // Store updated values for next iteration
    prev_state = updated_state;
    prev_covariance = updated_covariance;

    return updated_state;
}

Функция следует рекурсивной процедуре в соответствии с этой схемой:

схема процедуры

Для реализации режимного фильтра Калмана в советнике добавим эти строки к функции OnTick():

double kalman = KalmanFilter(price,mv,pv);
if(price<bbLower[0]&&price>kalman&&NotInPosition) executeBuy(_Symbol);
if(price>bbUpper[0]&&price<kalman&&NotInPosition) executeSell(_Symbol);

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

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

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

#include <Trade/Trade.mqh>
CTrade trade;

input double mv = 10;
input double pv = 1.0;
input int Magic = 0;
input int bbPeriod = 100;
input double d = 2.0;
input int maPeriod = 500;

double prev_state;       // Previous estimated price
double prev_covariance = 1;  // Previous covariance (uncertainty)
int barsTotal = 0;
int handleMa;
int handleBb;

//+------------------------------------------------------------------+
//| Initialization                                                   |
//+------------------------------------------------------------------+
int OnInit()
{   handleMa = iMA(_Symbol,PERIOD_CURRENT,maPeriod,0,MODE_EMA,PRICE_CLOSE);
    handleBb = iBands(_Symbol,PERIOD_CURRENT,bbPeriod,0,d,PRICE_CLOSE);
    prev_state = iClose(_Symbol,PERIOD_CURRENT,1);  
    trade.SetExpertMagicNumber(Magic);
    return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Deinitializer function                                           |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }

//+------------------------------------------------------------------+
//| OnTick Function                                                  |
//+------------------------------------------------------------------+
void OnTick()
{
  int bars = iBars(_Symbol,PERIOD_CURRENT);
  
  if (barsTotal!= bars){
     barsTotal = bars;
     bool NotInPosition = true;
     double price = iClose(_Symbol,PERIOD_CURRENT,1); 
     double bbLower[], bbUpper[], bbMiddle[];
     double ma[];
     double kalman = KalmanFilter(price,mv,pv);
     
     CopyBuffer(handleMa,0,1,1,ma);
     CopyBuffer(handleBb,UPPER_BAND,1,1,bbUpper);
     CopyBuffer(handleBb,LOWER_BAND,1,1,bbLower);
     CopyBuffer(handleBb,0,1,1,bbMiddle);
     
     for(int i = 0; i<PositionsTotal(); i++){
         ulong pos = PositionGetTicket(i);
         string symboll = PositionGetSymbol(i);
         if(PositionGetInteger(POSITION_MAGIC) == Magic&&symboll== _Symbol){
            NotInPosition = false;
            if((PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY&&price>bbMiddle[0])
            ||(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL&&price<bbMiddle[0]))trade.PositionClose(pos);  
      }
    }  
    
     if(price<bbLower[0]&&price>kalman&&NotInPosition) executeBuy(_Symbol);
     if(price>bbUpper[0]&&price<kalman&&NotInPosition) executeSell(_Symbol);
    }
}

//+------------------------------------------------------------------+
//| Kalman Filter Function                                           |
//+------------------------------------------------------------------+
double KalmanFilter(double price,double measurement_variance,double process_variance)
{
    // Prediction step (state does not change)
    double predicted_state = prev_state;
    double predicted_covariance = prev_covariance + process_variance;

    // Kalman gain calculation
    double kalman_gain = predicted_covariance / (predicted_covariance + measurement_variance);

    // Update step (incorporate new price observation)
    double updated_state = predicted_state + kalman_gain * (price - predicted_state);
    double updated_covariance = (1 - kalman_gain) * predicted_covariance;

    // Store updated values for next iteration
    prev_state = updated_state;
    prev_covariance = updated_covariance;

    return updated_state;
}

//+------------------------------------------------------------------+
//| Buy Function                                                     |
//+------------------------------------------------------------------+
void executeBuy(string symbol) {
       double ask = SymbolInfoDouble(symbol, SYMBOL_ASK);
       double lots=0.01;
       double sl = ask*(1-0.01);
       trade.Buy(lots,symbol,ask,sl);
}

//+------------------------------------------------------------------+
//| Sell Function                                                    |
//+------------------------------------------------------------------+
void executeSell(string symbol) {      
       double bid = SymbolInfoDouble(symbol, SYMBOL_BID);
       double lots=0.01;
       double sl = bid*(1+0.01);
       trade.Sell(lots,symbol,bid,sl);     
} 

Для изменения режимного фильтра просто скорректируйте окончательные критерии покупки/продажи.


Статистический анализ

Скомпилируйте советник и перейдите в терминал MetaTrader 5, в левом верхнем углу нажмите Вид->Символы->Форекс и выберите «Показать символ» для всех основных и второстепенных пар. Это добавит их в ваш список наблюдения за рынком (Market Watch) для последующего отслеживания.

показать символ

Затем переходим в Сканер рынка в разделе «Тестер стратегий» и тестируем стратегию на исторических данных за последние 3 года. Это поможет нам получить представление о том, повышают ли режимные фильтры прибыльность большинства валютных пар, которыми мы можем торговать.

настройка сканера рынка

Параметры

Конечно, количество отфильтрованных сделок зависит от параметров индикаторов. В этом исследовании мы используем общепринятые значения параметров, которые фильтруют аналогичное количество сделок: 500-периодная экспоненциальная скользящая средняя, дисперсия измерения 10 и дисперсия процесса 1 для фильтра Калмана. Читателям предлагается самостоятельно выполнить тонкую настройку этих параметров для получения наиболее эффективных результатов.

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

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

базовая производительность

распределение основного уровня

Мы видим, что в среднем стратегия выполняет более 800 сделок за последние 3 года для каждой пары, что обеспечивает достаточное количество выборок для того, чтобы считать выводы универсальными. Распределение преимущественно разбросано вокруг профит-фактора 0.8–1.1, что является приличным показателем, но ни одна пара не превышает профит-фактор 1.1 или коэффициент Шарпа 1. В целом, эта стратегия в общем виде работает на многих валютных парах, но прибыльность не особенно впечатляет. Помните об этом, поскольку мы сравниваем ее с эффективностью при использовании фильтров.

Затем проведем тестирование стратегии на исторических данных с использованием фильтра скользящей средней. Вот пример результата:

производительность скользящих средних

распределение скользящих средних

Мы видим, что с помощью фильтра скользящих средних мы отфильтровали около 70% исходных сделок, оставив для каждой пары примерно 250 сделок. Кроме того, качество отфильтрованных сделок в среднем выше по сравнению с базовым уровнем. Профит-фактор большинства валютных пар находится между 0.9 и 1.2, при этом наиболее эффективная пара имеет профит-фактор 1.33 и коэффициент Шарпа 2.34. Это говорит о том, что использование скользящей средней в качестве фильтра в целом повысило прибыльность этой классической возвратной стратегии.

Теперь рассмотрим «непримеченного слона»: как стратегия работает с фильтром Калмана.

производительность Калмана

распределение Калмана

Фильтр Калмана отфильтровал около 60% исходных сделок, оставив для каждой пары около 350 сделок. Из распределения видим, что большинство профит-факторов остаются в диапазоне от 0.85 до 1.2, что аналогично производительности скользящей средней и лучше базовых показателей. Более того, учитывая общее количество валютных пар с профит-фактором 1.0 и выше и 1.2 и выше, можем сделать вывод, что как скользящая средняя, так и фильтр Калмана похожи с точки зрения повышения среднего качества сделки для этой стратегии. В этом сценарии фильтр Калмана не превосходит скользящую среднюю. Это говорит о том, что сложность не всегда приводит к более высокой производительности.

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

Для сравнения выберем валютную пару AUDUSD, поскольку она показала наилучшие результаты по обоим вышеупомянутым условиям.

Результат тестирования базовой линии на исторических данных:

базовая кривая капитала

базовый результат

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

кривая капитала скользящей средней

результат скользящей средней

Результат фильтра Калмана:

кривая капитала Калмана

результат Калмана

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

отчет в Excel

Для каждого отчета отмечаем номер строки знака «Сделки»:

найти строку

Затем перейдем в Python или Jupyter Notebook. Копируем и вставляем следующий код, меняем номер skiprow на номер строки «Сделки» каждого отчета в Excel, и все готово.

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib_venn import venn3
df1 = pd.read_excel("baseline.xlsx", skiprows=1805)
df2 = pd.read_excel("ma.xlsx", skiprows =563 )
df3 = pd.read_excel("kalman.xlsx",skiprows = 751)
df1 = df1[['Time']][1:-1]
df1 = df1[df1.index % 2 == 0]  # Filter for rows with odd indices
df2 = df2[['Time']][1:-1]
df2 = df2[df2.index % 2 == 0]
df3 = df3[['Time']][1:-1]
df3 = df3[df3.index % 2 == 0]

# Convert "Time" columns to datetime
df1['Time'] = pd.to_datetime(df1['Time'])
df2['Time'] = pd.to_datetime(df2['Time'])
df3['Time'] = pd.to_datetime(df3['Time'])

# Find intersections
set1 = set(df1['Time'])
set2 = set(df2['Time'])
set3 = set(df3['Time'])

# Create the Venn diagram
venn_labels = {
    '100': len(set1 - set2 - set3),  # Only in df1
    '010': len(set2 - set1 - set3),  # Only in df2
    '001': len(set3 - set1 - set2),  # Only in df3
    '110': len(set1 & set2 - set3),  # In df1 and df2
    '011': len(set2 & set3 - set1),  # In df2 and df3
    '101': len(set1 & set3 - set2),  # In df1 and df3
    '111': len(set1 & set2 & set3)   # In all three
}

# Plot the Venn diagram
plt.figure(figsize=(8, 8))
venn3(subsets=venn_labels, set_labels=('Baseline', 'EMA', 'Kalman'))
plt.title("Venn Diagram of Time Overlap")
plt.show()

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

Вот результирующая диаграмма Венна:

перекрываются

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


Заключение

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

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


Таблица файлов

Название файла Использование файла
Kalman visualizations.ipynb Код Python для визуализаций, использованный в этой статье
MR-Kalman.mq5 Код экспертного советника

Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/17273

Прикрепленные файлы |
MR-Kalman.mq5 (4.22 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (4)
Too Chee Ng
Too Chee Ng | 29 апр. 2025 в 09:20

Мне понравилась ваша презентация.

Большое спасибо. Пожалуйста, продолжайте в том же духе.

Too Chee Ng
Too Chee Ng | 29 апр. 2025 в 10:21
Low Q and moderate R yield stable predictions, while high Q and low R make the filter more reactive but noisier.

Какова ваша точка зрения на оптимизацию этих входов (Q и R)?

Как бы вы определили их значения для эксперта?

Zhuo Kai Chen
Zhuo Kai Chen | 30 апр. 2025 в 01:20
Too Chee Ng #:

Понравилась ваша презентация.

Большое спасибо. Пожалуйста, продолжайте в том же духе.

Спасибо! Я буду продолжать улучшать качество своих статей по мере того, как я узнаю больше.

Zhuo Kai Chen
Zhuo Kai Chen | 30 апр. 2025 в 01:29
Too Chee Ng #:

Какова ваша точка зрения на оптимизацию этих входов (Q и R)?

Как бы вы определили их значения для эксперта?

Отличный вопрос! Я бы сказал, что не стоит слишком усердствовать в оптимизации именно этих значений. Попробуйте выбрать несколько стандартных значений и оптимизировать порог, а не оптимизировать параметры индикатора. Я бы рекомендовал выбрать дисперсию измерения из 1000, 100 и 10, а дисперсию процесса - из 1, 0,1 и 0,01.

Самообучающийся советник с нейросетью на матрице состояний Самообучающийся советник с нейросетью на матрице состояний
Самообучающийся советник с нейросетью на матрице состояний. Совмещаем марковские цепи с многослойной нейросетью MLP, написанной на библиотеке ALGLIB MQL5. Как могут быть совмещены для прогнозирования Форекс марковские цепи и нейросети?
Заголовок в Connexus (Часть 3): Освоение использования HTTP-заголовков для запросов Заголовок в Connexus (Часть 3): Освоение использования HTTP-заголовков для запросов
Продолжаем разработку библиотеки Connexus. В этой главе мы исследуем концепцию заголовков в протоколе HTTP, объясняя, что это такое, для чего они предназначены и как их использовать в запросах. Мы рассмотрим основные заголовки, используемые при взаимодействии с API, а также покажем практические примеры того, как настроить их в библиотеке.
Торговый инструментарий MQL5 (Часть 3): Разработка EX5-библиотеки для управления отложенными ордерами Торговый инструментарий MQL5 (Часть 3): Разработка EX5-библиотеки для управления отложенными ордерами
Вы узнаете, как разработать и внедрить комплексную библиотеку отложенных EX5-ордеров в ваш код или MQL5-проекты. Мы рассмотрим, как импортировать и реализовать такую библиотеку в составе торговой панели или графического пользовательского интерфейса (GUI). Панель ордеров советника позволит пользователям открывать, отслеживать и удалять отложенные ордера по магическому числу непосредственно из графического интерфейса в окне графика.
Матричная модель прогнозирования на марковской цепи Матричная модель прогнозирования на марковской цепи
Создаем матричную модель прогнозирования на марковской цепи. Что такое марковские цепи, и как можно использовать марковскую цепь для трейдинга на Форекс.