English
preview
Разработка индикатора рыночной энтропии: торговая система, основанная на теории информации

Разработка индикатора рыночной энтропии: торговая система, основанная на теории информации

MetaTrader 5 — Примеры |
339 0
Hlomohang John Borotho
Hlomohang John Borotho

Содержание:

  1. Введение
  2. Обзор индикатора и принципы его работы
  3. Начало работы
  4. Демонстрация индикатора
  5. Заключение


Введение

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

Для решения этой проблемы мы предлагаем методологию, которая формализует рыночную случайность с помощью энтропии Шеннона, применяемой к дискретизированным состояниям цены (рост, падение, движение без существенного изменения цены). Индикатор рыночной энтропии вычисляет нормализованный показатель энтропии в скользящем окне и сопоставляет его с отдельными рыночными режимами — TREND, TRANSITION и CHAOTIC — с использованием чётко определённых пороговых значений. Мы дополняем это быстрым и медленным горизонтами энтропии, импульсом энтропии, дивергенцией, а также обнаружением сжатия/расширения, чтобы информационное состояние было как измеримым, так и реализуемым в MQL5 в виде буферов, флагов режимов, визуальных маркеров и фильтров сигналов на основе правил.


Обзор индикатора и принципы его работы

Индикатор рыночной энтропии основан на теории информации Шеннона и преобразует ценовое движение в измеримое информационное содержание посредством расчёта энтропии. По своей сути индикатор анализирует ценовые движения, классифицируя каждый бар как одно из трёх состояний: восходящее движение, нисходящее движение или движение без существенного изменения цены (флэт), определяемое входным параметром PriceStep. Затем эти состояния обрабатываются в скользящем окне (EntropyPeriod), где индикатор подсчитывает частоту каждого состояния и применяет формулу энтропии:

Этот расчет показывает, какая степень случайности присутствует на рынке в данный момент. Когда преобладает один тип движения (например, преимущественно восходящие движения в условиях сильного тренда), энтропия становится низкой, как правило ниже 0,35, что свидетельствует о структурированных и предсказуемых рыночных условиях. Когда движения равномерно распределяются между направлениями вверх, вниз и состоянием без существенного изменения цены, энтропия поднимается выше 0,65, что указывает на хаотичное и непредсказуемое поведение рынка. Данный индикатор отображает режимы с помощью гистограммы с цветовой кодировкой: зеленый цвет обозначает трендовые условия, желтый — переходные, а красный — хаотические условия. Дополнительные линии отображают быструю энтропию (20), медленную энтропию (100) и дивергенцию между ними.

Переход от простого расчета энтропии к рабочим сигналам на покупку/продажу предполагает анализ взаимодействия энтропии на нескольких периодах и выявление критических переходов в структуре рынка. Сигналы на покупку, как правило, появляются во время перехода от фазы сжатия к фазе расширения. В частности, быстрая энтропия пересекает медленную снизу вверх, энтропия поднимается с уровня ниже 0,30 в диапазон 0,35–0,45, а импульс энтропии становится положительным. Это свидетельствует об организованном направленном движении после периода консолидации.

И наоборот, сигналы на продажу формируются, когда происходит обратное: быстрая энтропия пересекает медленную сверху вниз, энтропия пробивает отметку 0,55 и движется в сторону хаотической зоны, а импульс энтропии становится отрицательным, что указывает на разрушение рыночной структуры. Данный индикатор также выявляет «информационные шоки» (скачки энтропии на 25 % и более) и смены режимов. Все сигналы отображаются на основном графике в виде отдельных стрелок, чтобы избежать их скопления. Этот многоуровневый подход позволяет преобразовать абстрактную теорию информации в конкретные торговые сигналы, выявляя моменты, когда степень случайности рынка снижается (что благоприятно для торговли по тренду) или повышается (что служит предупреждением о флэте или хаотичных условиях).



Начало работы

//+------------------------------------------------------------------+
//|                                                   Entropy IT.mq5 |
//|                        GIT under Copyright 2025, MetaQuotes Ltd. |
//|                     https://www.mql5.com/en/users/johnhlomohang/ |
//+------------------------------------------------------------------+
#property copyright "GIT under Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com/en/users/johnhlomohang/"
#property version   "1.00"
#property description "Market Entropy Indicator – Information Theory Visualization"
#property description "Multi-period signal generation using entropy relationships"
#property description "Features Histogram Compression/Decompression visualization"
#property indicator_separate_window
#property indicator_minimum -0.2
#property indicator_maximum 1.2
#property indicator_buffers 16
#property indicator_plots   10

//--- Entropy Histogram
#property indicator_label1 "Entropy"
#property indicator_type1 DRAW_COLOR_HISTOGRAM
#property indicator_color1 clrGreen,clrYellow,clrRed
#property indicator_width1 2

//--- Smoothed Entropy
#property indicator_label2 "Smoothed Entropy"
#property indicator_type2 DRAW_LINE
#property indicator_color2 clrWhite

//--- Entropy Momentum
#property indicator_label3 "Entropy Momentum"
#property indicator_type3 DRAW_LINE
#property indicator_color3 clrCyan

//--- Fast Entropy (short period)
#property indicator_label4 "Fast Entropy"
#property indicator_type4 DRAW_LINE
#property indicator_color4 clrLime

//--- Slow Entropy (long period)
#property indicator_label5 "Slow Entropy"
#property indicator_type5 DRAW_LINE
#property indicator_color5 clrOrange

//--- Entropy Divergence
#property indicator_label6 "Divergence"
#property indicator_type6 DRAW_LINE
#property indicator_color6 clrMagenta

//--- Compression/Decompression Indicator
#property indicator_label7 "Compress/Decompress"
#property indicator_type7 DRAW_COLOR_HISTOGRAM
#property indicator_color7 clrBlue,clrRed,clrGray
#property indicator_width7 2

//--- Flow Arrows (plot-based)
#property indicator_label8 "Entropy Flow"
#property indicator_type8 DRAW_COLOR_ARROW
#property indicator_color8 clrLime,clrOrange

//--- Shock Marker
#property indicator_label9 "Information Shock"
#property indicator_type9 DRAW_ARROW
#property indicator_color9 clrMagenta

//--- Regime Change Marker
#property indicator_label10 "Regime Shift"
#property indicator_type10 DRAW_ARROW
#property indicator_color10 clrWhite

Для начала мы настроим индикатор так, чтобы он отображался в отдельном окне с нормализованным диапазоном от -0,2 до 1,2, что позволит нам наглядно визуализировать значения энтропии и их динамику. Мы определяем в общей сложности 16 буферов и 10 построений индикатора для поддержки нескольких уровней визуализации информации. Основой индикатора является гистограмма энтропии, в которой для обозначения различных рыночных режимов используется цветовая кодировка (зеленый, желтый, красный), а сглаженная линия энтропии позволяет более четко видеть базовый информационный тренд. Мы дополнительно расширяем эту концепцию, вводя импульс энтропии, который отражает скорость изменения информации, а также линии быстрой и медленной энтропии, позволяющие сравнивать краткосрочную и долгосрочную неопределенность на рынке.

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

//--- Inputs
input int      EntropyPeriod      = 50;          // Base entropy period
input int      SmoothingPeriod    = 10;          // Smoothing of entropy line
input int      MomentumPeriod     = 5;           // Momentum period
input int      FastEntropyPeriod  = 20;          // Fast entropy period for signals
input int      SlowEntropyPeriod  = 100;         // Slow entropy period for signals
input int      PriceStep          = 1;           // Minimum price change (points) to classify as move
input double   SignalThreshold    = 0.15;        // Threshold for signal generation
input bool     ShowSignals        = true;        // Draw buy/sell arrows on main chart
input int      SignalArrowOffset  = 15;          // Offset in points for arrow placement
input bool     UseDailyReset      = true;        // Reset entropy calculation daily
input double   CompressionZone    = 0.30;        // Entropy level considered compression zone
input double   DecompressionZone  = 0.50;        // Entropy level considered decompression zone
input int      CompressionBars    = 5;           // Bars to confirm compression/decompression
input int      MinSignalGap       = 10;          // Minimum bars between same signal types

//--- Buffers (for subwindow display)
double entropyBuffer[];
double entropyColors[];
double compressionIndicator[];
double compressionColors[];
double smoothBuffer[];
double momentumBuffer[];
double fastEntropyBuffer[];
double slowEntropyBuffer[];
double divergenceBuffer[];
double flowBuffer[];
double flowColors[];
double shockBuffer[];
double regimeShiftBuffer[];

//--- Signal buffers
double buySignalBuffer[];
double sellSignalBuffer[];

//--- Internal arrays
int states[];                // 0=flat, 1=up, 2=down
int regime[];                // 0=trend, 1=transition, 2=chaotic
int compressionState[];      // -1=compressing, 0=neutral, 1=decompressing

//--- Daily tracking
datetime   currentDay;
int        dailyUp, dailyDown, dailyFlat, dailyBars;
double     prevDailyEntropy;

//--- Multi-period tracking
double     prevFastEntropy, prevSlowEntropy;
double     prevMomentum;

//--- Compression tracking
double     compressionLevel[];
double     decompressionLevel[];

//--- Signal tracking to prevent duplicates
datetime   lastBuySignalTime;
datetime   lastSellSignalTime;
datetime   lastCompressionStartTime;
datetime   lastDecompressionStartTime;
int        lastBuyBar;
int        lastSellBar;
int        lastCompressionBar;
int        lastDecompressionBar;

//--- Chart object prefix
string objPrefix;

Здесь мы определяем входные параметры, которые управляют поведением системы, основанной на энтропии. Основные параметры, такие как EntropyPeriod, FastEntropyPeriod и SlowEntropyPeriod, позволяют измерять информацию на нескольких временных горизонтах, а SmoothingPeriod и MomentumPeriod помогают уточнять сигнал за счёт снижения шума и фиксации скорости изменения информации. Кроме того, мы вводим такие пороговые значения, как SignalThreshold, CompressionZone и DecompressionZone, для классификации состояний рынка и запуска значимых событий. Дополнительные параметры, такие как SignalArrowOffset, MinSignalGap и ShowSignals, обеспечивают чёткость визуальных сигналов и не дают им появляться слишком часто, а UseDailyReset позволяет индикатору ежедневно перезапускать расчёты энтропии, благодаря чему он адаптируется к внутридневному поведению рынка.

Для поддержки этой логики мы выделяем несколько буферов и внутренних массивов, которые обеспечивают как визуализацию, так и вычисления. Основные буферы (такие как entropyBuffer, momentumBuffer, fastEntropyBuffer и slowEntropyBuffer) хранят данные разных уровней анализа энтропии, тогда как другие, например compressionIndicator, flowBuffer и shockBuffer, предназначены для визуальных маркеров, выделяющих изменения структуры рынка. Буферы сигналов (buySignalBuffer и sellSignalBuffer) используются для вывода торговых возможностей на график, а внутренние массивы, такие как states, regime и compressionState, классифицируют поведение цены и рыночные условия. Кроме того, мы поддерживаем переменные отслеживания для дневной статистики, сравнений между периодами и времени подачи сигналов, чтобы предотвратить дублирование; это обеспечивает эффективность и логическую согласованность системы при обработке поступающих рыночных данных.

//+------------------------------------------------------------------+
//|  OnInit                                                          |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- Bind buffers
   SetIndexBuffer(0, entropyBuffer, INDICATOR_DATA);
   SetIndexBuffer(1, entropyColors, INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2, smoothBuffer, INDICATOR_DATA);
   SetIndexBuffer(3, momentumBuffer, INDICATOR_DATA);
   SetIndexBuffer(4, fastEntropyBuffer, INDICATOR_DATA);
   SetIndexBuffer(5, slowEntropyBuffer, INDICATOR_DATA);
   SetIndexBuffer(6, divergenceBuffer, INDICATOR_DATA);
   SetIndexBuffer(7, compressionIndicator, INDICATOR_DATA);
   SetIndexBuffer(8, compressionColors, INDICATOR_COLOR_INDEX);
   SetIndexBuffer(9, flowBuffer, INDICATOR_DATA);
   SetIndexBuffer(10, flowColors, INDICATOR_COLOR_INDEX);
   SetIndexBuffer(11, shockBuffer, INDICATOR_DATA);
   SetIndexBuffer(12, regimeShiftBuffer, INDICATOR_DATA);
   SetIndexBuffer(13, buySignalBuffer, INDICATOR_DATA);
   SetIndexBuffer(14, sellSignalBuffer, INDICATOR_DATA);

   //--- Set empty value for all plots
   for(int i = 0; i <= 14; i++)
      PlotIndexSetDouble(i, PLOT_EMPTY_VALUE, EMPTY_VALUE);

   //--- Arrow codes for plot-based markers
   PlotIndexSetInteger(8, PLOT_ARROW, 233);        // up/down arrows for flow
   PlotIndexSetInteger(9, PLOT_ARROW, 167);        // lightning
   PlotIndexSetInteger(10, PLOT_ARROW, 159);       // diamond

   //--- Prefix for chart objects
   objPrefix = "MktEntropy_" + IntegerToString(ChartID()) + "_";

   //--- Initialize tracking variables
   currentDay = 0;
   dailyUp = dailyDown = dailyFlat = dailyBars = 0;
   prevDailyEntropy = EMPTY_VALUE;
   prevFastEntropy = prevSlowEntropy = prevMomentum = EMPTY_VALUE;

   //--- Initialize signal tracking
   lastBuySignalTime = 0;
   lastSellSignalTime = 0;
   lastCompressionStartTime = 0;
   lastDecompressionStartTime = 0;
   lastBuyBar = -MinSignalGap;
   lastSellBar = -MinSignalGap;
   lastCompressionBar = -MinSignalGap;
   lastDecompressionBar = -MinSignalGap;

   //--- Initialize compression tracking arrays
   ArrayResize(compressionState, 1);
   ArrayResize(compressionLevel, 1);
   ArrayResize(decompressionLevel, 1);

   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
//|  OnDeinit                                                        |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ObjectsDeleteAll(0, objPrefix);
  }

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

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

//+------------------------------------------------------------------+
//|  OnCalculate                                                     |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   if(rates_total < SlowEntropyPeriod)
      return 0;

   //--- Ensure arrays are large enough
   ArrayResize(states, rates_total);
   ArrayResize(regime, rates_total);
   ArrayResize(compressionState, rates_total);
   ArrayResize(compressionLevel, rates_total);
   ArrayResize(decompressionLevel, rates_total);

   int start = prev_calculated > 0 ? prev_calculated - 1 : 0;
   if(start < 0)
      start = 0;

   //--- Process bars
   for(int i = start; i < rates_total; i++)
     {
      UpdateDailyReset(i, time);
      ClassifyPriceMovement(i, close, time);
      CalculateAllEntropy(i);
      CalculateDivergenceAndMomentum(i);
      DetectCompression(i);

      if(ShowSignals)
        {
         DrawCompressionArrows(i, time, high, low);
         DrawTradingSignal(i, time, high, low);
        }

      UpdateMarkers(i);
      CalculateSmoothedEntropy(i);
     }

   UpdateRegimeLabel(time, rates_total);

   return rates_total;
  }

//+------------------------------------------------------------------+
//|  Update daily reset and manage signal timers                     |
//+------------------------------------------------------------------+
void UpdateDailyReset(int i, const datetime &time[])
  {
   if(!UseDailyReset)
      return;

   MqlDateTime dt;
   TimeToStruct(time[i], dt);
   datetime barDate = dt.year * 10000 + dt.mon * 100 + dt.day;

   if(barDate != currentDay)
     {
      currentDay = barDate;
      dailyUp = dailyDown = dailyFlat = dailyBars = 0;
      prevDailyEntropy = EMPTY_VALUE;

      if(ShowSignals)
        {
         ObjectsDeleteAll(0, objPrefix);
         ResetSignalTimers();
        }
     }
  }

//+------------------------------------------------------------------+
//|  Reset all signal timers                                         |
//+------------------------------------------------------------------+
void ResetSignalTimers()
  {
   lastBuySignalTime = 0;
   lastSellSignalTime = 0;
   lastCompressionStartTime = 0;
   lastDecompressionStartTime = 0;
   lastBuyBar = -MinSignalGap;
   lastSellBar = -MinSignalGap;
   lastCompressionBar = -MinSignalGap;
   lastDecompressionBar = -MinSignalGap;
  }

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

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

//+------------------------------------------------------------------+
//|  Classify price movement into states (up/down/flat)              |
//+------------------------------------------------------------------+
void ClassifyPriceMovement(int i, const double &close[], const datetime &time[])
  {
   if(i == 0)
     {
      states[i] = 0;
      return;
     }

   double change = close[i] - close[i-1];
   double threshold = PriceStep * _Point;

   if(change > threshold)
      states[i] = 1;   // up
   else
      if(change < -threshold)
         states[i] = 2;   // down
      else
         states[i] = 0;   // flat

   if(UseDailyReset && time[i] >= time[i-1])
     {
      if(states[i] == 1)
         dailyUp++;
      else
         if(states[i] == 2)
            dailyDown++;
         else
            dailyFlat++;
      dailyBars++;
     }
  }

//+------------------------------------------------------------------+
//|  Calculate entropy for a given period                            |
//+------------------------------------------------------------------+
double CalculateEntropy(int startIdx, int period, const int &statesArray[])
  {
   int up = 0, down = 0, flat = 0;
   for(int j = startIdx - period; j < startIdx; j++)
     {
      if(statesArray[j] == 1)
         up++;
      else
         if(statesArray[j] == 2)
            down++;
         else
            flat++;
     }

   double p_up = (double)up / period;
   double p_down = (double)down / period;
   double p_flat = (double)flat / period;

   double entropy = 0.0;
   if(p_up > 0)
      entropy -= p_up * MathLog(p_up) / M_LN2;
   if(p_down > 0)
      entropy -= p_down * MathLog(p_down) / M_LN2;
   if(p_flat > 0)
      entropy -= p_flat * MathLog(p_flat) / M_LN2;

   return entropy / (MathLog(3) / M_LN2);  // Normalized entropy
  }

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

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

//+------------------------------------------------------------------+
//|  Calculate fast, slow, and base entropy                          |
//+------------------------------------------------------------------+
void CalculateAllEntropy(int i)
  {
   //--- Fast entropy
   if(i >= FastEntropyPeriod)
      fastEntropyBuffer[i] = CalculateEntropy(i, FastEntropyPeriod, states);
   else
      fastEntropyBuffer[i] = EMPTY_VALUE;

   //--- Slow entropy
   if(i >= SlowEntropyPeriod)
      slowEntropyBuffer[i] = CalculateEntropy(i, SlowEntropyPeriod, states);
   else
      slowEntropyBuffer[i] = EMPTY_VALUE;

   //--- Base entropy
   if(i >= EntropyPeriod)
     {
      entropyBuffer[i] = CalculateEntropy(i, EntropyPeriod, states);
      ClassifyRegime(i);
     }
   else
     {
      entropyBuffer[i] = EMPTY_VALUE;
      regime[i] = -1;
     }
  }

//+------------------------------------------------------------------+
//|  Classify market regime based on entropy value                   |
//+------------------------------------------------------------------+
void ClassifyRegime(int i)
  {
   if(entropyBuffer[i] < 0.35)
     {
      entropyColors[i] = 0;
      regime[i] = 0;  // trend
     }
   else
      if(entropyBuffer[i] < 0.65)
        {
         entropyColors[i] = 1;
         regime[i] = 1;  // transition
        }
      else
        {
         entropyColors[i] = 2;
         regime[i] = 2;  // chaotic
        }
  }

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

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

//+------------------------------------------------------------------+
//|  Calculate divergence and momentum                               |
//+------------------------------------------------------------------+
void CalculateDivergenceAndMomentum(int i)
  {
   //--- Divergence (fast - slow)
   if(fastEntropyBuffer[i] != EMPTY_VALUE && slowEntropyBuffer[i] != EMPTY_VALUE)
      divergenceBuffer[i] = fastEntropyBuffer[i] - slowEntropyBuffer[i];
   else
      divergenceBuffer[i] = EMPTY_VALUE;

   //--- Momentum
   if(i >= EntropyPeriod + MomentumPeriod &&
      entropyBuffer[i] != EMPTY_VALUE &&
      entropyBuffer[i - MomentumPeriod] != EMPTY_VALUE)
      momentumBuffer[i] = entropyBuffer[i] - entropyBuffer[i - MomentumPeriod];
   else
      momentumBuffer[i] = EMPTY_VALUE;
  }

//+------------------------------------------------------------------+
//|  Detect compression/decompression states                         |
//+------------------------------------------------------------------+
void DetectCompression(int i)
  {
   if(entropyBuffer[i] == EMPTY_VALUE)
     {
      compressionIndicator[i] = EMPTY_VALUE;
      return;
     }

   //--- Track levels
   compressionLevel[i] = entropyBuffer[i];
   decompressionLevel[i] = entropyBuffer[i];

   //--- Find local minima for compression
   if(i >= CompressionBars)
     {
      compressionLevel[i] = entropyBuffer[i];
      for(int j = i - CompressionBars; j <= i; j++)
        {
         if(entropyBuffer[j] != EMPTY_VALUE && entropyBuffer[j] < compressionLevel[i])
            compressionLevel[i] = entropyBuffer[j];
        }
     }
   
   //--- Find local maxima for decompression
   if(i >= CompressionBars)
     {
      decompressionLevel[i] = entropyBuffer[i];
      for(int j = i - CompressionBars; j <= i; j++)
        {
         if(entropyBuffer[j] != EMPTY_VALUE && entropyBuffer[j] > decompressionLevel[i])
            decompressionLevel[i] = entropyBuffer[j];
        }
     }

   //--- Determine state
   compressionState[i] = 0;  // neutral

   if(i > 0 && entropyBuffer[i-1] != EMPTY_VALUE)
     {
      if(entropyBuffer[i] < entropyBuffer[i-1] && entropyBuffer[i] < CompressionZone)
         compressionState[i] = -1;  // compressing
      else
         if(entropyBuffer[i] > entropyBuffer[i-1] && entropyBuffer[i] > DecompressionZone)
            compressionState[i] = 1;   // decompressing
     }

   //--- Set indicator buffer and colors
   if(compressionState[i] == -1)
     {
      compressionIndicator[i] = entropyBuffer[i];
      compressionColors[i] = 0;  // Blue
     }
   else
      if(compressionState[i] == 1)
        {
         compressionIndicator[i] = entropyBuffer[i];
         compressionColors[i] = 1;  // Red
        }
      else
         if(compressionState[i] == 0 && entropyBuffer[i] < CompressionZone)
           {
            compressionIndicator[i] = entropyBuffer[i];
            compressionColors[i] = 2;  // Gray
           }
         else
           {
            compressionIndicator[i] = EMPTY_VALUE;
           }
  }

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

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

//+------------------------------------------------------------------+
//|  Draw compression/decompression circles                          |
//+------------------------------------------------------------------+
void DrawCompressionArrows(int i, const datetime &time[], const double &high[], const double &low[])
  {
   if(!ShowSignals || i == 0 || compressionState[i] == 0)
      return;

   //--- Compression start
   if(compressionState[i] == -1 && compressionState[i-1] != -1)
     {
      if(i - lastCompressionBar >= MinSignalGap &&
         (lastCompressionStartTime == 0 || time[i] - lastCompressionStartTime > MinSignalGap * PeriodSeconds()))
        {
         double arrowY = low[i] - SignalArrowOffset * _Point * 2;
         string objName = objPrefix + "compress_" + IntegerToString(i);

         ObjectDelete(0, objName);

         if(ObjectCreate(0, objName, OBJ_ARROW, 0, time[i], arrowY))
           {
            ObjectSetInteger(0, objName, OBJPROP_ARROWCODE, 108);
            ObjectSetInteger(0, objName, OBJPROP_COLOR, clrBlue);
            ObjectSetInteger(0, objName, OBJPROP_WIDTH, 2);
            ObjectSetInteger(0, objName, OBJPROP_BACK, false);
            ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false);
            ObjectSetInteger(0, objName, OBJPROP_HIDDEN, true);

            lastCompressionStartTime = time[i];
            lastCompressionBar = i;
           }
        }
     }
   //--- Decompression start
   else
      if(compressionState[i] == 1 && compressionState[i-1] != 1)
        {
         if(i - lastDecompressionBar >= MinSignalGap &&
            (lastDecompressionStartTime == 0 || time[i] - lastDecompressionStartTime > MinSignalGap * PeriodSeconds()))
           {
            double arrowY = high[i] + SignalArrowOffset * _Point * 2;
            string objName = objPrefix + "decompress_" + IntegerToString(i);

            ObjectDelete(0, objName);

            if(ObjectCreate(0, objName, OBJ_ARROW, 0, time[i], arrowY))
              {
               ObjectSetInteger(0, objName, OBJPROP_ARROWCODE, 108);
               ObjectSetInteger(0, objName, OBJPROP_COLOR, clrOrange);
               ObjectSetInteger(0, objName, OBJPROP_WIDTH, 2);
               ObjectSetInteger(0, objName, OBJPROP_BACK, false);
               ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false);
               ObjectSetInteger(0, objName, OBJPROP_HIDDEN, true);

               lastDecompressionStartTime = time[i];
               lastDecompressionBar = i;
              }
           }
        }
  }

//+------------------------------------------------------------------+
//|  Check buy signal conditions                                     |
//+------------------------------------------------------------------+
bool IsBuySignal(int i)
  {
   bool buyCondition1 = (fastEntropyBuffer[i] > slowEntropyBuffer[i] &&
                         fastEntropyBuffer[i-1] <= slowEntropyBuffer[i-1]);

   bool buyCondition2 = (entropyBuffer[i] < 0.65);

   bool buyCondition3 = (momentumBuffer[i] > 0 && momentumBuffer[i] > momentumBuffer[i-1]);

   bool buyCondition4 = (divergenceBuffer[i] > -SignalThreshold);

   bool buyCondition5 = (regime[i] != 2);

   bool buyCondition6 = (compressionState[i] == 1 &&
                         entropyBuffer[i] > 0.25 && entropyBuffer[i] < 0.45);

   bool buyCondition7 = (compressionState[i-1] == -1 && compressionState[i] != -1 &&
                         momentumBuffer[i] > 0);

   return ((buyCondition1 && buyCondition2 && buyCondition3 && buyCondition4) ||
           buyCondition6 || buyCondition7);
  }

//+------------------------------------------------------------------+
//|  Check sell signal conditions                                    |
//+------------------------------------------------------------------+
bool IsSellSignal(int i)
  {
   bool sellCondition1 = (fastEntropyBuffer[i] < slowEntropyBuffer[i] &&
                          fastEntropyBuffer[i-1] >= slowEntropyBuffer[i-1]);

   bool sellCondition2 = (entropyBuffer[i] > 0.55);

   bool sellCondition3 = (momentumBuffer[i] < 0 && momentumBuffer[i] < momentumBuffer[i-1]);

   bool sellCondition4 = (divergenceBuffer[i] < SignalThreshold);

   bool sellCondition5 = (regime[i] == 2 && regime[i-1] != 2);

   bool sellCondition6 = (divergenceBuffer[i] < -SignalThreshold &&
                          MathAbs(divergenceBuffer[i]) > MathAbs(divergenceBuffer[i-1]));

   bool sellCondition7 = (compressionState[i-1] == 1 && compressionState[i] != 1 &&
                          momentumBuffer[i] < 0);

   return ((sellCondition1 && sellCondition2 && sellCondition3) ||
           sellCondition5 || sellCondition6 || sellCondition7);
  }

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

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

//+------------------------------------------------------------------+
//|  Draw buy/sell arrows                                            |
//+------------------------------------------------------------------+
void DrawTradingSignal(int i, const datetime &time[], const double &high[], const double &low[])
  {
   if(!ShowSignals || i < SlowEntropyPeriod ||
      fastEntropyBuffer[i] == EMPTY_VALUE || slowEntropyBuffer[i] == EMPTY_VALUE ||
      entropyBuffer[i] == EMPTY_VALUE || momentumBuffer[i] == EMPTY_VALUE)
      return;

   //--- Buy signal
   if(IsBuySignal(i))
     {
      if(i - lastBuyBar >= MinSignalGap &&
         (lastBuySignalTime == 0 || time[i] - lastBuySignalTime > MinSignalGap * PeriodSeconds()))
        {
         double arrowY = low[i] - SignalArrowOffset * _Point;
         string objName = objPrefix + "buy_" + IntegerToString(i);

         ObjectDelete(0, objName);

         if(ObjectCreate(0, objName, OBJ_ARROW, 0, time[i], arrowY))
           {
            ObjectSetInteger(0, objName, OBJPROP_ARROWCODE, 233);
            ObjectSetInteger(0, objName, OBJPROP_COLOR, clrGreen);
            ObjectSetInteger(0, objName, OBJPROP_WIDTH, 2);
            ObjectSetInteger(0, objName, OBJPROP_BACK, false);
            ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false);
            ObjectSetInteger(0, objName, OBJPROP_HIDDEN, true);

            buySignalBuffer[i] = low[i] - SignalArrowOffset * _Point;
            lastBuySignalTime = time[i];
            lastBuyBar = i;
           }
        }
     }

   //--- Sell signal
   if(IsSellSignal(i))
     {
      if(i - lastSellBar >= MinSignalGap &&
         (lastSellSignalTime == 0 || time[i] - lastSellSignalTime > MinSignalGap * PeriodSeconds()))
        {
         double arrowY = high[i] + SignalArrowOffset * _Point;
         string objName = objPrefix + "sell_" + IntegerToString(i);

         ObjectDelete(0, objName);

         if(ObjectCreate(0, objName, OBJ_ARROW, 0, time[i], arrowY))
           {
            ObjectSetInteger(0, objName, OBJPROP_ARROWCODE, 234);
            ObjectSetInteger(0, objName, OBJPROP_COLOR, clrRed);
            ObjectSetInteger(0, objName, OBJPROP_WIDTH, 2);
            ObjectSetInteger(0, objName, OBJPROP_ANCHOR, ANCHOR_BOTTOM);
            ObjectSetInteger(0, objName, OBJPROP_BACK, false);
            ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false);
            ObjectSetInteger(0, objName, OBJPROP_HIDDEN, true);

            sellSignalBuffer[i] = high[i] + SignalArrowOffset * _Point;
            lastSellSignalTime = time[i];
            lastSellBar = i;
           }
        }
     }
  }

//+------------------------------------------------------------------+
//|  Update flow arrows, shock, and regime shift markers             |
//+------------------------------------------------------------------+
void UpdateMarkers(int i)
  {
   //--- Flow arrows
   if(i > 0 && entropyBuffer[i] != EMPTY_VALUE && entropyBuffer[i-1] != EMPTY_VALUE)
     {
      double delta = entropyBuffer[i] - entropyBuffer[i-1];
      if(delta > 0.03)
        {
         flowBuffer[i] = 1.05;
         flowColors[i] = 0;
        }
      else
         if(delta < -0.03)
           {
            flowBuffer[i] = -0.05;
            flowColors[i] = 1;
           }
         else
            flowBuffer[i] = EMPTY_VALUE;
     }

   //--- Information shock
   if(i > 0 && entropyBuffer[i] != EMPTY_VALUE && entropyBuffer[i-1] != EMPTY_VALUE)
     {
      if(entropyBuffer[i] > entropyBuffer[i-1] * 1.25)
         shockBuffer[i] = 1.1;
      else
         shockBuffer[i] = EMPTY_VALUE;
     }

   //--- Regime shifts
   if(i > 0 && regime[i] != -1 && regime[i-1] != -1 && regime[i] != regime[i-1])
      regimeShiftBuffer[i] = 0.9;
   else
      regimeShiftBuffer[i] = EMPTY_VALUE;
  }

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

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

//+------------------------------------------------------------------+
//|  Calculate smoothed entropy                                      |
//+------------------------------------------------------------------+
void CalculateSmoothedEntropy(int i)
  {
   if(i < SmoothingPeriod)
     {
      smoothBuffer[i] = EMPTY_VALUE;
      return;
     }

   double sum = 0.0;
   int cnt = 0;
   for(int j = i - SmoothingPeriod + 1; j <= i; j++)
     {
      if(entropyBuffer[j] != EMPTY_VALUE)
        {
         sum += entropyBuffer[j];
         cnt++;
        }
     }
   smoothBuffer[i] = (cnt > 0) ? sum / cnt : EMPTY_VALUE;
  }

//+------------------------------------------------------------------+
//|  Update regime label                                             |
//+------------------------------------------------------------------+
void UpdateRegimeLabel(const datetime &time[], int rates_total)
  {
   string labelText = "";
   color labelColor = clrNONE;
   double lastEntropy = entropyBuffer[rates_total-1];
   double lastFast = fastEntropyBuffer[rates_total-1];
   double lastSlow = slowEntropyBuffer[rates_total-1];
   double lastDiv = divergenceBuffer[rates_total-1];
   int lastCompress = (rates_total-1 >= 0) ? compressionState[rates_total-1] : 0;

   if(lastEntropy != EMPTY_VALUE)
     {
      if(lastEntropy < 0.35)
         labelText = "TREND MODE  (" + DoubleToString(lastEntropy, 2) + ")";
      else
         if(lastEntropy < 0.65)
            labelText = "TRANSITION MODE  (" + DoubleToString(lastEntropy, 2) + ")";
         else
            labelText = "CHAOTIC MODE  (" + DoubleToString(lastEntropy, 2) + ")";

      if(lastCompress == -1)
         labelText += " | COMPRESSING";
      else
         if(lastCompress == 1)
            labelText += " | DECOMPRESSING";

      if(lastDiv != EMPTY_VALUE)
        {
         labelText += " | Div: " + DoubleToString(lastDiv, 2);
         if(lastFast != EMPTY_VALUE && lastSlow != EMPTY_VALUE)
           {
            if(lastFast > lastSlow)
               labelText += " (Bull)";
            else
               labelText += " (Bear)";
           }
        }

      labelColor = (lastEntropy < 0.35) ? clrGreen : (lastEntropy < 0.65) ? clrYellow : clrRed;
     }
   else
     {
      labelText = "MODE: WAITING FOR DATA";
      labelColor = clrGray;
     }

   ObjectCreate(0, objPrefix + "regimeLabel", OBJ_LABEL, 0, 0, 0);
   ObjectSetInteger(0, objPrefix + "regimeLabel", OBJPROP_XDISTANCE, 10);
   ObjectSetInteger(0, objPrefix + "regimeLabel", OBJPROP_YDISTANCE, 10);
   ObjectSetInteger(0, objPrefix + "regimeLabel", OBJPROP_CORNER, 0);
   ObjectSetString(0, objPrefix + "regimeLabel", OBJPROP_TEXT, labelText);
   ObjectSetInteger(0, objPrefix + "regimeLabel", OBJPROP_COLOR, labelColor);
   ObjectSetInteger(0, objPrefix + "regimeLabel", OBJPROP_FONTSIZE, 11);
   ObjectSetInteger(0, objPrefix + "regimeLabel", OBJPROP_BACK, false);
  }
//+------------------------------------------------------------------+

В этой части кода основное внимание уделяется обработке исходных показаний энтропии, чтобы сделать их более пригодными для практического использования и удобными для визуальной интерпретации. Функция CalculateSmoothedEntropy применяет к базовым значениям энтропии простое скользящее среднее за заданный период сглаживания (SmoothingPeriod), что позволяет уменьшить шум и краткосрочные колебания. Благодаря усреднению только достоверных значений энтропии за данный период обеспечивается точное отражение сглаженной линией основного тренда рыночной неопределённости. Это помогает трейдерам лучше выявлять устойчивые режимы или сдвиги, а не реагировать на каждое незначительное колебание исходной энтропии.

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


Демонстрация индикатора

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



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


Заключение

В данной работе абстрактная идея о том, что «рынки в той или иной степени носят случайный характер», превращается в конкретную реализуемую структуру и практическую реализацию для MQL5. Благодаря дискретизации баров, расчету нормированной энтропии Шеннона и применению четко определенных пороговых значений (например, энтропия < 0,35 → TREND, 0,35–0,65 → TRANSITION, > 0,65 → CHAOTIC) этот индикатор дает детерминированные метки режимов, а не расплывчатые впечатления. Дополнительные слои — быстрая и медленная энтропия, импульс энтропии, дивергенция и локальное сжатие/расширение — помогают выявлять структурное накопление, пробои и внезапные информационные шоки.

На практике, ознакомившись с этим индикатором и научившись им пользоваться, вы сможете:

  • обозначать режим рынка (TREND / TRANSITION / CHAOTIC) и использовать его в качестве торгового фильтра;
  • распознавать сжатие (низкую энтропию) и расширение (рост энтропии) как признаки подготовки движения и слома структуры;
  • генерировать и прореживать сигналы на покупку/продажу с помощью пересечений быстрой и медленной энтропии, а также проверок импульса и дивергенции;
  • выявлять информационные шоки и смены режимов для контроля рисков или автоматической приостановки сделок.

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

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

Прикрепленные файлы |
Entropy_IT.mq5 (28.28 KB)
От начального к среднему уровню: Технические индикаторы (II) От начального к среднему уровню: Технические индикаторы (II)
В этой статье мы покажем, как создать индикатор на MQL5, который рисует несколько скользящих средних на одном графике, сокращая объём дублирующегося кода. Используются iMA, буферы индикатора, CopyBuffer, PlotIndexSetInteger/String и постоянная структура, объединяющая периоды, методы и цвета. Размеры indicatorbuffers и indicatorplots определяются на основе Averange.Size(). Такой подход упрощает сопровождение и позволяет добавлять или удалять скользящие средние, изменяя только один список.
Нейронная сеть на практике: Градиентный спуск Нейронная сеть на практике: Градиентный спуск
В этой статье я постараюсь как можно проще и нагляднее изложить один из самых спорных вопросов, возникающих при обсуждении нейронных сетей: как найти наилучшую возможную точку или минимальную функцию потерь. Я покажу разницу между линейной регрессией и градиентным спуском. Оба случая довольно просты и служат примером того, что не всегда путь, который кажется очевидным, действительно является лучшим.
Автоматическое принятие и отклонение изменений ML-советника в MIDAS/MQL5: защита от переобучения через проверку устойчивости Автоматическое принятие и отклонение изменений ML-советника в MIDAS/MQL5: защита от переобучения через проверку устойчивости
В статье рассматривается Robustness Guard для отбора изменений торговой ML-модели в MIDAS. Кандидаты сравниваются с зафиксированной базовой версией на нескольких временных блоках и принимаются только при улучшении целевой оценки без нарушения ограничений по Profit Factor, просадке, числу сделок, стабильности месяцев и концентрации по инструментам. Механизм перенесён в MQL5 и дополнен self-test и shadow-режимом.
От начального к среднему уровню: Технические индикаторы (I) От начального к среднему уровню: Технические индикаторы (I)
В этой статье мы рассмотрим основные принципы использования технических индикаторов, встроенных в MetaTrader 5 и поддерживаемых этой платформой. Знание и понимание подобных индикаторов может значительно упростить, ускорить и сделать более эффективной реализацию решения, поскольку вам не придется беспокоиться о необходимых вычислениях. Платформа сама выполняет их за нас.