English Deutsch 日本語
preview
Разработка инструментария для анализа движения цен (Часть 6): Возврат к среднему значению

Разработка инструментария для анализа движения цен (Часть 6): Возврат к среднему значению

MetaTrader 5Торговые системы |
43 1
Christian Benjamin
Christian Benjamin

Введение

Возврат к среднему значению (mean reversion) — интересная торговая стратегия, которую многие опытные трейдеры используют для оптимизации своих рыночных знаний. В ее основе лежит идея о том, что цены на активы имеют тенденцию возвращаться к своим историческим средним значениям, создавая возможности для сделок. Однако ручной анализ движения цен требует много времени и несет риск ошибок. Здесь приходит на помощь автоматизация.

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

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



Что такое возврат к среднему?

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

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

Краткая история и происхождение

Возврат к среднему — это концепция, зародившаяся в статистике и финансах и впервые выявленная в начале XX века благодаря трудам таких математиков, как Фрэнсис Гальтон. Первоначально применявшийся при изучении природных явлений, таких как тенденция экстремальных характеристик популяций (например, роста) возвращаться к среднему значению на протяжении поколений, возврат к среднему значению впоследствии стал краеугольным камнем финансовой теории.
На финансовых рынках эту идею популяризировали такие экономисты, как Джон Мейнард Кейнс, который заметил, что цены на активы часто колеблются вокруг своих фундаментальных значений. Это привело к разработке торговых стратегий, использующих эти тенденции. Например, во время пузыря доткомов в конце 1990-х годов многие переоцененные акции технологических компаний в конечном итоге вернулись к своим фундаментальным значениям, продемонстрировав возврат к среднему значению.

Практические примеры возврата к среднему значению

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

Определение возврата к среднему в контексте нашего советника

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

  • Средняя (50 EMA): Для представления среднего значения код использует 50-периодную экспоненциальную скользящую среднюю (EMA). EMA динамически подстраивается под последние данные о ценах, обеспечивая надежный ориентир для текущего рыночного тренда. Когда цена существенно отклоняется от EMA, это сигнализирует о возможном развороте. 
  • Разворот в действии: Сигнал на покупку генерируется, когда цена находится ниже 50 EMA, а RSI находится в зоне перепроданности; советник прогнозирует восходящее движение цены обратно к EMA. Сигнал на продажу, наоборот, генерируется, когда цена выше 50 EMA и RSI перекуплен; советник ожидает нисходящую коррекцию цены.


Обзор стратегии

Стратегия построена на концепции возврата к среднему, которая предполагает, что цены имеют тенденцию возвращаться к своим средним уровням после значительных отклонений. Такое поведение создает торговые возможности в сочетании с надежными индикаторами, такими как 50 EMA и индекс относительной силы (RSI).

  • Принцип работы

Стратегия использует два ключевых показателя:

  1. 50 EMA выступает в качестве ориентира, отображая динамическую среднюю цену за определенный период. 
  2. RSI определяет состояния перекупленности или перепроданности.

Когда цены отклоняются слишком далеко от 50 EMA и RSI подтверждает экстремальные условия, стратегия предполагает вероятный разворот к среднему значению.

Концепция возврата к среднемуЦена 

Рис 1. Концепция возврата к среднему

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

Сигнал на покупку генерируется, когда:
Цена находится ниже 50-дневной EMA, что указывает на отклонение вниз. RSI ниже 30, что подтверждает перепроданность рынка. Такая ситуация сигнализирует о возможном отскоке цены к среднему значению.

Сигнал на продажу возникает, когда:
Цена находится выше 50-дневной EMA, что сигнализирует об отклонении вверх. RSI выше 70, что подтверждает перекупленность рынка. Такая конфигурация предполагает коррекцию цены к среднему значению.

  • Визуальные подсказки и краткое содержание текста:
Зеленые стрелки обозначают сигналы на покупку, красные - на продажу. В правом верхнем углу графика отображается сводка с типом сигнала (покупка/продажа). Стратегия включает четкие правила стоп-лосса и тейк-профита:
  1. Стоп-лосс: Размещается ниже недавнего минимума для позиций на покупку и выше недавнего максимума для позиций на продажу.
  2. Тейк-профит: Цель — около 50 EMA, где ожидается разворот цены.
  3. Механизм охлаждения. Чтобы избежать избыточных сигналов и чрезмерной торговли, применяется период охлаждения. После сигнала стратегия ждет определенное количество баров, прежде чем рассматривать новые сигналы. Эта функция помогает снизить уровень шума в условиях нестабильного рынка. 

ATR (средний истинный диапазон) используется для расчета динамических уровней для установки значений тейк-профита (TP) и стоп-лосса (SL).

  • Ключевые преимущества стратегии

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

  • MQL5-код советника.

//+------------------------------------------------------------------+
//|                                        Mean Reversion Reaper.mq5 |
//|                              Copyright 2024, Christian Benjamin. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Christian Benjamin"
#property link      "https://www.mql5.com"
#property version   "1.00"

#property strict
#property indicator_chart_window

//--- Input Parameters
input int EMA_Period = 50;                     // EMA Period
input int RSI_Period = 14;                     // RSI Period
input double RSI_Overbought = 70.0;            // RSI Overbought level
input double RSI_Oversold = 30.0;              // RSI Oversold level
input int CooldownBars = 3;                    // Cooldown bars between signals
input double ATR_Multiplier = 2.0;             // ATR Multiplier for TP and SL
input int ATR_Period = 14;                     // ATR Period
input color BuySignalColor = clrGreen;         // Buy signal arrow color
input color SellSignalColor = clrRed;          // Sell signal arrow color
input int ArrowSize = 2;                       // Arrow size
input color TextColor = clrDodgerBlue;         // Color for TP/SL text summary

//--- Global Variables
int EMA_Handle, RSI_Handle, ATR_Handle;
datetime lastSignalTime = 0;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
// Create handles for indicators
   EMA_Handle = iMA(NULL, 0, EMA_Period, 0, MODE_EMA, PRICE_CLOSE);
   RSI_Handle = iRSI(NULL, 0, RSI_Period, PRICE_CLOSE);
   ATR_Handle = iATR(NULL, 0, ATR_Period);

   if(EMA_Handle == INVALID_HANDLE || RSI_Handle == INVALID_HANDLE || ATR_Handle == INVALID_HANDLE)
     {
      Print("Failed to create indicator handles. Error: ", GetLastError());
      return INIT_FAILED;
     }

   Print("Mean Reversion EA initialized.");
   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
// Clear the Signal Summary text object upon deinitialization
   ObjectDelete(0, "SignalSummary");
   Print("Mean Reversion EA deinitialized.");
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
// Avoid repeating signals on cooldown
   if(BarsSinceLastSignal() < CooldownBars)
      return;

   double EMA_Value = GetEMA();
   double RSI_Value = GetRSI();
   double ATR_Value = GetATR();

   if(EMA_Value == 0 || RSI_Value == 0 || ATR_Value == 0)
      return;

   double closePrice = iClose(NULL, 0, 0); // Current close price
   double highPrice = iHigh(NULL, 0, 1);   // Previous bar high
   double lowPrice = iLow(NULL, 0, 1);     // Previous bar low

// Check for Buy Signal
   if(closePrice < EMA_Value && RSI_Value <= RSI_Oversold)
     {
      DrawSignalArrow("BuySignal", closePrice, BuySignalColor);
      DisplayTextSummary("BUY", closePrice, lowPrice, ATR_Value);
      UpdateSignalTime();
     }
// Check for Sell Signal
   else
      if(closePrice > EMA_Value && RSI_Value >= RSI_Overbought)
        {
         DrawSignalArrow("SellSignal", closePrice, SellSignalColor);
         DisplayTextSummary("SELL", closePrice, highPrice, ATR_Value);
         UpdateSignalTime();
        }
  }

//+------------------------------------------------------------------+
//| Get EMA Value                                                    |
//+------------------------------------------------------------------+
double GetEMA()
  {
   double emaValues[1];
   if(CopyBuffer(EMA_Handle, 0, 0, 1, emaValues) <= 0)
      return 0;
   return emaValues[0];
  }

//+------------------------------------------------------------------+
//| Get RSI Value                                                    |
//+------------------------------------------------------------------+
double GetRSI()
  {
   double rsiValues[1];
   if(CopyBuffer(RSI_Handle, 0, 0, 1, rsiValues) <= 0)
      return 0;
   return rsiValues[0];
  }

//+------------------------------------------------------------------+
//| Get ATR Value                                                    |
//+------------------------------------------------------------------+
double GetATR()
  {
   double atrValues[1];
   if(CopyBuffer(ATR_Handle, 0, 0, 1, atrValues) <= 0)
      return 0;
   return atrValues[0];
  }

//+------------------------------------------------------------------+
//| Draw signal arrow on the chart                                   |
//+------------------------------------------------------------------+
void DrawSignalArrow(string signalType, double price, color arrowColor)
  {
   string arrowName = signalType + "_" + TimeToString(TimeCurrent(), TIME_MINUTES);
// Delete the existing arrow if it exists
   if(ObjectFind(0, arrowName) != -1)  // If the object exists
     {
      ObjectDelete(0, arrowName); // Delete the existing object
     }
   ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), price);
   ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, (signalType == "BuySignal") ? 233 : 234);
   ObjectSetInteger(0, arrowName, OBJPROP_COLOR, arrowColor);
   ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, ArrowSize);
  }

//+------------------------------------------------------------------+
//| Display TP and SL as text summary                                |
//+------------------------------------------------------------------+
void DisplayTextSummary(string signalType, double price, double refPrice, double ATR)
  {
   string objectName = "SignalSummary"; // Unique object name for the summary

// Delete the existing summary if it exists
   if(ObjectFind(0, objectName) != -1)  // If the object exists
     {
      ObjectDelete(0, objectName); // Delete the existing object
     }

   double SL = (signalType == "BUY") ? refPrice - (ATR * ATR_Multiplier) : refPrice + (ATR * ATR_Multiplier);
   double TP = (signalType == "BUY") ? price + (ATR * ATR_Multiplier) : price - (ATR * ATR_Multiplier);

   string summary = signalType + " Signal\n" +
                    "Price: " + DoubleToString(price, 5) + "\n" +
                    "TP: " + DoubleToString(TP, 5) + "\n" +
                    "SL: " + DoubleToString(SL, 5);

   ObjectCreate(0, objectName, OBJ_LABEL, 0, 0, 0);
   ObjectSetString(0, objectName, OBJPROP_TEXT, summary);
   ObjectSetInteger(0, objectName, OBJPROP_COLOR, TextColor);
   ObjectSetInteger(0, objectName, OBJPROP_FONTSIZE, 10); // Adjust font size if needed

// Position the label at the left upper corner
   ObjectSetInteger(0, objectName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, objectName, OBJPROP_XDISTANCE, 10); // 10 pixels from the left
   ObjectSetInteger(0, objectName, OBJPROP_YDISTANCE, 10); // 10 pixels from the top
  }

//+------------------------------------------------------------------+
//| Update signal time to prevent frequent signals                   |
//+------------------------------------------------------------------+
void UpdateSignalTime()
  {
   lastSignalTime = iTime(NULL, 0, 0);
  }

//+------------------------------------------------------------------+
//| Calculate bars since the last signal                             |
//+------------------------------------------------------------------+
int BarsSinceLastSignal()
  {
   datetime currentBarTime = iTime(NULL, 0, 0);
   if(lastSignalTime == 0)
      return INT_MAX; // If no signal has been generated return a large number.
   return (int)((currentBarTime - lastSignalTime) / PeriodSeconds());
  }
//+------------------------------------------------------------------+


Разбор кода

Заголовок

Заголовок содержит основные метаданные о советнике, включая его имя, автора и версию. Эта информация полезна для идентификации советника и атрибуции. Директивы #property определяют метаданные, такие как авторские права, ссылка автора и версия, которые отображаются при использовании советника. Кроме того, директива #property indicator_chart_window указывает, что советник работает в главном окне графика, а не в отдельном подокне.
//+------------------------------------------------------------------+
//| Mean Reversion Reaper.mq5                                        |
//| Author: Christian Benjamin                                       |
//| Website: https://www.mql5.com                                    |
//+------------------------------------------------------------------+
#property copyright "Christian Benjamin"
#property link      "https://www.mql5.com"
#property version   "1.00"

// Indicator operates in the main chart window
#property indicator_chart_window

Входные параметры

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

input int EMA_Period = 50;                     // EMA Period
input int RSI_Period = 14;                     // RSI Period
input double RSI_Overbought = 75.0;            // RSI Overbought level
input double RSI_Oversold = 25.0;              // RSI Oversold level
input int CooldownBars = 3;                    // Cooldown bars between signals
input double ATR_Multiplier = 2.0;             // ATR Multiplier for TP and SL
input int ATR_Period = 14;                     // ATR Period
input color BuySignalColor = clrGreen;         // Buy signal arrow color
input color SellSignalColor = clrRed;          // Sell signal arrow color
input int ArrowSize = 2;                       // Arrow size
input color TextColor = clrDodgerBlue;         // Color for TP/SL text summary

Глобальные переменные

Раздел глобальных переменных определяет критические переменные отслеживания состояния и ссылки на индикаторы, используемые советником. Здесь объявляются хэндлы для индикаторов EMA, RSI и ATR, а также lastSignalTime, в котором хранится временная метка самого последнего сигнала. Эти переменные гарантируют, что советник может эффективно получать доступ к данным индикаторов и применять логику, например, период охлаждения между сигналами.

int EMA_Handle, RSI_Handle, ATR_Handle;        // Handles for EMA, RSI, and ATR
datetime lastSignalTime = 0;                   // Tracks last signal time
Инициализация (OnInit)

Функция OnInit выполняется при загрузке советника на график. Ее основная роль — инициализация хэндлов индикаторов с использованием таких функций, как iMA для EMA, iRSI для RSI и iATR для ATR. Эти хэндлы необходимы для извлечения значений индикаторов во время выполнения. Функция также выполняет проверку ошибок, чтобы гарантировать успешное создание всех хэндлов. Если создание какого-либо хэндла не удается, регистрируется сообщение об ошибке, и советник прекращает работу. Успешная инициализация выводит в журнал подтверждающее сообщение, сигнализирующее о готовности советника к работе.

int OnInit()
{
    EMA_Handle = iMA(NULL, 0, EMA_Period, 0, MODE_EMA, PRICE_CLOSE);
    RSI_Handle = iRSI(NULL, 0, RSI_Period, PRICE_CLOSE);
    ATR_Handle = iATR(NULL, 0, ATR_Period);

    if (EMA_Handle == INVALID_HANDLE || RSI_Handle == INVALID_HANDLE || ATR_Handle == INVALID_HANDLE) {
        Print("Failed to create indicator handles. Error: ", GetLastError());
        return INIT_FAILED; // Stops EA if initialization fails
    }

    Print("Mean Reversion EA initialized.");
    return INIT_SUCCEEDED;
}

Очистка (OnDeinit)

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

void OnDeinit(const int reason)
{
    ObjectDelete(0, "SignalSummary"); // Remove any signal summary text
    Print("Mean Reversion EA deinitialized.");
}

Обработка сигналов (OnTick)

Функция OnTick является ядром советника, обрабатывая каждый новый рыночный тик. Прежде всего она проверяет, истек ли период охлаждения с момента последнего сигнала. В противном случае функция завершает работу преждевременно, чтобы избежать лишних сигналов. Затем она извлекает последние значения для индикаторов EMA, RSI и ATR, используя их соответствующие идентификаторы. Используя эти значения, советник оценивает условия для сигналов покупки или продажи.

Сигнал на покупку срабатывает, когда цена находится ниже EMA, а RSI находится в зоне перепроданности. И наоборот, сигнал на продажу возникает, когда цена находится выше EMA, а RSI показывает перекупленность. Для каждого сигнала функция рисует стрелку на графике и отображает текстовую сводку с ценой, уровнями стоп-лосса (SL) и тейк-профита (TP). Временная метка сигнала обновляется для обеспечения работы механизма охлаждения.

void OnTick()
{
    if (BarsSinceLastSignal() < CooldownBars) return; // Skip if cooldown is active

    double EMA_Value = GetEMA();   // Fetch EMA value
    double RSI_Value = GetRSI();   // Fetch RSI value
    double ATR_Value = GetATR();   // Fetch ATR value

    double closePrice = iClose(NULL, 0, 0); // Current bar's close price

    if (closePrice < EMA_Value && RSI_Value <= RSI_Oversold) {
        // Buy Signal
        DrawSignalArrow("BuySignal", closePrice, BuySignalColor);
        DisplayTextSummary("BUY", closePrice, iLow(NULL, 0, 1), ATR_Value);
        UpdateSignalTime(); // Update last signal time
    } else if (closePrice > EMA_Value && RSI_Value >= RSI_Overbought) {
        // Sell Signal
        DrawSignalArrow("SellSignal", closePrice, SellSignalColor);
        DisplayTextSummary("SELL", closePrice, iHigh(NULL, 0, 1), ATR_Value);
        UpdateSignalTime(); // Update last signal time
    }
}

Вспомогательные функции
  • Получение значения индикатора

Такие служебные функции, как GetEMA, GetRSI и GetATR, предназначены для извлечения последних значений из соответствующих индикаторов. Эти функции используют метод CopyBuffer для извлечения данных из хэндлов индикаторов. Если по какой-либо причине извлечение данных не удалось, функции возвращают ноль, сигнализируя о том, что советник должен пропустить обработку текущего тика. Эти функции являются легкими и модульными, что позволяет сохранить код чистым и удобным для обслуживания.

double GetEMA()
{
    double emaValues[1];
    if (CopyBuffer(EMA_Handle, 0, 0, 1, emaValues) <= 0)
        return 0;
    return emaValues[0];
}

double GetRSI()
{
    double rsiValues[1];
    if (CopyBuffer(RSI_Handle, 0, 0, 1, rsiValues) <= 0)
        return 0;
    return rsiValues[0];
}

double GetATR()
{
    double atrValues[1];
    if (CopyBuffer(ATR_Handle, 0, 0, 1, atrValues) <= 0)
        return 0;
    return atrValues[0];
}
  • Отображение сигнальной стрелки

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

void DrawSignalArrow(string signalType, double price, color arrowColor)
{
    string arrowName = signalType + "_" + TimeToString(TimeCurrent(), TIME_MINUTES);
    if (ObjectFind(0, arrowName) != -1) ObjectDelete(0, arrowName);

    ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), price);
    ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, (signalType == "BuySignal") ? 233 : 234);
    ObjectSetInteger(0, arrowName, OBJPROP_COLOR, arrowColor);
    ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, ArrowSize);
}
  • Отображение сводки TP/SL

Функция DisplayTextSummary предоставляет краткую сводку по сигналу, включая цены, уровни стоп-лосса и тейк-профита. Эта информация отображается в виде метки на диаграмме, расположенной в верхнем левом углу. Функция рассчитывает уровни TP и SL на основе ATR и его множителя, предлагая динамические уровни, которые адаптируются к волатильности рынка. Если метка сводки уже существует, она удаляется перед созданием новой. Это гарантирует отображение только последней информации о сигнале, что улучшает читаемость.

void DisplayTextSummary(string signalType, double price, double refPrice, double ATR)
{
    string objectName = "SignalSummary";
    if (ObjectFind(0, objectName) != -1) ObjectDelete(0, objectName);

    double SL = (signalType == "BUY") ? refPrice - (ATR * ATR_Multiplier) : refPrice + (ATR * ATR_Multiplier);
    double TP = (signalType == "BUY") ? price + (ATR * ATR_Multiplier) : price - (ATR * ATR_Multiplier);

    string summary = signalType + " Signal\n" +
                     "Price: " + DoubleToString(price, 5) + "\n" +
                     "TP: " + DoubleToString(TP, 5) + "\n" +
                     "SL: " + DoubleToString(SL, 5);

    ObjectCreate(0, objectName, OBJ_LABEL, 0, 0, 0);
    ObjectSetString(0, objectName, OBJPROP_TEXT, summary);
    ObjectSetInteger(0, objectName, OBJPROP_COLOR, TextColor);
    ObjectSetInteger(0, objectName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
    ObjectSetInteger(0, objectName, OBJPROP_XDISTANCE, 10);
    ObjectSetInteger(0, objectName, OBJPROP_YDISTANCE, 10);
}
  • Управление охлаждением
Советник устанавливает период охлаждения между сигналами, чтобы предотвратить чрезмерную торговлю в условиях нестабильных рынков. Функция UpdateSignalTime обновляет переменную lastSignalTime с отметкой времени самого последнего сигнала, в то время как функция BarsSinceLastSignal рассчитывает количество баров, прошедших с момента последнего сигнала. Если сигнал еще не сгенерирован, возвращается большое значение для обеспечения нормальной работы. Этот механизм обеспечивает правильное распределение сигналов, предоставляя трейдерам более четкую и надежную информацию.
void UpdateSignalTime()
{
    lastSignalTime = iTime(NULL, 0, 0); // Store time of the current bar
}

int BarsSinceLastSignal()
{
    datetime currentBarTime = iTime(NULL, 0, 0);
    if (lastSignalTime == 0) return INT_MAX; // No signals generated yet
    return (int)((currentBarTime - lastSignalTime) / PeriodSeconds());
}


Тестирование и результаты

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

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

Тестовый сигнал

Рис 2. Результат теста 1

На графике выше показаны тесты, проведенные на двух разных таймфреймах для индекса Volatility 75 (1s) в течение 29-дневного периода. Ниже мы представили результаты двух тестов в таблице.

Таблицы генерации и производительности сигналов

  • Таблица 1

Тип сигнала  Таймфрейм  Общее количество сгенерированных сигналов
Истинные сигналы (цена выросла после сигнала)
Точность сигнала на покупку (%)
Покупка M30 41 33 80.5%
Продажа M30 21 15 71.4%

  • Таблица 2

Тип сигнала  Таймфрейм  Общее количество сгенерированных сигналов
Истинные сигналы (цена выросла после сигнала)
Точность сигнала на покупку (%)
 Покупка H1 19 14 73.6% 
 Продажа H1  13 61.5% 

Ниже представлена иллюстрация результатов тестирования советника в реальном времени.

Сигнал в реальном времени

Рис. 3. Результат теста 2

Давайте также посмотрим на GIF-анимацию ниже.

Результаты тестирования

Рис 4. Результат теста 3

Источники:


Заключение

Советник Mean Reversion Reaper предлагает надежную систему генерации сигналов, основанную на принципах возврата к среднему, достигая впечатляющего уровня точности не менее 70% для сигналов на покупку. Использование среднего истинного диапазона (ATR) для установки уровней стоп-лосса (SL) и тейк-профита (TP) позволяет системе адаптироваться к различным условиям волатильности рынка, что делает ее особенно эффективной на рынках с ограниченным диапазоном.

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

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

Дата Название инструмента  Описание Версия  Обновления  Примечания
01/10/24 Chart Projector Скрипт для наложения эффекта призрака на движение цены за предыдущий день. 1.0 Первоначальная версия Первый инструмент в Lynnchris Tools Chest
18/11/24 Analytical Comment Предоставляет информацию за предыдущий день в табличном формате, а также прогнозирует будущее направление рынка. 1.0 Первоначальная версия Второй инструмент в Lynnchris Tools Chest
27/11/24 Analytics Master Регулярное обновление рыночных показателей каждые два часа  1.01 Вторая версия Третий инструмент в Lynnchris Tools Chest
02/12/24 Analytics Forecaster  Регулярное обновление рыночных показателей каждые два часа с интеграцией с Telegram 1.1 Третья версия Инструмент номер 4
09/12/24 Volatility Navigator Советник анализирует рыночные условия с помощью полос Боллинджера, RSI и ATR. 1.0 Первоначальная версия Инструмент номер 5
19/12/24 Mean Reversion Signal Reaper  Анализирует рынок и генерирует сигналы, используя стратегию возврата к среднему  1.0  Первоначальная версия  Инструмент номер 6 

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

Прикрепленные файлы |
Mean_Reversion.mq5 (16.16 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (1)
linfo2
linfo2 | 7 янв. 2025 в 03:33
Спасибо, Кристиан, очень полезный шаблон
Особенности написания Пользовательских Индикаторов Особенности написания Пользовательских Индикаторов
Написание пользовательских индикаторов в торговой системе MetaTrader 4
От новичка до эксперта: Создание анимированного советника для новостей в MQL5 (I) От новичка до эксперта: Создание анимированного советника для новостей в MQL5 (I)
Доступность новостей является критическим фактором при торговле в терминале MetaTrader 5. Несмотря на наличие множества новостных API, многие трейдеры сталкиваются с трудностями доступа к ним и их эффективной интеграции в свою торговую среду. В ходе настоящего обсуждения нашей целью является разработать оптимизированное решение, которое выводило бы новости непосредственно на график — там, где они больше всего нужны. Мы добьемся этого, создав советника «Заголовки новостей», который отслеживает и отображает обновления новостей в режиме реального времени из источников API.
Особенности написания экспертов Особенности написания экспертов
Написание и тестирование экспертов в торговой системе MetaTrader 4.
Возвратные стратегии дневной торговли RSI2 Ларри Коннорса Возвратные стратегии дневной торговли RSI2 Ларри Коннорса
Ларри Коннорс — известный трейдер и автор книг, наиболее известный своими работами в области количественной (алгоритмизированной) торговли и таких стратегий, как 2-периодный индекс относительной силы RSI (RSI2), помогающих определять краткосрочные состояния перекупленности и перепроданности рынка. В этой статье объясним сначала актуальность нашего исследования, затем воссоздадим три самые известные стратегии Коннорса на языке MQL5 и применим их к внутридневной торговле на индексе CFD S&P 500.