Sprawdź mi ten kod: //+------------------------------------------------------------------+
//| Ekspert Doradca - FVG i OB z rysowaniem i handlem               |
//+------------------------------------------------------------------+
//| Opis: EA łączy analizę Fair Value Gaps (FVG), Order Blocks (OB), |
//| Equal Highs/Lows (EQH/EQL), Swing Structure (BOS/CHoCH),         |
//| Multi-Timeframe Levels, Premium/Discount Zones i Volatility Filter|
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, Private Use Only"
#property link      ""
#property version   "1.15" // Zaktualizowana wersja
#property strict

#include <Trade\Trade.mqh>
#include "PositionManager.mqh"
#include "SMCManager.mqh"
#include "FvgManager.mqh"
#include "Config.mqh"
#include "Utilities.mqh"

//+------------------------------------------------------------------+
//| Ustawienia ogólne                                                |
//+------------------------------------------------------------------+
input group "Ustawienia ogólne"
input double InpLotSize = 0.1;           // Stały rozmiar lota na transakcję
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_M15; // Interwał czasowy
input bool InpAllowWeekendTrading = false; // Handel w weekendy
input int InpMinTradeInterval = 60;      // Minimalny odstęp między transakcjami (sekundy)
input bool InpKeepSLTPDrawing = true;    // Pozostaw narysowane SL i TP
input double InpSellStopOffset = DEFAULT_SELL_STOP_OFFSET; // Odległość ENTRY poniżej BID dla Sell Stop (punkty)
input double InpRiskRewardRatio = DEFAULT_RISK_REWARD_RATIO; // Współczynnik Risk-to-Reward dla TP

//+------------------------------------------------------------------+
//| Typ rynku                                                        |
//+------------------------------------------------------------------+
input group "Typ rynku"
enum MarketType { Forex, Index, Crypto };
input MarketType InpMarketType = Forex;  // Typ rynku (domyślnie Forex)

//+------------------------------------------------------------------+
//| Ustawienia FVG                                                   |
//+------------------------------------------------------------------+
input group "Ustawienia FVG"
input bool InpUseFvg = true;             // Używaj FVG
input bool InpDrawFvg = true;            // Rysuj FVG na wykresie
input bool InpUseSeparateFvgTimeframe = true; // Używaj osobnego interwału dla FVG
input ENUM_TIMEFRAMES InpFvgTimeframe = PERIOD_H1; // Interwał FVG
input bool InpContinueToMitigation = true; // Kontynuuj do mitigacji
input double InpFvgMinWidthMultiplier = 1.0; // Mnożnik minimalnej szerokości FVG (względem ATR)
input int InpFvgExtendBars = 1;          // Liczba słupków do rozszerzenia FVG
input color InpDownTrendColor = clrLightPink; // Kolor trendu spadkowego
input color InpUpTrendColor = clrLightGreen; // Kolor trendu wzrostowego
input bool InpFill = true;               // Wypełnienie pełne (true) lub przezroczyste (false)
input ENUM_LINE_STYLE InpBorderStyle = STYLE_SOLID; // Styl linii obramowania
input int InpBorderWidth = 2;            // Szerokość linii obramowania

//+------------------------------------------------------------------+
//| Ustawienia Order Block                                           |
//+------------------------------------------------------------------+
input group "Ustawienia Order Block"
input bool InpUseOb = true;              // Używaj Order Blocks
input bool InpDrawOb = true;             // Rysuj Order Blocks na wykresie
input int InpObRange = 5;                // Zakres OB (świeczki)
input double InpObVolatilityMultiplier = 2.0; // Mnożnik zmienności dla OB (względem ATR)

//+------------------------------------------------------------------+
//| Ustawienia Equal Highs/Lows (EQH/EQL)                            |
//+------------------------------------------------------------------+
input group "Ustawienia Equal Highs/Lows"
input bool InpUseEqualHL = true;         // Używaj Equal Highs/Lows
input bool InpDrawEqualHL = true;        // Rysuj Equal Highs/Lows na wykresie
input int InpEqualHLLength = 3;          // Liczba barów do potwierdzenia EQH/EQL
input double InpEqualHLThreshold = 0.1;  // Próg czułości EQH/EQL (względem ATR)
input color InpEqualHLColor = clrYellow; // Kolor EQH/EQL

//+------------------------------------------------------------------+
//| Ustawienia Swing Structure (BOS/CHoCH)                           |
//+------------------------------------------------------------------+
input group "Ustawienia Swing Structure"
input bool InpUseSwingStructure = true;  // Używaj Swing Structure (BOS/CHoCH)
input bool InpDrawSwingStructure = true; // Rysuj Swing Structure na wykresie
input int InpSwingLength = 50;           // Długość analizy swingowej
input color InpSwingBullColor = clrGreen;// Kolor BOS/CHoCH wzrostowego
input color InpSwingBearColor = clrRed;  // Kolor BOS/CHoCH spadkowego

//+------------------------------------------------------------------+
//| Ustawienia Multi-Timeframe Levels                                |
//+------------------------------------------------------------------+
input group "Ustawienia Multi-Timeframe Levels"
input bool InpUseMTFLevels = true;       // Używaj poziomów MTF
input bool InpDrawMTFLevels = true;      // Rysuj poziomy MTF na wykresie
input bool InpShowDailyLevels = true;    // Pokazuj poziomy dzienne
input bool InpShowWeeklyLevels = true;   // Pokazuj poziomy tygodniowe
input bool InpShowMonthlyLevels = true;  // Pokazuj poziomy miesięczne
input color InpMTFLevelsColor = clrBlue; // Kolor poziomów MTF

//+------------------------------------------------------------------+
//| Ustawienia Premium/Discount Zones                                |
//+------------------------------------------------------------------+
input group "Ustawienia Premium/Discount Zones"
input bool InpUsePremiumDiscount = true; // Używaj stref Premium/Discount
input bool InpDrawPremiumDiscount = true;// Rysuj strefy Premium/Discount
input color InpPremiumColor = clrRed;    // Kolor strefy Premium
input color InpDiscountColor = clrGreen; // Kolor strefy Discount
input color InpEquilibriumColor = clrGray;// Kolor strefy Equilibrium

//+------------------------------------------------------------------+
//| Ustawienia Volatility Filter                                     |
//+------------------------------------------------------------------+
input group "Ustawienia Volatility Filter"
input bool InpUseVolatilityFilter = true;// Używaj filtru zmienności
input double InpVolatilityThreshold = 2.0;// Próg zmienności (względem ATR)

//+------------------------------------------------------------------+
//| Ustawienia logowania                                             |
//+------------------------------------------------------------------+
input group "Ustawienia logowania"
input bool InpLogToFile = false;         // Zapisywanie logów do pliku (false = tylko konsola)
input bool InpDebugEnabled = true;       // Włącz debugowanie (domyślnie true dla diagnostyki)

//+------------------------------------------------------------------+
//| Zmienne globalne                                                 |
//+------------------------------------------------------------------+
string dynamicSymbol;                    // Dynamiczny symbol
datetime g_lastTradeTime = 0;            // Czas ostatniej transakcji
CTrade g_trade;                          // Obiekt handlu
CPositionManager* g_positionManager = NULL; // Wskaźnik do zarządzania pozycjami
CSMCManager* g_smcManager = NULL;        // Wskaźnik do OB
CFvgManager* g_fvgManager = NULL;        // Wskaźnik do FVG
bool g_isATRInitialized = false;         // Flaga inicjalizacji ATR

struct TrailingExtremes
{
   double top;
   double bottom;
   datetime lastTopTime;
   datetime lastBottomTime;
   void Update(double high, double low, datetime currentTime)
   {
      if(high > top || top == 0) { top = high; lastTopTime = currentTime; }
      if(low < bottom || bottom == 0) { bottom = low; lastBottomTime = currentTime; }
   }
};
TrailingExtremes trailing;

ENUM_TREND swingTrend = TREND_NEUTRAL;   // Poprawiony typ z Utilities.mqh
double lastSwingHigh = 0, lastSwingLow = 0;

//+------------------------------------------------------------------+
//| Funkcja inicjalizacji EA                                         |
//+------------------------------------------------------------------+
int OnInit()
{
   Logger::Initialize(InpDebugEnabled ? 4 : 3, InpLogToFile ? "Logs\\FVG_Bot_Log.txt" : "", "FVG_Bot");
   Logger::LogInfo(__FUNCTION__, "Rozpoczynanie inicjalizacji EA, wersja=" + "1.15"); // Bezpośrednie użycie wartości z #property version

   if(InpDebugEnabled)
      Print("FVG bot initialization started");

   dynamicSymbol = Symbol();
   if(dynamicSymbol == "")
   {
      Logger::LogError(__FUNCTION__, "Nie udało się pobrać symbolu");
      return INIT_PARAMETERS_INCORRECT;
   }
   Logger::LogInfo(__FUNCTION__, "Symbol=" + dynamicSymbol + ", timeframe=" + EnumToString(InpTimeframe));

   // Inicjalizacja PositionManager z nowymi parametrami
   g_positionManager = new CPositionManager(MAGIC_NUMBER, InpSellStopOffset, InpRiskRewardRatio);
   if(!g_positionManager.IsInitialized())
   {
      Logger::LogError(__FUNCTION__, "Nie udało się zainicjować PositionManager");
      return INIT_FAILED;
   }

   // Wymuszenie ładowania danych historycznych
   ENUM_TIMEFRAMES fvgTimeframe = InpUseSeparateFvgTimeframe ? InpFvgTimeframe : InpTimeframe;
   MqlRates ratesM15[], ratesFvg[];
   ArraySetAsSeries(ratesM15, true);
   ArraySetAsSeries(ratesFvg, true);

   int copiedM15 = CopyRates(dynamicSymbol, PERIOD_M15, TimeCurrent(), 1000, ratesM15);
   int copiedFvg = CopyRates(dynamicSymbol, fvgTimeframe, TimeCurrent(), 1000, ratesFvg);

   if(copiedM15 < 100 || copiedFvg < 100)
   {
      Logger::LogError(__FUNCTION__, "Za mało danych historycznych: M15=" + IntegerToString(copiedM15) + 
                       ", " + EnumToString(fvgTimeframe) + "=" + IntegerToString(copiedFvg));
      return INIT_FAILED;
   }
   Logger::LogInfo(__FUNCTION__, "Pobrano dane: M15=" + IntegerToString(copiedM15) + " barów, " + 
                   EnumToString(fvgTimeframe) + "=" + IntegerToString(copiedFvg) + " barów");

   // Inicjalizacja managerów
   g_smcManager = new CSMCManager(dynamicSymbol, InpTimeframe, InpObRange, InpObVolatilityMultiplier, 
                                  InpLotSize, g_positionManager, InpDrawOb);
   g_fvgManager = new CFvgManager(dynamicSymbol, fvgTimeframe, InpContinueToMitigation, 
                                  InpFvgMinWidthMultiplier, InpFvgExtendBars, InpDownTrendColor, 
                                  InpUpTrendColor, InpFill, InpBorderStyle, InpBorderWidth, 
                                  InpDebugEnabled, InpLotSize, g_positionManager, InpDrawFvg);

   if(!g_smcManager.IsInitialized() || !g_fvgManager.IsInitialized())
   {
      Logger::LogError(__FUNCTION__, "Błąd inicjalizacji managerów: SMC=" + 
                       BoolToString(g_smcManager.IsInitialized()) + ", FVG=" + 
                       BoolToString(g_fvgManager.IsInitialized()));
      return INIT_FAILED;
   }

   g_trade.SetExpertMagicNumber(MAGIC_NUMBER);
   g_lastTradeTime = TimeTradeServer();

   Logger::LogInfo(__FUNCTION__, "Inicjalizacja zakończona pomyślnie dla symbol=" + dynamicSymbol + 
                   ", SellStopOffset=" + DoubleToString(InpSellStopOffset, 1) + 
                   ", RiskRewardRatio=" + DoubleToString(InpRiskRewardRatio, 1));
   if(InpDebugEnabled)
      Print("FVG bot initialization finished");
   return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Funkcja deinicjalizacji EA                                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   Logger::LogInfo(__FUNCTION__, "Deinicjalizacja EA, powód=" + IntegerToString(reason));
   if(InpDebugEnabled)
      Print("FVG bot deinitialization started");

   if(g_fvgManager != NULL) { delete g_fvgManager; g_fvgManager = NULL; }
   if(g_smcManager != NULL) { delete g_smcManager; g_smcManager = NULL; }
   if(g_positionManager != NULL) { delete g_positionManager; g_positionManager = NULL; }

   if(!MQLInfoInteger(MQL_TESTER))
   {
      ObjectsDeleteAll(0, SMC_FVG_PREFIX);
      ObjectsDeleteAll(0, SMC_OB_PREFIX);
      ObjectsDeleteAll(0, SMC_EQHL_PREFIX);
      ObjectsDeleteAll(0, SMC_SWING_PREFIX);
      ObjectsDeleteAll(0, SMC_MTF_PREFIX);
      ObjectsDeleteAll(0, SMC_ZONE_PREFIX);
   }

   if(InpDebugEnabled)
      Print("FVG bot deinitialization finished");
   Logger::LogInfo(__FUNCTION__, "Deinicjalizacja zakończona");
}

//+------------------------------------------------------------------+
//| Funkcje pomocnicze                                               |
//+------------------------------------------------------------------+
bool DetectEqualHighs(double &level, ENUM_TIMEFRAMES timeframe)
{
   double highLevel;
   if(DetectEqualHighs(dynamicSymbol, timeframe, InpEqualHLLength, InpEqualHLThreshold, highLevel))
   {
      level = highLevel;
      Logger::LogInfo(__FUNCTION__, "Wykryto Equal Highs (EQH): poziom=" + DoubleToString(highLevel, 5));
      if(InpDrawEqualHL)
      {
         string name = SMC_EQHL_PREFIX + "_H_" + TimeToString(TimeCurrent());
         ObjectCreate(0, name, OBJ_HLINE, 0, 0, highLevel);
         ObjectSetInteger(0, name, OBJPROP_COLOR, InpEqualHLColor);
         ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DOT);
      }
      return true;
   }
   return false;
}

bool DetectEqualLows(double &level, ENUM_TIMEFRAMES timeframe)
{
   double lowLevel;
   if(DetectEqualLows(dynamicSymbol, timeframe, InpEqualHLLength, InpEqualHLThreshold, lowLevel))
   {
      level = lowLevel;
      Logger::LogInfo(__FUNCTION__, "Wykryto Equal Lows (EQL): poziom=" + DoubleToString(lowLevel, 5));
      if(InpDrawEqualHL)
      {
         string name = SMC_EQHL_PREFIX + "_L_" + TimeToString(TimeCurrent());
         ObjectCreate(0, name, OBJ_HLINE, 0, 0, lowLevel);
         ObjectSetInteger(0, name, OBJPROP_COLOR, InpEqualHLColor);
         ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DOT);
      }
      return true;
   }
   return false;
}

void DrawMTFLevels()
{
   if(InpShowDailyLevels)
   {
      MqlRates rates[];
      ArraySetAsSeries(rates, true);
      if(CopyRates(dynamicSymbol, PERIOD_D1, 0, 2, rates) >= 2)
      {
         string highName = SMC_MTF_PREFIX + "_D_H_" + TimeToString(rates[1].time);
         string lowName = SMC_MTF_PREFIX + "_D_L_" + TimeToString(rates[1].time);
         ObjectCreate(0, highName, OBJ_HLINE, 0, 0, rates[1].high);
         ObjectCreate(0, lowName, OBJ_HLINE, 0, 0, rates[1].low);
         ObjectSetInteger(0, highName, OBJPROP_COLOR, InpMTFLevelsColor);
         ObjectSetInteger(0, lowName, OBJPROP_COLOR, InpMTFLevelsColor);
         ObjectSetInteger(0, highName, OBJPROP_STYLE, STYLE_SOLID);
         ObjectSetInteger(0, lowName, OBJPROP_STYLE, STYLE_SOLID);
      }
   }
   if(InpShowWeeklyLevels)
   {
      MqlRates rates[];
      ArraySetAsSeries(rates, true);
      if(CopyRates(dynamicSymbol, PERIOD_W1, 0, 2, rates) >= 2)
      {
         string highName = SMC_MTF_PREFIX + "_W_H_" + TimeToString(rates[1].time);
         string lowName = SMC_MTF_PREFIX + "_W_L_" + TimeToString(rates[1].time);
         ObjectCreate(0, highName, OBJ_HLINE, 0, 0, rates[1].high);
         ObjectCreate(0, lowName, OBJ_HLINE, 0, 0, rates[1].low);
         ObjectSetInteger(0, highName, OBJPROP_COLOR, InpMTFLevelsColor);
         ObjectSetInteger(0, lowName, OBJPROP_COLOR, InpMTFLevelsColor);
         ObjectSetInteger(0, highName, OBJPROP_STYLE, STYLE_SOLID);
         ObjectSetInteger(0, lowName, OBJPROP_STYLE, STYLE_SOLID);
      }
   }
   if(InpShowMonthlyLevels)
   {
      MqlRates rates[];
      ArraySetAsSeries(rates, true);
      if(CopyRates(dynamicSymbol, PERIOD_MN1, 0, 2, rates) >= 2)
      {
         string highName = SMC_MTF_PREFIX + "_M_H_" + TimeToString(rates[1].time);
         string lowName = SMC_MTF_PREFIX + "_M_L_" + TimeToString(rates[1].time);
         ObjectCreate(0, highName, OBJ_HLINE, 0, 0, rates[1].high);
         ObjectCreate(0, lowName, OBJ_HLINE, 0, 0, rates[1].low);
         ObjectSetInteger(0, highName, OBJPROP_COLOR, InpMTFLevelsColor);
         ObjectSetInteger(0, lowName, OBJPROP_COLOR, InpMTFLevelsColor);
         ObjectSetInteger(0, highName, OBJPROP_STYLE, STYLE_SOLID);
         ObjectSetInteger(0, lowName, OBJPROP_STYLE, STYLE_SOLID);
      }
   }
}

void UpdatePremiumDiscountZones()
{
   MqlRates rates[];
   ArraySetAsSeries(rates, true);
   if(CopyRates(dynamicSymbol, InpTimeframe, 0, 1, rates) < 1) return;

   double premium, discount, equilibrium;
   if(UpdatePremiumDiscountZones(dynamicSymbol, InpTimeframe, trailing.top, trailing.bottom, premium, discount, equilibrium) && InpDrawPremiumDiscount)
   {
      string premiumName = SMC_ZONE_PREFIX + "_Premium_" + TimeToString(TimeCurrent());
      string equilibriumName = SMC_ZONE_PREFIX + "_Equilibrium_" + TimeToString(TimeCurrent());
      string discountName = SMC_ZONE_PREFIX + "_Discount_" + TimeToString(TimeCurrent());

      ObjectCreate(0, premiumName, OBJ_RECTANGLE, 0, rates[0].time, trailing.top, TimeCurrent() + PeriodSeconds(InpTimeframe) * 5, premium);
      ObjectCreate(0, equilibriumName, OBJ_RECTANGLE, 0, rates[0].time, premium, TimeCurrent() + PeriodSeconds(InpTimeframe) * 5, discount);
      ObjectCreate(0, discountName, OBJ_RECTANGLE, 0, rates[0].time, discount, TimeCurrent() + PeriodSeconds(InpTimeframe) * 5, trailing.bottom);

      ObjectSetInteger(0, premiumName, OBJPROP_COLOR, InpPremiumColor);
      ObjectSetInteger(0, equilibriumName, OBJPROP_COLOR, InpEquilibriumColor);
      ObjectSetInteger(0, discountName, OBJPROP_COLOR, InpDiscountColor);
      ObjectSetInteger(0, premiumName, OBJPROP_FILL, true);
      ObjectSetInteger(0, equilibriumName, OBJPROP_FILL, true);
      ObjectSetInteger(0, discountName, OBJPROP_FILL, true);
   }
}

bool CheckVolatilityFilter()
{
   bool result = CheckVolatilityFilter(dynamicSymbol, InpTimeframe, InpVolatilityThreshold);
   if(InpDebugEnabled)
      Logger::LogDebug(__FUNCTION__, "Volatility Filter wynik=" + BoolToString(result));
   return result;
}

//+------------------------------------------------------------------+
//| Główna funkcja obsługująca ticki                                 |
//+------------------------------------------------------------------+
void OnTick()
{
   // Inicjalizacja ATR przy pierwszej świecy
   if(!g_isATRInitialized)
   {
      double atrM15 = GetATR(dynamicSymbol, PERIOD_M15);
      double atrFvg = GetATR(dynamicSymbol, InpUseSeparateFvgTimeframe ? InpFvgTimeframe : InpTimeframe);
      if(atrM15 <= 0 || atrFvg <= 0)
      {
         Logger::LogError(__FUNCTION__, "Nie udało się zainicjować ATR: M15=" + 
                          DoubleToString(atrM15, 5) + ", " + EnumToString(InpFvgTimeframe) + "=" + DoubleToString(atrFvg, 5));
         return;
      }
      Logger::LogInfo(__FUNCTION__, "ATR zainicjowane: M15=" + DoubleToString(atrM15, 5) + 
                      ", " + EnumToString(InpFvgTimeframe) + "=" + DoubleToString(atrFvg, 5));
      g_isATRInitialized = true;
   }

   // Sprawdzenie odstępu czasowego między transakcjami
   if(TimeTradeServer() - g_lastTradeTime < InpMinTradeInterval)
      return;

   // Walidacja interwału czasowego
   if(_Period != InpTimeframe)
   {
      Logger::LogWarning(__FUNCTION__, "Niewłaściwy interwał=" + EnumToString((ENUM_TIMEFRAMES)_Period));
      return;
   }

   // Sprawdzanie weekendu
   MqlDateTime timeStruct;
   TimeToStruct(TimeCurrent(), timeStruct);
   if(!InpAllowWeekendTrading && timeStruct.day_of_week >= 6)
   {
      Logger::LogInfo(__FUNCTION__, "Weekend, handel wstrzymany dla symbol=" + dynamicSymbol);
      return;
   }

   // Zarządzanie pozycjami
   if(g_smcManager != NULL) g_smcManager.ManagePositions(InpKeepSLTPDrawing);
   if(g_fvgManager != NULL) g_fvgManager.ManagePositions(InpKeepSLTPDrawing);

   // Sprawdzanie nowych świec
   static datetime lastFvgBarTime = 0;
   datetime currentFvgBarTime = iTime(dynamicSymbol, InpUseSeparateFvgTimeframe ? InpFvgTimeframe : InpTimeframe, 0);
   if(currentFvgBarTime == 0)
   {
      Logger::LogError(__FUNCTION__, "Nie udało się pobrać czasu świecy FVG na " + EnumToString(InpFvgTimeframe));
      return;
   }

   static datetime lastObBarTime = 0;
   datetime currentObBarTime = iTime(dynamicSymbol, InpTimeframe, 0);
   if(currentObBarTime == 0)
   {
      Logger::LogError(__FUNCTION__, "Nie udało się pobrać czasu świecy OB na " + EnumToString(InpTimeframe));
      return;
   }

   bool newFvgBar = (currentFvgBarTime != lastFvgBarTime);
   bool newObBar = (currentObBarTime != lastObBarTime);

   if(InpDebugEnabled)
   {
      Logger::LogDebug(__FUNCTION__, "newObBar=" + BoolToString(newObBar) + 
                       ", newFvgBar=" + BoolToString(newFvgBar));
   }

   double bid = SymbolInfoDouble(dynamicSymbol, SYMBOL_BID);
   double ask = SymbolInfoDouble(dynamicSymbol, SYMBOL_ASK);

   // Aktualizacja struktur na M15
   if(newObBar)
   {
      lastObBarTime = currentObBarTime;

      // Order Blocks (OB)
      if(InpUseOb && g_smcManager != NULL)
      {
         g_smcManager.UpdateOrderBlocks();
         double obHigh, obLow;
         if(g_smcManager.GetLiquidityPoolLevels(obHigh, obLow))
         {
            if(obHigh > bid)
               Logger::LogInfo(__FUNCTION__, "Wykryto niedźwiedzi OB: High=" + DoubleToString(obHigh, 5) + 
                               ", Low=" + DoubleToString(obLow, 5));
            else
               Logger::LogInfo(__FUNCTION__, "Wykryto byczy OB: High=" + DoubleToString(obHigh, 5) + 
                               ", Low=" + DoubleToString(obLow, 5));

            bool volatilityOk = !InpUseVolatilityFilter || CheckVolatilityFilter();
            if(volatilityOk)
            {
               if(!InpUseSwingStructure || 
                  (bid < obLow && (swingTrend == TREND_BULLISH || swingTrend == TREND_NEUTRAL)) || 
                  (bid > obHigh && (swingTrend == TREND_BEARISH || swingTrend == TREND_NEUTRAL)))
               {
                  if(bid < obLow)
                  {
                     Logger::LogDebug(__FUNCTION__, "Otwieram Buy Limit na OB: BID=" + DoubleToString(bid, 5) + 
                                      ", High=" + DoubleToString(obHigh, 5) + ", Low=" + DoubleToString(obLow, 5));
                     g_smcManager.OpenObOrders(obHigh, obLow, true, InpKeepSLTPDrawing);
                     g_lastTradeTime = TimeTradeServer();
                  }
                  else if(bid > obHigh && bid > obLow)
                  {
                     Logger::LogDebug(__FUNCTION__, "Otwieram Sell Stop na OB: BID=" + DoubleToString(bid, 5) + 
                                      ", High=" + DoubleToString(obHigh, 5) + ", Low=" + DoubleToString(obLow, 5));
                     g_smcManager.OpenObOrders(obHigh, obLow, false, InpKeepSLTPDrawing);
                     g_lastTradeTime = TimeTradeServer();
                  }
               }
               else
                  Logger::LogDebug(__FUNCTION__, "Swing Trend blokuje OB: swingTrend=" + EnumToString(swingTrend));
            }
         }
         else if(InpDebugEnabled)
            Logger::LogDebug(__FUNCTION__, "Brak aktywnych OB po aktualizacji");
         if(InpDrawOb) g_smcManager.DrawOrderBlocks();
      }

      // Equal Highs/Lows (EQH/EQL)
      if(InpUseEqualHL)
      {
         double eqHighLevel, eqLowLevel;
         DetectEqualHighs(eqHighLevel, InpTimeframe);
         DetectEqualLows(eqLowLevel, InpTimeframe);
      }

      // Swing Structure (BOS/CHoCH)
      if(InpUseSwingStructure)
      {
         UpdateSwingStructure(dynamicSymbol, InpTimeframe, InpSwingLength, lastSwingHigh, lastSwingLow, swingTrend);
         if(swingTrend == TREND_BULLISH)
         {
            Logger::LogInfo(__FUNCTION__, "Wykryto byczą strukturę swingową (BOS): High=" + DoubleToString(lastSwingHigh, 5) + 
                            ", Low=" + DoubleToString(lastSwingLow, 5));
            if(InpDrawSwingStructure)
            {
               string name = SMC_SWING_PREFIX + "_BOS_Bull_" + TimeToString(TimeCurrent());
               ObjectCreate(0, name, OBJ_HLINE, 0, 0, lastSwingLow);
               ObjectSetInteger(0, name, OBJPROP_COLOR, InpSwingBullColor);
               ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DASH);
            }
         }
         else if(swingTrend == TREND_BEARISH)
         {
            Logger::LogInfo(__FUNCTION__, "Wykryto niedźwiedzią strukturę swingową (BOS): High=" + DoubleToString(lastSwingHigh, 5) + 
                            ", Low=" + DoubleToString(lastSwingLow, 5));
            if(InpDrawSwingStructure)
            {
               string name = SMC_SWING_PREFIX + "_BOS_Bear_" + TimeToString(TimeCurrent());
               ObjectCreate(0, name, OBJ_HLINE, 0, 0, lastSwingHigh);
               ObjectSetInteger(0, name, OBJPROP_COLOR, InpSwingBearColor);
               ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DASH);
            }
         }
         // CHoCH
         if(swingTrend == TREND_BEARISH && lastSwingHigh > 0)
         {
            Logger::LogInfo(__FUNCTION__, "Wykryto CHoCH (zmiana trendu na niedźwiedzi): High=" + DoubleToString(lastSwingHigh, 5));
            if(InpDrawSwingStructure)
            {
               string name = SMC_SWING_PREFIX + "_CHoCH_Bear_" + TimeToString(TimeCurrent());
               ObjectCreate(0, name, OBJ_HLINE, 0, 0, lastSwingHigh);
               ObjectSetInteger(0, name, OBJPROP_COLOR, InpSwingBearColor);
               ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DASH);
            }
         }
         else if(swingTrend == TREND_BULLISH && lastSwingLow > 0)
         {
            Logger::LogInfo(__FUNCTION__, "Wykryto CHoCH (zmiana trendu na byczy): Low=" + DoubleToString(lastSwingLow, 5));
            if(InpDrawSwingStructure)
            {
               string name = SMC_SWING_PREFIX + "_CHoCH_Bull_" + TimeToString(TimeCurrent());
               ObjectCreate(0, name, OBJ_HLINE, 0, 0, lastSwingLow);
               ObjectSetInteger(0, name, OBJPROP_COLOR, InpSwingBullColor);
               ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DASH);
            }
         }
      }

      if(InpUseMTFLevels && InpDrawMTFLevels)
         DrawMTFLevels();

      if(InpUsePremiumDiscount)
         UpdatePremiumDiscountZones();
   }

   // Aktualizacja i handel na FVG
   if(newFvgBar && InpUseFvg && g_fvgManager != NULL)
   {
      lastFvgBarTime = currentFvgBarTime;
      bool volatilityOk = !InpUseVolatilityFilter || CheckVolatilityFilter();
      if(g_fvgManager.Update())
      {
         double fvgHigh, fvgLow, fvgTrend;
         if(g_fvgManager.GetLastFVG(fvgHigh, fvgLow, fvgTrend))
         {
            if(fvgTrend == -1)
               Logger::LogInfo(__FUNCTION__, "Wykryto niedźwiedzi FVG: High=" + DoubleToString(fvgHigh, 5) + 
                               ", Low=" + DoubleToString(fvgLow, 5));
            else if(fvgTrend == 1)
               Logger::LogInfo(__FUNCTION__, "Wykryto byczy FVG: High=" + DoubleToString(fvgHigh, 5) + 
                               ", Low=" + DoubleToString(fvgLow, 5));

            if(volatilityOk)
            {
               if(!InpUseSwingStructure || 
                  (fvgTrend == 1 && (swingTrend == TREND_BULLISH || swingTrend == TREND_NEUTRAL)) || 
                  (fvgTrend == -1 && (swingTrend == TREND_BEARISH || swingTrend == TREND_NEUTRAL)))
               {
                  if(fvgTrend == 1 && bid < fvgHigh)
                  {
                     Logger::LogDebug(__FUNCTION__, "Otwieram Buy Stop na FVG: BID=" + DoubleToString(bid, 5) + 
                                      ", High=" + DoubleToString(fvgHigh, 5) + ", Low=" + DoubleToString(fvgLow, 5));
                     g_fvgManager.OpenFvgOrders(fvgHigh, fvgLow, true, InpKeepSLTPDrawing);
                     g_lastTradeTime = TimeTradeServer();
                  }
                  else if(fvgTrend == -1 && ask > fvgLow)
                  {
                     Logger::LogDebug(__FUNCTION__, "Otwieram Sell Stop na FVG: ASK=" + DoubleToString(ask, 5) + 
                                      ", High=" + DoubleToString(fvgHigh, 5) + ", Low=" + DoubleToString(fvgLow, 5));
                     g_fvgManager.OpenFvgOrders(fvgHigh, fvgLow, false, InpKeepSLTPDrawing);
                     g_lastTradeTime = TimeTradeServer();
                  }
               }
               else
                  Logger::LogDebug(__FUNCTION__, "Swing Trend blokuje FVG: swingTrend=" + EnumToString(swingTrend));
            }
         }
         else if(InpDebugEnabled)
            Logger::LogDebug(__FUNCTION__, "Brak aktywnych FVG po aktualizacji");
      }
      if(InpDrawFvg) g_fvgManager.UpdateFvgBoxes();
   }

   // Mitigacja FVG w czasie rzeczywistym
   if(InpUseFvg && InpContinueToMitigation && g_fvgManager != NULL)
      g_fvgManager.UpdateFvgBoxes();
}

//+------------------------------------------------------------------+