Добавлен динамический режим в CEquilibrium: после пробоя BOS/MSS линия Equilibrium автоматически обновляется по новым экстремумам цены (running max/min), пока не появится следующий BOS/MSS. Изменения: - Новые поля: m_dynamic_mode, m_break_dir, m_track_high/low, m_break_bar - Calculate() принимает price_high/price_low для трекинга - Backfill от бара пробоя до текущего при каждом обновлении экстремума - AdjustShift корректирует m_break_bar при новом баре (AS_SERIES) - Геттеры также обновляются в dynamic mode - CSwingDetector передаёт high[bar]/low[bar] в Calculate() Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6.2 KiB
6.2 KiB
Dynamic Equilibrium After BOS/MSS Breakout
Дата: 2026-03-04 Модуль: CEquilibrium.mqh Статус: Утверждён
Проблема
После пробоя BOS/MSS уровня цена продолжает двигаться, но до формирования нового BOS/MSS линия Equilibrium остаётся на старых подтверждённых уровнях (in_high/in_low). Equilibrium становится неактуальным на время между пробоями.
Решение
Добавить динамический режим в CEquilibrium: после BOS/MSS пробоя отслеживать экстремум цены по направлению пробоя и пересчитывать Equilibrium в реальном времени.
Подход
Вся логика внутри CEquilibrium (Подход 1). Добавляются 2 параметра price_high, price_low в Calculate().
Новые поля CEquilibrium
//--- Динамический режим после пробоя BOS/MSS
bool m_dynamic_mode; // Активен ли динамический режим
int m_break_dir; // Направление пробоя: 1=вверх, -1=вниз
double m_track_high; // Running max(high[]) с момента пробоя
double m_track_low; // Running min(low[]) с момента пробоя
int m_break_bar; // AS_SERIES индекс бара начала трекинга
Изменение сигнатуры Calculate()
void Calculate(int bar, const SStructureSwingState &state,
double price_high, double price_low, // НОВЫЕ параметры
double &buf_equilibrium[],
double &buf_premium2[],
double &buf_discount2[],
int rates_total);
Логика динамического режима
Активация (при BOS/MSS)
bool is_bos_mss = state.bos_up || state.bos_down || state.mss_up || state.mss_down;
if(is_bos_mss)
{
//--- Предыдущий dynamic mode автоматически завершается
m_dynamic_mode = true;
m_break_bar = bar;
if(state.bos_up || state.mss_up)
{
m_break_dir = 1;
m_track_high = price_high;
m_track_low = EMPTY_VALUE;
}
else
{
m_break_dir = -1;
m_track_low = price_low;
m_track_high = EMPTY_VALUE;
}
}
Обновление трекинга (каждый бар в dynamic mode)
if(m_dynamic_mode && !is_bos_mss)
{
if(m_break_dir == 1)
m_track_high = MathMax(m_track_high, price_high);
else
m_track_low = MathMin(m_track_low, price_low);
}
Расчёт динамического Equilibrium (буферы)
if(m_dynamic_mode)
{
double dyn_eq = EMPTY_VALUE;
double dyn_prem2 = EMPTY_VALUE;
double dyn_disc2 = EMPTY_VALUE;
if(m_break_dir == 1 && state.in_low != EMPTY_VALUE && m_track_high != EMPTY_VALUE)
{
double range = m_track_high - state.in_low;
if(range > 0.0)
{
dyn_eq = m_track_high - (pre_dis_cal * range); // Discount
if(m_eq_con)
dyn_disc2 = m_track_high - (pre_dis_cal2 * range);
}
}
else if(m_break_dir == -1 && state.in_high != EMPTY_VALUE && m_track_low != EMPTY_VALUE)
{
double range = state.in_high - m_track_low;
if(range > 0.0)
{
dyn_eq = m_track_low + (pre_dis_cal * range); // Premium
if(m_eq_con)
dyn_prem2 = m_track_low + (pre_dis_cal2 * range);
}
}
//--- Backfill от бара пробоя до текущего
if(dyn_eq != EMPTY_VALUE)
{
int fill_start = MathMin(m_break_bar, rates_total - 1);
for(int i = fill_start; i >= bar && i >= 0; i--)
{
buf_equilibrium[i] = dyn_eq;
if(dyn_prem2 != EMPTY_VALUE) buf_premium2[i] = dyn_prem2;
if(dyn_disc2 != EMPTY_VALUE) buf_discount2[i] = dyn_disc2;
}
}
}
AdjustShift — корректировка при новом баре
void AdjustShift(int shift)
{
if(m_bar_eq_prev >= 0) m_bar_eq_prev += shift;
if(m_break_bar >= 0) m_break_bar += shift;
}
Деактивация
Dynamic mode завершается только при следующем BOS/MSS. На том же баре:
- Старый dynamic mode выключается
- Обычная логика (
structural_event = ch_in_h || ch_in_l) обновляетm_fixed_eq - Новый dynamic mode включается (если это BOS/MSS)
Простое подтверждение свинга (ch_in_h/ch_in_l без BOS/MSS) НЕ завершает dynamic mode.
Геттеры (для Entry сигналов)
В dynamic mode геттеры тоже обновляются:
if(m_dynamic_mode)
{
if(m_break_dir == 1 && state.in_low != EMPTY_VALUE && m_track_high != EMPTY_VALUE)
{
double range = m_track_high - state.in_low;
if(range > 0.0)
{
m_discount = m_track_high - (pre_dis_cal * range);
if(m_eq_con) m_discount2 = m_track_high - (pre_dis_cal2 * range);
}
}
else if(m_break_dir == -1 && state.in_high != EMPTY_VALUE && m_track_low != EMPTY_VALUE)
{
double range = state.in_high - m_track_low;
if(range > 0.0)
{
m_premium = m_track_low + (pre_dis_cal * range);
if(m_eq_con) m_premium2 = m_track_low + (pre_dis_cal2 * range);
}
}
}
Что НЕ меняется
- Обычная логика
structural_event(ch_in_h/ch_in_l) — продолжает работать m_fixed_eq— обновляется как раньше, но в dynamic mode буфер перезаписываетсяFullReset()— сбрасывает dynamic state- Логика
IsInDiscountZone()/IsInPremiumZone()— без изменений
Затронутые файлы
| Файл | Изменения |
|---|---|
CEquilibrium.mqh |
Новые поля, изменённый Calculate(), AdjustShift(), FullReset(), Init() |
CSwingDetector.mqh |
Обновить вызов equilibrium->Calculate() — добавить high[bar], low[bar] |