2026-02-16 21:25:58 +03:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| CEquilibrium.mqh |
|
|
|
|
|
//| Модуль расчёта Premium/Discount зон (Equilibrium) |
|
|
|
|
|
//| для ICT Entry индикатора |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
#ifndef CEQUILIBRIUM_MQH
|
|
|
|
|
#define CEQUILIBRIUM_MQH
|
|
|
|
|
|
|
|
|
|
//--- Требует SStructureSwingState из CSwingDetector.mqh
|
|
|
|
|
//--- Подключать ПОСЛЕ CSwingDetector.mqh
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Класс CEquilibrium — расчёт Premium/Discount зон |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
class CEquilibrium
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
CEquilibrium();
|
|
|
|
|
~CEquilibrium();
|
|
|
|
|
|
|
|
|
|
//--- Инициализация
|
|
|
|
|
bool Init(int pre_dis, int pre_dis2, bool eq_con);
|
|
|
|
|
|
|
|
|
|
//--- Расчёт на каждом баре (вызывается из цикла CSwingDetector)
|
|
|
|
|
void Calculate(int bar, const SStructureSwingState &state,
|
2026-03-04 13:51:14 +03:00
|
|
|
double price_high, double price_low,
|
2026-02-17 15:27:50 +03:00
|
|
|
double &buf_equilibrium[],
|
|
|
|
|
double &buf_premium2[],
|
|
|
|
|
double &buf_discount2[],
|
|
|
|
|
int rates_total);
|
2026-02-16 21:25:58 +03:00
|
|
|
|
|
|
|
|
//--- Полный сброс при prev_calculated == 0
|
2026-02-17 15:27:50 +03:00
|
|
|
void FullReset(double &buf_equilibrium[],
|
|
|
|
|
double &buf_premium2[],
|
|
|
|
|
double &buf_discount2[],
|
|
|
|
|
int rates_total);
|
2026-02-16 21:25:58 +03:00
|
|
|
|
2026-03-04 01:37:21 +03:00
|
|
|
//--- Корректировка AS_SERIES индекса при появлении нового бара
|
2026-03-04 13:51:14 +03:00
|
|
|
void AdjustShift(int shift) { if(m_bar_eq_prev >= 0) m_bar_eq_prev += shift; if(m_break_bar >= 0) m_break_bar += shift; }
|
2026-03-04 01:37:21 +03:00
|
|
|
|
2026-02-17 15:27:50 +03:00
|
|
|
//--- Геттеры для Entry условий
|
2026-02-16 21:25:58 +03:00
|
|
|
double GetPremium() const { return m_premium; }
|
|
|
|
|
double GetDiscount() const { return m_discount; }
|
|
|
|
|
double GetPremium2() const { return m_premium2; }
|
|
|
|
|
double GetDiscount2() const { return m_discount2; }
|
|
|
|
|
|
2026-02-17 15:27:50 +03:00
|
|
|
//--- Фильтры для Entry условий
|
|
|
|
|
bool IsInDiscountZone(double ifvg_bottom) const;
|
|
|
|
|
bool IsInPremiumZone(double ifvg_top) const;
|
|
|
|
|
|
2026-02-16 21:25:58 +03:00
|
|
|
private:
|
|
|
|
|
//--- Параметры
|
|
|
|
|
int m_pre_dis; // % для первого уровня (default 50)
|
|
|
|
|
int m_pre_dis2; // % для второго уровня (default 80)
|
|
|
|
|
bool m_eq_con; // Включить фильтрацию по зонам
|
|
|
|
|
|
2026-03-04 01:37:21 +03:00
|
|
|
//--- Состояние Premium/Discount (динамические значения для геттеров)
|
2026-02-16 21:25:58 +03:00
|
|
|
double m_premium;
|
|
|
|
|
double m_discount;
|
2026-02-17 15:27:50 +03:00
|
|
|
double m_premium2;
|
|
|
|
|
double m_discount2;
|
2026-03-04 01:37:21 +03:00
|
|
|
int m_bar_eq_prev; // Предыдущий bar_eq для контроля backfill
|
|
|
|
|
double m_fixed_eq; // Зафиксированный уровень для буфера Equilibrium
|
|
|
|
|
double m_fixed_prem2; // Зафиксированный уровень для буфера Premium2
|
|
|
|
|
double m_fixed_disc2; // Зафиксированный уровень для буфера Discount2
|
|
|
|
|
|
2026-03-04 13:51:14 +03:00
|
|
|
//--- Динамический режим после пробоя 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 индекс бара начала трекинга
|
|
|
|
|
|
2026-02-16 21:25:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Конструктор |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
CEquilibrium::CEquilibrium()
|
|
|
|
|
{
|
|
|
|
|
m_pre_dis = 50;
|
|
|
|
|
m_pre_dis2 = 80;
|
|
|
|
|
m_eq_con = false;
|
|
|
|
|
m_premium = EMPTY_VALUE;
|
|
|
|
|
m_discount = EMPTY_VALUE;
|
|
|
|
|
m_premium2 = EMPTY_VALUE;
|
|
|
|
|
m_discount2 = EMPTY_VALUE;
|
2026-03-04 01:37:21 +03:00
|
|
|
m_bar_eq_prev = -1;
|
|
|
|
|
m_fixed_eq = EMPTY_VALUE;
|
|
|
|
|
m_fixed_prem2 = EMPTY_VALUE;
|
|
|
|
|
m_fixed_disc2 = EMPTY_VALUE;
|
2026-03-04 13:51:14 +03:00
|
|
|
m_dynamic_mode = false;
|
|
|
|
|
m_break_dir = 0;
|
|
|
|
|
m_track_high = EMPTY_VALUE;
|
|
|
|
|
m_track_low = EMPTY_VALUE;
|
|
|
|
|
m_break_bar = -1;
|
2026-02-16 21:25:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Деструктор |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
CEquilibrium::~CEquilibrium()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Инициализация параметров |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
bool CEquilibrium::Init(int pre_dis, int pre_dis2, bool eq_con)
|
|
|
|
|
{
|
|
|
|
|
m_pre_dis = pre_dis;
|
|
|
|
|
m_pre_dis2 = pre_dis2;
|
|
|
|
|
m_eq_con = eq_con;
|
|
|
|
|
|
|
|
|
|
m_premium = EMPTY_VALUE;
|
|
|
|
|
m_discount = EMPTY_VALUE;
|
|
|
|
|
m_premium2 = EMPTY_VALUE;
|
|
|
|
|
m_discount2 = EMPTY_VALUE;
|
2026-03-04 01:37:21 +03:00
|
|
|
m_bar_eq_prev = -1;
|
|
|
|
|
m_fixed_eq = EMPTY_VALUE;
|
|
|
|
|
m_fixed_prem2 = EMPTY_VALUE;
|
|
|
|
|
m_fixed_disc2 = EMPTY_VALUE;
|
2026-03-04 13:51:14 +03:00
|
|
|
m_dynamic_mode = false;
|
|
|
|
|
m_break_dir = 0;
|
|
|
|
|
m_track_high = EMPTY_VALUE;
|
|
|
|
|
m_track_low = EMPTY_VALUE;
|
|
|
|
|
m_break_bar = -1;
|
2026-02-16 21:25:58 +03:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Полный сброс — вызывать при prev_calculated == 0 |
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-02-17 15:27:50 +03:00
|
|
|
void CEquilibrium::FullReset(double &buf_equilibrium[],
|
|
|
|
|
double &buf_premium2[],
|
|
|
|
|
double &buf_discount2[],
|
|
|
|
|
int rates_total)
|
2026-02-16 21:25:58 +03:00
|
|
|
{
|
|
|
|
|
ArrayInitialize(buf_equilibrium, EMPTY_VALUE);
|
2026-02-17 15:27:50 +03:00
|
|
|
ArrayInitialize(buf_premium2, EMPTY_VALUE);
|
|
|
|
|
ArrayInitialize(buf_discount2, EMPTY_VALUE);
|
2026-02-16 21:25:58 +03:00
|
|
|
m_premium = EMPTY_VALUE;
|
|
|
|
|
m_discount = EMPTY_VALUE;
|
|
|
|
|
m_premium2 = EMPTY_VALUE;
|
|
|
|
|
m_discount2 = EMPTY_VALUE;
|
2026-03-04 01:37:21 +03:00
|
|
|
m_bar_eq_prev = -1;
|
|
|
|
|
m_fixed_eq = EMPTY_VALUE;
|
|
|
|
|
m_fixed_prem2 = EMPTY_VALUE;
|
|
|
|
|
m_fixed_disc2 = EMPTY_VALUE;
|
2026-03-04 13:51:14 +03:00
|
|
|
m_dynamic_mode = false;
|
|
|
|
|
m_break_dir = 0;
|
|
|
|
|
m_track_high = EMPTY_VALUE;
|
|
|
|
|
m_track_low = EMPTY_VALUE;
|
|
|
|
|
m_break_bar = -1;
|
2026-02-17 15:27:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Проверка: iFVG в Discount зоне (для Buy Entry) |
|
|
|
|
|
//| Discount2 <= ifvg_bottom <= Discount |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
bool CEquilibrium::IsInDiscountZone(double ifvg_bottom) const
|
|
|
|
|
{
|
|
|
|
|
if(!m_eq_con) return true;
|
|
|
|
|
if(m_discount == EMPTY_VALUE || m_discount2 == EMPTY_VALUE) return false;
|
|
|
|
|
return (ifvg_bottom <= m_discount && ifvg_bottom >= m_discount2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| Проверка: iFVG в Premium зоне (для Sell Entry) |
|
|
|
|
|
//| Premium <= ifvg_top <= Premium2 |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
bool CEquilibrium::IsInPremiumZone(double ifvg_top) const
|
|
|
|
|
{
|
|
|
|
|
if(!m_eq_con) return true;
|
|
|
|
|
if(m_premium == EMPTY_VALUE || m_premium2 == EMPTY_VALUE) return false;
|
|
|
|
|
return (ifvg_top >= m_premium && ifvg_top <= m_premium2);
|
2026-02-16 21:25:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
2026-02-17 15:27:50 +03:00
|
|
|
//| Расчёт Premium/Discount и заполнение буферов |
|
|
|
|
|
//| Три случая по ARCHITECTURE_SWINGS_BOS_MSS.md секция 7.4 |
|
2026-02-16 21:25:58 +03:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
void CEquilibrium::Calculate(int bar, const SStructureSwingState &state,
|
2026-03-04 13:51:14 +03:00
|
|
|
double price_high, double price_low,
|
2026-02-17 15:27:50 +03:00
|
|
|
double &buf_equilibrium[],
|
|
|
|
|
double &buf_premium2[],
|
|
|
|
|
double &buf_discount2[],
|
|
|
|
|
int rates_total)
|
2026-02-16 21:25:58 +03:00
|
|
|
{
|
|
|
|
|
double pre_dis_cal = m_pre_dis / 100.0;
|
|
|
|
|
double pre_dis_cal2 = m_pre_dis2 / 100.0;
|
|
|
|
|
|
2026-03-04 01:37:21 +03:00
|
|
|
//=== Динамические значения для геттеров (Entry сигналы) ===
|
|
|
|
|
//--- Case 1: CF_In_low=true, CF_In_High=false (ждём пробой вверх)
|
2026-02-17 15:27:50 +03:00
|
|
|
if(state.cf_in_low && !state.cf_in_high
|
|
|
|
|
&& state.in_low != EMPTY_VALUE && state.i_high != EMPTY_VALUE)
|
|
|
|
|
{
|
|
|
|
|
double range = state.i_high - state.in_low;
|
|
|
|
|
if(range > 0.0)
|
|
|
|
|
{
|
|
|
|
|
m_discount = state.i_high - (pre_dis_cal * range);
|
|
|
|
|
m_premium = EMPTY_VALUE;
|
|
|
|
|
if(m_eq_con)
|
|
|
|
|
{
|
|
|
|
|
m_discount2 = state.i_high - (pre_dis_cal2 * range);
|
|
|
|
|
m_premium2 = EMPTY_VALUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-04 01:37:21 +03:00
|
|
|
//--- Case 2: CF_In_High=true, CF_In_low=false (ждём пробой вниз)
|
2026-02-17 15:27:50 +03:00
|
|
|
else if(state.cf_in_high && !state.cf_in_low
|
|
|
|
|
&& state.in_high != EMPTY_VALUE && state.i_low != EMPTY_VALUE)
|
|
|
|
|
{
|
|
|
|
|
double range = state.in_high - state.i_low;
|
|
|
|
|
if(range > 0.0)
|
|
|
|
|
{
|
|
|
|
|
m_premium = state.i_low + (pre_dis_cal * range);
|
|
|
|
|
m_discount = EMPTY_VALUE;
|
|
|
|
|
if(m_eq_con)
|
|
|
|
|
{
|
|
|
|
|
m_premium2 = state.i_low + (pre_dis_cal2 * range);
|
|
|
|
|
m_discount2 = EMPTY_VALUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-04 01:37:21 +03:00
|
|
|
//--- Case 3: Оба подтверждены
|
2026-02-17 15:27:50 +03:00
|
|
|
else if(state.cf_in_high && state.cf_in_low
|
|
|
|
|
&& state.in_high != EMPTY_VALUE && state.in_low != EMPTY_VALUE)
|
2026-02-16 21:25:58 +03:00
|
|
|
{
|
2026-02-17 09:52:38 +03:00
|
|
|
double range = state.in_high - state.in_low;
|
|
|
|
|
m_premium = state.in_low + (pre_dis_cal * range);
|
2026-02-17 15:27:50 +03:00
|
|
|
m_discount = state.in_high - (pre_dis_cal * range);
|
2026-02-17 09:52:38 +03:00
|
|
|
if(m_eq_con)
|
2026-02-16 21:25:58 +03:00
|
|
|
{
|
2026-02-17 09:52:38 +03:00
|
|
|
m_premium2 = state.in_low + (pre_dis_cal2 * range);
|
2026-02-17 15:27:50 +03:00
|
|
|
m_discount2 = state.in_high - (pre_dis_cal2 * range);
|
2026-02-16 21:25:58 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-04 13:51:14 +03:00
|
|
|
//=== Динамический режим: трекинг после 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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//=== Динамический пересчёт геттеров в 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-04 01:37:21 +03:00
|
|
|
//=== Стабильные значения для буферов (ТОЛЬКО подтверждённые in_high/in_low) ===
|
|
|
|
|
double draw_eq = EMPTY_VALUE;
|
|
|
|
|
double draw_prem2 = EMPTY_VALUE;
|
|
|
|
|
double draw_disc2 = EMPTY_VALUE;
|
|
|
|
|
int bar_eq = -1;
|
|
|
|
|
|
|
|
|
|
if(state.in_high != EMPTY_VALUE && state.in_low != EMPTY_VALUE
|
|
|
|
|
&& (state.cf_in_high || state.cf_in_low))
|
2026-02-17 09:57:07 +03:00
|
|
|
{
|
2026-03-04 01:37:21 +03:00
|
|
|
double range = state.in_high - state.in_low;
|
|
|
|
|
if(range > 0.0)
|
2026-02-17 09:57:07 +03:00
|
|
|
{
|
2026-03-04 01:37:21 +03:00
|
|
|
double stable_premium = state.in_low + (pre_dis_cal * range);
|
|
|
|
|
double stable_discount = state.in_high - (pre_dis_cal * range);
|
|
|
|
|
|
|
|
|
|
if(state.cf_in_low && !state.cf_in_high)
|
|
|
|
|
draw_eq = stable_discount;
|
|
|
|
|
else if(state.cf_in_high && !state.cf_in_low)
|
|
|
|
|
draw_eq = stable_premium;
|
|
|
|
|
else
|
|
|
|
|
draw_eq = (state.in_dir_big == 1) ? stable_discount : stable_premium;
|
|
|
|
|
|
|
|
|
|
if(m_eq_con)
|
2026-02-17 09:57:07 +03:00
|
|
|
{
|
2026-03-04 01:37:21 +03:00
|
|
|
double stable_premium2 = state.in_low + (pre_dis_cal2 * range);
|
|
|
|
|
double stable_discount2 = state.in_high - (pre_dis_cal2 * range);
|
|
|
|
|
|
|
|
|
|
if(state.cf_in_low && !state.cf_in_high)
|
|
|
|
|
draw_disc2 = stable_discount2;
|
|
|
|
|
else if(state.cf_in_high && !state.cf_in_low)
|
|
|
|
|
draw_prem2 = stable_premium2;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
draw_prem2 = stable_premium2;
|
|
|
|
|
draw_disc2 = stable_discount2;
|
|
|
|
|
}
|
2026-02-17 09:57:07 +03:00
|
|
|
}
|
2026-03-04 01:37:21 +03:00
|
|
|
|
|
|
|
|
bar_eq = MathMax(state.bar_in_high, state.bar_in_low);
|
2026-02-17 09:57:07 +03:00
|
|
|
}
|
2026-03-04 01:37:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//=== Отрисовка ===
|
|
|
|
|
if(bar >= 0 && bar < rates_total)
|
|
|
|
|
{
|
|
|
|
|
bool structural_event = state.ch_in_h || state.ch_in_l;
|
2026-02-17 15:27:50 +03:00
|
|
|
|
2026-03-04 01:37:21 +03:00
|
|
|
//--- При структурном событии — обновить уровень и backfill от нового свинга
|
|
|
|
|
if(draw_eq != EMPTY_VALUE && structural_event)
|
2026-02-17 15:27:50 +03:00
|
|
|
{
|
2026-03-04 01:37:21 +03:00
|
|
|
m_fixed_eq = draw_eq;
|
|
|
|
|
m_fixed_prem2 = draw_prem2;
|
|
|
|
|
m_fixed_disc2 = draw_disc2;
|
|
|
|
|
|
|
|
|
|
//--- Backfill от изменённого свинга
|
|
|
|
|
int fill_from = -1;
|
|
|
|
|
if(state.ch_in_h && state.bar_in_high >= 0)
|
|
|
|
|
fill_from = state.bar_in_high;
|
|
|
|
|
if(state.ch_in_l && state.bar_in_low >= 0)
|
|
|
|
|
fill_from = (fill_from >= 0) ? MathMax(fill_from, state.bar_in_low) : state.bar_in_low;
|
|
|
|
|
|
|
|
|
|
if(fill_from >= 0)
|
2026-02-17 15:27:50 +03:00
|
|
|
{
|
2026-03-04 01:37:21 +03:00
|
|
|
for(int i = fill_from; i > bar && i < rates_total; i--)
|
|
|
|
|
buf_equilibrium[i] = m_fixed_eq;
|
|
|
|
|
if(m_fixed_prem2 != EMPTY_VALUE)
|
|
|
|
|
{
|
|
|
|
|
for(int i = fill_from; i > bar && i < rates_total; i--)
|
|
|
|
|
buf_premium2[i] = m_fixed_prem2;
|
|
|
|
|
}
|
|
|
|
|
if(m_fixed_disc2 != EMPTY_VALUE)
|
|
|
|
|
{
|
|
|
|
|
for(int i = fill_from; i > bar && i < rates_total; i--)
|
|
|
|
|
buf_discount2[i] = m_fixed_disc2;
|
|
|
|
|
}
|
2026-02-17 15:27:50 +03:00
|
|
|
}
|
2026-02-17 09:57:07 +03:00
|
|
|
}
|
2026-03-04 01:37:21 +03:00
|
|
|
else if(draw_eq == EMPTY_VALUE)
|
2026-02-17 15:27:50 +03:00
|
|
|
{
|
2026-03-04 01:37:21 +03:00
|
|
|
m_fixed_eq = EMPTY_VALUE;
|
|
|
|
|
m_fixed_prem2 = EMPTY_VALUE;
|
|
|
|
|
m_fixed_disc2 = EMPTY_VALUE;
|
2026-02-17 15:27:50 +03:00
|
|
|
}
|
2026-03-04 01:37:21 +03:00
|
|
|
|
|
|
|
|
//--- Записать зафиксированный уровень в текущий бар
|
|
|
|
|
buf_equilibrium[bar] = m_fixed_eq;
|
|
|
|
|
buf_premium2[bar] = m_fixed_prem2;
|
|
|
|
|
buf_discount2[bar] = m_fixed_disc2;
|
2026-03-04 13:51:14 +03:00
|
|
|
|
|
|
|
|
//=== Динамическая отрисовка: перезаписать буфер, если 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;
|
|
|
|
|
buf_discount2[i] = dyn_disc2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-02-17 09:57:07 +03:00
|
|
|
}
|
2026-02-17 15:27:50 +03:00
|
|
|
|
2026-03-04 01:37:21 +03:00
|
|
|
m_bar_eq_prev = bar_eq;
|
2026-02-16 21:25:58 +03:00
|
|
|
}
|
|
|
|
|
|
2026-03-04 01:37:21 +03:00
|
|
|
|
2026-02-16 21:25:58 +03:00
|
|
|
#endif // CEQUILIBRIUM_MQH
|