Добавлен динамический режим в 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>
12 KiB
Dynamic Equilibrium Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: После пробоя BOS/MSS Equilibrium динамически обновляется по новым экстремумам цены до появления следующего BOS/MSS.
Architecture: Вся логика трекинга внутри CEquilibrium. Добавляются 2 параметра (price_high, price_low) в Calculate(). Новый динамический режим (m_dynamic_mode) активируется при BOS/MSS, трекает running extreme, пересчитывает буферы с backfill. Деактивируется при следующем BOS/MSS.
Tech Stack: MQL5, MetaEditor compiler (validate_mql_code)
Design doc: docs/plans/2026-03-04-dynamic-equilibrium-design.md
Task 1: Добавить новые поля в CEquilibrium
Files:
- Modify:
CEquilibrium.mqh:50-65(private секция, после m_fixed_disc2)
Step 1: Добавить поля динамического режима
В CEquilibrium.mqh, после строки 64 (m_fixed_disc2), добавить:
//--- Динамический режим после пробоя 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 индекс бара начала трекинга
Step 2: Инициализация в конструкторе
В CEquilibrium::CEquilibrium() (строка ~71-84), перед закрывающей }, добавить:
m_dynamic_mode = false;
m_break_dir = 0;
m_track_high = EMPTY_VALUE;
m_track_low = EMPTY_VALUE;
m_break_bar = -1;
Step 3: Инициализация в Init()
В CEquilibrium::Init() (строка ~96-112), перед return true;, добавить:
m_dynamic_mode = false;
m_break_dir = 0;
m_track_high = EMPTY_VALUE;
m_track_low = EMPTY_VALUE;
m_break_bar = -1;
Step 4: Сброс в FullReset()
В CEquilibrium::FullReset() (строка ~117-133), перед закрывающей }, добавить:
m_dynamic_mode = false;
m_break_dir = 0;
m_track_high = EMPTY_VALUE;
m_track_low = EMPTY_VALUE;
m_break_bar = -1;
Step 5: Обновить AdjustShift()
Заменить AdjustShift (строка 38):
void AdjustShift(int shift) { if(m_bar_eq_prev >= 0) m_bar_eq_prev += shift; if(m_break_bar >= 0) m_break_bar += shift; }
Step 6: Компиляция
Run: validate_mql_code(mq_file_path="<full_path>/Ind_Aleks_ICT_Entry_V2_TS_Indie.mq5")
Expected: success: true (поля добавлены, но ещё не используются — всё компилируется)
Step 7: Commit
git add CEquilibrium.mqh
git commit -m "feat(CEquilibrium): add dynamic mode fields for post-BOS/MSS tracking"
Task 2: Изменить сигнатуру Calculate() и обновить вызов
Files:
- Modify:
CEquilibrium.mqh:25-29(объявление Calculate) - Modify:
CEquilibrium.mqh:161-165(определение Calculate) - Modify:
CSwingDetector.mqh:492-493(вызов equilibrium.Calculate)
Step 1: Обновить объявление Calculate()
В CEquilibrium.mqh, строка 25-29. Заменить:
void Calculate(int bar, const SStructureSwingState &state,
double &buf_equilibrium[],
double &buf_premium2[],
double &buf_discount2[],
int rates_total);
На:
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);
Step 2: Обновить определение Calculate()
В CEquilibrium.mqh, строка 161-165. Заменить:
void CEquilibrium::Calculate(int bar, const SStructureSwingState &state,
double &buf_equilibrium[],
double &buf_premium2[],
double &buf_discount2[],
int rates_total)
На:
void CEquilibrium::Calculate(int bar, const SStructureSwingState &state,
double price_high, double price_low,
double &buf_equilibrium[],
double &buf_premium2[],
double &buf_discount2[],
int rates_total)
Step 3: Обновить вызов в CSwingDetector.mqh
В CSwingDetector.mqh, строка 493. Заменить:
equilibrium.Calculate(bar, m_str, buf_equilibrium, buf_premium2, buf_discount2, rates_total);
На:
equilibrium.Calculate(bar, m_str, high[bar], low[bar], buf_equilibrium, buf_premium2, buf_discount2, rates_total);
Step 4: Компиляция
Run: validate_mql_code(mq_file_path="<full_path>/Ind_Aleks_ICT_Entry_V2_TS_Indie.mq5")
Expected: success: true (сигнатура обновлена, новые параметры передаются но не используются)
Step 5: Commit
git add CEquilibrium.mqh CSwingDetector.mqh
git commit -m "refactor(CEquilibrium): add price_high/price_low params to Calculate()"
Task 3: Реализовать логику динамического режима
Files:
- Modify:
CEquilibrium.mqh:161-308(метод Calculate)
Step 1: Добавить динамическую логику в Calculate()
В метод CEquilibrium::Calculate(), ПОСЛЕ блока геттеров (строка ~215, перед комментарием //=== Стабильные значения для буферов) вставить:
//=== Динамический режим: трекинг после BOS/MSS ===
bool is_bos_mss = state.bos_up || state.bos_down || state.mss_up || state.mss_down;
if(is_bos_mss)
{
//--- Новый BOS/MSS → начать (или перезапустить) динамический режим
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;
}
}
else if(m_dynamic_mode)
{
//--- Обновление трекинга (без 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);
}
Step 2: Добавить динамический пересчёт геттеров
Сразу после блока из Step 1, ПЕРЕД //=== Стабильные значения для буферов, добавить:
//=== Динамический пересчёт геттеров в dynamic mode ===
if(m_dynamic_mode)
{
if(m_break_dir == 1 && state.in_low != EMPTY_VALUE && m_track_high != EMPTY_VALUE)
{
double dyn_range = m_track_high - state.in_low;
if(dyn_range > 0.0)
{
m_discount = m_track_high - (pre_dis_cal * dyn_range);
m_premium = EMPTY_VALUE;
if(m_eq_con)
{
m_discount2 = m_track_high - (pre_dis_cal2 * dyn_range);
m_premium2 = EMPTY_VALUE;
}
}
}
else if(m_break_dir == -1 && state.in_high != EMPTY_VALUE && m_track_low != EMPTY_VALUE)
{
double dyn_range = state.in_high - m_track_low;
if(dyn_range > 0.0)
{
m_premium = m_track_low + (pre_dis_cal * dyn_range);
m_discount = EMPTY_VALUE;
if(m_eq_con)
{
m_premium2 = m_track_low + (pre_dis_cal2 * dyn_range);
m_discount2 = EMPTY_VALUE;
}
}
}
}
Step 3: Добавить динамическую отрисовку буферов
В блок //=== Отрисовка === (строка ~259), ПОСЛЕ текущей логики записи буферов (строка ~304, buf_discount2[bar] = m_fixed_disc2;), добавить блок перезаписи буферов в динамическом режиме:
//=== Динамическая отрисовка: перезаписать буфер, если dynamic mode активен ===
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 dyn_range = m_track_high - state.in_low;
if(dyn_range > 0.0)
{
dyn_eq = m_track_high - (pre_dis_cal * dyn_range);
if(m_eq_con)
dyn_disc2 = m_track_high - (pre_dis_cal2 * dyn_range);
}
}
else if(m_break_dir == -1 && state.in_high != EMPTY_VALUE && m_track_low != EMPTY_VALUE)
{
double dyn_range = state.in_high - m_track_low;
if(dyn_range > 0.0)
{
dyn_eq = m_track_low + (pre_dis_cal * dyn_range);
if(m_eq_con)
dyn_prem2 = m_track_low + (pre_dis_cal2 * dyn_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;
buf_premium2[i] = (dyn_prem2 != EMPTY_VALUE) ? dyn_prem2 : EMPTY_VALUE;
buf_discount2[i] = (dyn_disc2 != EMPTY_VALUE) ? dyn_disc2 : EMPTY_VALUE;
}
}
}
Step 4: Компиляция
Run: validate_mql_code(mq_file_path="<full_path>/Ind_Aleks_ICT_Entry_V2_TS_Indie.mq5")
Expected: success: true
Step 5: Commit
git add CEquilibrium.mqh
git commit -m "feat(CEquilibrium): implement dynamic equilibrium tracking after BOS/MSS"
Task 4: Визуальная проверка на графике
Step 1: Открыть MetaTrader 5, наложить индикатор на график
Проверить визуально:
- До пробоя BOS/MSS — Equilibrium рисуется как раньше (без изменений)
- После пробоя BOS Up — линия Equilibrium динамически сдвигается вверх при новых максимумах
- После пробоя BOS Down — линия динамически сдвигается вниз при новых минимумах
- При появлении нового BOS/MSS — dynamic mode перезапускается с новыми уровнями
- Backfill корректный — вся линия от точки пробоя обновляется, а не только текущий бар
Step 2: Проверить в тестере стратегий
Запустить визуальный тестер на исторических данных, чтобы убедиться что:
AdjustShiftкорректно сдвигаетm_break_bar- Нет вылетов за границы буфера
- Линия не "улетает" на ноль
Step 3: Если всё ОК — финальный commit
git add -A
git commit -m "verified: dynamic equilibrium visual test passed"