XMC Hurst Regime Module
Сообщите нам, если считаете, что материал размещён без разрешения.
Сообщить о материале
Обращение по товару «xmc_hurstregime.mq5» отправится на рассмотрение. Укажите контакт для ответа и опишите причину.
О программе
XMC Hurst Regime Module — это библиотека MQL5 (include-файл .mqh) для расчёта показателя Хёрста и классификации рыночных режимов. Модуль реализует классический анализ R/S (Rescaled Range) с линейным шагом размеров отрезков и логарифмической регрессией для оценки показателя Хёрста в диапазоне [0, 1].
Класс CHurstRegimeFilter предоставляет готовое решение для интеграции в советники: автоматическое обнаружение новых баров, кэширование ценовых данных, EMA-сглаживание и классификация режима — тренд, средняя реверсия или случайное блуждание. Поддерживается работа на нескольких символах и таймфреймах одновременно.
Статистические функции доступны как для текущего состояния через класс, так и для произвольных исторических баров через свободные функции. Модуль не содержит торговой логики — он только предоставляет данные о режиме рынка.
Поиск по коду файла
#property version "2.10"
#property strict
#ifndef XMC_HURST_REGIME_MQH
#define XMC_HURST_REGIME_MQH
enum ENUM_HURST_REGIME
{
HURST_REGIME_TRENDING = 1, // Persistent / Trending
HURST_REGIME_RANDOM_WALK = 0, // Random Walk / Indeterminate
HURST_REGIME_MEAN_REVERT = -1 // Anti-Persistent / Mean Reverting
};
struct HurstConfig
{
string symbol; // "" = current chart symbol
ENUM_TIMEFRAMES timeframe; // PERIOD_CURRENT = current TF
int lookback; // Total lookback bars (min 32)
int min_chunk; // Smallest R/S chunk size (min 2)
int chunk_step; // Linear step between chunk sizes
int smoothing_period; // EMA period (0 = raw, no smoothing)
double trend_threshold; // H >= this -> TRENDING
double reversion_threshold; // H <= this -> MEAN_REVERT
ENUM_APPLIED_PRICE applied_price; // Price type for R/S input
};
#define MAX_HURST_BARS 1024
string HurstResolveSymbol(const string sym)
{
if(sym == "" || sym == NULL)
return Symbol();
return sym;
}
double HurstGetPrice(const string sym,
const ENUM_TIMEFRAMES tf,
const int bar,
const ENUM_APPLIED_PRICE applied_price)
{
switch(applied_price)
{
case PRICE_OPEN:
return iOpen(sym, tf, bar);
case PRICE_HIGH:
return iHigh(sym, tf, bar);
case PRICE_LOW:
return iLow(sym, tf, bar);
case PRICE_MEDIAN:
return (iHigh(sym, tf, bar) +
iLow(sym, tf, bar)) / 2.0;
case PRICE_TYPICAL:
return (iHigh(sym, tf, bar) +
iLow(sym, tf, bar) +
iClose(sym, tf, bar)) / 3.0;
case PRICE_WEIGHTED:
return (iHigh(sym, tf, bar) +
iLow(sym, tf, bar) +
2.0 * iClose(sym, tf, bar)) / 4.0;
case PRICE_CLOSE:
default:
return iClose(sym, tf, bar);
}
}
double HurstCalcRS(const string sym,
const ENUM_TIMEFRAMES tf,
const int start_shift,
const int size,
const ENUM_APPLIED_PRICE applied_price)
{
if(size < 2)
return 0.0;
double sum = 0.0;
for(int i = 0; i < size; i++)
sum += HurstGetPrice(sym, tf, start_shift - i, applied_price);
double mean = sum / size;
double sq_sum = 0.0;
for(int i = 0; i < size; i++)
{
double diff = HurstGetPrice(sym, tf, start_shift - i, applied_price) - mean;
sq_sum += diff * diff;
}
double std_dev = MathSqrt(sq_sum / size);
if(std_dev <= 1.0e-12)
return 0.0;
double cumulative = 0.0;
double cum_min = 0.0;
double cum_max = 0.0;
for(int i = 0; i < size; i++)
{
cumulative += HurstGetPrice(sym, tf, start_shift - i, applied_price) - mean;
if(cumulative < cum_min)
cum_min = cumulative;
if(cumulative > cum_max)
cum_max = cumulative;
}
double range = cum_max - cum_min;
if(range <= 0.0)
return 0.0;
return range / std_dev;
}
double GetHurstRaw(const string sym,
const ENUM_TIMEFRAMES tf,
const int bar,
const HurstConfig &cfg)
{
string symbol = HurstResolveSymbol(sym);
int lookback = MathMax(32, cfg.lookback);
if(iBars(symbol, tf) < lookback + bar + 1)
return -1.0;
int step = MathMax(1, cfg.chunk_step);
int min_c = MathMax(2, cfg.min_chunk);
double log_n[64];
double log_rs[64];
ArrayInitialize(log_n, 0.0);
ArrayInitialize(log_rs, 0.0);
int point_count = 0;
/*
Linear chunk stepping: 8, 14, 20, 26, 32, 38, ...
(faithful to the original MQL5 specification)
*/
for(int chunk_size = min_c;
chunk_size <= lookback && point_count < 64;
chunk_size += step)
{
int complete_chunks = lookback / chunk_size;
if(complete_chunks < 1)
continue;
double rs_sum = 0.0;
int valid_count = 0;
/*
Prices are chronological: oldest -> newest.
MQL4 shift increases toward older bars, so
the oldest part of the lookback has the largest shift.
*/
int oldest_shift = bar + lookback - 1;
for(int c = 0; c < complete_chunks; c++)
{
int start_shift = oldest_shift - c * chunk_size;
if(start_shift < bar)
break;
double rs = HurstCalcRS(symbol,
tf,
start_shift,
chunk_size,
cfg.applied_price);
if(rs > 0.0 && MathIsValidNumber(rs))
{
rs_sum += rs;
valid_count++;
}
}
if(valid_count > 0)
{
double avg_rs = rs_sum / valid_count;
if(avg_rs > 0.0)
{
log_n[point_count] = MathLog((double)chunk_size);
log_rs[point_count] = MathLog(avg_rs);
point_count++;
}
}
}
if(point_count < 2)
return -1.0;
double sum_x = 0.0;
double sum_y = 0.0;
double sum_xy = 0.0;
double sum_x2 = 0.0;
double n = (double)point_count;
for(int i = 0; i < point_count; i++)
{
sum_x += log_n[i];
sum_y += log_rs[i];
sum_xy += log_n[i] * log_rs[i];
sum_x2 += log_n[i] * log_n[i];
}
double denominator = n * sum_x2 - sum_x * sum_x;
if(MathAbs(denominator) <= 1.0e-12)
return -1.0;
double H = (n * sum_xy - sum_x * sum_y) / denominator;
if(H < 0.0)
H = 0.0;
else if(H > 1.0)
H = 1.0;
return H;
}
double HurstSmoothEMA(double current_h, double prev_smoothed, int period)
{
if(period <= 1)
return current_h;
double alpha = 2.0 / ((double)period + 1.0);
return alpha * current_h + (1.0 - alpha) * prev_smoothed;
}
ENUM_HURST_REGIME GetHurstRegime(double h, const HurstConfig &cfg)
{
if(h < 0.0 || !MathIsValidNumber(h))
return HURST_REGIME_RANDOM_WALK;
if(h >= cfg.trend_threshold)
return HURST_REGIME_TRENDING;
if(h <= cfg.reversion_threshold)
return HURST_REGIME_MEAN_REVERT;
return HURST_REGIME_RANDOM_WALK;
}
string HurstRegimeToString(ENUM_HURST_REGIME regime)
{
switch(regime)
{
case HURST_REGIME_TRENDING: return "TRENDING";
case HURST_REGIME_RANDOM_WALK: return "RANDOM_WALK";
case HURST_REGIME_MEAN_REVERT: return "MEAN_REVERTING";
default: return "UNKNOWN";
}
}
double GetHurstForBar(const string sym,
const ENUM_TIMEFRAMES tf,
const int bar,
const HurstConfig &cfg,
double prev_smoothed)
{
double raw_h = GetHurstRaw(sym, tf, bar, cfg);
if(raw_h < 0.0 || !MathIsValidNumber(raw_h))
return raw_h;
if(cfg.smoothing_period > 0)
return HurstSmoothEMA(raw_h, prev_smoothed, cfg.smoothing_period);
return raw_h;
}
class CHurstRegimeFilter
{
private:
HurstConfig m_cfg;
string m_symbol;
ENUM_TIMEFRAMES m_timeframe;
double m_price_cache[MAX_HURST_BARS];
int m_cache_count; // number of valid entries
double m_prev_smoothed;
double m_hurst; // current smoothed (or raw) H
double m_raw_hurst; // current raw H
ENUM_HURST_REGIME m_regime;
datetime m_last_bar; // new-bar cache
bool m_initialized;
bool m_valid; // false when history insufficient
string Sym() const
{
if(m_symbol != "" && m_symbol != NULL)
return m_symbol;
return Symbol();
}
double CalculateRaw(const int bar)
{
return GetHurstRaw(Sym(), m_timeframe, bar, m_cfg);
}
bool LoadPriceCache(int max_shift)
{
if(max_shift >= MAX_HURST_BARS)
return false;
if(iBars(Sym(), m_timeframe) < max_shift + 1)
return false;
for(int i = 0; i <= max_shift; i++)
{
double price = HurstGetPrice(Sym(), m_timeframe, i,
m_cfg.applied_price);
if(price <= 0.0 || !MathIsValidNumber(price))
{
m_cache_count = 0;
return false;
}
m_price_cache[i] = price;
}
m_cache_count = max_shift + 1;
return true;
}
double CalcRS_Cached(int start_shift, int size)
{
if(size < 2)
return 0.0;
if(start_shift >= m_cache_count)
return 0.0;
if(start_shift - size + 1 < 0)
return 0.0;
double sum = 0.0;
for(int i = 0; i < size; i++)
sum += m_price_cache[start_shift - i];
double mean = sum / size;
double sq_sum = 0.0;
for(int i = 0; i < size; i++)
{
double diff = m_price_cache[start_shift - i] - mean;
sq_sum += diff * diff;
}
double std_dev = MathSqrt(sq_sum / size);
if(std_dev <= 1.0e-12)
return 0.0;
double cumulative = 0.0;
double cum_min = 0.0;
double cum_max = 0.0;
for(int i = 0; i < size; i++)
{
cumulative += m_price_cache[start_shift - i] - mean;
if(cumulative < cum_min)
cum_min = cumulative;
if(cumulative > cum_max)
cum_max = cumulative;
}
double range = cum_max - cum_min;
if(range <= 0.0)
return 0.0;
return range / std_dev;
}
double CalculateRawCached(int bar)
{
int lookback = MathMax(32, m_cfg.lookback);
if(bar + lookback > m_cache_count)
return -1.0;
int step = MathMax(1, m_cfg.chunk_step);
int min_c = MathMax(2, m_cfg.min_chunk);
double log_n[64];
double log_rs[64];
ArrayInitialize(log_n, 0.0);
ArrayInitialize(log_rs, 0.0);
int point_count = 0;
int oldest_shift = bar + lookback - 1;
for(int chunk_size = min_c;
chunk_size <= lookback && point_count < 64;
chunk_size += step)
{
int complete_chunks = lookback / chunk_size;
if(complete_chunks < 1)
continue;
double rs_sum = 0.0;
int valid_count = 0;
for(int c = 0; c < complete_chunks; c++)
{
int start_shift = oldest_shift - c * chunk_size;
if(start_shift < bar)
break;
double rs = CalcRS_Cached(start_shift, chunk_size);
if(rs > 0.0 && MathIsValidNumber(rs))
{
rs_sum += rs;
valid_count++;
}
}
if(valid_count > 0)
{
double avg_rs = rs_sum / valid_count;
if(avg_rs > 0.0)
{
log_n[point_count] = MathLog((double)chunk_size);
log_rs[point_count] = MathLog(avg_rs);
point_count++;
}
}
}
if(point_count < 2)Показано первые 50% кода (символов: 14000)
Открыть по тарифу
Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.
Разовая покупка файла
На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.
Зачем нужен email? После подтверждения оплаты файл сохранится в кабинете на этот email. Если аккаунта ещё нет, мы создадим его и пришлём ссылку для задания пароля. Если аккаунт уже есть, покупка добавится в него. Укажите адрес, к которому у вас есть доступ.
Чтобы оформить заказ, введите email и перейдите к оплате.