← К каталогу
Исходный код · ID 4111

Hon-Matrix

hon-matrix.mq5

Похожие материалы по тегам

!!!-mt4 x-xardg-rsi.mq5MQL5 / MetaTrader 5 · 2 общих тегов!!! rsi ma simple+arrows 1.2 (mtf).mq5MQL5 / MetaTrader 5 · 2 общих теговea robofibo source v.11.2.mq4MQL4 / MetaTrader 4 · 2 общих теговsureforexhedingvonepointoneone.mq4MQL4 / MetaTrader 4 · 2 общих теговsureforexhedging 1.10 optimized.mq4MQL4 / MetaTrader 4 · 2 общих теговsureforexhedging 1.09 a (2).mq4MQL4 / MetaTrader 4 · 2 общих тегов
Вы автор или правообладатель?

Сообщите нам, если считаете, что материал размещён без разрешения.

Краткий обзор

О программе

Hon-Matrix — это торговый советник для MetaTrader 5, предназначенный для автоматической торговли на одном символе с использованием сеточного подхода. Советник анализирует рыночные данные через индикаторы (скользящие средние, ATR, RSI), определяет фазу рынка и направление тренда, после чего принимает решения об открытии начальной позиции и добавлении ордеров в сетку. В коде предусмотрены несколько режимов входа: по уровням Фибоначчи, по уровням поддержки и сопротивления, по границам канала, а также простой трендовый вход.

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

Для удобства мониторинга реализована информационная панель на графике, отображающая состояние счёта, рыночную аналитику, статус новостного фильтра и элементы ручного управления позициями. Советник обрабатывает события OnTick, OnTrade и OnChartEvent, использует торговые функции MetaTrader 5 и не является индикатором или библиотекой.

Настройки программы

НастройкаОписание
Start_Date Дата начала периода тестирования.
StartCapital Начальный капитал для проверки периода тестирования.
EnableBacktestValidation Включает или отключает проверку периода тестирования.
CloseLosesAtPercent Процент убытка от счёта, при достижении которого все позиции закрываются. Значение 0 отключает функцию.
CloseProfitsAtPercent Процент прибыли от счёта, при достижении которого все позиции закрываются. Значение 0 отключает функцию.
InitialLotSize Начальный размер лота для первой позиции.
MaxLotSize Максимально допустимый размер лота.
LotMultiplier Множитель лота для последующих ордеров сетки.
MaxGridOrders Максимальное количество ордеров в сетке.
TakeProfitPips Целевой уровень прибыли в пунктах для закрытия корзины позиций.
BreakevenTrigger Прибыль в пунктах, при достижении которой позиция переводится в безубыток.
TrailingDistance Расстояние трейлинг-стопа в пунктах.
UseTrailingStop Включает или отключает трейлинг-стоп и перевод в безубыток.
EnableNewsFilter Включает или отключает новостной фильтр.
StopBeforeNewsMin Количество минут до новости, в течение которых торговля приостанавливается.
StopAfterNewsMin Количество минут после новости, в течение которых торговля приостанавливается.
EnableHighImpact Включает или отключает фильтр новостей высокой важности.
EnableMediumImpact Включает или отключает фильтр новостей средней важности.
EnableLowImpact Включает или отключает фильтр новостей низкой важности.
UseInternalCalendar Включает или отключает использование внутреннего календаря MetaTrader 5.
NewsSymbols Список валют, учитываемых новостным фильтром, через запятую.
ClosePositionsBeforeNews Включает или отключает закрытие всех позиций перед новостями.
AlertOnUpcomingNews Включает или отключает уведомления о предстоящих новостях.
DrawNewsLines Включает или отключает отрисовку вертикальных линий новостей на графике.
HighImpactColor Цвет линий новостей высокой важности.
MediumImpactColor Цвет линий новостей средней важности.
LowImpactColor Цвет линий новостей низкой важности.
AMA_Period Период скользящей средней, используемой в анализе рыночной фазы.
ATR_Period Период индикатора ATR для оценки волатильности.
ATR_Threshold Пороговое значение волатильности ATR для определения рыночной фазы.
TrendTimeframe Таймфрейм для фильтра тренда.
TrendMA_Period Период скользящей средней для определения тренда.
SwingLookback Количество баров для поиска экстремумов.
UseFibonacciGrid Включает или отключает использование сетки Фибоначчи.
FibLevel1 Первый уровень Фибоначчи для сетки.
FibLevel2 Второй уровень Фибоначчи для сетки.
FibLevel3 Третий уровень Фибоначчи для сетки.
FibLevel4 Четвёртый уровень Фибоначчи для сетки.
UseEnhancedEntry Включает или отключает расширенную систему входа по уровням поддержки и сопротивления.
SR_LookbackPeriod Количество баров для поиска уровней поддержки и сопротивления.
SR_MinStrength Минимальное количество касаний для уровня поддержки или сопротивления.
SR_ZoneBuffer Буфер зоны поддержки и сопротивления в пунктах.
UseChannelTrading Включает или отключает торговлю по каналу.
ChannelMinBars Минимальное количество баров для определения канала.
ChannelThreshold Пороговое значение силы канала.
UseDynamicLotSizing Включает или отключает динамический расчёт лота на основе силы уровней.
BreakoutMinPips Минимальное расстояние пробоя в пунктах.
BreakoutMaxPips Максимальное расстояние пробоя в пунктах.
UseMomentumFilter Включает или отключает фильтр импульса.
MomentumThreshold Пороговое значение импульса для фильтра.
UseVolumeFilter Включает или отключает фильтр объёма.
VolumeMultiplier Множитель объёма для фильтра.
FalseBreakoutFilter Порог фильтра ложных пробоев в диапазоне от 0 до 1.
VolumeConfirmPeriod Период подтверждения объёма.
BreakoutConfirmBars Количество баров для подтверждения пробоя.
UseRSIFilter Включает или отключает фильтр RSI.
RSI_Period Период индикатора RSI.
RSI_Oversold Уровень перепроданности RSI.
RSI_Overbought Уровень перекупленности RSI.
EntryDistance Расстояние от уровня Фибоначчи для входа в пунктах.
UseSimpleEntry Включает или отключает простой вход по тренду.
UseTimeFilter Включает или отключает фильтр времени торговли.
StartTime Время начала торговли в формате часы:минуты.
EndTime Время окончания торговли в формате часы:минуты.
MagicNumber Уникальный идентификатор ордеров советника.
Commentary Текст комментария, добавляемый к торговым ордерам.
ShowPanel Включает или отключает отображение информационной панели на графике.
Получить полный код

Поиск по коду файла

#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\OrderInfo.mqh>

#property version "1.2";
#property strict

enum ENUM_MARKET_PHASE
  {
   MARKET_RANGING,
   MARKET_TRENDING,
   MARKET_CONSOLIDATING,
   MARKET_UNKNOWN
  };

enum ENUM_TREND_DIRECTION
  {
   TREND_BULLISH,
   TREND_BEARISH,
   TREND_NEUTRAL
  };
input group "=== BACKTEST VALIDATION ===";
input datetime Start_Date = D'2020.01.01';     // Backtest Start Date (Min 1 Year)
input double   StartCapital = 10000;           // Starting Capital for Validation
input bool     EnableBacktestValidation = true; // Enable Backtest Validation

input group "=== RISK MANAGEMENT ===";
input double MaxAccountExposure = 15.0;       // Max Account Exposure (%)
input double CloseLosesAtPercent = 30.0;      // Close all if loss reaches this % of account (0=disable)
input double CloseProfitsAtPercent = 40.0;    // Close all if profit reaches this % of account (0=disable)
input double InitialLotSize = 0.06;           // Initial Lot Size
input double MaxLotSize = 1.0;                // Maximum Lot Size
input double LotMultiplier = 1.1;             // Lot Multiplier (Safe Default)
input int    MaxGridOrders = 5;               // Max Grid Orders (Safe Default)
input double TakeProfitPips = 50.0;           // Ultimate Take Profit (Pips)
input double BreakevenTrigger = 20.0;         // Breakeven Trigger (Pips)
input double TrailingDistance = 15.0;         // Trailing Stop Distance (Pips)
input bool   UseTrailingStop = true;          // Use Trailing Stop & Breakeven

input group "=== NEWS FILTER SETTINGS ===";
input bool     EnableNewsFilter = true;       // Enable/Disable the news filter
input int      StopBeforeNewsMin = 30;        // Stop trading Before News (minutes)
input int      StopAfterNewsMin = 30;         // Stop trading After News (minutes)
input bool     EnableHighImpact = true;       // Enable high impact news filter
input bool     EnableMediumImpact = true;     // Enable medium impact news filter
input bool     EnableLowImpact = false;       // Enable low impact news filter
input bool     UseInternalCalendar = true;    // Use MT5 internal calendar (recommended)
input string   NewsSymbols = "USD,EUR,GBP,CHF,CAD,AUD,NZD,JPY"; // Currencies for news filter
input bool     ClosePositionsBeforeNews = false; // Close all positions before news
input bool     AlertOnUpcomingNews = true;    // Alert for upcoming news
input bool     DrawNewsLines = true;          // Draw news lines on chart
input color    HighImpactColor = clrRed;      // High impact news line color
input color    MediumImpactColor = clrOrange; // Medium impact news line color
input color    LowImpactColor = clrYellow;    // Low impact news line color

input group "=== MARKET ANALYSIS ===";
input int    AMA_Period = 21;                 // AMA Period
input int    ATR_Period = 14;                 // ATR Period
input double ATR_Threshold = 1.5;             // ATR Volatility Threshold
input ENUM_TIMEFRAMES TrendTimeframe = PERIOD_H4; // Trend Filter Timeframe
input int    TrendMA_Period = 100;            // Trend MA Period

input group "=== FIBONACCI SETTINGS ===";
input int    SwingLookback = 50;              // Swing Points Lookback
input bool   UseFibonacciGrid = true;         // Use Fibonacci Grid Spacing
input double FibLevel1 = 38.2;                // Fibonacci Level 1
input double FibLevel2 = 50.0;                // Fibonacci Level 2
input double FibLevel3 = 61.8;                // Fibonacci Level 3
input double FibLevel4 = 78.6;                // Fibonacci Level 4

input group "=== ENHANCED SIMPLE ENTRY ===";
input bool   UseEnhancedEntry = true;          // Use Enhanced S/R Entry System
input int    SR_LookbackPeriod = 100;          // S/R Detection Lookback Period
input double SR_MinStrength = 3.0;             // Minimum S/R Touch Count
input double SR_ZoneBuffer = 20.0;             // S/R Zone Buffer (Pips)
input bool   UseChannelTrading = true;         // Enable Channel Trading
input int    ChannelMinBars = 50;              // Minimum Channel Length
input double ChannelThreshold = 0.8;           // Channel Strength Threshold
input bool   UseDynamicLotSizing = true;       // Dynamic Lot Sizing based on S/R strength
input group "=== BREAKOUT DETECTION SETTINGS ===";
input double BreakoutMinPips = 5.0;               // Minimum Breakout Distance (Pips)
input double BreakoutMaxPips = 50.0;              // Maximum Breakout Distance (Pips)
input bool   UseMomentumFilter = true;            // Use Momentum Filter
input double MomentumThreshold = 1.2;             // Momentum Threshold
input bool   UseVolumeFilter = true;              // Use Volume Filter
input double VolumeMultiplier = 1.5;              // Volume Multiplier
input double FalseBreakoutFilter = 0.6;           // False Breakout Filter (0-1)
input int    VolumeConfirmPeriod = 10;            // Volume Confirmation Period
input int    BreakoutConfirmBars = 3;             // Breakout Confirmation Bars
input group "=== ENTRY FILTERS ===";
input bool   UseRSIFilter = false;            // Use RSI Filter
input int    RSI_Period = 14;                 // RSI Period
input double RSI_Oversold = 30.0;             // RSI Oversold Level
input double RSI_Overbought = 70.0;           // RSI Overbought Level
input double EntryDistance = 30.0;            // Entry Distance from Fib (Pips)
input bool   UseSimpleEntry = false;          // Use simple trend-following entry

input group "=== TIME FILTER ===";
input bool   UseTimeFilter = false;           // Use Time Filter
input string StartTime = "08:00";             // Trading Start Time
input string EndTime = "18:00";               // Trading End Time

input group "=== ADVANCED ===";
input int    MagicNumber = 777777;            // Magic Number
input string Commentary = "Hon-Matrix";       // Order Comment
input bool   ShowPanel = true;                // Show Control Panel

CTrade trade;
CPositionInfo position;
COrderInfo order;

double g_live_multiplier = 0.0;    // 0.0 = use input parameter
double g_live_start_lot = 0.0;     // 0.0 = use input parameter
bool g_live_adjustments_active = false;

struct NewsWebData
  {
   string            time_str;
   string            currency;
   string            impact;
   string            title;

                     NewsWebData()
     {
      time_str = "";
      currency = "";
      impact = "";
      title = "";
     }
  };
struct NewsEvent
  {
   datetime          time;
   string            currency;
   string            title;
   int               impact;  // 1=Low, 2=Medium, 3=High
   bool              processed;

                     NewsEvent()
     {
      time = 0;
      currency = "";
      title = "";
      impact = 0;
      processed = false;
     }

                     NewsEvent(const NewsEvent &other)
     {
      time = other.time;
      currency = other.currency;
      title = other.title;
      impact = other.impact;
      processed = other.processed;
     }
  };
struct SRLevel
  {
   double            price;
   int               touch_count;
   datetime          first_touch;
   datetime          last_touch;
   bool              is_support;
   double            strength;
   bool              is_active;

                     SRLevel()
     {
      price = 0.0;
      touch_count = 0;
      first_touch = 0;
      last_touch = 0;
      is_support = true;
      strength = 0.0;
      is_active = false;
     }

                     SRLevel(const SRLevel &other)
     {
      price = other.price;
      touch_count = other.touch_count;
      first_touch = other.first_touch;
      last_touch = other.last_touch;
      is_support = other.is_support;
      strength = other.strength;
      is_active = other.is_active;
     }
  };
struct ChannelInfo
  {
   double            upper_line;
   double            lower_line;
   double            slope;
   int               bar_count;
   double            strength;
   bool              is_active;
   datetime          start_time;

                     ChannelInfo()
     {
      upper_line = 0.0;
      lower_line = 0.0;
      slope = 0.0;
      bar_count = 0;
      strength = 0.0;
      is_active = false;
      start_time = 0;
     }
  };
struct BreakoutInfo
  {
   double            sr_level;
   bool              is_resistance_break;
   datetime          break_time;
   double            break_price;
   double            momentum_score;
   double            volume_score;
   bool              is_confirmed;
   int               confirmation_bars;

                     BreakoutInfo()
     {
      sr_level = 0.0;
      is_resistance_break = false;
      break_time = 0;
      break_price = 0.0;
      momentum_score = 0.0;
      volume_score = 0.0;
      is_confirmed = false;
      confirmation_bars = 0;
     }
  };

class CAdvancedNewsFilter
  {
private:

   NewsEvent         m_news_events[];
   int               m_news_count;
   datetime          m_last_update;
   datetime          m_last_alert_time;
   bool              m_trading_halted;
   string            m_halt_reason;
   string            m_filtered_symbols[];

   NewsWebData       m_web_news_records[];
   int               m_web_news_count;

public:
                     CAdvancedNewsFilter() : m_news_count(0), m_last_update(0), m_last_alert_time(0),
                     m_trading_halted(false), m_web_news_count(0)
     {
      ParseFilteredSymbols();
     }

   bool              Initialize()
     {
      if(!EnableNewsFilter)
         return true;

      Print("News Filter: Initializing advanced news filter...");

      Print("News Filter: Please ensure WebRequest is enabled in Tools->Options->Expert Advisors");

      UpdateNewsData();
      m_last_update = TimeCurrent();

      Print("News Filter: Initialized successfully with ", m_news_count, " upcoming events");
      return true;
     }

private:
   void              ParseFilteredSymbols()
     {
      string symbols = NewsSymbols;
      StringReplace(symbols, " ", "");

      string parts[];
      int total = StringSplit(symbols, ',', parts);

      ArrayResize(m_filtered_symbols, total);
      for(int i = 0; i < total; i++)
        {
         m_filtered_symbols[i] = parts[i];
         StringToUpper(m_filtered_symbols[i]);
        }
     }

   bool              IsSymbolFiltered(string currency)
     {
      StringToUpper(currency);
      for(int i = 0; i < ArraySize(m_filtered_symbols); i++)
        {
         if(m_filtered_symbols[i] == currency)
            return true;
        }
      return false;
     }

   void              UpdateNewsData()
     {
      m_news_count = 0;
      m_trading_halted = false;
      m_halt_reason = "";

      if(UseInternalCalendar)
        {
         LoadFromInternalCalendar();
        }
      else
        {
         LoadFromWebSource();
        }

      SortNewsByTime();

      if(DrawNewsLines)
        {
         DrawNewsVerticalLines();
        }
     }

   void              LoadFromInternalCalendar()
     {
      MqlCalendarValue calendar_values[];

      datetime from_time = TimeCurrent();
      datetime to_time = from_time + 7 * 24 * 3600; // Next 7 days

      int total = CalendarValueHistory(calendar_values, from_time, to_time);

      if(total <= 0)
        {
         Print("News Filter: No calendar data available from internal calendar");
         return;
        }

      ArrayResize(m_news_events, total);

      for(int i = 0; i < total && m_news_count < total; i++)
        {
         MqlCalendarEvent event_info;
         MqlCalendarCountry country_info;

         if(!CalendarEventById(calendar_values[i].event_id, event_info))
            continue;
         if(!CalendarCountryById(event_info.country_id, country_info))
            continue;

         if(!ShouldProcessImpact(event_info.importance))
            continue;

         if(!IsSymbolFiltered(country_info.currency))
            continue;

         m_news_events[m_news_count].time = calendar_values[i].time;
         m_news_events[m_news_count].currency = country_info.currency;
         m_news_events[m_news_count].title = event_info.name;
         m_news_events[m_news_count].impact = (int)event_info.importance;
         m_news_events[m_news_count].processed = false;

         m_news_count++;
        }

      Print("News Filter: Loaded ", m_news_count, " events from internal calendar");
     }

   void              LoadFromWebSource()
     {

      string html_content = FetchWebNewsData();
      if(StringLen(html_content) == 0)
        {
         Print("News Filter: Web source unavailable, using internal calendar only");
         return;
        }

      ParseWebNewsData(html_content);

      ArrayResize(m_news_events, m_web_news_count);
      for(int i = 0; i < m_web_news_count; i++)
        {
         m_news_events[i].time = ParseWebTime(m_web_news_records[i].time_str);
         m_news_events[i].currency = m_web_news_records[i].currency;
         m_news_events[i].title = m_web_news_records[i].title;
         m_news_events[i].impact = ParseWebImpact(m_web_news_records[i].impact);
         m_news_events[i].processed = false;
        }
      m_news_count = m_web_news_count;

      Print("News Filter: Loaded ", m_news_count, " events from web source");
     }

   string            FetchWebNewsData()
     {
      string cookie = NULL, headers;
      string reqheaders = "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\r\n";
      char post[], result[];

      string news_url = "";

      ResetLastError();
      int timeout = 10000;
      int res = WebRequest("GET", news_url, reqheaders, timeout, post, result, headers);

      if(res == -1)
        {
         int error_code = GetLastError();
         Print("News Filter: WebRequest failed. Error: ", error_code);
         if(error_code == 4060) // ERR_FUNCTION_NOT_CONFIRMED
           {
            Print("News Filter: Please add ", news_url, " to allowed URLs in terminal settings");
           }
         return "";
        }

      return CharArrayToString(result);
     }

   void              ParseWebNewsData(string html_content)
     {

      m_web_news_count = 0;
      ArrayResize(m_web_news_records, 100); // Reasonable initial size

      Print("News Filter: Web parsing completed (placeholder implementation)");
     }

   datetime          ParseWebTime(string time_str)
     {

      return StringToTime(time_str);
     }

   int               ParseWebImpact(string impact_str)
     {
      if(StringFind(impact_str, "High") >= 0 || StringFind(impact_str, "3") >= 0)
         return 3;
      if(StringFind(impact_str, "Medium") >= 0 || StringFind(impact_str, "Moderate") >= 0 || StringFind(impact_str, "2") >= 0)
         return 2;
      return 1;
     }

   bool              ShouldProcessImpact(ENUM_CALENDAR_EVENT_IMPORTANCE importance)
     {
      switch(importance)
        {
         case CALENDAR_IMPORTANCE_LOW:
            return EnableLowImpact;
         case CALENDAR_IMPORTANCE_MODERATE:
            return EnableMediumImpact;
         case CALENDAR_IMPORTANCE_HIGH:
            return EnableHighImpact;
         default:
            return false;
        }
     }

   void              SortNewsByTime()
     {

      for(int i = 0; i < m_news_count - 1; i++)
        {
         for(int j = 0; j < m_news_count - i - 1; j++)
           {
            if(m_news_events[j].time > m_news_events[j + 1].time)
              {
               NewsEvent temp = m_news_events[j];
               m_news_events[j] = m_news_events[j + 1];
               m_news_events[j + 1] = temp;
              }
           }
        }
     }

   void              DrawNewsVerticalLines()
     {

      ObjectsDeleteAll(0, "NewsLine_");

      for(int i = 0; i < m_news_count; i++)
        {
         datetime news_time = m_news_events[i].time;
         if(news_time < TimeCurrent())
            continue; // Skip past events

         color line_color = GetImpactColor(m_news_events[i].impact);
         string obj_name = "NewsLine_" + IntegerToString((int)news_time);

         ObjectCreate(0, obj_name, OBJ_VLINE, 0, news_time, 0);
         ObjectSetInteger(0, obj_name, OBJPROP_COLOR, line_color);
         ObjectSetInteger(0, obj_name, OBJPROP_STYLE, STYLE_DOT);
         ObjectSetInteger(0, obj_name, OBJPROP_WIDTH, 2);
         ObjectSetInteger(0, obj_name, OBJPROP_BACK, true);

         string tooltip = StringFormat("%s\n%s - %s\nImpact: %s",
                                       TimeToString(news_time),
                                       m_news_events[i].currency,
                                       m_news_events[i].title,
                                       GetImpactString(m_news_events[i].impact));
         ObjectSetString(0, obj_name, OBJPROP_TOOLTIP, tooltip);
        }
     }

   color             GetImpactColor(int impact)
     {
      switch(impact)
        {
         case 3:
            return HighImpactColor;
         case 2:
            return MediumImpactColor;
         case 1:
            return LowImpactColor;
         default:
            return clrGray;
        }
     }

   string            GetImpactString(int impact)
     {
      switch(impact)
        {
         case 3:
            return "HIGH";
         case 2:
            return "MEDIUM";
         case 1:
            return "LOW";
         default:
            return "UNKNOWN";
        }
     }

public:
   bool              IsTradingAllowed()
     {
      if(!EnableNewsFilter)
         return true;

      if(TimeCurrent() - m_last_update >= 21600)
        {
         UpdateNewsData();
         m_last_update = TimeCurrent();
        }

      datetime current_time = TimeCurrent();
      m_trading_halted = false;
      m_halt_reason = "";

      for(int i = 0; i < m_news_count; i++)
        {
         datetime news_time = m_news_events[i].time;
         datetime start_halt = news_time - StopBeforeNewsMin * 60;
         datetime end_halt = news_time + StopAfterNewsMin * 60;

         if(current_time >= start_halt && current_time <= end_halt)
           {
            m_trading_halted = true;
            m_halt_reason = StringFormat("NEWS: %s %s (%s) in %d min",
                                         m_news_events[i].currency,
                                         m_news_events[i].title,
                                         GetImpactString(m_news_events[i].impact),
                                         (int)((news_time - current_time) / 60));

            if(AlertOnUpcomingNews && (current_time - m_last_alert_time > 300)) // 5 min cooldown
              {
               Alert("Trading Halted: ", m_halt_reason);
               m_last_alert_time = current_time;
              }

            if(ClosePositionsBeforeNews && current_time <= news_time && !m_news_events[i].processed)
              {
               CloseAllNewsPositions();
               m_news_events[i].processed = true;
              }

            return false;
           }
        }

      return true;
     }

 void              CloseAllNewsPositions()
     {
      Print("News Filter: Closing all positions due to upcoming high-impact news");

      for(int i = PositionsTotal() - 1; i >= 0; i--)
        {
         if(position.SelectByIndex(i) && position.Magic() == MagicNumber && position.Symbol() == _Symbol)
           {
            trade.PositionClose(position.Ticket());
            Sleep(100);
           }
        }

      double freeze_level = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_FREEZE_LEVEL) * _Point;

      for(int i = OrdersTotal() - 1; i >= 0; i--)
        {
         if(order.SelectByIndex(i) && order.Magic() == MagicNumber && order.Symbol() == _Symbol)
           {
            double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
            double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
            double order_price = order.PriceOpen();
            bool is_frozen = false;

            if(order.OrderType() == ORDER_TYPE_BUY_LIMIT || order.OrderType() == ORDER_TYPE_BUY_STOP)
              {
               if(MathAbs(ask - order_price) <= freeze_level) is_frozen = true;
              }
            else if(order.OrderType() == ORDER_TYPE_SELL_LIMIT || order.OrderType() == ORDER_TYPE_SELL_STOP)
              {
               if(MathAbs(bid - order_price) <= freeze_level) is_frozen = true;
              }

            if(!is_frozen)
              {
               trade.OrderDelete(order.Ticket());
               Sleep(100);
              }
            else
              {
               Print("⚠️ News Filter: Order #", order.Ticket(), " is frozen and cannot be canceled.");
              }
           }
        }
     }
   bool              IsTradingHalted() { return m_trading_halted; }
   string            GetHaltReason() { return m_halt_reason; }

   string            GetNextNewsInfo()
     {
      if(!EnableNewsFilter || m_news_count == 0)
         return "No upcoming news";

      datetime current_time = TimeCurrent();

      for(int i = 0; i < m_news_count; i++)
        {
         if(m_news_events[i].time > current_time)
           {
            int minutes_to_news = (int)((m_news_events[i].time - current_time) / 60);
            return StringFormat("%s %s in %d min (%s)",
                                m_news_events[i].currency,
                                m_news_events[i].title,
                                minutes_to_news,
                                GetImpactString(m_news_events[i].impact));
           }
        }

      return "No upcoming news today";
     }

   void              Cleanup()
     {
      ObjectsDeleteAll(0, "NewsLine_");
     }
  };

class CMarketAnalyzer
  {
private:
   int               m_ema_fast_handle;
   int               m_ema_slow_handle;
   int               m_atr_handle;
   int               m_rsi_handle;
   int               m_trend_ma_handle;

   double            m_ema_fast_buffer[];
   double            m_ema_slow_buffer[];
   double            m_atr_buffer[];
   double            m_rsi_buffer[];
   double            m_trend_ma_buffer[];

public:
                     CMarketAnalyzer() : m_ema_fast_handle(INVALID_HANDLE), m_ema_slow_handle(INVALID_HANDLE),
                     m_atr_handle(INVALID_HANDLE), m_rsi_handle(INVALID_HANDLE),
                     m_trend_ma_handle(INVALID_HANDLE) {}

                    ~CMarketAnalyzer() { Release(); }

   bool              Initialize()
     {
      m_ema_fast_handle = iMA(_Symbol, PERIOD_CURRENT, 10, 0, MODE_EMA, PRICE_CLOSE);
      m_ema_slow_handle = iMA(_Symbol, PERIOD_CURRENT, AMA_Period, 0, MODE_EMA, PRICE_CLOSE);
      m_atr_handle = iATR(_Symbol, PERIOD_CURRENT, ATR_Period);

      if(UseRSIFilter)
         m_rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, RSI_Period, PRICE_CLOSE);

      m_trend_ma_handle = iMA(_Symbol, TrendTimeframe, TrendMA_Period, 0, MODE_EMA, PRICE_CLOSE);

      ArraySetAsSeries(m_ema_fast_buffer, true);
      ArraySetAsSeries(m_ema_slow_buffer, true);
      ArraySetAsSeries(m_atr_buffer, true);
      ArraySetAsSeries(m_rsi_buffer, true);
      ArraySetAsSeries(m_trend_ma_buffer, true);

      return (m_ema_fast_handle != INVALID_HANDLE && m_ema_slow_handle != INVALID_HANDLE &&
              m_atr_handle != INVALID_HANDLE && m_trend_ma_handle != INVALID_HANDLE);
     }

   void              Release()
     {
      if(m_ema_fast_handle != INVALID_HANDLE)
         IndicatorRelease(m_ema_fast_handle);
      if(m_ema_slow_handle != INVALID_HANDLE)
         IndicatorRelease(m_ema_slow_handle);
      if(m_atr_handle != INVALID_HANDLE)
         IndicatorRelease(m_atr_handle);
      if(m_rsi_handle != INVALID_HANDLE)
         IndicatorRelease(m_rsi_handle);
      if(m_trend_ma_handle != INVALID_HANDLE)
         IndicatorRelease(m_trend_ma_handle);
     }

   bool              UpdateData()
     {
      bool result = true;
      result &= (CopyBuffer(m_ema_fast_handle, 0, 0, 3, m_ema_fast_buffer) > 0);
      result &= (CopyBuffer(m_ema_slow_handle, 0, 0, 3, m_ema_slow_buffer) > 0);
      result &= (CopyBuffer(m_atr_handle, 0, 0, 3, m_atr_buffer) > 0);
      result &= (CopyBuffer(m_trend_ma_handle, 0, 0, 3, m_trend_ma_buffer) > 0);

      if(UseRSIFilter && m_rsi_handle != INVALID_HANDLE)
         result &= (CopyBuffer(m_rsi_handle, 0, 0, 3, m_rsi_buffer) > 0);

      return result;
     }

   ENUM_MARKET_PHASE GetMarketPhase()
     {
      if(!UpdateData())
         return MARKET_UNKNOWN;

      double ema_diff = MathAbs(m_ema_fast_buffer[0] - m_ema_slow_buffer[0]) / _Point;
      double atr_current = m_atr_buffer[0] / _Point;
      double atr_avg = (m_atr_buffer[0] + m_atr_buffer[1] + m_atr_buffer[2]) / 3.0 / _Point;

      if(ema_diff > 50 && atr_current > atr_avg * 2.0)
         return MARKET_TRENDING;

      return MARKET_RANGING;
     }

   ENUM_TREND_DIRECTION GetTrendDirection()
     {
      if(!UpdateData())
         return TREND_NEUTRAL;

      double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
      double trend_ma = m_trend_ma_buffer[0];

      if(current_price > trend_ma * 1.0005)
         return TREND_BULLISH;
      else
         if(current_price < trend_ma * 0.9995)
            return TREND_BEARISH;

      double ma_slope = (m_trend_ma_buffer[0] - m_trend_ma_buffer[2]) / _Point;
      if(ma_slope > 5)
         return TREND_BULLISH;
      if(ma_slope < -5)
         return TREND_BEARISH;

      return TREND_NEUTRAL;
     }

   bool              IsRSIOversold()
     {
      if(!UseRSIFilter || m_rsi_handle == INVALID_HANDLE)
         return true;
      return m_rsi_buffer[0] < 40.0;
     }

   bool              IsRSIOverbought()
     {
      if(!UseRSIFilter || m_rsi_handle == INVALID_HANDLE)
         return true;
      return m_rsi_buffer[0] > 60.0;
     }

   bool              GetSwingLevels(double &swing_high, double &swing_low)
     {
      double high_buffer[], low_buffer[];
      ArraySetAsSeries(high_buffer, true);
      ArraySetAsSeries(low_buffer, true);

      if(CopyHigh(_Symbol, PERIOD_CURRENT, 0, SwingLookback, high_buffer) <= 0 ||
         CopyLow(_Symbol, PERIOD_CURRENT, 0, SwingLookback, low_buffer) <= 0)
         return false;

      swing_high = high_buffer[ArrayMaximum(high_buffer)];
      swing_low = low_buffer[ArrayMinimum(low_buffer)];

      return true;
     }

   double            CalculateFibonacciLevel(double high, double low, double fib_percent, bool is_retracement = true)
     {
      if(is_retracement)
         return high - (high - low) * fib_percent / 100.0;
      else
         return low + (high - low) * fib_percent / 100.0;
     }

   double            GetATR() { return UpdateData() ? m_atr_buffer[0] : 0; }
   double            GetRSI() { return (UseRSIFilter && UpdateData()) ? m_rsi_buffer[0] : 50; }
  };

class CEnhancedSRDetector
  {
private:

   SRLevel           m_sr_levels[];
   int               m_sr_count;

   ChannelInfo       m_current_channel;
   bool              m_in_channel;

   BreakoutInfo      m_last_breakout;
   bool              m_breakout_pending;

public:
                     CEnhancedSRDetector() : m_sr_count(0), m_in_channel(false) {}

   bool              Initialize()
     {
      ArrayResize(m_sr_levels, 50); // Max 50 S/R levels
      DetectSupportResistanceLevels();
      DetectCurrentChannel();
      return true;
     };
   bool              DetectBreakout(double current_price, double &breakout_level, bool &is_bullish_breakout, double &confidence_score)
     {
      if(!IsNewBar())
         return false; // Only check on new bars

      double nearest_resistance, nearest_support;
      double resistance_strength, support_strength;

      bool near_resistance = IsNearResistanceLevel(current_price, nearest_resistance, resistance_strength);
      bool near_support = IsNearSupportLevel(current_price, nearest_support, support_strength);

      if(CheckResistanceBreakout(current_price, nearest_resistance, resistance_strength, breakout_level, confidence_score))
        {
         is_bullish_breakout = true;
         return true;
        }

      if(CheckSupportBreakdown(current_price, nearest_support, support_strength, breakout_level, confidence_score))
        {
         is_bullish_breakout = false;
         return true;
        }

      return false;
     }
   bool              IsBreakoutPending() { return m_breakout_pending; }

private:
   void              DetectSupportResistanceLevels()
     {
      double high_buffer[], low_buffer[];
      ArraySetAsSeries(high_buffer, true);
      ArraySetAsSeries(low_buffer, true);

      if(CopyHigh(_Symbol, PERIOD_CURRENT, 0, SR_LookbackPeriod, high_buffer) <= 0 ||
         CopyLow(_Symbol, PERIOD_CURRENT, 0, SR_LookbackPeriod, low_buffer) <= 0)
         return;

      m_sr_count = 0;

      for(int i = 5; i < SR_LookbackPeriod - 5; i++)
        {

         if(IsSwingHigh(high_buffer, i, 3))
           {
            double level = high_buffer[i];
            AddOrUpdateSRLevel(level, false); // resistance
           }

         if(IsSwingLow(low_buffer, i, 3))
           {
            double level = low_buffer[i];
            AddOrUpdateSRLevel(level, true); // support
           }
        }

      CalculateSRStrengths();

      SortSRLevelsByStrength();

      Print("✓ Detected ", m_sr_count, " S/R levels");
     }

   bool              IsSwingHigh(const double &highs[], int index, int lookback)
     {
      double current = highs[index];
      for(int i = index - lookback; i <= index + lookback; i++)
        {
         if(i != index && highs[i] >= current)
            return false;
        }
      return true;
     }

   bool              IsSwingLow(const double &lows[], int index, int lookback)
     {
      double current = lows[index];
      for(int i = index - lookback; i <= index + lookback; i++)
        {
         if(i != index && lows[i] <= current)
            return false;
        }
      return true;
     }

   void              AddOrUpdateSRLevel(double price, bool is_support)
     {
      double buffer = SR_ZoneBuffer * _Point;

      for(int i = 0; i < m_sr_count; i++)
        {
         if(MathAbs(m_sr_levels[i].price - price) <= buffer &&
            m_sr_levels[i].is_support == is_support)
           {
            m_sr_levels[i].touch_count++;
            m_sr_levels[i].last_touch = TimeCurrent();
            return;
           }
        }

      if(m_sr_count < ArraySize(m_sr_levels))
        {
         m_sr_levels[m_sr_count].price = price;
         m_sr_levels[m_sr_count].is_support = is_support;
         m_sr_levels[m_sr_count].touch_count = 1;
         m_sr_levels[m_sr_count].first_touch = TimeCurrent();
         m_sr_levels[m_sr_count].last_touch = TimeCurrent();
         m_sr_levels[m_sr_count].is_active = true;
         m_sr_count++;
        }
     }

   void              CalculateSRStrengths()
     {
      for(int i = 0; i < m_sr_count; i++)
        {
         double time_factor = 1.0;
         double touch_factor = m_sr_levels[i].touch_count;
         double age_hours = (TimeCurrent() - m_sr_levels[i].first_touch) / 3600.0;

         if(age_hours < 24)
            time_factor = 1.2;
         else
            if(age_hours < 168)
               time_factor = 1.0; // 1 week
            else
               time_factor = 0.8;

         m_sr_levels[i].strength = touch_factor * time_factor;
        }
     }

   void              SortSRLevelsByStrength()
     {

      for(int i = 0; i < m_sr_count - 1; i++)
        {
         for(int j = 0; j < m_sr_count - i - 1; j++)
           {
            if(m_sr_levels[j].strength < m_sr_levels[j + 1].strength)
              {
               SRLevel temp = m_sr_levels[j];
               m_sr_levels[j] = m_sr_levels[j + 1];
               m_sr_levels[j + 1] = temp;
              }
           }
        }

      if(m_sr_count > 20)
         m_sr_count = 20;
     }

   void              DetectCurrentChannel()
     {
      m_in_channel = false;

      double high_buffer[], low_buffer[];
      ArraySetAsSeries(high_buffer, true);
      ArraySetAsSeries(low_buffer, true);

      if(CopyHigh(_Symbol, PERIOD_CURRENT, 0, ChannelMinBars, high_buffer) <= 0 ||
         CopyLow(_Symbol, PERIOD_CURRENT, 0, ChannelMinBars, low_buffer) <= 0)
         return;

      double upper_slope, upper_intercept, lower_slope, lower_intercept;
      double upper_correlation = CalculateLinearRegression(high_buffer, ChannelMinBars, upper_slope, upper_intercept);
      double lower_correlation = CalculateLinearRegression(low_buffer, ChannelMinBars, lower_slope, lower_intercept);

      if(MathAbs(upper_correlation) > ChannelThreshold &&
         MathAbs(lower_correlation) > ChannelThreshold &&
         MathAbs(upper_slope - lower_slope) < 0.0001) // Parallel lines
        {
         m_current_channel.upper_line = upper_intercept;
         m_current_channel.lower_line = lower_intercept;
         m_current_channel.slope = (upper_slope + lower_slope) / 2.0;
         m_current_channel.strength = (MathAbs(upper_correlation) + MathAbs(lower_correlation)) / 2.0;
         m_current_channel.is_active = true;
         m_current_channel.start_time = TimeCurrent();
         m_in_channel = true;

         Print("✓ Channel detected - Upper: ", m_current_channel.upper_line,
               " Lower: ", m_current_channel.lower_line,
               " Strength: ", m_current_channel.strength);
        }
     }

   double            CalculateLinearRegression(const double &prices[], int period, double &slope, double &intercept)
     {
      double sum_x = 0, sum_y = 0, sum_xy = 0, sum_x2 = 0;

      for(int i = 0; i < period; i++)
        {
         sum_x += i;
         sum_y += prices[i];
         sum_xy += i * prices[i];
         sum_x2 += i * i;
        }

      slope = (period * sum_xy - sum_x * sum_y) / (period * sum_x2 - sum_x * sum_x);
      intercept = (sum_y - slope * sum_x) / period;

      double sum_y2 = 0;
      for(int i = 0; i < period; i++)
         sum_y2 += prices[i] * prices[i];

      double numerator = period * sum_xy - sum_x * sum_y;
      double denominator = MathSqrt((period * sum_x2 - sum_x * sum_x) * (period * sum_y2 - sum_y * sum_y));

      return (denominator != 0) ? numerator / denominator : 0;
     }
   bool              IsNewBar()
     {
      static datetime last_bar_time = 0;
      datetime current_bar_time = iTime(_Symbol, PERIOD_CURRENT, 0);

      if(current_bar_time != last_bar_time)
        {
         last_bar_time = current_bar_time;
         return true;
        }
      return false;
     }
   bool              CheckResistanceBreakout(double current_price, double resistance_level, double strength,
                                double &breakout_level, double &confidence_score)
     {
      if(resistance_level == 0 || strength < SR_MinStrength)
         return false;

      double breakout_distance = (current_price - resistance_level) / _Point;

      if(breakout_distance < BreakoutMinPips || breakout_distance > BreakoutMaxPips)
         return false;

      double momentum_score = CalculateMomentumScore(true);
      if(UseMomentumFilter && momentum_score < MomentumThreshold)
         return false;

      double volume_score = CalculateVolumeScore();
      if(UseVolumeFilter && volume_score < VolumeMultiplier)
         return false;

      if(!PassesFalseBreakoutFilter(current_price, resistance_level, true))
         return false;

      confidence_score = CalculateBreakoutConfidence(strength, momentum_score, volume_score, breakout_distance);

      if(confidence_score >= FalseBreakoutFilter)
        {
         breakout_level = resistance_level;

         m_last_breakout.sr_level = resistance_level;
         m_last_breakout.is_resistance_break = true;
         m_last_breakout.break_time = TimeCurrent();
         m_last_breakout.break_price = current_price;
         m_last_breakout.momentum_score = momentum_score;
         m_last_breakout.volume_score = volume_score;
         m_last_breakout.is_confirmed = false;
         m_last_breakout.confirmation_bars = 0;
         m_breakout_pending = true;

         return true;
        }

      return false;
     }
   bool              CheckSupportBreakdown(double current_price, double support_level, double strength,
                              double &breakout_level, double &confidence_score)
     {
      if(support_level == 0 || strength < SR_MinStrength)
         return false;

      double breakout_distance = (support_level - current_price) / _Point;

      if(breakout_distance < BreakoutMinPips || breakout_distance > BreakoutMaxPips)
         return false;

      double momentum_score = CalculateMomentumScore(false);
      if(UseMomentumFilter && momentum_score < MomentumThreshold)
         return false;

      double volume_score = CalculateVolumeScore();
      if(UseVolumeFilter && volume_score < VolumeMultiplier)
         return false;

      if(!PassesFalseBreakoutFilter(current_price, support_level, false))
         return false;

      confidence_score = CalculateBreakoutConfidence(strength, momentum_score, volume_score, breakout_distance);

      if(confidence_score >= FalseBreakoutFilter)
        {
         breakout_level = support_level;

         m_last_breakout.sr_level = support_level;
         m_last_breakout.is_resistance_break = false;
         m_last_breakout.break_time = TimeCurrent();
         m_last_breakout.break_price = current_price;
         m_last_breakout.momentum_score = momentum_score;
         m_last_breakout.volume_score = volume_score;
         m_last_breakout.is_confirmed = false;
         m_last_breakout.confirmation_bars = 0;
         m_breakout_pending = true;

         return true;
        }

      return false;
     }

   double            CalculateMomentumScore(bool bullish_breakout)
     {

      double atr_current = g_market_analyzer.GetATR();
      double atr_buffer[];
      ArraySetAsSeries(atr_buffer, true);

      int atr_handle = iATR(_Symbol, PERIOD_CURRENT, 14);
      if(CopyBuffer(atr_handle, 0, 0, 10, atr_buffer) <= 0)
         return 0;

      double atr_avg = 0;
      for(int i = 1; i < 10; i++) // Skip current bar
         atr_avg += atr_buffer[i];
      atr_avg /= 9;

      double momentum_ratio = (atr_avg > 0) ? atr_current / atr_avg : 1.0;

      double close_buffer[];
      ArraySetAsSeries(close_buffer, true);
      if(CopyClose(_Symbol, PERIOD_CURRENT, 0, 5, close_buffer) <= 0)
         return momentum_ratio;

      double price_velocity = 0;
      if(bullish_breakout)
         price_velocity = (close_buffer[0] - close_buffer[4]) / (4 * _Point);
      else
         price_velocity = (close_buffer[4] - close_buffer[0]) / (4 * _Point);

      double velocity_score = MathMax(0, price_velocity / 20.0); // Normalize velocity

      return momentum_ratio + velocity_score;
     }

   double            CalculateVolumeScore()
     {
      if(!UseVolumeFilter)
         return VolumeMultiplier; // Pass if not using volume

      long volume_buffer[];
      ArraySetAsSeries(volume_buffer, true);

      if(CopyTickVolume(_Symbol, PERIOD_CURRENT, 0, VolumeConfirmPeriod + 1, volume_buffer) <= 0)
         return 1.0; // Default if no volume data

      long current_volume = volume_buffer[0];
      long avg_volume = 0;

      for(int i = 1; i <= VolumeConfirmPeriod; i++)
         avg_volume += volume_buffer[i];

      avg_volume /= VolumeConfirmPeriod;

      return (avg_volume > 0) ? (double)current_volume / (double)avg_volume : 1.0;
     }

   bool              PassesFalseBreakoutFilter(double current_price, double sr_level, bool is_resistance_break)
     {

      double close_buffer[];
      ArraySetAsSeries(close_buffer, true);

      if(CopyClose(_Symbol, PERIOD_CURRENT, 0, 3, close_buffer) <= 0)
         return true; // Default pass if no data

      double min_penetration = BreakoutMinPips * _Point;

      if(is_resistance_break)
        {

         return (close_buffer[0] > sr_level + min_penetration);
        }
      else
        {

         return (close_buffer[0] < sr_level - min_penetration);
        }
     }

   double            CalculateBreakoutConfidence(double sr_strength, double momentum_score, double volume_score, double breakout_distance)
     {

      double strength_score = MathMin(sr_strength / 10.0, 1.0); // Max 10 touches
      double momentum_normalized = MathMin(momentum_score / 3.0, 1.0); // Max 3x momentum
      double volume_normalized = MathMin(volume_score / 3.0, 1.0); // Max 3x volume
      double distance_score = MathMin(breakout_distance / BreakoutMaxPips, 1.0);

      double confidence = (strength_score * 0.3) +
                          (momentum_normalized * 0.3) +
                          (volume_normalized * 0.2) +
                          (distance_score * 0.2);

      return confidence;
     }

public:
   bool              IsNearSupportLevel(double price, double &support_level, double &strength)
     {
      double buffer = SR_ZoneBuffer * _Point;

      for(int i = 0; i < m_sr_count; i++)
        {
         if(m_sr_levels[i].is_support && m_sr_levels[i].is_active &&
            m_sr_levels[i].strength >= SR_MinStrength)
           {
            if(MathAbs(price - m_sr_levels[i].price) <= buffer)
              {
               support_level = m_sr_levels[i].price;
               strength = m_sr_levels[i].strength;
               return true;
              }
           }
        }
      return false;
     }

   bool              IsNearResistanceLevel(double price, double &resistance_level, double &strength)
     {
      double buffer = SR_ZoneBuffer * _Point;

      for(int i = 0; i < m_sr_count; i++)
        {
         if(!m_sr_levels[i].is_support && m_sr_levels[i].is_active &&
            m_sr_levels[i].strength >= SR_MinStrength)
           {
            if(MathAbs(price - m_sr_levels[i].price) <= buffer)
              {
               resistance_level = m_sr_levels[i].price;
               strength = m_sr_levels[i].strength;
               return true;
              }
           }
        }
      return false;
     }

   bool              IsInChannel() { return m_in_channel && UseChannelTrading; }

   bool              IsNearChannelSupport(double price)
     {
      if(!m_in_channel)
         return false;
      double buffer = SR_ZoneBuffer * _Point;
      return MathAbs(price - m_current_channel.lower_line) <= buffer;
     }

   bool              IsNearChannelResistance(double price)
     {
      if(!m_in_channel)
         return false;
      double buffer = SR_ZoneBuffer * _Point;
      return MathAbs(price - m_current_channel.upper_line) <= buffer;
     }

   double            GetChannelSupport() { return m_current_channel.lower_line; }
   double            GetChannelResistance() { return m_current_channel.upper_line; }
   double            GetChannelStrength() { return m_current_channel.strength; }

   void              UpdateSRLevels()
     {
      DetectSupportResistanceLevels();
      DetectCurrentChannel();
     }
   bool              IsBreakoutConfirmed(double current_price)
     {
      if(!m_breakout_pending)
         return false;

      m_last_breakout.confirmation_bars++;

      bool still_valid = false;
      double min_distance = BreakoutMinPips * _Point * 0.5; // Half the minimum distance

      if(m_last_breakout.is_resistance_break)
        {
         still_valid = (current_price > m_last_breakout.sr_level + min_distance);
        }
      else
        {
         still_valid = (current_price < m_last_breakout.sr_level - min_distance);
        }

      if(!still_valid)
        {
         m_breakout_pending = false; // Failed breakout
         return false;
        }

      if(m_last_breakout.confirmation_bars >= BreakoutConfirmBars)
        {
         m_last_breakout.is_confirmed = true;
         m_breakout_pending = false;
         return true;
        }

      return false;
     }

   bool              CheckSRBreakoutEntry(double current_price, ENUM_TREND_DIRECTION trend, datetime &last_trade_time)
     {

      static datetime last_breakout_trade = 0;
      if(TimeCurrent() - last_breakout_trade < 7200)
         return false; // 2 hours minimum

      double breakout_level = 0, confidence_score = 0;
      bool is_bullish_breakout = false;

      if(DetectBreakout(current_price, breakout_level, is_bullish_breakout, confidence_score))
        {
         Print("⚡ Potential breakout detected at level: ", breakout_level,
               " Direction: ", is_bullish_breakout ? "BULLISH" : "BEARISH",
               " Confidence: ", confidence_score);
         return false; // Wait for confirmation
        }

      if(IsBreakoutConfirmed(current_price))
        {

         bool is_resistance_break = (current_price > breakout_level);

         if(!PassesBreakoutFilters(is_resistance_break, trend))
            return false;

         double base_lot = g_risk_manager.CalculatePositionSize(1);
         double confidence_multiplier = MathMin(confidence_score * 2.0, 1.5); // Max 1.5x
         double lot_size = base_lot * confidence_multiplier;
         lot_size = MathMin(lot_size, MaxLotSize);

         lot_size = NormalizeLots(lot_size);

         if(is_resistance_break)
           {

            if(g_risk_manager.ValidateTrade(lot_size, ORDER_TYPE_BUY))
              {
               if(g_trade_manager.OpenInitialPosition(ORDER_TYPE_BUY, lot_size, Commentary + "_Breakout_Buy"))
                 {
                  Print("✅ BREAKOUT BUY executed at: ", current_price,
                        " Breaking resistance: ", breakout_level,
                        " Lot size: ", lot_size,
                        " Confidence: ", confidence_score);
                  last_trade_time = TimeCurrent();
                  last_breakout_trade = TimeCurrent();
                  return true;
                 }
              }
           }
         else
           {

            if(g_risk_manager.ValidateTrade(lot_size, ORDER_TYPE_SELL))
              {
               if(g_trade_manager.OpenInitialPosition(ORDER_TYPE_SELL, lot_size, Commentary + "_Breakout_Sell"))
                 {
                  Print("✅ BREAKOUT SELL executed at: ", current_price,
                        " Breaking support: ", breakout_level,
                        " Lot size: ", lot_size,
                        " Confidence: ", confidence_score);
                  last_trade_time = TimeCurrent();
                  last_breakout_trade = TimeCurrent();
                  return true;
                 }
              }
           }
        }

      return false;
     }

   bool              PassesBreakoutFilters(bool is_bullish_breakout, ENUM_TREND_DIRECTION trend)
     {

      if(trend != TREND_NEUTRAL)
        {
         if(is_bullish_breakout && trend == TREND_BEARISH)
            return false;
         if(!is_bullish_breakout && trend == TREND_BULLISH)
            return false;
        }

      double atr_current = g_market_analyzer.GetATR();
      if(atr_current < 20 * _Point)
         return false; // Minimum volatility required

      if(UseRSIFilter)
        {
         double rsi = g_market_analyzer.GetRSI();
         if(is_bullish_breakout && rsi > 80)
            return false; // Avoid extreme overbought
         if(!is_bullish_breakout && rsi < 20)
            return false; // Avoid extreme oversold
        }

      MqlDateTime current_time;
      TimeToStruct(TimeCurrent(), current_time);

      if(current_time.hour >= 22 || current_time.hour <= 6)
         return false;

      return true;
     }

   void              UpdateBreakoutInfo()
     {

      string breakout_status = "No active breakouts";

      if(g_sr_detector.IsBreakoutPending())
        {
         breakout_status = "Breakout pending confirmation...";
        }

     }

  };

void CheckEnhancedSimpleEntry()
  {
   if(!UseEnhancedEntry)
      return;

   static datetime last_update = 0;
   static datetime last_trade_time = 0;

   if(TimeCurrent() - last_update > 3600)
     {
      g_sr_detector.UpdateSRLevels();
      last_update = TimeCurrent();
     }

   if(TimeCurrent() - last_trade_time < 14400)
      return; // 4 hours minimum

   double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   ENUM_MARKET_PHASE market_phase = g_market_analyzer.GetMarketPhase();
   ENUM_TREND_DIRECTION trend = g_market_analyzer.GetTrendDirection();

   if(g_sr_detector.IsInChannel() && market_phase == MARKET_RANGING)
     {
      if(CheckChannelEntry(current_price, last_trade_time))
         return;
     }

   if(market_phase == MARKET_TRENDING && trend != TREND_NEUTRAL)
     {
      if(CheckSRBounceEntry(current_price, trend, last_trade_time))
         return;
     }

   if(CheckSRBreakoutEntry(current_price, trend, last_trade_time))
      return;
  }

bool CheckChannelEntry(double current_price, datetime &last_trade_time)
  {

   if(g_sr_detector.IsNearChannelSupport(current_price))
     {
      if(g_market_analyzer.IsRSIOversold())
        {
         double lot_size = CalculateEnhancedLotSize(g_sr_detector.GetChannelStrength());

         if(g_risk_manager.ValidateTrade(lot_size, ORDER_TYPE_BUY))
           {
            if(g_trade_manager.OpenInitialPosition(ORDER_TYPE_BUY, lot_size, Commentary + "_Channel_Support"))
              {
               Print("✓ CHANNEL BUY at support: ", g_sr_detector.GetChannelSupport(),
                     " Strength: ", g_sr_detector.GetChannelStrength());
               last_trade_time = TimeCurrent();
               return true;
              }
           }
        }
     }

   if(g_sr_detector.IsNearChannelResistance(current_price))
     {
      if(g_market_analyzer.IsRSIOverbought())
        {
         double lot_size = CalculateEnhancedLotSize(g_sr_detector.GetChannelStrength());

         if(g_risk_manager.ValidateTrade(lot_size, ORDER_TYPE_SELL))
           {
            if(g_trade_manager.OpenInitialPosition(ORDER_TYPE_SELL, lot_size, Commentary + "_Channel_Resistance"))
              {
               Print("✓ CHANNEL SELL at resistance: ", g_sr_detector.GetChannelResistance(),
                     " Strength: ", g_sr_detector.GetChannelStrength());
               last_trade_time = TimeCurrent();
               return true;
              }
           }
        }
     }

   return false;
  }

bool CheckSRBounceEntry(double current_price, ENUM_TREND_DIRECTION trend, datetime &last_trade_time)
  {
   double level, strength;

   if(trend == TREND_BULLISH && g_sr_detector.IsNearSupportLevel(current_price, level, strength))
     {
      if(g_market_analyzer.IsRSIOversold())
        {
         double lot_size = CalculateEnhancedLotSize(strength);

         if(g_risk_manager.ValidateTrade(lot_size, ORDER_TYPE_BUY))
           {
            if(g_trade_manager.OpenInitialPosition(ORDER_TYPE_BUY, lot_size, Commentary + "_SR_Support"))
              {
               Print("✓ S/R BUY bounce at: ", level, " Strength: ", strength);
               last_trade_time = TimeCurrent();
               return true;
              }
           }
        }
     }

   if(trend == TREND_BEARISH && g_sr_detector.IsNearResistanceLevel(current_price, level, strength))
     {
      if(g_market_analyzer.IsRSIOverbought())
        {
         double lot_size = CalculateEnhancedLotSize(strength);

         if(g_risk_manager.ValidateTrade(lot_size, ORDER_TYPE_SELL))
           {
            if(g_trade_manager.OpenInitialPosition(ORDER_TYPE_SELL, lot_size, Commentary + "_SR_Resistance"))
              {
               Print("✓ S/R SELL bounce at: ", level, " Strength: ", strength);
               last_trade_time = TimeCurrent();
               return true;
              }
           }
        }
     }

   return false;
  }

bool CheckSRBreakoutEntry(double current_price, ENUM_TREND_DIRECTION trend, datetime &last_trade_time)
  {

   static datetime last_breakout_trade = 0;
   if(TimeCurrent() - last_breakout_trade < 7200)
      return false; // 2 hours minimum

   double resistance_level, resistance_strength;
   if(g_sr_detector.IsNearResistanceLevel(current_price, resistance_level, resistance_strength))
     {

      double breakout_distance = (current_price - resistance_level) / _Point;

      if(breakout_distance >= BreakoutMinPips && breakout_distance <= BreakoutMaxPips)
        {

         if(trend == TREND_BEARISH)
            return false; // Don't trade against strong trend

         if(UseMomentumFilter)
           {
            double atr_current = g_market_analyzer.GetATR();
            if(atr_current < 20 * _Point)
               return false; // Minimum volatility required
           }

         if(UseRSIFilter)
           {
            double rsi = g_market_analyzer.GetRSI();
            if(rsi > 80)
               return false; // Avoid extreme overbought
           }

         double confidence_score = MathMin(resistance_strength / 5.0, 1.0); // Normalize strength
         double base_lot = g_risk_manager.CalculatePositionSize(1);
         double lot_size = base_lot * (0.5 + confidence_score * 0.5); // 50%-100% based on confidence
         lot_size = MathMin(lot_size, MaxLotSize);

         lot_size = NormalizeLots(lot_size);

         if(g_risk_manager.ValidateTrade(lot_size, ORDER_TYPE_BUY))
           {
            if(g_trade_manager.OpenInitialPosition(ORDER_TYPE_BUY, lot_size, Commentary + "_Breakout_Buy"))
              {
               Print("✅ RESISTANCE BREAKOUT BUY at: ", current_price,
                     " Breaking resistance: ", resistance_level,
                     " Distance: ", breakout_distance, " pips",
                     " Strength: ", resistance_strength,
                     " Lot size: ", lot_size);
               last_trade_time = TimeCurrent();
               last_breakout_trade = TimeCurrent();
               return true;
              }
           }
        }
     }

   double support_level, support_strength;
   if(g_sr_detector.IsNearSupportLevel(current_price, support_level, support_strength))
     {

      double breakout_distance = (support_level - current_price) / _Point;

      if(breakout_distance >= BreakoutMinPips && breakout_distance <= BreakoutMaxPips)
        {

         if(trend == TREND_BULLISH)
            return false; // Don't trade against strong trend

         if(UseMomentumFilter)
           {
            double atr_current = g_market_analyzer.GetATR();
            if(atr_current < 20 * _Point)
               return false; // Minimum volatility required
           }

         if(UseRSIFilter)
           {
            double rsi = g_market_analyzer.GetRSI();
            if(rsi < 20)
               return false; // Avoid extreme oversold
           }

         double confidence_score = MathMin(support_strength / 5.0, 1.0); // Normalize strength
         double base_lot = g_risk_manager.CalculatePositionSize(1);
         double lot_size = base_lot * (0.5 + confidence_score * 0.5); // 50%-100% based on confidence
         lot_size = MathMin(lot_size, MaxLotSize);

         lot_size = NormalizeLots(lot_size);

         if(g_risk_manager.ValidateTrade(lot_size, ORDER_TYPE_SELL))
           {
            if(g_trade_manager.OpenInitialPosition(ORDER_TYPE_SELL, lot_size, Commentary + "_Breakout_Sell"))
              {
               Print("✅ SUPPORT BREAKDOWN SELL at: ", current_price,
                     " Breaking support: ", support_level,
                     " Distance: ", breakout_distance, " pips",
                     " Strength: ", support_strength,
                     " Lot size: ", lot_size);
               last_trade_time = TimeCurrent();
               last_breakout_trade = TimeCurrent();
               return true;
              }
           }
        }
     }

   return false;
  }

double CalculateEnhancedLotSize(double sr_strength)
  {
   int current_positions = g_risk_manager.GetGridPositionCount();
   double base_lot = g_risk_manager.CalculatePositionSize(current_positions);

   if(!UseDynamicLotSizing)
      return base_lot;

   double strength_multiplier = 1.0;
   if(sr_strength >= 5.0)
      strength_multiplier = 1.2; // Reduced from 1.5 to avoid over-sizing
   else
      if(sr_strength >= 3.0)
         strength_multiplier = 1.1;
      else
         strength_multiplier = 0.9;

   double final_lot = base_lot * strength_multiplier;

   return NormalizeLots(final_lot);
  }

class CRiskManager
  {
private:
   double            m_initial_balance;
   datetime          m_last_check_time;

public:
                     CRiskManager() : m_initial_balance(AccountInfoDouble(ACCOUNT_BALANCE)), m_last_check_time(0) {}

   double            GetCurrentExposure()
     {
      double total_profit = 0.0;
      double total_floating = 0.0;

      for(int i = 0; i < PositionsTotal(); i++)
        {
         if(position.SelectByIndex(i) && position.Magic() == MagicNumber && position.Symbol() == _Symbol)
           {
            total_profit += position.Profit();
            total_floating += position.Swap() + position.Commission();
           }
        }

      double current_equity = AccountInfoDouble(ACCOUNT_EQUITY);
      if(current_equity <= 0)
         return 0;

      return ((total_profit + total_floating) / current_equity) * 100.0;
     }

   bool              IsExposureAcceptable()
     {
 

Показано первые 50% кода (символов: 79149)

Открыть по тарифу

Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.

Разовая покупка файла

На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.

Чтобы оформить заказ, введите email и перейдите к оплате.

Стоимость полного кода
7 914,90₽ ≈ $96.75