//+------------------------------------------------------------------+ //| SecUnit B22 Premium EURUSD 4H | //+------------------------------------------------------------------+ #property copyright "Copyright © 2025 Jawad Ait Ali Ouichou " #property link "https://www.mql5.com/en/users/jawadexpo/seller" #property version "1.01" #property description "SecUnit B22 Premium EURUSD 4H Strategy 4 System )" #include #include //+------------------------------------------------------------------+ //| STRATEGY 1: SuperTrend REVERSAL | //+------------------------------------------------------------------+ input group "════════════════Strategy 1: SuperTrend REVERSAL Strategy═════ " input int PivotPeriod = 1; // Pivot Point Period input double ATR_Factor = 3; // ATR Factor input int ATR_Period = 9; // ATR Period input group "1: ADX Filter Settings" input int ADX_Period = 13; // ADX Period input double ADX_Level = 20; // Minimum ADX Level input group "1: ATR Movement Filter" input double MinATR_Multiplier = 0.9; // Minimum ATR Multiplier (vs Average) input int ATR_LookbackPeriod = 1; // ATR Average Lookback Period input group "1: Moving Average Trend Filter" input int MA_Period = 190; // MA Period input ENUM_MA_METHOD MA_Method = MODE_EMA; // MA Method input ENUM_APPLIED_PRICE MA_Price = PRICE_CLOSE; // MA Applied Price input group "1: Supertrend TP/SL" input bool UseReversalStrategy = true; // Enable REVERSAL Strategy? input double ReversalSL_Points = 500; // Reversal: Stop Loss input double ReversalTP1_Points = 364; // Reversal: Take Profit //+------------------------------------------------------------------+ //| STRATEGY 2: Smart Money BOS | //+------------------------------------------------------------------+ input group "════════════════Strategy 2: Smart Money BOS Strategy═════════ " input bool UseBOSStrategy = true; // Enable BOS Strategy? input int BOS_SwingSize = 14; // BOS: Market Structure Time-Horizon input string BOS_ConfirmationType = "Candle Close"; // BOS: Confirmation Type (Candle Close/Wicks) input double BOS_SL_Points = 200; // BOS: Stop Loss input double BOS_TP2_Points = 110; // BOS: Take Profit //+------------------------------------------------------------------+ //| STRATEGY 3: Smart Money Structure (Market Range-Based) | //+------------------------------------------------------------------+ input group "════════════════Strategy 3: Smart Money Structure════════════ " input bool UseStructureStrategy = true; // Enable Structure Strategy? input int Structure_SwingSize = 5; // Market Structure Horizon (Pivot Period) input bool Structure_UseWicks = true; // Use Wicks for Confirmation? (false = Close) input double Structure_SL_Points = 200; // Structure: Stop Loss (Fixed Points) input double Structure_TP_Points = 200; // Structure: Take Profit (Fixed Points) //+------------------------------------------------------------------+ //| STRATEGY 4: Consolidation Range Strategy (SINGLE POSITION) | //+------------------------------------------------------------------+ input group "════════════════Strategy 4: Consolidation Range══════════════ " input bool UseRangeStrategy = true; // Enable Range Strategy? input int Range_Period = 9; // Range Period input double Range_Multiplier = 2.1; // Range Band Multiplier input int Range_Cooldown = 6; // Cooldown Between Trades (Bars) input group "4: Range Detection - ADX Settings" input double Range_ADX_Threshold = 18.0; // ADX Threshold (Below = Ranging) input int Range_ADX_Smooth = 14; // ADX Smoothing Period input group "4: Range TP/SL" input double Range_SL_Mult = 0.4; // SL Multiplier (from Range) input double Range_TP_Mult = 0.3; // TP Multiplier (Single Target) //+------------------------------------------------------------------+ //| GENERAL SETTINGS | //+------------------------------------------------------------------+ input group "═══════Lot Size════════" input double Lots = 0.01; // Lot Size input group "Magic Numbers" input int MagicNumber_Reversal = 101010; // Magic Number: Reversal Strategy input int MagicNumber_BOS = 202020; // Magic Number: BOS Strategy input int MagicNumber_Structure = 303030; // Magic Number: Structure Strategy input int MagicNumber_Range = 404040; // Magic Number: Range Strategy //+------------------------------------------------------------------+ //| GLOBAL VARIABLES | //+------------------------------------------------------------------+ CTrade *Trade_Reversal; CTrade *Trade_BOS; CTrade *Trade_Structure; CTrade *Trade_Range; CPositionInfo PositionInfo; int ADX_Handle = INVALID_HANDLE; int Range_ADX_Handle = INVALID_HANDLE; bool HaveLongPosition; bool HaveShortPosition; int PrevSuperTrend = 0; datetime LastTradeBarTime = 0; int TradesInCurrentDirection = 0; int LastTrendDirection = 0; int CurrentReversalDirection = 0; double CurrentATR = 0; int CurrentBOSDirection = 0; int CurrentStructureDirection = 0; int CurrentRangeDirection = 0; struct BOSData { double prevHigh; double prevLow; int prevHighIndex; int prevLowIndex; bool highActive; bool lowActive; int prevBreakoutDir; }; BOSData BOS; struct StructureData { double lastHigh; double lastLow; int lastHighIndex; int lastLowIndex; bool highActive; bool lowActive; int prevBreakoutDir; datetime lastTradeTime; }; StructureData Structure; struct RangeData { double rngfilt; double prev_rngfilt; double hiband; double loband; double prev_hi; double prev_lo; bool rangeVisible; datetime lastTradeTime; int lastBreakoutBar; bool lastMethodDetected; datetime lastCheckTime; }; RangeData Range; //+------------------------------------------------------------------+ //| Lot Normalization (No Min/Max Enforcement) | //+------------------------------------------------------------------+ double NormalizeLot(double lots) { double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); if(lotStep == 0) return 0; int ratio = (int)MathRound(lots / lotStep); lots = ratio * lotStep; int digits = 2; if(lotStep >= 0.1) digits = 1; else if(lotStep >= 0.01) digits = 2; else digits = 3; return NormalizeDouble(lots, digits); } //+------------------------------------------------------------------+ //| Check if Lot Size is Valid | //+------------------------------------------------------------------+ bool IsLotValid(double lots) { double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); if(lots < minLot) { Print("Trade skipped: Lot ", lots, " < minimum ", minLot); return false; } if(lots > maxLot) { Print("Trade skipped: Lot ", lots, " > maximum ", maxLot); return false; } return true; } //+------------------------------------------------------------------+ //| Complete SL/TP Validation (From Official MQL5 Article) | //+------------------------------------------------------------------+ bool CheckStopLoss_Takeprofit(ENUM_ORDER_TYPE type, double SL, double TP) { double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); long stops_level = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL); long spread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD); double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); stops_level = MathMax(stops_level, spread); if(stops_level < 10) stops_level = 10; bool SL_check = false, TP_check = false; switch(type) { case ORDER_TYPE_BUY: { SL_check = (SL == 0 || (Bid - SL > stops_level * point)); if(!SL_check) PrintFormat("Buy SL=%.5f invalid (must be < %.5f, Bid=%.5f)", SL, Bid - stops_level * point, Bid); TP_check = (TP == 0 || (TP - Ask > stops_level * point)); if(!TP_check) PrintFormat("Buy TP=%.5f invalid (must be > %.5f, Ask=%.5f)", TP, Ask + stops_level * point, Ask); return (SL_check && TP_check); } case ORDER_TYPE_SELL: { SL_check = (SL == 0 || (SL - Ask > stops_level * point)); if(!SL_check) PrintFormat("Sell SL=%.5f invalid (must be > %.5f, Ask=%.5f)", SL, Ask + stops_level * point, Ask); TP_check = (TP == 0 || (Bid - TP > stops_level * point)); if(!TP_check) PrintFormat("Sell TP=%.5f invalid (must be < %.5f, Bid=%.5f)", TP, Bid - stops_level * point, Bid); return (TP_check && SL_check); } } return false; } //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ void OnInit() { Trade_Reversal = new CTrade; Trade_Reversal.SetExpertMagicNumber(MagicNumber_Reversal); Trade_BOS = new CTrade; Trade_BOS.SetExpertMagicNumber(MagicNumber_BOS); Trade_Structure = new CTrade; Trade_Structure.SetExpertMagicNumber(MagicNumber_Structure); Trade_Range = new CTrade; Trade_Range.SetExpertMagicNumber(MagicNumber_Range); ADX_Handle = iADX(_Symbol, _Period, ADX_Period); if (ADX_Handle == INVALID_HANDLE) { Print("ERROR: ADX indicator failed"); return; } Range_ADX_Handle = iADX(_Symbol, _Period, Range_Period); if (Range_ADX_Handle == INVALID_HANDLE) { Print("ERROR: Range ADX indicator failed"); return; } LastTradeBarTime = 0; TradesInCurrentDirection = 0; LastTrendDirection = 0; CurrentReversalDirection = 0; CurrentBOSDirection = 0; CurrentStructureDirection = 0; CurrentRangeDirection = 0; CurrentATR = 0; BOS.prevHigh = 0; BOS.prevLow = 0; BOS.prevHighIndex = 0; BOS.prevLowIndex = 0; BOS.highActive = false; BOS.lowActive = false; BOS.prevBreakoutDir = 0; Structure.lastHigh = 0; Structure.lastLow = 0; Structure.lastHighIndex = 0; Structure.lastLowIndex = 0; Structure.highActive = false; Structure.lowActive = false; Structure.prevBreakoutDir = 0; Structure.lastTradeTime = 0; Range.rngfilt = 0; Range.prev_rngfilt = 0; Range.hiband = 0; Range.loband = 0; Range.prev_hi = 0; Range.prev_lo = 0; Range.rangeVisible = false; Range.lastTradeTime = 0; Range.lastBreakoutBar = 0; Range.lastMethodDetected = false; Range.lastCheckTime = 0; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if (ADX_Handle != INVALID_HANDLE) IndicatorRelease(ADX_Handle); if (Range_ADX_Handle != INVALID_HANDLE) IndicatorRelease(Range_ADX_Handle); delete Trade_Reversal; delete Trade_BOS; delete Trade_Structure; delete Trade_Range; } //+------------------------------------------------------------------+ //| Moving Average Trend Filter (ALWAYS ENABLED) | //+------------------------------------------------------------------+ bool CheckMA_TrendFilter(int direction) { double ma[]; ArraySetAsSeries(ma, true); int ma_handle = iMA(_Symbol, _Period, MA_Period, 0, MA_Method, MA_Price); if (ma_handle == INVALID_HANDLE) return true; if (CopyBuffer(ma_handle, 0, 0, 1, ma) <= 0) { IndicatorRelease(ma_handle); return true; } double currentPrice = iClose(_Symbol, _Period, 0); bool priceAboveMA = currentPrice > ma[0]; IndicatorRelease(ma_handle); if (direction == 1 && priceAboveMA) return true; if (direction == -1 && !priceAboveMA) return true; return false; } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { if ((!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) || (!TerminalInfoInteger(TERMINAL_CONNECTED)) || (SymbolInfoInteger(_Symbol, SYMBOL_TRADE_MODE) != SYMBOL_TRADE_MODE_FULL)) return; datetime currentBarTime = iTime(_Symbol, _Period, 0); bool isNewBar = (currentBarTime != LastTradeBarTime); int CurrentSuperTrend = CalculateSuperTrend(); if (PrevSuperTrend != 0 && CurrentSuperTrend != 0 && PrevSuperTrend != CurrentSuperTrend) { if (HasOpenPosition(MagicNumber_Reversal)) { bool shouldClose = false; if (CurrentSuperTrend == -1 && CurrentReversalDirection == 1) { if (CheckADXFilter(-1) && CheckATRMovementFilter() && CheckMA_TrendFilter(-1)) shouldClose = true; } else if (CurrentSuperTrend == 1 && CurrentReversalDirection == -1) { if (CheckADXFilter(1) && CheckATRMovementFilter() && CheckMA_TrendFilter(1)) shouldClose = true; } if (shouldClose) ClosePositionsByMagic(MagicNumber_Reversal); } CurrentReversalDirection = 0; TradesInCurrentDirection = 0; LastTrendDirection = CurrentSuperTrend; if (UseReversalStrategy) { if (CurrentSuperTrend == 1) { if (CheckADXFilter(1) && CheckATRMovementFilter() && CheckMA_TrendFilter(1)) { fBuy(); CurrentReversalDirection = 1; } } else if (CurrentSuperTrend == -1) { if (CheckADXFilter(-1) && CheckATRMovementFilter() && CheckMA_TrendFilter(-1)) { fSell(); CurrentReversalDirection = -1; } } } } if (LastTrendDirection == 0) LastTrendDirection = CurrentSuperTrend; PrevSuperTrend = CurrentSuperTrend; GetPositionStates(); if (UseBOSStrategy && isNewBar) { int bosSignal = DetectBOSSignal(); if (bosSignal == 1) { if (CurrentBOSDirection == -1 && HasOpenPosition(MagicNumber_BOS)) ClosePositionsByMagic(MagicNumber_BOS); if (!HasOpenPosition(MagicNumber_BOS)) { ExecuteBOSEntry(true); CurrentBOSDirection = 1; LastTradeBarTime = currentBarTime; } } else if (bosSignal == -1) { if (CurrentBOSDirection == 1 && HasOpenPosition(MagicNumber_BOS)) ClosePositionsByMagic(MagicNumber_BOS); if (!HasOpenPosition(MagicNumber_BOS)) { ExecuteBOSEntry(false); CurrentBOSDirection = -1; LastTradeBarTime = currentBarTime; } } } if (UseStructureStrategy && isNewBar) { UpdateMarketStructure(); int structureSignal = CheckStructureSignals(); if (structureSignal == 1) { if (CurrentStructureDirection == -1 && HasOpenPosition(MagicNumber_Structure)) ClosePositionsByMagic(MagicNumber_Structure); if (!HasOpenPosition(MagicNumber_Structure)) { ProcessBullishStructureBreakout(); CurrentStructureDirection = 1; } } else if (structureSignal == -1) { if (CurrentStructureDirection == 1 && HasOpenPosition(MagicNumber_Structure)) ClosePositionsByMagic(MagicNumber_Structure); if (!HasOpenPosition(MagicNumber_Structure)) { ProcessBearishStructureBreakout(); CurrentStructureDirection = -1; } } } if (UseRangeStrategy && isNewBar) { UpdateRangeFilter(); int rangeSignal = CheckRangeSignals(); if (rangeSignal == 1) { if (CurrentRangeDirection == -1 && HasOpenPosition(MagicNumber_Range)) ClosePositionsByMagic(MagicNumber_Range); if (!HasOpenPosition(MagicNumber_Range)) { ExecuteRangeEntry(true); CurrentRangeDirection = 1; } } else if (rangeSignal == -1) { if (CurrentRangeDirection == 1 && HasOpenPosition(MagicNumber_Range)) ClosePositionsByMagic(MagicNumber_Range); if (!HasOpenPosition(MagicNumber_Range)) { ExecuteRangeEntry(false); CurrentRangeDirection = -1; } } } } //+------------------------------------------------------------------+ //| ATR Movement Filter (ALWAYS ENABLED) | //+------------------------------------------------------------------+ bool CheckATRMovementFilter() { if (CurrentATR <= 0) return false; MqlRates rates[]; ArraySetAsSeries(rates, true); int requiredBars = ATR_LookbackPeriod + ATR_Period + 5; if (CopyRates(_Symbol, _Period, 0, requiredBars, rates) <= 0) return false; double atrSum = 0; int atrCount = 0; for (int period = 1; period <= ATR_LookbackPeriod; period++) { double periodATR = 0; for (int i = period; i < period + ATR_Period; i++) { if (i + 1 >= ArraySize(rates)) break; double tr = MathMax(rates[i].high - rates[i].low, MathMax(MathAbs(rates[i].high - rates[i+1].close), MathAbs(rates[i].low - rates[i+1].close))); periodATR += tr; } if (period + ATR_Period < ArraySize(rates)) { periodATR = periodATR / ATR_Period; atrSum += periodATR; atrCount++; } } if (atrCount == 0) return false; double avgATR = atrSum / atrCount; return (CurrentATR >= avgATR * MinATR_Multiplier); } //+------------------------------------------------------------------+ //| ADX Filter Function | //+------------------------------------------------------------------+ bool CheckADXFilter(int direction) { if (ADX_Handle == INVALID_HANDLE) return false; double adx_buffer[], plusdi_buffer[], minusdi_buffer[]; ArraySetAsSeries(adx_buffer, true); ArraySetAsSeries(plusdi_buffer, true); ArraySetAsSeries(minusdi_buffer, true); if (CopyBuffer(ADX_Handle, 0, 0, 2, adx_buffer) <= 0) return false; if (CopyBuffer(ADX_Handle, 1, 0, 2, plusdi_buffer) <= 0) return false; if (CopyBuffer(ADX_Handle, 2, 0, 2, minusdi_buffer) <= 0) return false; double adx = adx_buffer[0]; double plusDI = plusdi_buffer[0]; double minusDI = minusdi_buffer[0]; if (adx < ADX_Level) return false; if (direction == 1 && plusDI > minusDI) return true; if (direction == -1 && minusDI > plusDI) return true; return false; } //+------------------------------------------------------------------+ //| STRATEGY 3: Market Structure Functions | //+------------------------------------------------------------------+ void UpdateMarketStructure() { double pivotHigh = FindPivotHigh(Structure_SwingSize); if(pivotHigh > 0) { Structure.lastHigh = pivotHigh; Structure.lastHighIndex = Structure_SwingSize; Structure.highActive = true; } double pivotLow = FindPivotLow(Structure_SwingSize); if(pivotLow > 0) { Structure.lastLow = pivotLow; Structure.lastLowIndex = Structure_SwingSize; Structure.lowActive = true; } } double FindPivotHigh(int period) { if(iBars(_Symbol, _Period) < period * 2 + 1) return 0; double centerHigh = iHigh(_Symbol, _Period, period); for(int i = 1; i <= period; i++) { if(iHigh(_Symbol, _Period, period - i) >= centerHigh) return 0; if(iHigh(_Symbol, _Period, period + i) >= centerHigh) return 0; } return centerHigh; } double FindPivotLow(int period) { if(iBars(_Symbol, _Period) < period * 2 + 1) return 0; double centerLow = iLow(_Symbol, _Period, period); for(int i = 1; i <= period; i++) { if(iLow(_Symbol, _Period, period - i) <= centerLow) return 0; if(iLow(_Symbol, _Period, period + i) <= centerLow) return 0; } return centerLow; } int CheckStructureSignals() { if(!Structure.highActive && !Structure.lowActive) return 0; datetime currentBarTime = iTime(_Symbol, _Period, 0); if(currentBarTime == Structure.lastTradeTime) return 0; double currentPrice; if(Structure_UseWicks) { currentPrice = iHigh(_Symbol, _Period, 0); if(Structure.highActive && currentPrice > Structure.lastHigh) { Structure.highActive = false; Structure.prevBreakoutDir = 1; Structure.lastTradeTime = currentBarTime; return 1; } currentPrice = iLow(_Symbol, _Period, 0); if(Structure.lowActive && currentPrice < Structure.lastLow) { Structure.lowActive = false; Structure.prevBreakoutDir = -1; Structure.lastTradeTime = currentBarTime; return -1; } } else { currentPrice = iClose(_Symbol, _Period, 0); if(Structure.highActive && currentPrice > Structure.lastHigh) { Structure.highActive = false; Structure.prevBreakoutDir = 1; Structure.lastTradeTime = currentBarTime; return 1; } if(Structure.lowActive && currentPrice < Structure.lastLow) { Structure.lowActive = false; Structure.prevBreakoutDir = -1; Structure.lastTradeTime = currentBarTime; return -1; } } return 0; } void ProcessBullishStructureBreakout() { double entry = Structure.lastHigh; OpenStructureBuy(entry); } void ProcessBearishStructureBreakout() { double entry = Structure.lastLow; OpenStructureSell(entry); } void OpenStructureBuy(double entry) { double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); double sl = NormalizeDouble(ask - (Structure_SL_Points * point), digits); double tp = NormalizeDouble(ask + (Structure_TP_Points * point), digits); if(!CheckStopLoss_Takeprofit(ORDER_TYPE_BUY, sl, tp)) return; double volume = NormalizeLot(Lots); if(!IsLotValid(volume)) return; Trade_Structure.PositionOpen(_Symbol, ORDER_TYPE_BUY, volume, ask, sl, tp); } void OpenStructureSell(double entry) { double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); double sl = NormalizeDouble(bid + (Structure_SL_Points * point), digits); double tp = NormalizeDouble(bid - (Structure_TP_Points * point), digits); if(!CheckStopLoss_Takeprofit(ORDER_TYPE_SELL, sl, tp)) return; double volume = NormalizeLot(Lots); if(!IsLotValid(volume)) return; Trade_Structure.PositionOpen(_Symbol, ORDER_TYPE_SELL, volume, bid, sl, tp); } //+------------------------------------------------------------------+ //| STRATEGY 4: Consolidation Range Detection (SINGLE POSITION) | //+------------------------------------------------------------------+ bool DetectRangeCondition() { double adx_buffer[]; ArraySetAsSeries(adx_buffer, true); if (CopyBuffer(Range_ADX_Handle, 0, 0, 1, adx_buffer) <= 0) return false; return (adx_buffer[0] < Range_ADX_Threshold); } void UpdateRangeFilter() { MqlRates rates[]; ArraySetAsSeries(rates, true); if (CopyRates(_Symbol, _Period, 0, 50, rates) <= 0) return; double diff_sum = 0; int avg_bars = MathMin(10, ArraySize(rates) - 1); for(int i = 0; i < avg_bars; i++) { diff_sum += MathAbs(rates[i].high - rates[i+1].low); } double avg_diff = diff_sum / avg_bars; double r = avg_diff * 2.618 * Range_Multiplier; if (Range.rngfilt == 0) Range.rngfilt = rates[0].close; double prev = Range.rngfilt; double currentClose = rates[0].close; double highJump = prev + MathAbs(currentClose - prev) / r * r; double lowJump = prev - MathAbs(currentClose - prev) / r * r; bool hhBreak = currentClose > prev; bool hhTooClose = (currentClose - r) < prev; bool llTooClose = (currentClose + r) > prev; double hhShift = currentClose - r; double llShift = currentClose + r; double step1 = hhBreak ? (hhTooClose ? prev : hhShift) : (llTooClose ? prev : llShift); bool hhAbove = currentClose >= prev + r; bool llBelow = currentClose <= prev - r; Range.prev_rngfilt = Range.rngfilt; Range.rngfilt = hhAbove ? highJump : (llBelow ? lowJump : step1); Range.hiband = Range.rngfilt + r; Range.loband = Range.rngfilt - r; datetime currentTime = iTime(_Symbol, _Period, 0); int currentBars = Bars(_Symbol, _Period); if(currentTime != Range.lastCheckTime || (currentBars - Range.lastCheckTime) > 3) { Range.lastMethodDetected = DetectRangeCondition(); Range.lastCheckTime = currentTime; } if (Range.lastMethodDetected) { Range.rangeVisible = true; Range.prev_hi = Range.hiband; Range.prev_lo = Range.loband; } if (!Range.lastMethodDetected && (rates[0].close > Range.prev_hi || rates[0].close < Range.prev_lo)) { Range.rangeVisible = false; } } int CheckRangeSignals() { if (!Range.rangeVisible) return 0; int currentBar = Bars(_Symbol, _Period); bool canTrigger = (Range.lastBreakoutBar == 0 || currentBar - Range.lastBreakoutBar >= Range_Cooldown); if (!canTrigger) return 0; bool rngfilt_step_up = Range.rngfilt > Range.prev_rngfilt; bool rngfilt_step_down = Range.rngfilt < Range.prev_rngfilt; bool enterLong = Range.rangeVisible && rngfilt_step_up && canTrigger; bool enterShort = Range.rangeVisible && rngfilt_step_down && canTrigger; if (enterLong) { Range.lastBreakoutBar = currentBar; Range.lastTradeTime = iTime(_Symbol, _Period, 0); return 1; } else if (enterShort) { Range.lastBreakoutBar = currentBar; Range.lastTradeTime = iTime(_Symbol, _Period, 0); return -1; } return 0; } void ExecuteRangeEntry(bool isBuy) { double entryPrice = isBuy ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID); int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); double r = Range.hiband - Range.rngfilt; double sl, tp; if (isBuy) { sl = Range.rngfilt - (r * Range_SL_Mult); tp = Range.rngfilt + (r * Range_TP_Mult); } else { sl = Range.rngfilt + (r * Range_SL_Mult); tp = Range.rngfilt - (r * Range_TP_Mult); } sl = NormalizeDouble(sl, digits); tp = NormalizeDouble(tp, digits); ENUM_ORDER_TYPE orderType = isBuy ? ORDER_TYPE_BUY : ORDER_TYPE_SELL; if(!CheckStopLoss_Takeprofit(orderType, sl, tp)) return; double volume = NormalizeLot(Lots); if(!IsLotValid(volume)) return; Trade_Range.PositionOpen(_Symbol, orderType, volume, entryPrice, sl, tp); } //+------------------------------------------------------------------+ //| STRATEGY 1: Reversal Functions (SINGLE POSITION) | //+------------------------------------------------------------------+ void fBuy() { double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); double sl = NormalizeDouble(Ask - (ReversalSL_Points * point), digits); double tp1 = NormalizeDouble(Ask + (ReversalTP1_Points * point), digits); if(!CheckStopLoss_Takeprofit(ORDER_TYPE_BUY, sl, tp1)) return; double volume = NormalizeLot(Lots); if(!IsLotValid(volume)) return; Trade_Reversal.PositionOpen(_Symbol, ORDER_TYPE_BUY, volume, Ask, sl, tp1); if (Trade_Reversal.ResultRetcode() == TRADE_RETCODE_DONE) TradesInCurrentDirection++; } void fSell() { double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); double sl = NormalizeDouble(Bid + (ReversalSL_Points * point), digits); double tp1 = NormalizeDouble(Bid - (ReversalTP1_Points * point), digits); if(!CheckStopLoss_Takeprofit(ORDER_TYPE_SELL, sl, tp1)) return; double volume = NormalizeLot(Lots); if(!IsLotValid(volume)) return; Trade_Reversal.PositionOpen(_Symbol, ORDER_TYPE_SELL, volume, Bid, sl, tp1); if (Trade_Reversal.ResultRetcode() == TRADE_RETCODE_DONE) TradesInCurrentDirection++; } //+------------------------------------------------------------------+ //| STRATEGY 2: BOS Functions - FIXED VERSION | //+------------------------------------------------------------------+ int DetectBOSSignal() { MqlRates rates[]; ArraySetAsSeries(rates, true); int lookback = BOS_SwingSize * 2 + 10; if (CopyRates(_Symbol, _Period, 0, lookback, rates) <= 0) return 0; bool foundNewHigh = false; for (int i = BOS_SwingSize; i < ArraySize(rates) - BOS_SwingSize; i++) { bool isPivotHigh = true; for (int j = 1; j <= BOS_SwingSize; j++) { if (rates[i].high <= rates[i - j].high || rates[i].high <= rates[i + j].high) { isPivotHigh = false; break; } } if (isPivotHigh) { BOS.prevHigh = rates[i].high; BOS.prevHighIndex = i; BOS.highActive = true; foundNewHigh = true; break; } } bool foundNewLow = false; for (int i = BOS_SwingSize; i < ArraySize(rates) - BOS_SwingSize; i++) { bool isPivotLow = true; for (int j = 1; j <= BOS_SwingSize; j++) { if (rates[i].low >= rates[i - j].low || rates[i].low >= rates[i + j].low) { isPivotLow = false; break; } } if (isPivotLow) { BOS.prevLow = rates[i].low; BOS.prevLowIndex = i; BOS.lowActive = true; foundNewLow = true; break; } } double checkPrice; if (BOS.highActive) { checkPrice = (BOS_ConfirmationType == "Candle Close") ? rates[0].close : rates[0].high; if (checkPrice > BOS.prevHigh) { BOS.highActive = false; BOS.prevBreakoutDir = 1; return 1; } } if (BOS.lowActive) { checkPrice = (BOS_ConfirmationType == "Candle Close") ? rates[0].close : rates[0].low; if (checkPrice < BOS.prevLow) { BOS.lowActive = false; BOS.prevBreakoutDir = -1; return -1; } } return 0; } void ExecuteBOSEntry(bool isBuy) { double entryPrice = isBuy ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID); double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); double sl = isBuy ? entryPrice - (BOS_SL_Points * point) : entryPrice + (BOS_SL_Points * point); double tp2 = isBuy ? entryPrice + (BOS_TP2_Points * point) : entryPrice - (BOS_TP2_Points * point); sl = NormalizeDouble(sl, digits); tp2 = NormalizeDouble(tp2, digits); ENUM_ORDER_TYPE orderType = isBuy ? ORDER_TYPE_BUY : ORDER_TYPE_SELL; if(!CheckStopLoss_Takeprofit(orderType, sl, tp2)) return; double volume = NormalizeLot(Lots); if(!IsLotValid(volume)) return; Trade_BOS.PositionOpen(_Symbol, orderType, volume, entryPrice, sl, tp2); } //+------------------------------------------------------------------+ //| SHARED FUNCTIONS | //+------------------------------------------------------------------+ int CalculateSuperTrend() { int lookback = PivotPeriod * 2 + ATR_Period + 10; MqlRates rates[]; if (CopyRates(_Symbol, _Period, 0, lookback, rates) <= 0) return 0; int size = ArraySize(rates); if (size < lookback) return 0; double pivotHigh = 0, pivotLow = 0, lastPP = 0; for (int i = size - PivotPeriod - 1; i >= PivotPeriod; i--) { bool isPH = true; for (int j = 1; j <= PivotPeriod; j++) { if (rates[i].high <= rates[i - j].high || rates[i].high <= rates[i + j].high) { isPH = false; break; } } if (isPH) { pivotHigh = rates[i].high; lastPP = pivotHigh; break; } } for (int i = size - PivotPeriod - 1; i >= PivotPeriod; i--) { bool isPL = true; for (int j = 1; j <= PivotPeriod; j++) { if (rates[i].low >= rates[i - j].low || rates[i].low >= rates[i + j].low) { isPL = false; break; } } if (isPL) { pivotLow = rates[i].low; if (lastPP == 0) lastPP = pivotLow; break; } } if (lastPP == 0) return PrevSuperTrend != 0 ? PrevSuperTrend : 1; static double center = 0; if (center == 0) center = lastPP; else center = (center * 2 + lastPP) / 3; CurrentATR = 0; for (int i = size - ATR_Period; i < size; i++) { double tr = MathMax(rates[i].high - rates[i].low, MathMax(MathAbs(rates[i].high - rates[i - 1].close), MathAbs(rates[i].low - rates[i - 1].close))); CurrentATR += tr; } CurrentATR = CurrentATR / ATR_Period; double Up = center - (ATR_Factor * CurrentATR); double Dn = center + (ATR_Factor * CurrentATR); static double TUp = 0, TDown = 0; static int Trend = 1; double currentClose = rates[size - 1].close; double prevClose = rates[size - 2].close; if (prevClose > TUp) TUp = MathMax(Up, TUp); else TUp = Up; if (prevClose < TDown) TDown = MathMin(Dn, TDown); else TDown = Dn; if (currentClose > TDown) Trend = 1; else if (currentClose < TUp) Trend = -1; return Trend; } void GetPositionStates() { HaveLongPosition = false; HaveShortPosition = false; for (int i = PositionsTotal() - 1; i >= 0; i--) { if (PositionInfo.SelectByIndex(i) && PositionInfo.Symbol() == _Symbol) { if (PositionInfo.PositionType() == POSITION_TYPE_BUY) HaveLongPosition = true; else HaveShortPosition = true; } } } bool HasOpenPosition(int magicNumber) { for (int i = PositionsTotal() - 1; i >= 0; i--) { if (PositionInfo.SelectByIndex(i) && PositionInfo.Symbol() == _Symbol && PositionInfo.Magic() == magicNumber) return true; } return false; } void ClosePositionsByMagic(int magicNumber) { CTrade closeTrade; for (int i = PositionsTotal() - 1; i >= 0; i--) { if (PositionInfo.SelectByIndex(i) && PositionInfo.Symbol() == _Symbol && PositionInfo.Magic() == magicNumber) { closeTrade.PositionClose(PositionInfo.Ticket()); } } }