0% found this document useful (0 votes)
151 views44 pages

ICT Code Blueprint

MySmartMoneyEA is an Expert Advisor designed to implement multiple Smart Money Concepts strategies for trading. It includes various configurable strategies such as Liquidity Sweep, Fibonacci Retracement, and RSI Divergence, allowing users to customize their trading approach. The EA utilizes standard MQL5 libraries for trade execution and market data analysis, ensuring efficient performance in the MetaTrader 5 environment.

Uploaded by

ajaydhande77
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
151 views44 pages

ICT Code Blueprint

MySmartMoneyEA is an Expert Advisor designed to implement multiple Smart Money Concepts strategies for trading. It includes various configurable strategies such as Liquidity Sweep, Fibonacci Retracement, and RSI Divergence, allowing users to customize their trading approach. The EA utilizes standard MQL5 libraries for trade execution and market data analysis, ensuring efficient performance in the MetaTrader 5 environment.

Uploaded by

ajaydhande77
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 44

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

//| MySmartMoneyEA |
//| Copyright 2024, [Your Name/Company] |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, [Your Name/Company]"
#property link "https://www.mql5.com"
#property version "1.00"
#property description "Expert Advisor implementing multiple Smart Money Concepts
strategies."

//--- Includes (Standard Libraries - essential for basic MQL5 functions)


// Corrected include paths to standard MQL5 locations
#include <stdlib.mqh> // For MQL5 standard library functions like NormalizeDouble,
MathAbs
#include <Trade\Trade.mqh> // For CTrade class or MqlTradeRequest/MqlTradeResult
structures
#include <Math\Math.mqh> // For mathematical functions like MathAtan
// If 'file not found' errors persist for standard includes like stdlib.mqh or
Math\Math.mqh,
// it often indicates an issue with your MetaTrader 5 installation or corrupt
files.
// Please verify your MT5 installation and ensure these files exist in your MQL5\
Include directory.

//--- Define constants for array sizes to prevent 'undeclared identifier' errors
#define MAX_BARS_FOR_IMPULSIVE_MOVE 20 // Max bars for impulsive move
(InpImpulsiveMoveMaxBars + buffer)
#define MAX_LOOKBACK_FOR_OB 25 // Max lookback for Order Block
(lookbackBars + 2 + buffer)
#define MAX_LOOKBACK_FOR_BREAKER 60 // Max lookback for Breaker Block
(lookbackBars + 5 + buffer)

//--- Global Variables ---


datetime g_lastTradeDay[12]; // Array to track the last trading day for each
strategy (index 0-11 for 12 strategies)
string g_strategyNames[12]; // Array to map strategy index to its name
int g_magicNumberBase = 12345; // Base magic number for trades, unique for
each EA instance

//--- Helper Variables for OnTick logic ---


datetime g_prevBarTime = 0; // To detect new bars
MqlTick g_tick; // To get current tick data (Bid/Ask)

//--- EA Inputs (configurable by user) ---


input double InpLotSize = 0.05; // Fixed lot size for all trades
input bool InpEnableStrategy1 = true; // Liquidity Sweep (Double Top/Bottom
Based)
input bool InpEnableStrategy2 = true; // Power of Three
input bool InpEnableStrategy3 = true; // Break and Retest (S/R Flip)
input bool InpEnableStrategy4 = true; // Fibonacci Retracement
input bool InpEnableStrategy5 = true; // Moving Average (20/50 SMA) Pullback
input bool InpEnableStrategy6 = true; // Trend Line Pullback
input bool InpEnableStrategy7 = true; // Fair Value Gap (FVG) Pullback
input bool InpEnableStrategy8 = true; // Institutional Funding Candles (IFC)
Pullback
input bool InpEnableStrategy9 = true; // Order Blocks Pullback
input bool InpEnableStrategy10 = true; // Breaker Block Pullback
input bool InpEnableStrategy11 = true; // RSI Divergence with Confluence

// --- Common Strategy Parameters ---


input int InpSwingPointBars = 3; // Bars required on each side for swing
high/low detection
input double InpEqualHighLowPipsDeviation = 5.0; // Pips deviation for equal
highs/lows
input int InpLiquiditySweepReversalBars = 2; // Max candles to confirm reversal
after sweep
input int InpATRPeriod = 14; // Period for ATR calculation (used for
volatility, pips conversion)
input double InpATRMagnifier = 0.25; // ATR multiplier for minor penetration, SL
distance, etc. (0.25 = 25% of ATR)
input ENUM_TIMEFRAMES InpHTFPeriod = PERIOD_H4; // Higher Time Frame for alignment
check (e.g., H4)
input int InpMovingAveragePeriod = 20; // Period for 20 SMA
input int InpLongMovingAveragePeriod = 50; // Period for 50 SMA
input double InpADXPeriod = 14; // Period for ADX calculation
input double InpADXThreshold = 25.0; // ADX threshold for trending market
input int InpRSIPeriod = 14; // Period for RSI
input int InpRSIDivergenceLookbackBars = 20; // Max bars between points for RSI
divergence
input double InpRSIPointsDeviation = 3.0; // Min RSI points deviation for
divergence
input double InpMinRiskRewardRatio = 2.0; // Minimum R:R for TP calculation

// --- Specific Strategy Parameters ---


input double InpConsolidationATRMultiplier = 1.5; // ATR multiplier for
consolidation range size
input int InpConsolidationMinBars = 10; // Min bars to check for consolidation
input int InpConsolidationMaxBars = 20; // Max bars to check for consolidation
input double InpBreakPipsBeyondLevel = 5.0; // Min pips for S/R break confirmation
(Break and Retest)
input double InpBodyPenetrationRatio = 0.75; // Min ratio of candle body
penetrating S/R for a break (0.75 = 75%)
input double InpMinImpulsiveMoveATR = 3.0; // Min ATR for strong impulsive move
(Fibonacci)
input int InpImpulsiveMoveMaxBars = 15; // Max bars for impulsive move
(Fibonacci)
input double InpFVGMinATRHeight = 0.5; // Min FVG height in ATR for filtering
input int InpFVGMaxBarsFromOrigin = 10; // Max bars from origin for FVG filter
(closer to origin)
input double InpIFCMinATRBody = 1.5; // Min IFC body size in ATR
input double InpIFCSubsequentMoveATR = 3.0; // Min subsequent move size after IFC
in ATR
input int InpOrderBlockUnmitigatedBodyPenetration = 25; // Max % body
penetration to consider OB unmitigated
input double InpBreakerBlockMinATRRange = 1.0; // Min range for Breaker Block zone
(in ATR)

//+------------------------------------------------------------------+
//| Helper Function: TimeToDay - Extracts the date part of a datetime |
//+------------------------------------------------------------------+
datetime TimeToDay(datetime inputTime) {
MqlDateTime dt;
TimeToStruct(inputTime, dt);
dt.hour = 0;
dt.min = 0;
dt.sec = 0;
return StructToTime(dt);
}

//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit() {
// Initialize strategy names for logging/identification
g_strategyNames[0] = "Liquidity Sweep (Double Top/Bottom)";
g_strategyNames[1] = "Power of Three (Bullish)";
g_strategyNames[2] = "Power of Three (Bearish)";
g_strategyNames[3] = "Break and Retest (S/R Flip)";
g_strategyNames[4] = "Fibonacci Retracement";
g_strategyNames[5] = "Moving Average Pullback";
g_strategyNames[6] = "Trend Line Pullback";
g_strategyNames[7] = "Fair Value Gap (FVG) Pullback";
g_strategyNames[8] = "Institutional Funding Candles Pullback";
g_strategyNames[9] = "Order Blocks Pullback";
g_strategyNames[10] = "Breaker Block Pullback";
g_strategyNames[11] = "RSI Divergence with Confluence";

// Initialize lastTradeDay array to 0 (no trades taken yet)


for (int i = 0; i < 12; i++) { // Corrected size to 12
g_lastTradeDay[i] = 0;
}

// Check if the symbol is XAUUSDm (or allow any symbol if flexibility is


desired)
// Removed strict check for XAUUSDm to allow flexibility.
Print("MySmartMoneyEA Initialized Successfully! Current Symbol: ", Symbol());
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
Print("MySmartMoneyEA Deinitialized. Reason: ", reason);
// Add any cleanup code here, e.g., closing open positions if desired (careful
with this!)
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick() {
// Get current tick info for real-time Bid/Ask
if (!SymbolInfoTick(Symbol(), g_tick)) {
Print("Error getting tick data for ", Symbol());
return;
}

// Check for a new bar (candle) to ensure strategy evaluation is done on closed
bars
datetime currentBarTime = iTime(Symbol(), Period(), 0);
if (currentBarTime == g_prevBarTime) {
return; // Not a new bar yet, wait for the next tick
}
g_prevBarTime = currentBarTime;

// --- Daily Reset Logic ---


// This ensures the daily trade limit is reset at the start of a new day
OnStartOfNewDay();

// --- Strategy Evaluation ---


// Iterate through each strategy and check for trade setups
// Only one trade per strategy per day is allowed

// Strategy 1: Liquidity Sweep (Double Top/Bottom Based)


if (InpEnableStrategy1 && TimeToDay(TimeCurrent()) !=
TimeToDay(g_lastTradeDay[0])) {
CheckStrategy_LiquiditySweep_DoubleTopBottom();
}

// Strategy 2: Power of Three (Bullish)


if (InpEnableStrategy2 && TimeToDay(TimeCurrent()) !=
TimeToDay(g_lastTradeDay[1])) {
CheckStrategy_PowerOfThree_Bullish();
}
// Strategy 2: Power of Three (Bearish) - Using separate daily flag
if (InpEnableStrategy2 && TimeToDay(TimeCurrent()) !=
TimeToDay(g_lastTradeDay[2])) {
CheckStrategy_PowerOfThree_Bearish();
}

// Strategy 3: Break and Retest (S/R Flip)


if (InpEnableStrategy3 && TimeToDay(TimeCurrent()) !=
TimeToDay(g_lastTradeDay[3])) {
CheckStrategy_BreakAndRetest();
}

// Strategy 4: Fibonacci Retracement


if (InpEnableStrategy4 && TimeToDay(TimeCurrent()) !=
TimeToDay(g_lastTradeDay[4])) {
CheckStrategy_FibonacciRetracement();
}

// Strategy 5: Moving Average (20/50 SMA) Pullback


if (InpEnableStrategy5 && TimeToDay(TimeCurrent()) !=
TimeToDay(g_lastTradeDay[5])) {
CheckStrategy_MAPullback();
}

// Strategy 6: Trend Line Pullback


if (InpEnableStrategy6 && TimeToDay(TimeCurrent()) !=
TimeToDay(g_lastTradeDay[6])) {
CheckStrategy_TrendLinePullback();
}

// Strategy 7: Fair Value Gap (FVG) Pullback


if (InpEnableStrategy7 && TimeToDay(TimeCurrent()) !=
TimeToDay(g_lastTradeDay[7])) {
CheckStrategy_FVGPullback();
}

// Strategy 8: Institutional Funding Candles (IFC) Pullback


if (InpEnableStrategy8 && TimeToDay(TimeCurrent()) !=
TimeToDay(g_lastTradeDay[8])) {
CheckStrategy_IFCPullback();
}
// Strategy 9: Order Blocks Pullback
if (InpEnableStrategy9 && TimeToDay(TimeCurrent()) !=
TimeToDay(g_lastTradeDay[9])) {
CheckStrategy_OrderBlockPullback();
}

// Strategy 10: Breaker Block Pullback


if (InpEnableStrategy10 && TimeToDay(TimeCurrent()) !=
TimeToDay(g_lastTradeDay[10])) {
CheckStrategy_BreakerBlockPullback();
}

// Strategy 11: RSI Divergence with Confluence


if (InpEnableStrategy11 && TimeToDay(TimeCurrent()) !=
TimeToDay(g_lastTradeDay[11])) {
CheckStrategy_RSIDivergence();
}
}
// --- Order Management ---
// Function to send a buy order
bool SendBuyOrder(string symbol, double lotSize, double price, double stopLoss,
double takeProfit, ENUM_TIMEFRAMES timeframe, string comment) {
MqlTradeRequest request;
MqlTradeResult result;

ZeroMemory(request);
request.action = TRADE_ACTION_DEAL;
request.symbol = symbol;
request.volume = lotSize;
request.type = ORDER_TYPE_BUY;
request.price = g_tick.ask; // Use current Ask for Buy Market Order
request.sl = NormalizeDouble(stopLoss, _Digits);
request.tp = NormalizeDouble(takeProfit, _Digits);
request.deviation = 10; // Allowed deviation from requested price
request.type_filling = ORDER_FILLING_FOK; // Fill or Kill
request.comment = comment;
request.magic = g_magicNumberBase; // Use a unique magic number for this EA

if(!OrderSend(request, result)) {
Print("Failed to send BUY order: ", result.retcode, " - ", result.comment);
return false;
}
Print("BUY order sent successfully. Ticket: ", result.deal);
return true;
}

// Function to send a sell order


bool SendSellOrder(string symbol, double lotSize, double price, double stopLoss,
double takeProfit, ENUM_TIMEFRAMES timeframe, string comment) {
MqlTradeRequest request;
MqlTradeResult result;

ZeroMemory(request);
request.action = TRADE_ACTION_DEAL;
request.symbol = symbol;
request.volume = lotSize;
request.type = ORDER_TYPE_SELL;
request.price = g_tick.bid; // Use current Bid for Sell Market Order
request.sl = NormalizeDouble(stopLoss, _Digits);
request.tp = NormalizeDouble(takeProfit, _Digits);
request.deviation = 10; // Allowed deviation from requested price
request.type_filling = ORDER_FILLING_FOK; // Fill or Kill
request.comment = comment;
request.magic = g_magicNumberBase; // Use a unique magic number for this EA

if(!OrderSend(request, result)) {
Print("Failed to send SELL order: ", result.retcode, " - ",
result.comment);
return false;
}
Print("SELL order sent successfully. Ticket: ", result.deal);
return true;
}

// --- Market Data & Indicator Functions ---


// Get candlestick data for a specific symbol and timeframe
// Returns true on success and populates 'rates', false on failure
bool GetCandleData(string symbol, ENUM_TIMEFRAMES timeframe, int shift, MqlRates&
rates) {
MqlRates temp_rates[1];
if (CopyRates(symbol, timeframe, shift, 1, temp_rates) > 0) {
rates = temp_rates[0];
return true;
}
// Print("Failed to get candle data for ", symbol, " ", timeframe, " shift ",
shift); // Often too much logging
ZeroMemory(rates); // Ensure rates is zeroed on failure
return false;
}

// Get ATR value


double GetATR(string symbol, ENUM_TIMEFRAMES timeframe, int period, int shift) {
int atr_handle = iATR(symbol, timeframe, period);
if (atr_handle == INVALID_HANDLE) {
Print("Failed to get ATR handle for ", symbol, " ", timeframe, " period ",
period);
return 0.0;
}
double atr_value[];
if (CopyBuffer(atr_handle, 0, shift, 1, atr_value) <= 0) {
// Print("Failed to copy ATR buffer for ", symbol, " ", timeframe, " shift
", shift); // Often too much logging
return 0.0;
}
return atr_value[0];
}

// Get SMA value


double GetSMA(string symbol, ENUM_TIMEFRAMES timeframe, int period, ENUM_MA_METHOD
method, int shift) {
int ma_handle = iMA(symbol, timeframe, period, 0, method, PRICE_CLOSE);
if (ma_handle == INVALID_HANDLE) {
Print("Failed to get MA handle for ", symbol, " ", timeframe, " period ",
period);
return 0.0;
}
double ma_value[];
if (CopyBuffer(ma_handle, 0, shift, 1, ma_value) <= 0) {
// Print("Failed to copy MA buffer for ", symbol, " ", timeframe, " shift
", shift); // Often too much logging
return 0.0;
}
return ma_value[0];
}

// Get ADX value


double GetADX(string symbol, ENUM_TIMEFRAMES timeframe, int period, int shift) {
int adx_handle = iADX(symbol, timeframe, period);
if (adx_handle == INVALID_HANDLE) {
Print("Failed to get ADX handle for ", symbol, " ", timeframe, " period ",
period);
return 0.0;
}
double adx_value[];
if (CopyBuffer(adx_handle, MAIN_LINE, shift, 1, adx_value) <= 0) {
// Print("Failed to copy ADX buffer for ", symbol, " ", timeframe, " shift
", shift); // Often too much logging
return 0.0;
}
return adx_value[0];
}

// Get RSI value


double GetRSI(string symbol, ENUM_TIMEFRAMES timeframe, int period,
ENUM_APPLIED_PRICE appliedPrice, int shift) {
int rsi_handle = iRSI(symbol, timeframe, period, appliedPrice);
if (rsi_handle == INVALID_HANDLE) {
Print("Failed to get RSI handle for ", symbol, " ", timeframe, " period ",
period);
return 0.0;
}
double rsi_value[];
if (CopyBuffer(rsi_handle, 0, shift, 1, rsi_value) <= 0) {
// Print("Failed to copy RSI buffer for ", symbol, " ", timeframe, " shift
", shift); // Often too much logging
return 0.0;
}
return rsi_value[0];
}

// --- Geometric & Pattern Detection ---


// Function to identify Swing High (candle has X lower highs on left and X lower
highs on right)
bool IsSwingHigh(string symbol, ENUM_TIMEFRAMES timeframe, int currentBar, int
swingBars) {
// Ensure we have enough historical data to look back 'swingBars' candles on
either side
// And that the currentBar is not too recent to form a swing point
if (currentBar < swingBars || currentBar + swingBars >= Bars(symbol,
timeframe)) {
return false;
}

// Ensure there are enough bars available in total before attempting CopyRates
if (Bars(symbol, timeframe) < (currentBar + swingBars + 1)) {
return false;
}

MqlRates rates[2 * swingBars + 1];


// CopyRates should use currentBar - swingBars as the start index (oldest bar
in window)
// and copy 2*swingBars + 1 bars (total length of the window).
int copied_count = CopyRates(symbol, timeframe, currentBar - swingBars, 2 *
swingBars + 1, rates);
if (copied_count < (2 * swingBars + 1)) { // Not enough bars copied
return false;
}

double currentHigh = rates[swingBars].high; // The high of the potential swing


point (middle of the array)
for (int i = 0; i < swingBars; i++) {
if (rates[i].high >= currentHigh || rates[swingBars + 1 + i].high >=
currentHigh) {
return false; // Found a higher high on left or right
}
}
return true; // It's a swing high
}

// Function to identify Swing Low (candle has X higher lows on left and X higher
lows on right)
bool IsSwingLow(string symbol, ENUM_TIMEFRAMES timeframe, int currentBar, int
swingBars) {
// Ensure we have enough historical data to look back 'swingBars' candles on
either side
// And that the currentBar is not too recent to form a swing point
if (currentBar < swingBars || currentBar + swingBars >= Bars(symbol,
timeframe)) {
return false;
}

// Ensure there are enough bars available in total before attempting CopyRates
if (Bars(symbol, timeframe) < (currentBar + swingBars + 1)) {
return false;
}

MqlRates rates[2 * swingBars + 1];


// CopyRates should use currentBar - swingBars as the start index (oldest bar
in window)
// and copy 2*swingBars + 1 bars (total length of the window).
int copied_count = CopyRates(symbol, timeframe, currentBar - swingBars, 2 *
swingBars + 1, rates);
if (copied_count < (2 * swingBars + 1)) { // Not enough bars copied
return false;
}

double currentLow = rates[swingBars].low; // The low of the potential swing


point (middle of the array)
for (int i = 0; i < swingBars; i++) {
if (rates[i].low <= currentLow || rates[swingBars + 1 + i].low <=
currentLow) {
return false; // Found a lower low on left or right
}
// Check for same low within tiny tolerance (important for flat lows)
if (MathAbs(rates[i].low - currentLow) < _Point * 0.1 ||
MathAbs(rates[swingBars + 1 + i].low - currentLow) < _Point * 0.1) {
// Consider exact same low as not lower, so it's a swing
}
}
return true; // It's a swing low
}

// Function to identify Equal Highs (two swing highs within deviation)


bool IsEqualHighs(string symbol, ENUM_TIMEFRAMES timeframe, int currentBar, int
lookbackBars, double pipsDeviation) {
MqlRates currentCandle;
if (!GetCandleData(symbol, timeframe, currentBar, currentCandle)) return false;
double currentHigh = currentCandle.high;

MqlRates prevCandle;
for (int i = currentBar + 1; i < currentBar + lookbackBars; i++) { // Loop back
from currentBar + 1 (older bars)
if (IsSwingHigh(symbol, timeframe, i, InpSwingPointBars)) {
if (!GetCandleData(symbol, timeframe, i, prevCandle)) continue;
double prevHigh = prevCandle.high;
if (MathAbs(currentHigh - prevHigh) <= pipsDeviation * _Point) {
return true; // Found an equal high
}
}
}
return false;
}

// Function to identify Equal Lows (two swing lows within deviation)


bool IsEqualLows(string symbol, ENUM_TIMEFRAMES timeframe, int currentBar, int
lookbackBars, double pipsDeviation) {
MqlRates currentCandle;
if (!GetCandleData(symbol, timeframe, currentBar, currentCandle)) return false;
double currentLow = currentCandle.low;

MqlRates prevCandle;
for (int i = currentBar + 1; i < currentBar + lookbackBars; i++) { // Loop back
from currentBar + 1 (older bars)
if (IsSwingLow(symbol, timeframe, i, InpSwingPointBars)) {
if (!GetCandleData(symbol, timeframe, i, prevCandle)) continue;
double prevLow = prevCandle.low;
if (MathAbs(currentLow - prevLow) <= pipsDeviation * _Point) {
return true; // Found an equal low
}
}
}
return false;
}

// Function to determine if a Liquidity Sweep occurred


// Takes potential sweep high/low and returns true if confirmed reversal after
sweep
bool IsLiquiditySweep(string symbol, ENUM_TIMEFRAMES timeframe, double sweepLevel,
int sweepBar, bool isBullishSweep) {
MqlRates sweepCandle;
if (!GetCandleData(symbol, timeframe, sweepBar, sweepCandle)) return false;

// Check if price indeed moved beyond sweepLevel at sweepBar


bool swept = false;
if (isBullishSweep) { // Looking for bearish reversal (bullish sweep)
if (sweepCandle.high > sweepLevel) swept = true;
} else { // Looking for bullish reversal (bearish sweep)
if (sweepCandle.low < sweepLevel) swept = true;
}
if (!swept) return false;

// Check if subsequent candles (within InpLiquiditySweepReversalBars) close


back inside/decisively against sweep direction
MqlRates subsequentCandle;
for (int i = 0; i < InpLiquiditySweepReversalBars; i++) { // Check from current
bar (0)
if (!GetCandleData(symbol, timeframe, i, subsequentCandle)) continue;

if (isBullishSweep) { // Bearish reversal after bullish sweep


if (subsequentCandle.close < sweepLevel) { // Closed below the swept
level
return true;
}
} else { // Bullish reversal after bearish sweep
if (subsequentCandle.close > sweepLevel) { // Closed above the swept
level
return true;
}
}
}
return false;
}

// Function to identify a Fair Value Gap (FVG)


// Returns true if FVG found and populates fvgHigh, fvgLow. Else returns false.
// currentBar: The shift of the latest candle of the 3-candle FVG pattern (C3)
bool FindFVG(string symbol, ENUM_TIMEFRAMES timeframe, int currentBar, bool&
isBullishFVG, double& fvgHigh, double& fvgLow) {
fvgHigh = 0.0; // Initialize output parameters
fvgLow = 0.0;
isBullishFVG = false;

MqlRates c1, c2, c3;


// C1 is the oldest (currentBar + 2), C2 is middle (currentBar + 1), C3 is the
most recent (currentBar)
if (!GetCandleData(symbol, timeframe, currentBar + 2, c1) ||
!GetCandleData(symbol, timeframe, currentBar + 1, c2) ||
!GetCandleData(symbol, timeframe, currentBar, c3)) {
return false;
}

// Bullish FVG: Low of C1 > High of C3 (gap between C1 low and C3 high)
if (c1.low > c3.high && c2.low > c3.high) { // Ensure C2 also doesn't fill the
gap
fvgHigh = c1.low; // FVG High (upper boundary of the gap)
fvgLow = c3.high; // FVG Low (lower boundary of the gap)
isBullishFVG = true;
return true;
}
// Bearish FVG: High of C1 < Low of C3 (gap between C1 high and C3 low)
else if (c1.high < c3.low && c2.high < c3.low) { // Ensure C2 also doesn't fill
the gap
fvgHigh = c3.low; // FVG High (upper boundary of the gap)
fvgLow = c1.high; // FVG Low (lower boundary of the gap)
isBullishFVG = false;
return true;
}
return false; // No FVG found
}

// Function to check if FVG is unmitigated


// fvgCreationBar is the shift of the third candle (C3 in FindFVG)
bool IsFVGUnmitigated(string symbol, ENUM_TIMEFRAMES timeframe, double fvgHigh,
double fvgLow, int fvgCreationBar) {
MqlRates candle;
for (int i = 0; i < fvgCreationBar; i++) { // Loop from current bar (0) up to
the FVG creation bar (exclusive)
if (!GetCandleData(symbol, timeframe, i, candle)) continue;

// Check if any part of the candle (wick or body) has touched or crossed
the FVG zone
if (MathMax(candle.low, fvgLow) <= MathMin(candle.high, fvgHigh)) {
return false; // FVG has been touched/mitigated
}
}
return true; // FVG is untouched
}

// Function to check for specific Candlestick Rejection Patterns (e.g., Pin Bar,
Engulfing)
bool IsRejectionCandle(string symbol, ENUM_TIMEFRAMES timeframe, int currentBar,
bool& isBullishRejection) {
MqlRates current, prev;
if (!GetCandleData(symbol, timeframe, currentBar, current) || !
GetCandleData(symbol, timeframe, currentBar + 1, prev)) return false;

double bodySize = MathAbs(current.open - current.close);


double totalRange = current.high - current.low;

if (totalRange == 0) return false; // Avoid division by zero

// --- Pin Bar ---


// Bullish Pin Bar: Small body, long lower wick (at least 2x body), closes near
high
if (current.close > current.open && // Bullish candle
(current.open - current.low) > (2 * bodySize) && // Lower wick is long
(current.high - current.close) < (0.5 * bodySize) && // Small upper wick
bodySize < (0.5 * totalRange)) { // Body is small (less than half total
range)
isBullishRejection = true;
return true;
}
// Bearish Pin Bar: Small body, long upper wick (at least 2x body), closes near
low
if (current.close < current.open && // Bearish candle
(current.high - current.open) > (2 * bodySize) && // Upper wick is long
(current.close - current.low) < (0.5 * bodySize) && // Small lower wick
bodySize < (0.5 * totalRange)) { // Body is small (less than half total
range)
isBullishRejection = false;
return true;
}

// --- Engulfing Pattern ---


// Bullish Engulfing: Current bullish body fully engulfs previous bearish body
if (current.close > current.open && prev.close < prev.open &&
current.open < prev.close && current.close > prev.open) {
isBullishRejection = true;
return true;
}
// Bearish Engulfing: Current bearish body fully engulfs previous bullish body
if (current.close < current.open && prev.close > prev.open &&
current.open > prev.close && current.close < prev.open) {
isBullishRejection = false;
return true;
}

return false; // No rejection pattern found


}

// Function to find the "Next Major S/R Level" for TP


double FindNextMajorSR(string symbol, ENUM_TIMEFRAMES timeframe, double
currentPrice, bool isLookingForResistance) {
double targetLevel = 0.0;
MqlRates rates[100]; // Look back 100 bars
int count = CopyRates(symbol, timeframe, 0, 100, rates);
if (count <= 0) return 0.0;

for (int i = 1; i < count; i++) { // Start from 1 as 0 is current bar


if (isLookingForResistance) {
// Find a swing high above currentPrice
if (rates[i].high > currentPrice && IsSwingHigh(symbol, timeframe, i,
InpSwingPointBars)) {
targetLevel = rates[i].high;
break; // Take the first one found (most recent)
}
} else {
// Find a swing low below currentPrice
if (rates[i].low < currentPrice && IsSwingLow(symbol, timeframe, i,
InpSwingPointBars)) {
targetLevel = rates[i].low;
break; // Take the first one found (most recent)
}
}
}
return targetLevel; // This needs to be much more sophisticated in real code
}

// Function for Higher Time Frame (HTF) Alignment


bool CheckHTFAlignment(string symbol, ENUM_TIMEFRAMES mainTimeframe,
ENUM_TIMEFRAMES htfTimeframe, bool isBullishBias) {
// Get HTF MAs
double sma20_htf = GetSMA(symbol, htfTimeframe, InpMovingAveragePeriod,
MODE_SMA, 1); // 1 for previous closed bar
double sma50_htf = GetSMA(symbol, htfTimeframe, InpLongMovingAveragePeriod,
MODE_SMA, 1);

// Check for valid MA values (e.g., not 0.0 from error)


if (sma20_htf == 0.0 || sma50_htf == 0.0) return false;
// Check MA slopes
double sma20_htf_prev = GetSMA(symbol, htfTimeframe, InpMovingAveragePeriod,
MODE_SMA, 2);
double sma50_htf_prev = GetSMA(symbol, htfTimeframe,
InpLongMovingAveragePeriod, MODE_SMA, 2);

if (sma20_htf_prev == 0.0 || sma50_htf_prev == 0.0) return false;

bool maSlopeOk = false;


if (isBullishBias) {
if (sma20_htf > sma20_htf_prev && sma50_htf > sma50_htf_prev) maSlopeOk =
true;
} else {
if (sma20_htf < sma20_htf_prev && sma50_htf < sma50_htf_prev) maSlopeOk =
true;
}
if (!maSlopeOk) return false;

// Check ADX on HTF


double adx_htf = GetADX(symbol, htfTimeframe, InpADXPeriod, 1);
if (adx_htf < InpADXThreshold) return false;

// Check HTF price position relative to HTF MAs


MqlRates htf_candle;
if (!GetCandleData(symbol, htfTimeframe, 1, htf_candle)) return false;
bool maPositionOk = false;
if (isBullishBias) {
if (htf_candle.close > sma20_htf && sma20_htf > sma50_htf) maPositionOk =
true;
} else {
if (htf_candle.close < sma20_htf && sma20_htf < sma50_htf) maPositionOk =
true;
}
if (!maPositionOk) return false;

return true; // HTF alignment confirmed


}

// Helper function to check if price is retesting a zone (used by OB, FVG, Breaker)
bool IsPriceRetestingZone(double currentPrice, double zoneHigh, double zoneLow,
double maxPenetrationATR) {
double atr = GetATR(Symbol(), Period(), InpATRPeriod, 1);
if (atr == 0.0) return false;

MqlRates currentCandle;
if (!GetCandleData(Symbol(), Period(), 0, currentCandle)) return false;

// Check if any part of the current candle (wick or body) has entered the zone
if (MathMax(currentCandle.low, zoneLow) <= MathMin(currentCandle.high,
zoneHigh)) {
return true; // Current candle is inside or touching the zone
}

// Check for minor wick penetration beyond the zone


double upperPenetration = currentCandle.high - zoneHigh;
double lowerPenetration = zoneLow - currentCandle.low;

if (upperPenetration > 0 && upperPenetration <= maxPenetrationATR * atr &&


currentCandle.close < zoneHigh) {
return true; // Wick penetrated up, but closed back below zone high
(rejection from resistance)
}
if (lowerPenetration > 0 && lowerPenetration <= maxPenetrationATR * atr &&
currentCandle.close > zoneLow) {
return true; // Wick penetrated down, but closed back above zone low
(rejection from support)
}

return false; // Not retesting according to rules


}

// Helper function to define consolidation for Power of Three


bool IsConsolidation(string symbol, ENUM_TIMEFRAMES timeframe, int minBars, int
maxBars, double atrMultiplier) {
MqlRates rates[50]; // Increased size for maxBars + margin
int count = CopyRates(symbol, timeframe, 1, maxBars, rates); // Start from 1
for closed bars
if (count < minBars) return false; // Need at least minBars for consolidation
check
if (count == 0) return false; // Ensure there's data before accessing rates[0]

double currentATR = GetATR(symbol, timeframe, InpATRPeriod, 1);


if (currentATR == 0.0) return false;

// Check if volatility is low (Current ATR below average of last 100 bars)
double longTermATR = GetATR(symbol, timeframe, 100, 1); // Get average ATR over
100 bars
if (longTermATR == 0.0 || currentATR > 0.75 * longTermATR) return false; //
Current ATR is too high

// Check if price is within a tight percentage of recent high/low over X bars


double highestHigh = 0;
double lowestLow = 9999999.9; // Initialize with a very high value for XAUUSDm
for (int i = 0; i < count; i++) { // Iterate through copied bars
if (rates[i].high > highestHigh) highestHigh = rates[i].high;
if (rates[i].low < lowestLow) lowestLow = rates[i].low;
}

double range = highestHigh - lowestLow;


if (range > atrMultiplier * currentATR) return false; // Range is too wide for
consolidation

return true; // Likely in consolidation


}

// Function to calculate Risk-Reward Ratio


double CalculateRiskRewardRatio(double entryPrice, double stopLoss, double
takeProfit, bool isBuy) {
if (isBuy) {
double risk = entryPrice - stopLoss;
double reward = takeProfit - entryPrice;
if (risk <= 0) return 0.0; // Risk cannot be zero or negative
return reward / risk;
} else { // Sell
double risk = stopLoss - entryPrice;
double reward = entryPrice - takeProfit;
if (risk <= 0) return 0.0; // Risk cannot be zero or negative
return reward / risk;
}
}

// Function to reset daily trade flags


void OnStartOfNewDay() {
datetime now = TimeCurrent();
datetime today = TimeToDay(now);

for (int i = 0; i < 12; i++) { // Corrected size to 12


if (TimeToDay(g_lastTradeDay[i]) != today) {
g_lastTradeDay[i] = 0; // Reset for new day
}
}
}

// Function to detect an impulsive move


// Returns true if there's a strong directional move over recent bars
bool IsImpulsiveMove(string symbol, ENUM_TIMEFRAMES timeframe, int maxBars, double
minATR, bool& isBullish) {
MqlRates rates[MAX_BARS_FOR_IMPULSIVE_MOVE];
int count = CopyRates(symbol, timeframe, 1, maxBars, rates); // Copy previous
maxBars candles
if (count < maxBars) return false;
if (count == 0) return false; // Ensure there's data

double currentATR = GetATR(symbol, timeframe, InpATRPeriod, 1);


if (currentATR == 0.0) return false;

double firstClose = rates[count - 1].close;


double lastClose = rates[0].close;

double totalMovement = MathAbs(lastClose - firstClose);

if (totalMovement < minATR * currentATR) {


return false; // Not enough movement
}

// Check for mostly unidirectional movement


int bullishCount = 0;
int bearishCount = 0;
for (int i = 0; i < count; i++) {
if (rates[i].close > rates[i].open) bullishCount++;
else if (rates[i].close < rates[i].open) bearishCount++;
}

if (bullishCount > bearishCount * 2) { // Significantly more bullish candles


isBullish = true;
return true;
} else if (bearishCount > bullishCount * 2) { // Significantly more bearish
candles
isBullish = false;
return true;
}

return false; // Not a clear impulsive move


}

// Function to find an Order Block


// Returns true if found and populates obHigh, obLow, isBullishOB. Else returns
false.
bool FindOrderBlock(string symbol, ENUM_TIMEFRAMES timeframe, int lookbackBars,
bool& isBullishOB, double& obHigh, double& obLow) {
obHigh = 0.0;
obLow = 0.0;
isBullishOB = false;

// The array needs to be large enough to hold 'lookbackBars + 2' bars.


// For safer indexing (i-1, i, i+1), we need at least 3 bars (i=1, i-1=0,
i+1=2)
// The loop should go from i=1 to count-2
// So, CopyRates needs at least 3 bars (or more if lookbackBars is larger)
MqlRates rates[MAX_LOOKBACK_FOR_OB];
int count = CopyRates(symbol, timeframe, 0, lookbackBars + 2, rates);
if (count < 3) return false; // Need at least 3 bars for the pattern (i-1, i,
i+1)

// Iterate from older bars towards current (shift from latest bar is 'i')
// Loop from index 1 to count - 2 to ensure rates[i-1], rates[i], rates[i+1]
are all valid.
for (int i = 1; i < count - 1; i++) {
MqlRates current = rates[i]; // The potential OB candle
MqlRates prev = rates[i+1]; // Candle before potential OB (older)
MqlRates next = rates[i-1]; // Candle after potential OB (newer)

// Bullish Order Block: Last down candle before an impulsive move up


// Conditions:
// 1. Current candle is bearish (close < open)
// 2. Next candle is strongly bullish and breaks above 'current' candle's
high
// 3. 'current' candle is part of a recent swing low formation (simplified)
if (current.close < current.open && // Current candle is bearish
next.close > current.high && // Next candle closes above current
high (impulsive move start)
next.open < current.high && // Next candle started below current
high
IsSwingLow(symbol, timeframe, i, InpSwingPointBars)) // 'current' is a
swing low (use 'i' as bar shift)
{
obHigh = current.high;
obLow = current.low;
isBullishOB = true;
// Print("Found potential Bullish OB at bar ", i, ": High=", obHigh, ",
Low=", obLow);
return true;
}

// Bearish Order Block: Last up candle before an impulsive move down


// Conditions:
// 1. Current candle is bullish (close > open)
// 2. Next candle is strongly bearish and breaks below 'current' candle's
low
// 3. 'current' candle is part of a recent swing high formation
(simplified)
if (current.close > current.open && // Current candle is bullish
next.close < current.low && // Next candle closes below current low
(impulsive move start)
next.open > current.low && // Next candle started above current
low
IsSwingHigh(symbol, timeframe, i, InpSwingPointBars)) // 'current' is a
swing high (use 'i' as bar shift)
{
obHigh = current.high;
obLow = current.low;
isBullishOB = false;
// Print("Found potential Bearish OB at bar ", i, ": High=", obHigh, ",
Low=", obLow);
return true;
}
}
return false;
}

// Function to check if an Order Block is unmitigated


// obCreationBar is the shift of the candle that formed the OB
bool IsOrderBlockUnmitigated(string symbol, ENUM_TIMEFRAMES timeframe, double
obHigh, double obLow, int obCreationBar) {
MqlRates candle;
// Iterate from current bar (shift 0) up to the OB creation bar (exclusive)
for (int i = 0; i < obCreationBar; i++) {
if (!GetCandleData(symbol, timeframe, i, candle)) continue;

// Check if any part of the candle (wick or body) has touched or crossed
the OB zone
if (MathMax(candle.low, obLow) <= MathMin(candle.high, obHigh)) {
return false; // OB has been touched/mitigated
}
}
return true; // OB is untouched
}

// Function to find a Breaker Block


// Returns true if found and populates breakerHigh, breakerLow, isBullishBreaker.
Else returns false.
bool FindBreakerBlock(string symbol, ENUM_TIMEFRAMES timeframe, int lookbackBars,
bool& isBullishBreaker, double& breakerHigh, double& breakerLow) {
breakerHigh = 0.0;
breakerLow = 0.0;
isBullishBreaker = false;

MqlRates rates[MAX_LOOKBACK_FOR_BREAKER];
int count = CopyRates(symbol, timeframe, 0, lookbackBars + 5, rates);
if (count < InpSwingPointBars * 2 + 3) return false; // Need enough bars for at
least two swing points and a break

// Look for a Swing Low/High that has been broken and retested (the "breaker"
is the swing point that was broken)
// Loop ensures that rates[i] and its neighbors (for swing point check) are
within bounds.
// The range for 'i' must ensure 'i + InpSwingPointBars + 1' and 'i - 1' are
valid.
for (int i = InpSwingPointBars + 1; i < count - InpSwingPointBars - 1; i++) {
// Bearish Breaker (price breaks swing low, then retests previous swing
high (now resistance))
// Sequence: Swing High -> Swing Low -> Break of Swing Low -> Retest of
Swing High
if (IsSwingLow(symbol, timeframe, i, InpSwingPointBars)) {
double swlPrice = rates[i].low;
int swlBar = i;

// Look for a Swing High (SWH) *before* this Swing Low (j > swlBar for
older bars)
for (int j = swlBar + InpSwingPointBars + 1; j < count; j++) {
if (IsSwingHigh(symbol, timeframe, j, InpSwingPointBars)) {
double swhPrice = rates[j].high;
int swhBar = j;

// Check if SWL was broken (close below it after its formation)


bool brokenSwl = false;
for (int k = swlBar - 1; k >= 0; k--) { // Check from candle
after SWL towards current (k=0 is current bar)
if (rates[k].close < swlPrice - InpBreakPipsBeyondLevel *
_Point) { // Significant break
brokenSwl = true;
break;
}
}

if (brokenSwl) {
// The breaker zone is the last candle of the original
Swing High or the Swing High itself.
// For a Bearish Breaker, the original Swing High becomes
resistance.
// We use the range of the candle that formed the swing
high.
breakerHigh = rates[swhBar].high;
breakerLow = rates[swlBar].low; // The breaker zone is the
original swing low that was broken
isBullishBreaker = false; // This is a bearish setup
// Print("Found potential Bearish Breaker from SWH at bar
", swhBar, " and SWL at ", swlBar);
return true;
}
}
}
}

// Bullish Breaker (price breaks swing high, then retests previous swing
low (now support))
// Sequence: Swing Low -> Swing High -> Break of Swing High -> Retest of
Swing Low
if (IsSwingHigh(symbol, timeframe, i, InpSwingPointBars)) {
double swhPrice = rates[i].high;
int swhBar = i;

// Look for a Swing Low (SWL) *before* this Swing High (j > swhBar for
older bars)
for (int j = swhBar + InpSwingPointBars + 1; j < count; j++) {
if (IsSwingLow(symbol, timeframe, j, InpSwingPointBars)) {
double swlPrice = rates[j].low;
int swlBar = j;

// Check if SWH was broken (close above it after its formation)


bool brokenSwh = false;
for (int k = swhBar - 1; k >= 0; k--) { // Check from candle
after SWH towards current
if (rates[k].close > swhPrice + InpBreakPipsBeyondLevel *
_Point) { // Significant break
brokenSwh = true;
break;
}
}

if (brokenSwh) {
// The breaker zone is the last candle of the original
Swing Low or the Swing Low itself.
// For a Bullish Breaker, the original Swing Low becomes
support.
// We use the range of the candle that formed the swing
low.
breakerHigh = rates[swhBar].high; // The breaker zone is
the original swing high that was broken
breakerLow = rates[swlBar].low;
isBullishBreaker = true; // This is a bullish setup
// Print("Found potential Bullish Breaker from SWL at bar
", swlBar, " and SWH at ", swhBar);
return true;
}
}
}
}
}
return false;
}

// Function to get the angle of a trend line (simple approximation)


double GetTrendLineAngle(string symbol, ENUM_TIMEFRAMES timeframe, int
point1_shift, int point2_shift, double point1_price, double point2_price) {
if (point1_shift == point2_shift) return 0.0;
if (point1_price == point2_price) return 0.0; // Flat line

// Calculate time difference in minutes


// double casts below are for clarity, as MQL5 arithmetic typically handles int
to double promotion
double barsDiff = MathAbs((double)point1_shift - (double)point2_shift);
if (barsDiff == 0) return 0.0; // Same bar

double priceDiff = point1_price - point2_price;


// This line might be the source of "MathAtan - undeclared identifier" if
Math.mqh is not found.
// The "some operator expected" might be a cascading error from MathAtan not
being recognized.
double angle = MathAtan(priceDiff / (barsDiff * SymbolInfoDouble(symbol,
SYMBOL_POINT)));
return angle * 180 / M_PI; // Convert to degrees
}

//+------------------------------------------------------------------+
//| Strategy Implementations |
//+------------------------------------------------------------------+

// Strategy 1: Liquidity Sweep (Double Top/Bottom Based)


void CheckStrategy_LiquiditySweep_DoubleTopBottom() {
if (!InpEnableStrategy1 || TimeToDay(TimeCurrent()) ==
TimeToDay(g_lastTradeDay[0])) return;

int sweepBar = 1; // The latest completed bar


MqlRates currentCandle;
if (!GetCandleData(Symbol(), Period(), 0, currentCandle)) return; // Current
closed candle

double atr = GetATR(Symbol(), Period(), InpATRPeriod, 1);


if (atr == 0.0) return;

// Simplified approach for finding recent swing highs/lows to sweep


// For a more robust implementation, you would need functions like:
// bool FindDoubleTop(string symbol, ENUM_TIMEFRAMES timeframe, int lookback,
double pipsDeviation, double& firstTopPrice, double& secondTopPrice, int&
secondTopBar);
// bool FindDoubleBottom(string symbol, ENUM_TIMEFRAMES timeframe, int
lookback, double pipsDeviation, double& firstBottomPrice, double&
secondBottomPrice, int& secondBottomBar);

double lastSwingHigh = 0.0;


double lastSwingLow = 0.0;
int lastSwingHighBar = -1;
int lastSwingLowBar = -1;

// Find the most recent swing high/low that occurred at least 2 bars ago (to
allow for the sweep candle itself)
for (int i = 2; i <= InpLiquiditySweepReversalBars + InpSwingPointBars + 5; i+
+) {
if (IsSwingHigh(Symbol(), Period(), i, InpSwingPointBars)) {
MqlRates tempRates;
if (GetCandleData(Symbol(), Period(), i, tempRates)) {
lastSwingHigh = tempRates.high;
lastSwingHighBar = i;
break; // Take the most recent one
}
}
}
for (int i = 2; i <= InpLiquiditySweepReversalBars + InpSwingPointBars + 5; i+
+) {
if (IsSwingLow(Symbol(), Period(), i, InpSwingPointBars)) {
MqlRates tempRates;
if (GetCandleData(Symbol(), Period(), i, tempRates)) {
lastSwingLow = tempRates.low;
lastSwingLowBar = i;
break; // Take the most recent one
}
}
}

// Check for Bearish Liquidity Sweep (price sweeps above lastSwingHigh then
reverses)
if (lastSwingHighBar != -1 && IsLiquiditySweep(Symbol(), Period(),
lastSwingHigh, sweepBar, true)) { // isBullishSweep = true (swept upwards)
// Ensure HTF alignment for bearish move
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, false)) {
// Print("Strategy 1: Bearish sweep, but HTF not aligned for bearish
bias.");
return;
}
double entryPrice = currentCandle.close;
double stopLoss = currentCandle.high + InpATRMagnifier * atr;
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice, false);
// Looking for support

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice, stopLoss,


takeProfit, false) >= InpMinRiskRewardRatio) {
if (SendSellOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[0])) {
g_lastTradeDay[0] = TimeCurrent();
Print("Strategy 1: Bearish Liquidity Sweep Trade taken. SL: ",
DoubleToString(stopLoss, _Digits), ", TP: ", DoubleToString(takeProfit, _Digits));
}
} else {
Print("Strategy 1: Bearish Liquidity Sweep setup found, but R:R or TP
invalid. R:R = ", DoubleToString(CalculateRiskRewardRatio(entryPrice, stopLoss,
takeProfit, false), 2));
}
}
// Check for Bullish Liquidity Sweep (price sweeps below lastSwingLow then
reverses)
else if (lastSwingLowBar != -1 && IsLiquiditySweep(Symbol(), Period(),
lastSwingLow, sweepBar, false)) { // isBullishSweep = false (swept downwards)
// Ensure HTF alignment for bullish move
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, true)) {
// Print("Strategy 1: Bullish sweep, but HTF not aligned for bullish
bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = currentCandle.low - InpATRMagnifier * atr;
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
true); // Looking for resistance

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice, stopLoss,


takeProfit, true) >= InpMinRiskRewardRatio) {
if (SendBuyOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[0])) {
g_lastTradeDay[0] = TimeCurrent();
Print("Strategy 1: Bullish Liquidity Sweep Trade taken. SL: ",
DoubleToString(stopLoss, _Digits), ", TP: ", DoubleToString(takeProfit, _Digits));
}
} else {
Print("Strategy 1: Bullish Liquidity Sweep setup found, but R:R or TP
invalid. R:R = ", DoubleToString(CalculateRiskRewardRatio(entryPrice, stopLoss,
takeProfit, true), 2));
}
}
}

// Strategy 2: Power of Three - Bullish


void CheckStrategy_PowerOfThree_Bullish() {
if (!InpEnableStrategy2 || TimeToDay(TimeCurrent()) ==
TimeToDay(g_lastTradeDay[1])) return;

MqlRates currentCandle, prevCandle, twoPrevCandle;


if (!GetCandleData(Symbol(), Period(), 0, currentCandle) ||
!GetCandleData(Symbol(), Period(), 1, prevCandle) ||
!GetCandleData(Symbol(), Period(), 2, twoPrevCandle)) {
return;
}

// Power of Three (Accumulation, Manipulation, Distribution) - Bullish scenario


// 1. Consolidation (Accumulation) - check previous 10-20 bars
if (!IsConsolidation(Symbol(), Period(), InpConsolidationMinBars,
InpConsolidationMaxBars, InpConsolidationATRMultiplier)) {
// Print("Strategy 2 (Bullish): Not in consolidation.");
return;
}

// 2. Manipulation (False Breakout/Sweep lower)


// The previous candle (prevCandle) should have swept below the consolidation
low.
// The candle before that (twoPrevCandle) should ideally be part of the
consolidation.
// Calculate consolidation range
MqlRates consolidationRates[InpConsolidationMaxBars];
int count = CopyRates(Symbol(), Period(), 2, InpConsolidationMaxBars,
consolidationRates);
if (count < InpConsolidationMinBars) return;
if (count == 0) return; // Ensure consolidationRates has data

double consolidationLow = consolidationRates[0].low; // Initial lowest


for (int i=0; i<count; i++) {
if (consolidationRates[i].low < consolidationLow) consolidationLow =
consolidationRates[i].low;
}

// Check if previous candle swept below consolidation low and closed back above
or near it
if (prevCandle.low < consolidationLow && prevCandle.close > consolidationLow -
InpATRMagnifier * GetATR(Symbol(),Period(),InpATRPeriod,1)) {
// This is a simplified manipulation. A true manipulation would have a
deeper sweep and then reversal.
// Also, the previous candle should ideally be a rejection candle.
bool isRejection;
if (!IsRejectionCandle(Symbol(), Period(), 1, isRejection) || !isRejection)
{ // Check if prevCandle is a bullish rejection
// Print("Strategy 2 (Bullish): Previous candle not a bullish rejection
after sweep.");
return;
}

// 3. Distribution (Impulsive move up, i.e., current candle)


// Current candle should be a strong bullish candle, closing significantly
higher.
if (currentCandle.close > currentCandle.open &&
(currentCandle.close - currentCandle.open) > (0.5 * GetATR(Symbol(),
Period(), InpATRPeriod, 1))) { // Strong bullish candle
// Check HTF alignment for bullish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, true)) {
// Print("Strategy 2 (Bullish): HTF not aligned for bullish
bias.");
return;
}
double entryPrice = currentCandle.close;
double stopLoss = prevCandle.low - InpATRMagnifier * GetATR(Symbol(),
Period(), InpATRPeriod, 1); // Below manipulation low
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
true);

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice, stopLoss,


takeProfit, true) >= InpMinRiskRewardRatio) {
if (SendBuyOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[1])) {
g_lastTradeDay[1] = TimeCurrent();
Print("Strategy 2 (Bullish): Power of Three Trade taken. SL: ",
DoubleToString(stopLoss, _Digits), ", TP: ", DoubleToString(takeProfit, _Digits));
}
} else {
Print("Strategy 2 (Bullish): Power of Three setup found, but R:R or
TP invalid. R:R = ", DoubleToString(CalculateRiskRewardRatio(entryPrice, stopLoss,
takeProfit, true), 2));
}
}
}
}

// Strategy 2: Power of Three - Bearish


void CheckStrategy_PowerOfThree_Bearish() {
if (!InpEnableStrategy2 || TimeToDay(TimeCurrent()) ==
TimeToDay(g_lastTradeDay[2])) return;

MqlRates currentCandle, prevCandle, twoPrevCandle;


if (!GetCandleData(Symbol(), Period(), 0, currentCandle) ||
!GetCandleData(Symbol(), Period(), 1, prevCandle) ||
!GetCandleData(Symbol(), Period(), 2, twoPrevCandle)) {
return;
}

// Power of Three (Accumulation, Manipulation, Distribution) - Bearish scenario


// 1. Consolidation (Accumulation) - check previous 10-20 bars
if (!IsConsolidation(Symbol(), Period(), InpConsolidationMinBars,
InpConsolidationMaxBars, InpConsolidationATRMultiplier)) {
// Print("Strategy 2 (Bearish): Not in consolidation.");
return;
}

// 2. Manipulation (False Breakout/Sweep higher)


// The previous candle (prevCandle) should have swept above the consolidation
high.
MqlRates consolidationRates[InpConsolidationMaxBars];
int count = CopyRates(Symbol(), Period(), 2, InpConsolidationMaxBars,
consolidationRates);
if (count < InpConsolidationMinBars) return;
if (count == 0) return; // Ensure consolidationRates has data

double consolidationHigh = consolidationRates[0].high; // Initial highest


for (int i=0; i<count; i++) {
if (consolidationRates[i].high > consolidationHigh) consolidationHigh =
consolidationRates[i].high;
}

// Check if previous candle swept above consolidation high and closed back
below or near it
if (prevCandle.high > consolidationHigh && prevCandle.close < consolidationHigh
+ InpATRMagnifier * GetATR(Symbol(),Period(),InpATRPeriod,1)) {
bool isRejection;
if (!IsRejectionCandle(Symbol(), Period(), 1, isRejection) || isRejection)
{ // Check if prevCandle is a bearish rejection
// Print("Strategy 2 (Bearish): Previous candle not a bearish rejection
after sweep.");
return;
}

// 3. Distribution (Impulsive move down, i.e., current candle)


// Current candle should be a strong bearish candle, closing significantly
lower.
if (currentCandle.close < currentCandle.open &&
(currentCandle.open - currentCandle.close) > (0.5 * GetATR(Symbol(),
Period(), InpATRPeriod, 1))) { // Strong bearish candle
// Check HTF alignment for bearish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, false)) {
// Print("Strategy 2 (Bearish): HTF not aligned for bearish
bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = prevCandle.high + InpATRMagnifier * GetATR(Symbol(),
Period(), InpATRPeriod, 1); // Above manipulation high
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
false);

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice, stopLoss,


takeProfit, false) >= InpMinRiskRewardRatio) {
if (SendSellOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[2])) {
g_lastTradeDay[2] = TimeCurrent();
Print("Strategy 2 (Bearish): Power of Three Trade taken. SL: ",
DoubleToString(stopLoss, _Digits), ", TP: ", DoubleToString(takeProfit, _Digits));
}
} else {
Print("Strategy 2 (Bearish): Power of Three setup found, but R:R or
TP invalid. R:R = ", DoubleToString(CalculateRiskRewardRatio(entryPrice, stopLoss,
takeProfit, false), 2));
}
}
}
}

// Strategy 3: Break and Retest (S/R Flip)


void CheckStrategy_BreakAndRetest() {
if (!InpEnableStrategy3 || TimeToDay(TimeCurrent()) ==
TimeToDay(g_lastTradeDay[3])) return;

MqlRates currentCandle, prevCandle;


if (!GetCandleData(Symbol(), Period(), 0, currentCandle) || !
GetCandleData(Symbol(), Period(), 1, prevCandle)) return;

double atr = GetATR(Symbol(), Period(), InpATRPeriod, 1);


if (atr == 0.0) return;
double srLevel = 0.0;
bool isResistanceBroken = false; // True if resistance was broken (now support)
bool isSupportBroken = false; // True if support was broken (now resistance)

// Simplified S/R detection: find a strong swing high/low that acted as S/R
for (int i = 5; i < 50; i++) { // Look back 50 bars for S/R
if (IsSwingHigh(Symbol(), Period(), i, InpSwingPointBars)) {
srLevel = iHigh(Symbol(), Period(), i);
// Check if it was resistance and now broken to become support
if (prevCandle.high > srLevel + InpBreakPipsBeyondLevel * _Point) { //
Previous candle broke above
// Ensure the break was significant and body penetration
if (MathAbs(prevCandle.open - prevCandle.close) / (prevCandle.high
- prevCandle.low) >= InpBodyPenetrationRatio) {
// Check if current candle is retesting from above and closes
above or near the level
if (currentCandle.low < srLevel + InpATRMagnifier * atr &&
currentCandle.close > srLevel - InpATRMagnifier * atr) {
isResistanceBroken = true;
break;
}
}
}
}
if (IsSwingLow(Symbol(), Period(), i, InpSwingPointBars)) {
srLevel = iLow(Symbol(), Period(), i);
// Check if it was support and now broken to become resistance
if (prevCandle.low < srLevel - InpBreakPipsBeyondLevel * _Point) { //
Previous candle broke below
// Ensure the break was significant and body penetration
if (MathAbs(prevCandle.open - prevCandle.close) / (prevCandle.high
- prevCandle.low) >= InpBodyPenetrationRatio) {
// Check if current candle is retesting from below and closes
below or near the level
if (currentCandle.high > srLevel - InpATRMagnifier * atr &&
currentCandle.close < srLevel + InpATRMagnifier * atr) {
isSupportBroken = true;
break;
}
}
}
}
}

// Bullish Re-test (Resistance becomes Support)


if (isResistanceBroken) {
bool isRejection;
if (IsRejectionCandle(Symbol(), Period(), 0, isRejection) && isRejection) {
// Bullish rejection at the level
// Check HTF alignment for bullish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, true)) {
// Print("Strategy 3 (Bullish): HTF not aligned for bullish
bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = srLevel - InpATRMagnifier * atr; // Below the flipped
support
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
true);

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice, stopLoss,


takeProfit, true) >= InpMinRiskRewardRatio) {
if (SendBuyOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[3])) {
g_lastTradeDay[3] = TimeCurrent();
Print("Strategy 3 (Bullish): Break and Retest (R -> S) Trade
taken. SL: ", DoubleToString(stopLoss, _Digits), ", TP: ",
DoubleToString(takeProfit, _Digits));
}
} else {
Print("Strategy 3 (Bullish): Break and Retest (R -> S) setup found,
but R:R or TP invalid. R:R = ", DoubleToString(CalculateRiskRewardRatio(entryPrice,
stopLoss, takeProfit, true), 2));
}
}
}
// Bearish Re-test (Support becomes Resistance)
else if (isSupportBroken) {
bool isRejection;
if (IsRejectionCandle(Symbol(), Period(), 0, isRejection) && !isRejection)
{ // Bearish rejection at the level
// Check HTF alignment for bearish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, false)) {
// Print("Strategy 3 (Bearish): HTF not aligned for bearish
bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = srLevel + InpATRMagnifier * atr; // Above the flipped
resistance
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
false);

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice, stopLoss,


takeProfit, false) >= InpMinRiskRewardRatio) {
if (SendSellOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[3])) {
g_lastTradeDay[3] = TimeCurrent();
Print("Strategy 3 (Bearish): Break and Retest (S -> R) Trade
taken. SL: ", DoubleToString(stopLoss, _Digits), ", TP: ",
DoubleToString(takeProfit, _Digits));
}
} else {
Print("Strategy 3 (Bearish): Break and Retest (S -> R) setup found,
but R:R or TP invalid. R:R = ", DoubleToString(CalculateRiskRewardRatio(entryPrice,
stopLoss, takeProfit, false), 2));
}
}
}
}

// Strategy 4: Fibonacci Retracement


void CheckStrategy_FibonacciRetracement() {
if (!InpEnableStrategy4 || TimeToDay(TimeCurrent()) ==
TimeToDay(g_lastTradeDay[4])) return;
MqlRates currentCandle;
if (!GetCandleData(Symbol(), Period(), 0, currentCandle)) return;

double atr = GetATR(Symbol(), Period(), InpATRPeriod, 1);


if (atr == 0.0) return;

// 1. Identify a recent impulsive move


bool isBullishImpulse = false;
bool impulsiveMoveFound = IsImpulsiveMove(Symbol(), Period(),
InpImpulsiveMoveMaxBars, InpMinImpulsiveMoveATR, isBullishImpulse);

if (!impulsiveMoveFound) {
// Print("Strategy 4: No impulsive move found.");
return;
}

double swingHigh = 0.0;


double swingLow = 0.0;

// Find the actual swing high/low points for the impulsive move
// Need to find the start and end of the impulsive move
int impulseStartBar = -1;
int impulseEndBar = -1; // Usually bar 1 (previous closed bar)

MqlRates impulseRates[InpImpulsiveMoveMaxBars + 1];


int count = CopyRates(Symbol(), Period(), 0, InpImpulsiveMoveMaxBars + 1,
impulseRates);
if (count <= 0) return;

if (isBullishImpulse) {
swingLow = impulseRates[count -1].low; // Start of impulse (oldest candle's
low)
swingHigh = impulseRates[0].high; // End of impulse (most recent candle's
high)
// Find the actual lowest low and highest high within the impulsive move
range
for(int i = 0; i < count; i++) {
if (impulseRates[i].low < swingLow) swingLow = impulseRates[i].low;
if (impulseRates[i].high > swingHigh) swingHigh = impulseRates[i].high;
}
} else { // Bearish impulse
swingHigh = impulseRates[count -1].high; // Start of impulse (oldest
candle's high)
swingLow = impulseRates[0].low; // End of impulse (most recent candle's
low)
// Find the actual highest high and lowest low within the impulsive move
range
for(int i = 0; i < count; i++) {
if (impulseRates[i].high > swingHigh) swingHigh = impulseRates[i].high;
if (impulseRates[i].low < swingLow) swingLow = impulseRates[i].low;
}
}

if (swingHigh == 0.0 || swingLow == 0.0 || swingHigh == swingLow) return;

// Define Fibonacci levels (e.g., 0.5, 0.618, 0.786)


double fib50 = 0.0;
double fib618 = 0.0;
double fib786 = 0.0;

if (isBullishImpulse) { // From Low to High


fib50 = swingLow + (swingHigh - swingLow) * 0.50;
fib618 = swingLow + (swingHigh - swingLow) * 0.618;
fib786 = swingLow + (swingHigh - swingLow) * 0.786;
} else { // From High to Low
fib50 = swingHigh - (swingHigh - swingLow) * 0.50;
fib618 = swingHigh - (swingHigh - swingLow) * 0.618;
fib786 = swingHigh - (swingHigh - swingLow) * 0.786;
}

// Check for pullback to Fibonacci levels AND a rejection candle


bool isRejection;
if (isBullishImpulse) { // Looking for bullish entry on pullback (price drops
to fib level)
if (currentCandle.low <= fib618 && currentCandle.close > fib50 && // Price
retested between 50-61.8% or deeper
IsRejectionCandle(Symbol(), Period(), 0, isRejection) && isRejection) {
// Bullish rejection
// Check HTF alignment for bullish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, true)) {
// Print("Strategy 4 (Bullish): HTF not aligned for bullish
bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = swingLow - InpATRMagnifier * atr; // Below the swing
low of the impulse
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
true); // Target next resistance

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice, stopLoss,


takeProfit, true) >= InpMinRiskRewardRatio) {
if (SendBuyOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[4])) {
g_lastTradeDay[4] = TimeCurrent();
Print("Strategy 4 (Bullish): Fibonacci Retracement Trade taken.
SL: ", DoubleToString(stopLoss, _Digits), ", TP: ", DoubleToString(takeProfit,
_Digits));
}
} else {
Print("Strategy 4 (Bullish): Fibonacci Retracement setup found, but
R:R or TP invalid. R:R = ", DoubleToString(CalculateRiskRewardRatio(entryPrice,
stopLoss, takeProfit, true), 2));
}
}
} else { // Bearish impulse, looking for bearish entry on pullback (price rises
to fib level)
if (currentCandle.high >= fib618 && currentCandle.close < fib50 && // Price
retested between 50-61.8% or deeper
IsRejectionCandle(Symbol(), Period(), 0, isRejection) && !isRejection)
{ // Bearish rejection
// Check HTF alignment for bearish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, false)) {
// Print("Strategy 4 (Bearish): HTF not aligned for bearish
bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = swingHigh + InpATRMagnifier * atr; // Above the swing
high of the impulse
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
false); // Target next support

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice, stopLoss,


takeProfit, false) >= InpMinRiskRewardRatio) {
if (SendSellOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[4])) {
g_lastTradeDay[4] = TimeCurrent();
Print("Strategy 4 (Bearish): Fibonacci Retracement Trade taken.
SL: ", DoubleToString(stopLoss, _Digits), ", TP: ", DoubleToString(takeProfit,
_Digits));
}
} else {
Print("Strategy 4 (Bearish): Fibonacci Retracement setup found, but
R:R or TP invalid. R:R = ", DoubleToString(CalculateRiskRewardRatio(entryPrice,
stopLoss, takeProfit, false), 2));
}
}
}
}

// Strategy 5: Moving Average (20/50 SMA) Pullback


void CheckStrategy_MAPullback() {
if (!InpEnableStrategy5 || TimeToDay(TimeCurrent()) ==
TimeToDay(g_lastTradeDay[5])) return;

MqlRates currentCandle;
if (!GetCandleData(Symbol(), Period(), 0, currentCandle)) return;

double atr = GetATR(Symbol(), Period(), InpATRPeriod, 1);


if (atr == 0.0) return;

double sma20 = GetSMA(Symbol(), Period(), InpMovingAveragePeriod, MODE_SMA, 1);


// Previous closed bar
double sma50 = GetSMA(Symbol(), Period(), InpLongMovingAveragePeriod, MODE_SMA,
1);
double sma20_prev = GetSMA(Symbol(), Period(), InpMovingAveragePeriod,
MODE_SMA, 2);
double sma50_prev = GetSMA(Symbol(), Period(), InpLongMovingAveragePeriod,
MODE_SMA, 2);

if (sma20 == 0.0 || sma50 == 0.0 || sma20_prev == 0.0 || sma50_prev == 0.0)


return; // Ensure valid MA data

// Bullish scenario: Price above MAs, MAs pointing up, pullback to 20/50 SMA,
bullish rejection
if (sma20 > sma50 && sma20 > sma20_prev && sma50 > sma50_prev) { // Uptrend
confirmed by MA crossover and slope
// Price pulled back to 20 SMA
if (currentCandle.low <= sma20 + _Point * 5 && currentCandle.close > sma20
- _Point * 5) { // Price touches/closes near 20 SMA
bool isRejection;
if (IsRejectionCandle(Symbol(), Period(), 0, isRejection) &&
isRejection) { // Bullish rejection
// Check HTF alignment for bullish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, true)) {
// Print("Strategy 5 (Bullish): HTF not aligned for bullish
bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = MathMin(currentCandle.low, sma50) -
InpATRMagnifier * atr; // Below 50 SMA or rejection low
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
true);

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice,


stopLoss, takeProfit, true) >= InpMinRiskRewardRatio) {
if (SendBuyOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[5])) {
g_lastTradeDay[5] = TimeCurrent();
Print("Strategy 5 (Bullish): MA Pullback Trade taken. SL:
", DoubleToString(stopLoss, _Digits), ", TP: ", DoubleToString(takeProfit,
_Digits));
}
} else {
Print("Strategy 5 (Bullish): MA Pullback setup found, but R:R
or TP invalid. R:R = ", DoubleToString(CalculateRiskRewardRatio(entryPrice,
stopLoss, takeProfit, true), 2));
}
}
}
}
// Bearish scenario: Price below MAs, MAs pointing down, pullback to 20/50 SMA,
bearish rejection
else if (sma20 < sma50 && sma20 < sma20_prev && sma50 < sma50_prev) { //
Downtrend confirmed by MA crossover and slope
// Price pulled back to 20 SMA
if (currentCandle.high >= sma20 - _Point * 5 && currentCandle.close < sma20
+ _Point * 5) { // Price touches/closes near 20 SMA
bool isRejection;
if (IsRejectionCandle(Symbol(), Period(), 0, isRejection) && !
isRejection) { // Bearish rejection
// Check HTF alignment for bearish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, false)) {
// Print("Strategy 5 (Bearish): HTF not aligned for bearish
bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = MathMax(currentCandle.high, sma50) +
InpATRMagnifier * atr; // Above 50 SMA or rejection high
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
false);

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice,


stopLoss, takeProfit, false) >= InpMinRiskRewardRatio) {
if (SendSellOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[5])) {
g_lastTradeDay[5] = TimeCurrent();
Print("Strategy 5 (Bearish): MA Pullback Trade taken. SL:
", DoubleToString(stopLoss, _Digits), ", TP: ", DoubleToString(takeProfit,
_Digits));
}
} else {
Print("Strategy 5 (Bearish): MA Pullback setup found, but R:R
or TP invalid. R:R = ", DoubleToString(CalculateRiskRewardRatio(entryPrice,
stopLoss, takeProfit, false), 2));
}
}
}
}
}

// Strategy 6: Trend Line Pullback


void CheckStrategy_TrendLinePullback() {
if (!InpEnableStrategy6 || TimeToDay(TimeCurrent()) ==
TimeToDay(g_lastTradeDay[6])) return;

MqlRates currentCandle;
if (!GetCandleData(Symbol(), Period(), 0, currentCandle)) return;

double atr = GetATR(Symbol(), Period(), InpATRPeriod, 1);


if (atr == 0.0) return;

double trendLinePrice = 0.0;


bool isBullishTrendLine = false; // True for uptrend, false for downtrend

// Simplified Trend Line Detection: Find two recent swing highs/lows


// Bullish Trend Line (connecting two swing lows)
int firstLowBar = -1, secondLowBar = -1;
double firstLowPrice = 0.0, secondLowPrice = 0.0;

for (int i = InpSwingPointBars + 1; i < 100; i++) { // Look back for swing lows
(oldest bar is i)
if (IsSwingLow(Symbol(), Period(), i, InpSwingPointBars)) {
MqlRates tempRates;
if (GetCandleData(Symbol(), Period(), i, tempRates)) {
if (firstLowBar == -1) { // Found the first (older) swing low
firstLowBar = i;
firstLowPrice = tempRates.low;
} else { // Found the second (more recent) swing low
secondLowBar = i;
secondLowPrice = tempRates.low;
// Ensure it's an upward sloping line (newer low is higher than
older low)
if (secondLowPrice > firstLowPrice) {
isBullishTrendLine = true;
// Calculate expected price of trendline at currentBar
(shift 0)
// Using linear interpolation: y = y1 + ((y2-y1)/(x2-x1)) *
(x-x1)
// x is bar shift (0 for current), y is price
// For CopyRates, index 0 is current, so older bars have
higher shifts.
// Here, firstLowBar is older (larger shift), secondLowBar
is newer (smaller shift).
// Let x1 = secondLowBar, y1 = secondLowPrice
// Let x2 = firstLowBar, y2 = firstLowPrice
trendLinePrice = secondLowPrice + ((firstLowPrice -
secondLowPrice) / (double)(firstLowBar - secondLowBar)) * (0.0 - secondLowBar);
break;
} else { // Not an ascending trendline, reset older point to
current found swing low
firstLowBar = secondLowBar;
firstLowPrice = secondLowPrice;
secondLowBar = -1; secondLowPrice = 0.0;
}
}
}
}
}

// Bearish Trend Line (connecting two swing highs)


if (!isBullishTrendLine) { // Only check for bearish if no bullish found
int firstHighBar = -1, secondHighBar = -1;
double firstHighPrice = 0.0, secondHighPrice = 0.0;
for (int i = InpSwingPointBars + 1; i < 100; i++) {
if (IsSwingHigh(Symbol(), Period(), i, InpSwingPointBars)) {
MqlRates tempRates;
if (GetCandleData(Symbol(), Period(), i, tempRates)) {
if (firstHighBar == -1) {
firstHighBar = i;
firstHighPrice = tempRates.high;
} else {
secondHighBar = i;
secondHighPrice = tempRates.high;
// Ensure it's a downward sloping line (newer high is lower
than older high)
if (secondHighPrice < firstHighPrice) {
isBullishTrendLine = false; // Explicitly set false for
bearish
trendLinePrice = secondHighBar + ((firstHighPrice -
secondHighPrice) / (double)(firstHighBar - secondHighBar)) * (0.0 - secondHighBar);
// Corrected calculation
break;
} else {
firstHighBar = secondHighBar;
firstHighPrice = secondHighPrice;
secondHighBar = -1; secondHighPrice = 0.0;
}
}
}
}
}
}

if (trendLinePrice == 0.0) return; // No valid trend line found

// Check for pullback and rejection


bool isRejection;
if (isBullishTrendLine) { // Bullish Trend Line (support)
// Price should be near or touching the trend line from above, and form
bullish rejection
if (currentCandle.low <= trendLinePrice + InpATRMagnifier * atr &&
currentCandle.close > trendLinePrice - InpATRMagnifier * atr) {
if (IsRejectionCandle(Symbol(), Period(), 0, isRejection) &&
isRejection) { // Bullish rejection
// Check HTF alignment for bullish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, true)) {
// Print("Strategy 6 (Bullish): HTF not aligned for bullish
bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = currentCandle.low - InpATRMagnifier * atr;
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
true);

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice,


stopLoss, takeProfit, true) >= InpMinRiskRewardRatio) {
if (SendBuyOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[6])) {
g_lastTradeDay[6] = TimeCurrent();
Print("Strategy 6 (Bullish): Trend Line Pullback Trade
taken. SL: ", DoubleToString(stopLoss, _Digits), ", TP: ",
DoubleToString(takeProfit, _Digits));
}
} else {
Print("Strategy 6 (Bullish): Trend Line Pullback setup found,
but R:R or TP invalid. R:R = ", DoubleToString(CalculateRiskRewardRatio(entryPrice,
stopLoss, takeProfit, true), 2));
}
}
}
} else { // Bearish Trend Line (resistance)
// Price should be near or touching the trend line from below, and form
bearish rejection
if (currentCandle.high >= trendLinePrice - InpATRMagnifier * atr &&
currentCandle.close < trendLinePrice + InpATRMagnifier * atr) {
if (IsRejectionCandle(Symbol(), Period(), 0, isRejection) && !
isRejection) { // Bearish rejection
// Check HTF alignment for bearish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, false)) {
// Print("Strategy 6 (Bearish): HTF not aligned for bearish
bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = currentCandle.high + InpATRMagnifier * atr;
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
false);

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice,


stopLoss, takeProfit, false) >= InpMinRiskRewardRatio) {
if (SendSellOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[6])) {
g_lastTradeDay[6] = TimeCurrent();
Print("Strategy 6 (Bearish): Trend Line Pullback Trade
taken. SL: ", DoubleToString(stopLoss, _Digits), ", TP: ",
DoubleToString(takeProfit, _Digits));
}
} else {
Print("Strategy 6 (Bearish): Trend Line Pullback setup found,
but R:R or TP invalid. R:R = ", DoubleToString(CalculateRiskRewardRatio(entryPrice,
stopLoss, takeProfit, false), 2));
}
}
}
}
}

// Strategy 7: Fair Value Gap (FVG) Pullback


void CheckStrategy_FVGPullback() {
if (!InpEnableStrategy7 || TimeToDay(TimeCurrent()) ==
TimeToDay(g_lastTradeDay[7])) return;

MqlRates currentCandle;
if (!GetCandleData(Symbol(), Period(), 0, currentCandle)) return;

double atr = GetATR(Symbol(), Period(), InpATRPeriod, 1);


if (atr == 0.0) return;

double fvgHigh = 0.0;


double fvgLow = 0.0;
bool isBullishFVG = false;
int fvgOriginBar = -1; // Bar where the FVG was created

// Find the most recent unmitigated FVG within lookback bars


for (int i = 0; i < InpFVGMaxBarsFromOrigin; i++) { // Check recent bars for
FVG formation (i is shift for C3)
if (FindFVG(Symbol(), Period(), i, isBullishFVG, fvgHigh, fvgLow)) {
// Filter by FVG height (must be significant enough)
if (MathAbs(fvgHigh - fvgLow) < InpFVGMinATRHeight * atr) continue;

if (IsFVGUnmitigated(Symbol(), Period(), fvgHigh, fvgLow, i)) {


fvgOriginBar = i;
break; // Take the most recent unmitigated FVG
}
}
}

if (fvgOriginBar == -1) {
// Print("Strategy 7: No unmitigated FVG found within lookback bars.");
return;
}

bool isRejection;
if (isBullishFVG) { // Bullish FVG (price expected to retest FVG Low and
bounce)
if (IsPriceRetestingZone(currentCandle.close, fvgHigh, fvgLow,
InpATRMagnifier)) {
if (IsRejectionCandle(Symbol(), Period(), 0, isRejection) &&
isRejection) { // Bullish rejection at FVG
// Check HTF alignment for bullish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, true)) {
// Print("Strategy 7 (Bullish): HTF not aligned for bullish
bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = fvgLow - InpATRMagnifier * atr; // Below FVG low
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
true);

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice,


stopLoss, takeProfit, true) >= InpMinRiskRewardRatio) {
if (SendBuyOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[7])) {
g_lastTradeDay[7] = TimeCurrent();
Print("Strategy 7 (Bullish): FVG Pullback Trade taken. SL:
", DoubleToString(stopLoss, _Digits), ", TP: ", DoubleToString(takeProfit,
_Digits));
}
} else {
Print("Strategy 7 (Bullish): FVG Pullback setup found, but R:R
or TP invalid. R:R = ", DoubleToString(CalculateRiskRewardRatio(entryPrice,
stopLoss, takeProfit, true), 2));
}
}
}
} else { // Bearish FVG (price expected to retest FVG High and fall)
if (IsPriceRetestingZone(currentCandle.close, fvgHigh, fvgLow,
InpATRMagnifier)) {
if (IsRejectionCandle(Symbol(), Period(), 0, isRejection) && !
isRejection) { // Bearish rejection at FVG
// Check HTF alignment for bearish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, false)) {
// Print("Strategy 7 (Bearish): HTF not aligned for bearish
bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = fvgHigh + InpATRMagnifier * atr; // Above FVG
high
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
false);

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice,


stopLoss, takeProfit, false) >= InpMinRiskRewardRatio) {
if (SendSellOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[7])) {
g_lastTradeDay[7] = TimeCurrent();
Print("Strategy 7 (Bearish): FVG Pullback Trade taken. SL:
", DoubleToString(stopLoss, _Digits), ", TP: ", DoubleToString(takeProfit,
_Digits));
}
} else {
Print("Strategy 7 (Bearish): FVG Pullback setup found, but R:R
or TP invalid. R:R = ", DoubleToString(CalculateRiskRewardRatio(entryPrice,
stopLoss, takeProfit, false), 2));
}
}
}
}
}

// Strategy 8: Institutional Funding Candles (IFC) Pullback


void CheckStrategy_IFCPullback() {
if (!InpEnableStrategy8 || TimeToDay(TimeCurrent()) ==
TimeToDay(g_lastTradeDay[8])) return;
MqlRates currentCandle;
if (!GetCandleData(Symbol(), Period(), 0, currentCandle)) return;

double atr = GetATR(Symbol(), Period(), InpATRPeriod, 1);


if (atr == 0.0) return;

double ifcOpen = 0.0, ifcClose = 0.0, ifcHigh = 0.0, ifcLow = 0.0;


bool isBullishIFC = false;
int ifcBar = -1; // Shift of the IFC candle

for (int i = 1; i <= InpImpulsiveMoveMaxBars; i++) { // Look for an IFC within


max bars (i is shift of potential IFC)
MqlRates candle;
if (!GetCandleData(Symbol(), Period(), i, candle)) continue;

double bodySize = MathAbs(candle.open - candle.close);


double range = candle.high - candle.low;

if (range == 0) continue; // Avoid division by zero

// Check for large body and significant portion of range (strong momentum
candle)
if (bodySize > InpIFCMinATRBody * atr && bodySize / range > 0.75) {
MqlRates subsequentCandle; // The candle immediately after IFC (closer
to current)
if (!GetCandleData(Symbol(), Period(), i - 1, subsequentCandle))
continue;

if (candle.close > candle.open) { // Bullish IFC


// Check if subsequent candle moved significantly away
if (subsequentCandle.close > candle.high && (subsequentCandle.close
- candle.close) > InpIFCSubsequentMoveATR * atr) {
ifcOpen = candle.open;
ifcClose = candle.close;
ifcHigh = candle.high;
ifcLow = candle.low;
isBullishIFC = true;
ifcBar = i;
break;
}
} else { // Bearish IFC
// Check if subsequent candle moved significantly away
if (subsequentCandle.close < candle.low && (candle.close -
subsequentCandle.close) > InpIFCSubsequentMoveATR * atr) {
ifcOpen = candle.open;
ifcClose = candle.close;
ifcHigh = candle.high;
ifcLow = candle.low;
isBullishIFC = false;
ifcBar = i;
break;
}
}
}
}

if (ifcBar == -1) return; // No IFC found


// Now check for pullback to the IFC's range (e.g., 50% level or open/close)
// The entry zone for IFC is usually the open of the IFC candle.
double ifcEntryZoneHigh = isBullishIFC ? ifcClose : ifcOpen;
double ifcEntryZoneLow = isBullishIFC ? ifcOpen : ifcClose;

bool isRejection;
if (isBullishIFC) { // Bullish IFC pullback
if (IsPriceRetestingZone(currentCandle.close, ifcEntryZoneHigh,
ifcEntryZoneLow, InpATRMagnifier)) {
if (IsRejectionCandle(Symbol(), Period(), 0, isRejection) &&
isRejection) { // Bullish rejection
// Check HTF alignment for bullish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, true)) {
// Print("Strategy 8 (Bullish): HTF not aligned for bullish
bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = ifcLow - InpATRMagnifier * atr;
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
true);

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice,


stopLoss, takeProfit, true) >= InpMinRiskRewardRatio) {
if (SendBuyOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[8])) {
g_lastTradeDay[8] = TimeCurrent();
Print("Strategy 8 (Bullish): IFC Pullback Trade taken. SL:
", DoubleToString(stopLoss, _Digits), ", TP: ", DoubleToString(takeProfit,
_Digits));
}
} else {
Print("Strategy 8 (Bullish): IFC Pullback setup found, but R:R
or TP invalid. R:R = ", DoubleToString(CalculateRiskRewardRatio(entryPrice,
stopLoss, takeProfit, true), 2));
}
}
}
} else { // Bearish IFC pullback
if (IsPriceRetestingZone(currentCandle.close, ifcEntryZoneHigh,
ifcEntryZoneLow, InpATRMagnifier)) {
if (IsRejectionCandle(Symbol(), Period(), 0, isRejection) && !
isRejection) { // Bearish rejection
// Check HTF alignment for bearish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, false)) {
// Print("Strategy 8 (Bearish): HTF not aligned for bearish
bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = ifcHigh + InpATRMagnifier * atr;
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
false);

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice,


stopLoss, takeProfit, false) >= InpMinRiskRewardRatio) {
if (SendSellOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[8])) {
g_lastTradeDay[8] = TimeCurrent();
Print("Strategy 8 (Bearish): IFC Pullback Trade taken. SL:
", DoubleToString(stopLoss, _Digits), ", TP: ", DoubleToString(takeProfit,
_Digits));
}
} else {
Print("Strategy 8 (Bearish): IFC Pullback setup found, but R:R
or TP invalid. R:R = ", DoubleToString(CalculateRiskRewardRatio(entryPrice,
stopLoss, takeProfit, false), 2));
}
}
}
}
}

// Strategy 9: Order Blocks Pullback


void CheckStrategy_OrderBlockPullback() {
if (!InpEnableStrategy9 || TimeToDay(TimeCurrent()) ==
TimeToDay(g_lastTradeDay[9])) return;

MqlRates currentCandle;
if (!GetCandleData(Symbol(), Period(), 0, currentCandle)) return;

double atr = GetATR(Symbol(), Period(), InpATRPeriod, 1);


if (atr == 0.0) return;

double obHigh = 0.0;


double obLow = 0.0;
bool isBullishOB = false;
int obCreationBar = -1;

// Find the most recent unmitigated Order Block (look back up to 20 bars for
OB)
// Iterate from recent bars (small shift) to older bars (larger shift)
for (int i = 0; i <= 20; i++) { // Check for OBs starting from current bar
(i=0) to 20 bars back
if (FindOrderBlock(Symbol(), Period(), i, isBullishOB, obHigh, obLow)) {
// Corrected call to IsOrderBlockUnmitigated
if (IsOrderBlockUnmitigated(Symbol(), Period(), obHigh, obLow, i)) {
obCreationBar = i;
break; // Found the most recent unmitigated OB
}
}
}

if (obCreationBar == -1) {
// Print("Strategy 9: No unmitigated Order Block found.");
return;
}

bool isRejection;
if (isBullishOB) { // Bullish OB (price expected to retest OB and bounce up)
if (IsPriceRetestingZone(currentCandle.close, obHigh, obLow,
InpATRMagnifier)) {
if (IsRejectionCandle(Symbol(), Period(), 0, isRejection) &&
isRejection) { // Bullish rejection
// Check HTF alignment for bullish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, true)) {
// Print("Strategy 9 (Bullish): HTF not aligned for bullish
bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = obLow - InpATRMagnifier * atr; // Below OB low
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
true);

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice,


stopLoss, takeProfit, true) >= InpMinRiskRewardRatio) {
if (SendBuyOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[9])) {
g_lastTradeDay[9] = TimeCurrent();
Print("Strategy 9 (Bullish): Order Block Pullback Trade
taken. SL: ", DoubleToString(stopLoss, _Digits), ", TP: ",
DoubleToString(takeProfit, _Digits));
}
} else {
Print("Strategy 9 (Bullish): Order Block Pullback setup found,
but R:R or TP invalid. R:R = ", DoubleToString(CalculateRiskRewardRatio(entryPrice,
stopLoss, takeProfit, true), 2));
}
}
}
} else { // Bearish OB (price expected to retest OB and fall down)
if (IsPriceRetestingZone(currentCandle.close, obHigh, obLow,
InpATRMagnifier)) {
if (IsRejectionCandle(Symbol(), Period(), 0, isRejection) && !
isRejection) { // Bearish rejection
// Check HTF alignment for bearish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, false)) {
// Print("Strategy 9 (Bearish): HTF not aligned for bearish
bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = obHigh + InpATRMagnifier * atr; // Above OB high
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
false);

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice,


stopLoss, takeProfit, false) >= InpMinRiskRewardRatio) {
if (SendSellOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[9])) {
g_lastTradeDay[9] = TimeCurrent();
Print("Strategy 9 (Bearish): Order Block Pullback Trade
taken. SL: ", DoubleToString(stopLoss, _Digits), ", TP: ",
DoubleToString(takeProfit, _Digits));
}
} else {
Print("Strategy 9 (Bearish): Order Block Pullback setup found,
but R:R or TP invalid. R:R = ", DoubleToString(CalculateRiskRewardRatio(entryPrice,
stopLoss, takeProfit, false), 2));
}
}
}
}
}

// Strategy 10: Breaker Block Pullback


void CheckStrategy_BreakerBlockPullback() {
if (!InpEnableStrategy10 || TimeToDay(TimeCurrent()) ==
TimeToDay(g_lastTradeDay[10])) return;

MqlRates currentCandle;
if (!GetCandleData(Symbol(), Period(), 0, currentCandle)) return;

double atr = GetATR(Symbol(), Period(), InpATRPeriod, 1);


if (atr == 0.0) return;

double breakerHigh = 0.0;


double breakerLow = 0.0;
bool isBullishBreaker = false;
int breakerOriginBar = -1;

// Find the most recent Breaker Block (look back up to 50 bars for Breaker)
for (int i = 0; i <= 50; i++) { // Check recent bars for Breaker formation
if (FindBreakerBlock(Symbol(), Period(), i, isBullishBreaker, breakerHigh,
breakerLow)) {
// Filter breaker by min range
if (MathAbs(breakerHigh - breakerLow) < InpBreakerBlockMinATRRange *
atr) continue;
breakerOriginBar = i;
break; // Found most recent valid breaker
}
}

if (breakerOriginBar == -1) {
// Print("Strategy 10: No Breaker Block found.");
return;
}

bool isRejection;
if (isBullishBreaker) { // Bullish Breaker (price expected to retest and bounce
up)
if (IsPriceRetestingZone(currentCandle.close, breakerHigh, breakerLow,
InpATRMagnifier)) {
if (IsRejectionCandle(Symbol(), Period(), 0, isRejection) &&
isRejection) { // Bullish rejection
// Check HTF alignment for bullish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, true)) {
// Print("Strategy 10 (Bullish): HTF not aligned for bullish
bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = breakerLow - InpATRMagnifier * atr; // Below
Breaker low
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
true);

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice,


stopLoss, takeProfit, true) >= InpMinRiskRewardRatio) {
if (SendBuyOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[10])) {
g_lastTradeDay[10] = TimeCurrent();
Print("Strategy 10 (Bullish): Breaker Block Pullback Trade
taken. SL: ", DoubleToString(stopLoss, _Digits), ", TP: ",
DoubleToString(takeProfit, _Digits));
}
} else {
Print("Strategy 10 (Bullish): Breaker Block Pullback setup
found, but R:R or TP invalid. R:R = ",
DoubleToString(CalculateRiskRewardRatio(entryPrice, stopLoss, takeProfit, true),
2));
}
}
}
} else { // Bearish Breaker (price expected to retest and fall down)
if (IsPriceRetestingZone(currentCandle.close, breakerHigh, breakerLow,
InpATRMagnifier)) {
if (IsRejectionCandle(Symbol(), Period(), 0, isRejection) && !
isRejection) { // Bearish rejection
// Check HTF alignment for bearish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod, false)) {
// Print("Strategy 10 (Bearish): HTF not aligned for bearish
bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = breakerHigh + InpATRMagnifier * atr; // Above
Breaker high
double takeProfit = FindNextMajorSR(Symbol(), Period(), entryPrice,
false);

if (takeProfit != 0.0 && CalculateRiskRewardRatio(entryPrice,


stopLoss, takeProfit, false) >= InpMinRiskRewardRatio) {
if (SendSellOrder(Symbol(), InpLotSize, entryPrice, stopLoss,
takeProfit, Period(), g_strategyNames[10])) {
g_lastTradeDay[10] = TimeCurrent();
Print("Strategy 10 (Bearish): Breaker Block Pullback Trade
taken. SL: ", DoubleToString(stopLoss, _Digits), ", TP: ",
DoubleToString(takeProfit, _Digits));
}
} else {
Print("Strategy 10 (Bearish): Breaker Block Pullback setup
found, but R:R or TP invalid. R:R = ",
DoubleToString(CalculateRiskRewardRatio(entryPrice, stopLoss, takeProfit, false),
2));
}
}
}
}
}

// Strategy 11: RSI Divergence with Confluence


void CheckStrategy_RSIDivergence() {
if (!InpEnableStrategy11 || TimeToDay(TimeCurrent()) ==
TimeToDay(g_lastTradeDay[11])) return;

MqlRates currentCandle;
if (!GetCandleData(Symbol(), Period(), 0, currentCandle)) return;
double atr = GetATR(Symbol(), Period(), InpATRPeriod, 1);
if (atr == 0.0) return;

double rsiCurrent = GetRSI(Symbol(), Period(), InpRSIPeriod, PRICE_CLOSE, 0);


if (rsiCurrent == 0.0) return;

// Bearish Divergence (Price Higher High, RSI Lower High)


int currentHighBar = iHighest(Symbol(), Period(), MODE_HIGH,
InpRSIDivergenceLookbackBars, 0); // Recent highest high
double currentHighPrice = iHigh(Symbol(), Period(), currentHighBar);

int prevHighBar = -1;


double prevHighPrice = 0.0;
double prevRSI = 0.0;

// Find a previous swing high that is lower than currentHighPrice but has a
higher RSI
for (int i = currentHighBar + 1; i < InpRSIDivergenceLookbackBars; i++) {
if (IsSwingHigh(Symbol(), Period(), i, InpSwingPointBars)) {
MqlRates tempCandle;
if (GetCandleData(Symbol(), Period(), i, tempCandle)) {
prevHighPrice = tempCandle.high;
prevRSI = GetRSI(Symbol(), Period(), InpRSIPeriod, PRICE_CLOSE, i);
prevHighBar = i;
// Check Price: newer high > older high AND RSI: newer RSI < older
RSI
if (currentHighPrice > prevHighPrice && rsiCurrent < prevRSI -
InpRSIPointsDeviation) {
// Found Bearish Divergence
bool isRejection;
if (IsRejectionCandle(Symbol(), Period(), 0, isRejection) && !
isRejection) { // Bearish rejection
// Check HTF alignment for bearish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod,
false)) {
// Print("Strategy 11 (Bearish): HTF not aligned for
bearish bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = currentCandle.high + InpATRMagnifier *
atr;
double takeProfit = FindNextMajorSR(Symbol(), Period(),
entryPrice, false);

if (takeProfit != 0.0 &&


CalculateRiskRewardRatio(entryPrice, stopLoss, takeProfit, false) >=
InpMinRiskRewardRatio) {
if (SendSellOrder(Symbol(), InpLotSize, entryPrice,
stopLoss, takeProfit, Period(), g_strategyNames[11])) {
g_lastTradeDay[11] = TimeCurrent();
Print("Strategy 11 (Bearish): RSI Divergence Trade
taken. SL: ", DoubleToString(stopLoss, _Digits), ", TP: ",
DoubleToString(takeProfit, _Digits));
}
} else {
Print("Strategy 11 (Bearish): RSI Divergence setup
found, but R:R or TP invalid. R:R = ",
DoubleToString(CalculateRiskRewardRatio(entryPrice, stopLoss, takeProfit, false),
2));
}
}
return; // Only look for one divergence
}
}
}
}

// Bullish Divergence (Price Lower Low, RSI Higher Low)


int currentLowBar = iLowest(Symbol(), Period(), MODE_LOW,
InpRSIDivergenceLookbackBars, 0); // Recent lowest low
double currentLowPrice = iLow(Symbol(), Period(), currentLowBar);

int prevLowBar_bullish = -1; // Declared for this specific block


double prevLowPrice_bullish = 0.0; // Declared for this specific block
double prevRSI_bullish = 0.0; // Declared for this specific block

// Find a previous swing low that is higher than currentLowPrice but has a
lower RSI
for (int i = currentLowBar + 1; i < InpRSIDivergenceLookbackBars; i++) {
if (IsSwingLow(Symbol(), Period(), i, InpSwingPointBars)) {
MqlRates tempCandle;
if (GetCandleData(Symbol(), Period(), i, tempCandle)) {
prevLowPrice_bullish = tempCandle.low;
prevRSI_bullish = GetRSI(Symbol(), Period(), InpRSIPeriod,
PRICE_CLOSE, i);
prevLowBar_bullish = i;
// Check Price: newer low < older low AND RSI: newer RSI > older
RSI
if (currentLowPrice < prevLowPrice_bullish && rsiCurrent >
prevRSI_bullish + InpRSIPointsDeviation) {
// Found Bullish Divergence
bool isRejection;
if (IsRejectionCandle(Symbol(), Period(), 0, isRejection) &&
isRejection) { // Bullish rejection
// Check HTF alignment for bullish bias
if (!CheckHTFAlignment(Symbol(), Period(), InpHTFPeriod,
true)) {
// Print("Strategy 11 (Bullish): HTF not aligned for
bullish bias.");
return;
}

double entryPrice = currentCandle.close;


double stopLoss = currentCandle.low - InpATRMagnifier *
atr;
double takeProfit = FindNextMajorSR(Symbol(), Period(),
entryPrice, true);

if (takeProfit != 0.0 &&


CalculateRiskRewardRatio(entryPrice, stopLoss, takeProfit, true) >=
InpMinRiskRewardRatio) {
if (SendBuyOrder(Symbol(), InpLotSize, entryPrice,
stopLoss, takeProfit, Period(), g_strategyNames[11])) {
g_lastTradeDay[11] = TimeCurrent();
Print("Strategy 11 (Bullish): RSI Divergence Trade
taken. SL: ", DoubleToString(stopLoss, _Digits), ", TP: ",
DoubleToString(takeProfit, _Digits));
}
} else {
Print("Strategy 11 (Bullish): RSI Divergence setup
found, but R:R or TP invalid. R:R = ",
DoubleToString(CalculateRiskRewardRatio(entryPrice, stopLoss, takeProfit, true),
2));
}
}
return; // Only look for one divergence
}
}
}
}
}

You might also like