//+------------------------------------------------------------------+ //| TestRefactor.mq5 – EA v OOP, zapouzdřené třídy | //+------------------------------------------------------------------+ #property copyright "TestRefactor" #property version "1.00" #property strict #include "Context.mqh" #include "Logger.mqh" #include "Position.mqh" #include "Positions.mqh" #include "ClosedPosition.mqh" #include "ClosedPositions.mqh" #include "SignalEngine.mqh" #include #include "EquityDrawdown.mqh" #include "TrailingStop.mqh" #include "Grid.mqh" #include "Dashboard.mqh" //--- Inputy (pouze zde, do tříd jdou přes CContext) input int InpFastMaPeriod = 5; // Perioda rychlé SMA – kratší MA pro detekci crossoveru input int InpSlowMaPeriod = 15; // Perioda pomalé SMA – delší MA pro trend input int InpRsiPeriod = 14; // Perioda RSI indikátoru input double InpRsiOverbought = 70; // RSI horní hranice – signál BUY jen když RSI < tato hodnota input double InpRsiOversold = 30; // RSI dolní hranice – signál SELL jen když RSI > tato hodnota input double InpLotSize = 0.1; // Velikost lotu pro otevření pozic input double InpTrailingTriggerUSD = 3.0; // Zisk v USD, od kterého se aktivuje trailing stop (Single režim) input double InpTrailingDistanceUSD = 1.0; // Vzdálenost trailing stop od aktuálního zisku v USD input double InpSmaMinDistancePoints = 0; // Min. vzdálenost SMA v bodech – signál jen když Fast-Slow >= tato hodnota (0 = vypnuto) input int InpH1TrendMaPeriod = 50; // Perioda SMA na H1 – trend: close > MA = uptrend (0 = vypnuto) input group "=== Ověření směru pozic (2 další timeframy) ===" input ENUM_TIMEFRAMES InpTimeframe1 = PERIOD_H4; // TF1 – první timeframe pro filtrování otevření Grid pozic input int InpTimeframe1MaPeriod = 20; // Perioda SMA na TF1 – BUY jen když close > MA (0 = vypnuto) input ENUM_TIMEFRAMES InpTimeframe2 = PERIOD_D1; // TF2 – druhý timeframe pro filtrování otevření Grid pozic input int InpTimeframe2MaPeriod = 50; // Perioda SMA na TF2 – oba TF musí souhlasit se směrem (0 = vypnuto) input group "=== Obchodování ===" input ENUM_TRADE_MODE InpTradeMode = TRADE_SINGLE; // Režim: Single (jedna pozice) nebo Grid (více úrovní) input group "=== Grid ===" input double InpGridDistancePoints = 50; // Vzdálenost mezi úrovněmi Gridu v bodech – nová pozice při pohybu ceny input double InpGridTargetProfitUSD = 20.0; // Cílový zisk v USD – při dosažení se uzavře celý Grid input int InpGridMaxLevels = 20; // Max. počet úrovní (pozic) v jednom směru input group "=== Ostatní ===" input double InpMaxEquityDrawdownPct = 10.0; // Max. povolený drawdown equity v % – při překročení uzavřít všechny pozice (jen Single) input ENUM_EXIT_MODE InpExitMode = EXIT_BY_SL_TRAIL; // Režim uzavření: SL & Trailing nebo Opposite Crossover //--- Globální objekty CContext g_ctx; CLogger g_log; CPositions g_positions(_Symbol); CSignalEngine g_signals; CEquityDrawdown g_equityDD; CTrailingStop g_trailing; CGrid g_grid; CDashboard g_dashboard; CTrade g_trade; //+------------------------------------------------------------------+ int OnInit() { g_ctx.SetFromInputs( InpFastMaPeriod, InpSlowMaPeriod, InpRsiPeriod, InpRsiOverbought, InpRsiOversold, InpLotSize, InpTrailingTriggerUSD, InpTrailingDistanceUSD, InpSmaMinDistancePoints, InpH1TrendMaPeriod, InpTimeframe1, InpTimeframe1MaPeriod, InpTimeframe2, InpTimeframe2MaPeriod, InpTradeMode, InpGridDistancePoints, InpGridTargetProfitUSD, InpMaxEquityDrawdownPct, InpExitMode ); g_ctx.SetGridMaxLevels(InpGridMaxLevels); g_signals.SetSymbol(_Symbol); g_signals.SetContext(g_ctx.Get()); g_signals.SetLogger(&g_log); if(!g_signals.Init()) return INIT_FAILED; g_equityDD.SetContext(g_ctx.Get()); g_equityDD.SetPositions(&g_positions); g_equityDD.SetLogger(&g_log); g_equityDD.SetTrade(&g_trade); g_equityDD.SetSymbol(_Symbol); g_trailing.SetContext(g_ctx.Get()); g_trailing.SetPositions(&g_positions); g_trailing.SetTrade(&g_trade); g_trailing.SetSymbol(_Symbol); g_grid.SetContext(g_ctx.Get()); g_grid.SetPositions(&g_positions); g_grid.SetLogger(&g_log); g_grid.SetTrade(&g_trade); g_grid.SetSymbol(_Symbol); g_dashboard.SetContext(g_ctx.Get()); g_dashboard.SetPositions(&g_positions); g_dashboard.SetSignalEngine(&g_signals); g_dashboard.SetSymbol(_Symbol); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ void OnDeinit(const int reason) { g_signals.Deinit(); } //+------------------------------------------------------------------+ void OnTick() { g_positions.Refresh(); g_equityDD.CheckAndClose(); g_grid.CheckProfitTargetAndClose(); g_trailing.Update(); if(g_signals.IsNewBar()) { SSignalResult sig = g_signals.GetSignals(); if(!sig.ok) return; SContext ctx = g_ctx.Get(); if(ctx.exitMode == EXIT_BY_OPPOSITE_SIGNAL && ctx.tradeMode == TRADE_SINGLE) { ulong tickets[]; g_positions.GetTickets(tickets); int n = ArraySize(tickets); for(int i = 0; i < n; i++) { if(!PositionSelectByTicket(tickets[i])) continue; if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue; if(sig.buySignal && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) g_trade.PositionClose(tickets[i]); if(sig.sellSignal && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) g_trade.PositionClose(tickets[i]); } g_positions.Refresh(); } if(ctx.tradeMode == TRADE_SINGLE) { if(sig.buySignal) { g_log.Info("Fast MA > Slow MA & RSI < " + DoubleToString(ctx.rsiOverbought, 0)); g_trade.Buy(sig.volume, _Symbol, SymbolInfoDouble(_Symbol, SYMBOL_ASK), 0, 0, "Buy"); } if(sig.sellSignal) { g_log.Info("Fast MA < Slow MA & RSI > " + DoubleToString(ctx.rsiOversold, 0)); g_trade.Sell(sig.volume, _Symbol, SymbolInfoDouble(_Symbol, SYMBOL_BID), 0, 0, "Sell"); } } else { bool tfBuyValid = true, tfSellValid = true; if(ctx.timeframe1MaPeriod > 0 || ctx.timeframe2MaPeriod > 0) { tfBuyValid = g_signals.IsBuyDirectionValid(); tfSellValid = g_signals.IsSellDirectionValid(); } g_grid.OnNewBar(sig.buySignal, sig.sellSignal, sig.volume, tfBuyValid, tfSellValid); } } g_dashboard.Update(); }