1836 lines
No EOL
127 KiB
MQL5
1836 lines
No EOL
127 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| QuarterTheory_MFIB_Enhanced.mq5 |
|
|
//| MFIB 0.32 + EMA14 Magnet + Stoch Confirmations + Labels |
|
|
//| Aggressive Multi-Setup System with Smart Filtering |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "MFIB Enhanced System"
|
|
#property version "16.00"
|
|
#property strict
|
|
|
|
#include <Trade/Trade.mqh>
|
|
CTrade Trade;
|
|
|
|
//================ INPUT PARAMETERS ==================//
|
|
input group "=== GENERAL ==="
|
|
input int MagicNumber = 456789;
|
|
input double Risk_Per_Trade = 1.2;
|
|
input int Min_Active_Entries = 4; // Changed to 4 minimum
|
|
input int Max_Simultaneous_Trades = 20;
|
|
|
|
input group "=== SYMBOL-SPECIFIC RATIOS (AUTO-DETECT) ==="
|
|
input bool Use_Auto_Symbol_Config = true; // Auto-configure based on symbol
|
|
// Manual overrides (used if Auto_Symbol_Config = false)
|
|
input int Manual_SL_Points = 800;
|
|
input int Manual_TP_Points = 5000;
|
|
input double Manual_RR_Ratio = 6.25;
|
|
|
|
input group "=== MOVING FIBS (PRIMARY!) ==="
|
|
input int MFIB_Lookback = 200;
|
|
input bool Show_MFIB_Levels = true;
|
|
input int MFIB_Touch_Buffer = 30; // Buffer in points for level detection
|
|
input bool Require_MFIB_Interaction = true; // No MFIB = no trade
|
|
|
|
input group "=== MA MAGNET SYSTEM ==="
|
|
input int MA_1 = 7; // Trigger
|
|
input int MA_2 = 14; // MAGNET (Core)
|
|
input int MA_3 = 21; // Structure
|
|
input int MA_4 = 50; // Structure
|
|
input int MA_5 = 140; // Flow
|
|
input int MA_6 = 230; // Mean
|
|
input int MA_7 = 500; // Macro
|
|
input int MA_8 = 1000;
|
|
input int MA_9 = 1100;
|
|
input int MA_10 = 1400; // Gravity
|
|
input int MA_Touch_Buffer = 30;
|
|
input int Min_MA14_Crosses = 1; // Using MA14 as primary now
|
|
|
|
input group "=== STOCHASTIC CONFIRMATION ==="
|
|
input int Stoch_K_Period = 5;
|
|
input int Stoch_D_Period = 3;
|
|
input int Stoch_Slowing = 3;
|
|
input bool Use_Stoch_Confirmation = true;
|
|
|
|
input group "=== TRADE SETUP FILTERS ==="
|
|
input bool Allow_Structural_Bounce = true; // Setup 1
|
|
input bool Allow_Structural_Break = true; // Setup 2
|
|
input bool Allow_Magnet_Snapback = true; // Setup 3
|
|
input bool Allow_MFIB_Continuation = true; // Setup 4
|
|
input bool Allow_Failed_Break = true; // Setup 5
|
|
input bool Allow_Triple_Confluence = true; // Setup 6
|
|
input bool Filter_Dead_Zones = true; // Block chop zones
|
|
|
|
input group "=== RISK MANAGEMENT (800pts → 5000pts) ==="
|
|
input double Risk_Reward_Ratio = 6.25; // 800 pts risk → 5000 pts profit
|
|
input bool Use_Fib_Based_SLTP = true; // SL/TP to nearest Fib
|
|
input int Default_SL_Points = 800; // Default SL distance
|
|
input int Default_TP_Points = 5000; // Default TP distance
|
|
input int Move_BE_At_Points = 300; // Move to BE
|
|
input int Trailing_SL_Points = 500; // Trailing distance
|
|
input double Partial_TP_Percent = 25.0; // Close 25% per hit
|
|
|
|
input group "=== DAILY LIMITS ==="
|
|
input double Max_Daily_Loss_Percent = 5.0;
|
|
input double Max_Daily_Profit_Percent = 30.0;
|
|
input int Max_Trades_Per_Day = 40;
|
|
|
|
//================ GLOBALS ==================//
|
|
int Stoch_Handle;
|
|
double Stoch_K_Current = 0;
|
|
double Stoch_K_Previous = 0;
|
|
double Stoch_K_Old = 0;
|
|
|
|
// Symbol-specific settings (auto-configured)
|
|
int Symbol_SL_Points = 800;
|
|
int Symbol_TP_Points = 5000;
|
|
double Symbol_RR_Ratio = 6.25;
|
|
string Symbol_Type = "UNKNOWN";
|
|
|
|
// MFIB System
|
|
double MFIB_ATH = 0;
|
|
double MFIB_ATL = 0;
|
|
double MFIB_032 = 0; // Key structural level
|
|
double MFIB_0236 = 0;
|
|
double MFIB_05 = 0;
|
|
double MFIB_0618 = 0;
|
|
double MFIB_0786 = 0;
|
|
bool MFIB_Bull_Mode = false;
|
|
bool MFIB_Bear_Mode = false;
|
|
datetime Last_MFIB_Calc = 0;
|
|
|
|
int MA_Handles[10];
|
|
double MA_Current[10];
|
|
double MA_Previous[10];
|
|
double MA_Old[10];
|
|
|
|
bool Current_Trend_Bullish = false;
|
|
bool Current_Trend_Bearish = false;
|
|
bool Previous_Trend_Bullish = false;
|
|
bool Previous_Trend_Bearish = false;
|
|
datetime Last_Trend_Check = 0;
|
|
|
|
// MA Retest tracking
|
|
datetime Last_MA_Retest_Time = 0;
|
|
int Retest_Cooldown = 60; // Seconds between retest entries
|
|
|
|
// RE-ENTRY TRACKING (After SL hit or BE stopped out)
|
|
struct ReEntryOpportunity
|
|
{
|
|
ulong original_ticket;
|
|
bool was_buy;
|
|
double exit_price;
|
|
double original_entry;
|
|
datetime exit_time;
|
|
string exit_reason;
|
|
bool re_entered;
|
|
int re_entry_attempts;
|
|
};
|
|
ReEntryOpportunity ReEntryQueue[];
|
|
|
|
input group "=== RE-ENTRY SYSTEM ==="
|
|
input bool Enable_ReEntry = true; // Re-enter after SL/BE if setup still valid
|
|
input int ReEntry_Max_Attempts = 2; // Max re-entries per original trade
|
|
input int ReEntry_Cooldown = 30; // Seconds before re-entry allowed
|
|
input bool ReEntry_After_SL = true; // Re-enter after stop loss hit
|
|
input bool ReEntry_After_BE = true; // Re-enter after BE stop hit
|
|
input bool Require_Stronger_Signal = true; // Need stronger confirmation for re-entry
|
|
|
|
struct Position
|
|
{
|
|
ulong ticket;
|
|
double entry;
|
|
double sl_level;
|
|
double tp_level;
|
|
double original_lot;
|
|
bool is_buy;
|
|
bool be_set;
|
|
int partials_closed;
|
|
string setup_type;
|
|
};
|
|
Position OpenPositions[];
|
|
|
|
double DailyStart = 0;
|
|
int TodayTrades = 0;
|
|
datetime LastDay = 0;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| AUTO-CONFIGURE SYMBOL-SPECIFIC PARAMETERS
|
|
//+------------------------------------------------------------------+
|
|
void ConfigureSymbolSettings()
|
|
{
|
|
string symbol = _Symbol;
|
|
|
|
if(!Use_Auto_Symbol_Config)
|
|
{
|
|
Symbol_SL_Points = Manual_SL_Points;
|
|
Symbol_TP_Points = Manual_TP_Points;
|
|
Symbol_RR_Ratio = Manual_RR_Ratio;
|
|
Symbol_Type = "MANUAL";
|
|
Print("Using MANUAL configuration: SL=", Symbol_SL_Points, " TP=", Symbol_TP_Points);
|
|
return;
|
|
}
|
|
|
|
// GOLD (XAUUSD) - Avg daily range: 2000-3000 pips
|
|
if(StringFind(symbol, "XAU") >= 0 || StringFind(symbol, "GOLD") >= 0)
|
|
{
|
|
Symbol_Type = "GOLD";
|
|
Symbol_SL_Points = 500; // $5 risk
|
|
Symbol_TP_Points = 3500; // $35 target (1:7 RR)
|
|
Symbol_RR_Ratio = 7.0;
|
|
Print("GOLD detected: SL=500pts ($5) TP=3500pts ($35) RR=1:7");
|
|
}
|
|
// US30 (Dow Jones) - Avg daily range: 400-800 points
|
|
else if(StringFind(symbol, "US30") >= 0 || StringFind(symbol, "DOW") >= 0)
|
|
{
|
|
Symbol_Type = "US30";
|
|
Symbol_SL_Points = 150; // 150 pts risk
|
|
Symbol_TP_Points = 1000; // 1000 pts target (1:6.67 RR)
|
|
Symbol_RR_Ratio = 6.67;
|
|
Print("US30 detected: SL=150pts TP=1000pts RR=1:6.67");
|
|
}
|
|
// NAS100 (Nasdaq) - Avg daily range: 500-1000 points
|
|
else if(StringFind(symbol, "NAS") >= 0 || StringFind(symbol, "NDX") >= 0)
|
|
{
|
|
Symbol_Type = "NAS100";
|
|
Symbol_SL_Points = 200; // 200 pts risk
|
|
Symbol_TP_Points = 1400; // 1400 pts target (1:7 RR)
|
|
Symbol_RR_Ratio = 7.0;
|
|
Print("NAS100 detected: SL=200pts TP=1400pts RR=1:7");
|
|
}
|
|
// OIL (USOIL/UKOIL) - Avg daily range: 150-300 pips
|
|
else if(StringFind(symbol, "OIL") >= 0 || StringFind(symbol, "WTI") >= 0 || StringFind(symbol, "BRENT") >= 0)
|
|
{
|
|
Symbol_Type = "OIL";
|
|
Symbol_SL_Points = 80; // 80 pips risk
|
|
Symbol_TP_Points = 600; // 600 pips target (1:7.5 RR)
|
|
Symbol_RR_Ratio = 7.5;
|
|
Print("OIL detected: SL=80pts TP=600pts RR=1:7.5");
|
|
}
|
|
// MAJOR FOREX (EUR, GBP, AUD, NZD vs USD) - Avg daily range: 80-150 pips
|
|
else if(StringFind(symbol, "EUR") >= 0 || StringFind(symbol, "GBP") >= 0 ||
|
|
StringFind(symbol, "AUD") >= 0 || StringFind(symbol, "NZD") >= 0)
|
|
{
|
|
Symbol_Type = "FOREX_MAJOR";
|
|
Symbol_SL_Points = 50; // 50 pips risk
|
|
Symbol_TP_Points = 350; // 350 pips target (1:7 RR)
|
|
Symbol_RR_Ratio = 7.0;
|
|
Print("FOREX MAJOR detected: SL=50pts TP=350pts RR=1:7");
|
|
}
|
|
// COMMODITY FOREX (USD/CAD, NZD/CAD, etc.) - Avg daily range: 60-120 pips
|
|
else if(StringFind(symbol, "CAD") >= 0 || StringFind(symbol, "CHF") >= 0)
|
|
{
|
|
Symbol_Type = "FOREX_COMMODITY";
|
|
Symbol_SL_Points = 40; // 40 pips risk
|
|
Symbol_TP_Points = 300; // 300 pips target (1:7.5 RR)
|
|
Symbol_RR_Ratio = 7.5;
|
|
Print("FOREX COMMODITY detected: SL=40pts TP=300pts RR=1:7.5");
|
|
}
|
|
// YEN PAIRS (USD/JPY, EUR/JPY, etc.) - Avg daily range: 80-150 pips
|
|
else if(StringFind(symbol, "JPY") >= 0)
|
|
{
|
|
Symbol_Type = "FOREX_YEN";
|
|
Symbol_SL_Points = 60; // 60 pips risk
|
|
Symbol_TP_Points = 450; // 450 pips target (1:7.5 RR)
|
|
Symbol_RR_Ratio = 7.5;
|
|
Print("YEN PAIR detected: SL=60pts TP=450pts RR=1:7.5");
|
|
}
|
|
// CRYPTO (BTC, ETH, etc.) - Avg daily range: 1000-3000 points
|
|
else if(StringFind(symbol, "BTC") >= 0 || StringFind(symbol, "ETH") >= 0)
|
|
{
|
|
Symbol_Type = "CRYPTO";
|
|
Symbol_SL_Points = 800; // 800 pts risk
|
|
Symbol_TP_Points = 6000; // 6000 pts target (1:7.5 RR)
|
|
Symbol_RR_Ratio = 7.5;
|
|
Print("CRYPTO detected: SL=800pts TP=6000pts RR=1:7.5");
|
|
}
|
|
// DEFAULT (Unknown symbol) - Conservative
|
|
else
|
|
{
|
|
Symbol_Type = "DEFAULT";
|
|
Symbol_SL_Points = 800;
|
|
Symbol_TP_Points = 5000;
|
|
Symbol_RR_Ratio = 6.25;
|
|
Print("DEFAULT configuration: SL=800pts TP=5000pts RR=1:6.25");
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
Print("========================================");
|
|
Print("MFIB ENHANCED SYSTEM v16.0");
|
|
Print("AGGRESSIVE + SMART RETESTS");
|
|
Print("========================================");
|
|
|
|
// Configure symbol-specific settings
|
|
ConfigureSymbolSettings();
|
|
|
|
Trade.SetExpertMagicNumber(MagicNumber);
|
|
Trade.SetDeviationInPoints(50);
|
|
|
|
Stoch_Handle = iStochastic(_Symbol, PERIOD_CURRENT, Stoch_K_Period, Stoch_D_Period,
|
|
Stoch_Slowing, MODE_SMA, STO_LOWHIGH);
|
|
if(Stoch_Handle == INVALID_HANDLE)
|
|
{
|
|
Print("ERROR: Stochastic failed");
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
int periods[10] = {MA_1, MA_2, MA_3, MA_4, MA_5, MA_6, MA_7, MA_8, MA_9, MA_10};
|
|
for(int i=0; i<10; i++)
|
|
{
|
|
MA_Handles[i] = iMA(_Symbol, PERIOD_CURRENT, periods[i], 0, MODE_EMA, PRICE_CLOSE);
|
|
if(MA_Handles[i] == INVALID_HANDLE)
|
|
{
|
|
Print("ERROR: MA ", periods[i], " failed");
|
|
return INIT_FAILED;
|
|
}
|
|
}
|
|
|
|
CalculateMFIB();
|
|
if(Show_MFIB_Levels) DrawMFIBLevels();
|
|
|
|
DailyStart = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
|
|
Print("Symbol Type: ", Symbol_Type);
|
|
Print("Risk:Reward = 1:", Symbol_RR_Ratio);
|
|
Print("SL: ", Symbol_SL_Points, " pts | TP: ", Symbol_TP_Points, " pts");
|
|
Print("MFIB 0.32 Level: ", MFIB_032);
|
|
Print("EMA14 Magnet + MA Retest: ENABLED");
|
|
Print("Min Active Entries: ", Min_Active_Entries);
|
|
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
for(int i=0; i<10; i++)
|
|
if(MA_Handles[i] != INVALID_HANDLE)
|
|
IndicatorRelease(MA_Handles[i]);
|
|
if(Stoch_Handle != INVALID_HANDLE)
|
|
IndicatorRelease(Stoch_Handle);
|
|
ObjectsDeleteAll(0, "MFIB_");
|
|
ObjectsDeleteAll(0, "Arrow_");
|
|
ObjectsDeleteAll(0, "Label_");
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| CALCULATE MOVING FIBS (MFIB)
|
|
//+------------------------------------------------------------------+
|
|
void CalculateMFIB()
|
|
{
|
|
// Find ATH and ATL over lookback period
|
|
MFIB_ATH = iHigh(_Symbol, PERIOD_CURRENT, 0);
|
|
MFIB_ATL = iLow(_Symbol, PERIOD_CURRENT, 0);
|
|
|
|
for(int i=1; i<=MFIB_Lookback; i++)
|
|
{
|
|
double h = iHigh(_Symbol, PERIOD_CURRENT, i);
|
|
double l = iLow(_Symbol, PERIOD_CURRENT, i);
|
|
if(h > MFIB_ATH) MFIB_ATH = h;
|
|
if(l < MFIB_ATL) MFIB_ATL = l;
|
|
}
|
|
|
|
double range = MFIB_ATH - MFIB_ATL;
|
|
|
|
// Calculate key Fib levels (Bull Fib: ATL → ATH)
|
|
MFIB_0236 = MFIB_ATL + range * 0.236;
|
|
MFIB_032 = MFIB_ATL + range * 0.382; // KEY STRUCTURAL LEVEL
|
|
MFIB_05 = MFIB_ATL + range * 0.5;
|
|
MFIB_0618 = MFIB_ATL + range * 0.618;
|
|
MFIB_0786 = MFIB_ATL + range * 0.786;
|
|
|
|
// Determine MFIB Mode
|
|
double current = (SymbolInfoDouble(_Symbol, SYMBOL_BID) + SymbolInfoDouble(_Symbol, SYMBOL_ASK)) / 2;
|
|
|
|
if(current > MFIB_032)
|
|
MFIB_Bull_Mode = true;
|
|
else
|
|
MFIB_Bull_Mode = false;
|
|
|
|
if(current < MFIB_032)
|
|
MFIB_Bear_Mode = true;
|
|
else
|
|
MFIB_Bear_Mode = false;
|
|
}
|
|
|
|
void DrawMFIBLevels()
|
|
{
|
|
ObjectsDeleteAll(0, "MFIB_");
|
|
|
|
// Draw key MFIB levels
|
|
CreateHLine("MFIB_ATH", MFIB_ATH, clrWhite, STYLE_SOLID, 2, "ATH");
|
|
CreateHLine("MFIB_ATL", MFIB_ATL, clrWhite, STYLE_SOLID, 2, "ATL");
|
|
CreateHLine("MFIB_0786", MFIB_0786, clrDodgerBlue, STYLE_DOT, 1, "0.786");
|
|
CreateHLine("MFIB_0618", MFIB_0618, clrDodgerBlue, STYLE_DOT, 1, "0.618");
|
|
CreateHLine("MFIB_05", MFIB_05, clrYellow, STYLE_DOT, 1, "0.5");
|
|
CreateHLine("MFIB_032", MFIB_032, clrRed, STYLE_SOLID, 3, "0.32 KEY"); // Most important
|
|
CreateHLine("MFIB_0236", MFIB_0236, clrDodgerBlue, STYLE_DOT, 1, "0.236");
|
|
}
|
|
|
|
void CreateHLine(string name, double price, color clr, ENUM_LINE_STYLE style, int width, string label)
|
|
{
|
|
ObjectCreate(0, name, OBJ_HLINE, 0, 0, price);
|
|
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
|
|
ObjectSetInteger(0, name, OBJPROP_STYLE, style);
|
|
ObjectSetInteger(0, name, OBJPROP_WIDTH, width);
|
|
ObjectSetInteger(0, name, OBJPROP_BACK, true);
|
|
ObjectSetString(0, name, OBJPROP_TEXT, label);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void UpdateMAs()
|
|
{
|
|
for(int i=0; i<10; i++)
|
|
{
|
|
MA_Old[i] = MA_Previous[i];
|
|
MA_Previous[i] = MA_Current[i];
|
|
|
|
double curr[1];
|
|
if(CopyBuffer(MA_Handles[i], 0, 0, 1, curr) > 0)
|
|
MA_Current[i] = curr[0];
|
|
}
|
|
}
|
|
|
|
void UpdateStochastic()
|
|
{
|
|
Stoch_K_Old = Stoch_K_Previous;
|
|
Stoch_K_Previous = Stoch_K_Current;
|
|
|
|
double k_curr[1];
|
|
if(CopyBuffer(Stoch_Handle, MAIN_LINE, 0, 1, k_curr) > 0)
|
|
Stoch_K_Current = k_curr[0];
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| MFIB DETECTION FUNCTIONS
|
|
//+------------------------------------------------------------------+
|
|
bool IsPriceAtMFIB032(double price)
|
|
{
|
|
double buffer = MFIB_Touch_Buffer * _Point;
|
|
return (MathAbs(price - MFIB_032) <= buffer);
|
|
}
|
|
|
|
string GetMFIBLabel(double price, bool is_bullish)
|
|
{
|
|
if(!IsPriceAtMFIB032(price)) return "";
|
|
|
|
if(is_bullish)
|
|
{
|
|
if(price > MFIB_032)
|
|
return "MFIB 0.32 SUPPORT";
|
|
else if(price <= MFIB_032 && MA_Current[1] > MFIB_032) // EMA14 above
|
|
return "MFIB 0.32 RECLAIM";
|
|
}
|
|
else
|
|
{
|
|
if(price < MFIB_032)
|
|
return "MFIB 0.32 RESIST";
|
|
else if(price >= MFIB_032 && MA_Current[1] < MFIB_032) // EMA14 below
|
|
return "MFIB 0.32 REJECT";
|
|
}
|
|
|
|
return "MFIB 0.32 TEST";
|
|
}
|
|
|
|
bool IsMFIBStaircase(bool check_bullish)
|
|
{
|
|
// Check if price is making higher lows (bull) or lower highs (bear) at MFIB levels
|
|
double close_curr = iClose(_Symbol, PERIOD_CURRENT, 0);
|
|
double close_prev = iClose(_Symbol, PERIOD_CURRENT, 1);
|
|
double close_old = iClose(_Symbol, PERIOD_CURRENT, 2);
|
|
|
|
if(check_bullish)
|
|
return (close_curr > close_prev && close_prev > close_old && MFIB_Bull_Mode);
|
|
else
|
|
return (close_curr < close_prev && close_prev < close_old && MFIB_Bear_Mode);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| EMA14 MAGNET DETECTION
|
|
//+------------------------------------------------------------------+
|
|
bool IsPriceAtEMA14(double price)
|
|
{
|
|
double buffer = MA_Touch_Buffer * _Point;
|
|
return (MathAbs(price - MA_Current[1]) <= buffer); // MA_Current[1] = EMA14
|
|
}
|
|
|
|
string GetEMA14Label(double price, bool is_bullish)
|
|
{
|
|
if(!IsPriceAtEMA14(price)) return "";
|
|
|
|
double ema14 = MA_Current[1];
|
|
double ema14_prev = MA_Previous[1];
|
|
|
|
if(is_bullish)
|
|
{
|
|
if(price > ema14 && ema14 > ema14_prev)
|
|
return "EMA14 MAGNET HOLD";
|
|
else if(price >= ema14 && MA_Previous[1] < ema14)
|
|
return "EMA14 MAGNET RECLAIM";
|
|
else if(MathAbs(price - ema14) < 50 * _Point)
|
|
return "EMA14 COILED SPRING";
|
|
}
|
|
else
|
|
{
|
|
if(price < ema14 && ema14 < ema14_prev)
|
|
return "EMA14 MAGNET REJECT";
|
|
else if(price > ema14 * 1.01) // Extended far from EMA14
|
|
return "EMA14 SNAPBACK";
|
|
}
|
|
|
|
return "EMA14 TEST";
|
|
}
|
|
|
|
bool IsMicroBullAlign()
|
|
{
|
|
// 7 > 14 > 21
|
|
return (MA_Current[0] > MA_Current[1] && MA_Current[1] > MA_Current[2]);
|
|
}
|
|
|
|
bool IsMicroBearAlign()
|
|
{
|
|
// 7 < 14 < 21
|
|
return (MA_Current[0] < MA_Current[1] && MA_Current[1] < MA_Current[2]);
|
|
}
|
|
|
|
int CountMA14Crosses(bool check_bullish)
|
|
{
|
|
int crosses = 0;
|
|
// Count how many MAs the EMA14 has crossed
|
|
for(int i=2; i<6; i++) // Check against 21, 50, 140, 230
|
|
{
|
|
if(check_bullish && MA_Current[1] > MA_Current[i])
|
|
crosses++;
|
|
else if(!check_bullish && MA_Current[1] < MA_Current[i])
|
|
crosses++;
|
|
}
|
|
return crosses;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| STOCHASTIC LABELS
|
|
//+------------------------------------------------------------------+
|
|
string GetStochLabel(bool is_bullish)
|
|
{
|
|
if(is_bullish)
|
|
{
|
|
if(Stoch_K_Current >= 20 && Stoch_K_Current <= 30)
|
|
return "STOCH OS HOLD";
|
|
else if(Stoch_K_Current >= 40 && Stoch_K_Current <= 50 && Stoch_K_Current > Stoch_K_Previous)
|
|
return "STOCH BULL RESET";
|
|
else if(Stoch_K_Current >= 50 && Stoch_K_Current > Stoch_K_Previous)
|
|
return "STOCH 50 HOLD";
|
|
else if(Stoch_K_Current < 70)
|
|
return "STOCH STRUCTURAL CONFIRM";
|
|
}
|
|
else
|
|
{
|
|
if(Stoch_K_Current >= 80 && Stoch_K_Current <= 100)
|
|
return "STOCH OB REJECT";
|
|
else if(Stoch_K_Current >= 50 && Stoch_K_Current <= 60 && Stoch_K_Current < Stoch_K_Previous)
|
|
return "STOCH BEAR RESET";
|
|
else if(Stoch_K_Current <= 50 && Stoch_K_Current < Stoch_K_Previous)
|
|
return "STOCH 50 FAIL";
|
|
else if(Stoch_K_Current > 30)
|
|
return "STOCH STRUCTURAL FAIL";
|
|
}
|
|
|
|
return "STOCH NEUTRAL";
|
|
}
|
|
|
|
bool IsStochOversold()
|
|
{
|
|
return (Stoch_K_Current >= 20 && Stoch_K_Current <= 30);
|
|
}
|
|
|
|
bool IsStochOverbought()
|
|
{
|
|
return (Stoch_K_Current >= 80);
|
|
}
|
|
|
|
bool IsStochReset(bool check_bullish)
|
|
{
|
|
if(check_bullish)
|
|
return (Stoch_K_Old >= 80 && Stoch_K_Current >= 40 && Stoch_K_Current <= 50);
|
|
else
|
|
return (Stoch_K_Old <= 20 && Stoch_K_Current >= 50 && Stoch_K_Current <= 60);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| MA RETEST / PULLBACK DETECTION (Catches circled opportunities!)
|
|
//+------------------------------------------------------------------+
|
|
bool DetectMARetest(bool check_bullish, int &ma_index, string &retest_label)
|
|
{
|
|
// Check if we're in cooldown period
|
|
if(TimeCurrent() - Last_MA_Retest_Time < Retest_Cooldown)
|
|
return false;
|
|
|
|
double close_curr = iClose(_Symbol, PERIOD_CURRENT, 0);
|
|
double close_prev = iClose(_Symbol, PERIOD_CURRENT, 1);
|
|
double close_old = iClose(_Symbol, PERIOD_CURRENT, 2);
|
|
|
|
double high_curr = iHigh(_Symbol, PERIOD_CURRENT, 0);
|
|
double low_curr = iLow(_Symbol, PERIOD_CURRENT, 0);
|
|
|
|
// Check key MAs: 14, 21, 50, 140, 230
|
|
int test_mas[] = {1, 2, 3, 4, 5}; // MA indices to test
|
|
string ma_names[] = {"EMA14", "EMA21", "EMA50", "EMA140", "EMA230"};
|
|
|
|
for(int i=0; i<ArraySize(test_mas); i++)
|
|
{
|
|
int idx = test_mas[i];
|
|
double ma_value = MA_Current[idx];
|
|
double ma_prev = MA_Previous[idx];
|
|
|
|
double touch_buffer = MA_Touch_Buffer * _Point;
|
|
|
|
if(check_bullish)
|
|
{
|
|
// BULLISH RETEST:
|
|
// 1. Price was above MA
|
|
// 2. Price pulled back to touch/slightly below MA
|
|
// 3. Price is now bouncing back up
|
|
|
|
bool was_above = (close_old > ma_value + 50 * _Point);
|
|
bool touched_ma = (low_curr <= ma_value + touch_buffer && low_curr >= ma_value - touch_buffer);
|
|
bool bouncing = (close_curr > close_prev) || (close_curr > ma_value);
|
|
|
|
// Alternative: Price crossed below then reclaimed
|
|
bool crossed_below = (close_prev < ma_value && close_old > ma_value);
|
|
bool reclaimed = (close_curr > ma_value);
|
|
|
|
// Check if MA is sloping up (bullish)
|
|
bool ma_bullish = (ma_value > ma_prev);
|
|
|
|
if(ma_bullish && ((was_above && touched_ma && bouncing) || (crossed_below && reclaimed)))
|
|
{
|
|
ma_index = idx;
|
|
retest_label = ma_names[i] + " RETEST LONG";
|
|
Last_MA_Retest_Time = TimeCurrent();
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// BEARISH RETEST:
|
|
// 1. Price was below MA
|
|
// 2. Price pulled back to touch/slightly above MA
|
|
// 3. Price is now rejecting back down
|
|
|
|
bool was_below = (close_old < ma_value - 50 * _Point);
|
|
bool touched_ma = (high_curr >= ma_value - touch_buffer && high_curr <= ma_value + touch_buffer);
|
|
bool rejecting = (close_curr < close_prev) || (close_curr < ma_value);
|
|
|
|
// Alternative: Price crossed above then rejected
|
|
bool crossed_above = (close_prev > ma_value && close_old < ma_value);
|
|
bool rejected = (close_curr < ma_value);
|
|
|
|
// Check if MA is sloping down (bearish)
|
|
bool ma_bearish = (ma_value < ma_prev);
|
|
|
|
if(ma_bearish && ((was_below && touched_ma && rejecting) || (crossed_above && rejected)))
|
|
{
|
|
ma_index = idx;
|
|
retest_label = ma_names[i] + " RETEST SHORT";
|
|
Last_MA_Retest_Time = TimeCurrent();
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Detect MA rejection (price hits MA and bounces hard)
|
|
bool DetectMAReject(bool check_bullish, string &reject_label)
|
|
{
|
|
double close_curr = iClose(_Symbol, PERIOD_CURRENT, 0);
|
|
double close_prev = iClose(_Symbol, PERIOD_CURRENT, 1);
|
|
double high_prev = iHigh(_Symbol, PERIOD_CURRENT, 1);
|
|
double low_prev = iLow(_Symbol, PERIOD_CURRENT, 1);
|
|
|
|
// Check rejection at EMA14, 21, 50
|
|
int test_mas[] = {1, 2, 3};
|
|
string ma_names[] = {"EMA14", "EMA21", "EMA50"};
|
|
|
|
for(int i=0; i<ArraySize(test_mas); i++)
|
|
{
|
|
int idx = test_mas[i];
|
|
double ma_value = MA_Current[idx];
|
|
|
|
if(check_bullish)
|
|
{
|
|
// Bullish rejection: Price dipped to MA and shot back up
|
|
double wick = high_prev - MathMax(iOpen(_Symbol, PERIOD_CURRENT, 1), close_prev);
|
|
double body = MathAbs(close_prev - iOpen(_Symbol, PERIOD_CURRENT, 1));
|
|
|
|
bool hit_ma = (low_prev <= ma_value + MA_Touch_Buffer * _Point);
|
|
bool strong_wick = (wick > body * 2);
|
|
bool bullish_close = (close_curr > ma_value);
|
|
|
|
if(hit_ma && strong_wick && bullish_close)
|
|
{
|
|
reject_label = ma_names[i] + " REJECT → LONG";
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Bearish rejection: Price spiked to MA and shot back down
|
|
double wick = MathMin(iOpen(_Symbol, PERIOD_CURRENT, 1), close_prev) - low_prev;
|
|
double body = MathAbs(close_prev - iOpen(_Symbol, PERIOD_CURRENT, 1));
|
|
|
|
bool hit_ma = (high_prev >= ma_value - MA_Touch_Buffer * _Point);
|
|
bool strong_wick = (wick > body * 2);
|
|
bool bearish_close = (close_curr < ma_value);
|
|
|
|
if(hit_ma && strong_wick && bearish_close)
|
|
{
|
|
reject_label = ma_names[i] + " REJECT → SHORT";
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| DEAD ZONE DETECTION (with exceptions for strong confirmations)
|
|
//+------------------------------------------------------------------+
|
|
bool IsDeadZone()
|
|
{
|
|
if(!Filter_Dead_Zones) return false;
|
|
|
|
int dead_zone_score = 0; // Count how many dead zone conditions exist
|
|
|
|
// 1. MFIB whipsaw + MA chop
|
|
bool mfib_whipsaw = (IsPriceAtMFIB032(iClose(_Symbol, PERIOD_CURRENT, 0)) &&
|
|
IsPriceAtMFIB032(iClose(_Symbol, PERIOD_CURRENT, 1)));
|
|
|
|
// 2. EMA14 flat
|
|
double ema14_change = MathAbs(MA_Current[1] - MA_Previous[1]) / _Point;
|
|
bool ema14_flat = (ema14_change < 20);
|
|
|
|
// 3. Stoch in dead zone (40-60)
|
|
bool stoch_chop = (Stoch_K_Current >= 40 && Stoch_K_Current <= 60);
|
|
|
|
// 4. MFIB mode against EMA500
|
|
bool mode_conflict = false;
|
|
if(MFIB_Bull_Mode && MA_Current[1] < MA_Current[6]) // EMA14 below EMA500
|
|
mode_conflict = true;
|
|
if(MFIB_Bear_Mode && MA_Current[1] > MA_Current[6]) // EMA14 above EMA500
|
|
mode_conflict = true;
|
|
|
|
// Count dead zone conditions
|
|
if(mfib_whipsaw && ema14_flat) dead_zone_score += 2; // This combo is worst
|
|
if(ema14_flat && stoch_chop) dead_zone_score += 1;
|
|
if(mode_conflict) dead_zone_score += 2; // Mode conflict is serious
|
|
if(stoch_chop && !mfib_whipsaw) dead_zone_score += 1; // Stoch chop alone is minor
|
|
|
|
// CHECK FOR STRONG CONFIRMATIONS THAT OVERRIDE DEAD ZONES
|
|
bool has_strong_confirmations = false;
|
|
|
|
// Strong confirmation 1: Triple confluence (MFIB + EMA14 + Stoch extreme)
|
|
double current = (SymbolInfoDouble(_Symbol, SYMBOL_BID) + SymbolInfoDouble(_Symbol, SYMBOL_ASK)) / 2;
|
|
bool triple_confluence = IsPriceAtMFIB032(current) && IsPriceAtEMA14(current) &&
|
|
(Stoch_K_Current <= 25 || Stoch_K_Current >= 75);
|
|
|
|
// Strong confirmation 2: Fresh structural break with momentum
|
|
double close_curr = iClose(_Symbol, PERIOD_CURRENT, 0);
|
|
double close_prev = iClose(_Symbol, PERIOD_CURRENT, 1);
|
|
bool fresh_break = (MathAbs(close_curr - MFIB_032) < 50 * _Point) &&
|
|
(MathAbs(close_prev - MFIB_032) > 100 * _Point);
|
|
bool has_momentum = (Stoch_K_Current > Stoch_K_Previous + 5) ||
|
|
(Stoch_K_Current < Stoch_K_Previous - 5);
|
|
bool structural_break_momentum = fresh_break && has_momentum;
|
|
|
|
// Strong confirmation 3: Strong micro alignment (7-14-21 perfect stack)
|
|
bool perfect_bull_stack = (MA_Current[0] > MA_Current[1] + 30 * _Point) &&
|
|
(MA_Current[1] > MA_Current[2] + 30 * _Point);
|
|
bool perfect_bear_stack = (MA_Current[0] < MA_Current[1] - 30 * _Point) &&
|
|
(MA_Current[1] < MA_Current[2] - 30 * _Point);
|
|
bool perfect_micro_align = perfect_bull_stack || perfect_bear_stack;
|
|
|
|
// Strong confirmation 4: MFIB mode + Multiple MA alignment
|
|
bool strong_mode = (MFIB_Bull_Mode || MFIB_Bear_Mode);
|
|
int ma_alignment = 0;
|
|
for(int i=0; i<4; i++)
|
|
{
|
|
if(MFIB_Bull_Mode && MA_Current[i] > MA_Current[i+1])
|
|
ma_alignment++;
|
|
else if(MFIB_Bear_Mode && MA_Current[i] < MA_Current[i+1])
|
|
ma_alignment++;
|
|
}
|
|
bool strong_ma_alignment = (ma_alignment >= 3);
|
|
|
|
// Strong confirmation 5: Failed break (high probability reversal)
|
|
double close_old = iClose(_Symbol, PERIOD_CURRENT, 2);
|
|
bool failed_break_bull = (close_old > MFIB_032 && close_prev < MFIB_032 && close_curr > MFIB_032);
|
|
bool failed_break_bear = (close_old < MFIB_032 && close_prev > MFIB_032 && close_curr < MFIB_032);
|
|
bool failed_break = failed_break_bull || failed_break_bear;
|
|
|
|
// Count strong confirmations
|
|
if(triple_confluence) has_strong_confirmations = true;
|
|
if(structural_break_momentum) has_strong_confirmations = true;
|
|
if(perfect_micro_align && strong_mode) has_strong_confirmations = true;
|
|
if(strong_mode && strong_ma_alignment && !mode_conflict) has_strong_confirmations = true;
|
|
if(failed_break) has_strong_confirmations = true;
|
|
|
|
// DECISION LOGIC:
|
|
// - Score 0-1: Minor chop → Allow trade if ANY confirmation
|
|
// - Score 2-3: Moderate chop → Allow trade if STRONG confirmations
|
|
// - Score 4+: Severe chop → Block all trades
|
|
|
|
if(dead_zone_score >= 4)
|
|
{
|
|
UpdateStatusLabel("DEAD ZONE — SEVERE CHOP", clrRed);
|
|
return true; // Block all trades
|
|
}
|
|
|
|
if(dead_zone_score >= 2 && !has_strong_confirmations)
|
|
{
|
|
UpdateStatusLabel("DEAD ZONE — Waiting for Strong Signal", clrOrange);
|
|
return true; // Block weak trades
|
|
}
|
|
|
|
if(dead_zone_score == 1 && has_strong_confirmations)
|
|
{
|
|
UpdateStatusLabel("Minor Chop but Strong Confirmation", clrYellow);
|
|
return false; // Allow trade
|
|
}
|
|
|
|
// If we have strong confirmations, override minor dead zones
|
|
if(has_strong_confirmations && dead_zone_score <= 2)
|
|
{
|
|
UpdateStatusLabel("Dead Zone Override - Strong Setup", clrLime);
|
|
return false; // Allow trade
|
|
}
|
|
|
|
// Light dead zone with no confirmations
|
|
if(dead_zone_score > 0)
|
|
{
|
|
UpdateStatusLabel("DEAD ZONE — LOW CONFIDENCE", clrOrange);
|
|
return true;
|
|
}
|
|
|
|
return false; // Clear conditions
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| TRADE SETUPS
|
|
//+------------------------------------------------------------------+
|
|
bool CheckSetup1_StructuralBounce(bool is_buy, string &setup_label)
|
|
{
|
|
if(!Allow_Structural_Bounce) return false;
|
|
|
|
double current = (SymbolInfoDouble(_Symbol, SYMBOL_BID) + SymbolInfoDouble(_Symbol, SYMBOL_ASK)) / 2;
|
|
|
|
bool at_mfib = IsPriceAtMFIB032(current);
|
|
bool at_ema14 = IsPriceAtEMA14(current);
|
|
bool stoch_ok = IsStochOversold() || IsStochReset(is_buy);
|
|
|
|
if(at_mfib && (at_ema14 || IsPriceAtHigherMA(current)) && stoch_ok)
|
|
{
|
|
setup_label = "STRUCTURAL BOUNCE";
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CheckSetup2_StructuralBreak(bool is_buy, string &setup_label)
|
|
{
|
|
if(!Allow_Structural_Break) return false;
|
|
|
|
double close_curr = iClose(_Symbol, PERIOD_CURRENT, 0);
|
|
double close_prev = iClose(_Symbol, PERIOD_CURRENT, 1);
|
|
|
|
bool broke_mfib = false;
|
|
bool broke_ema14 = false;
|
|
bool held = false;
|
|
|
|
if(is_buy)
|
|
{
|
|
broke_mfib = (close_prev < MFIB_032 && close_curr > MFIB_032);
|
|
broke_ema14 = (close_prev < MA_Current[1] && close_curr > MA_Current[1]);
|
|
held = (close_curr > MFIB_032);
|
|
}
|
|
else
|
|
{
|
|
broke_mfib = (close_prev > MFIB_032 && close_curr < MFIB_032);
|
|
broke_ema14 = (close_prev > MA_Current[1] && close_curr < MA_Current[1]);
|
|
held = (close_curr < MFIB_032);
|
|
}
|
|
|
|
bool stoch_ok = is_buy ? (Stoch_K_Current > 50) : (Stoch_K_Current < 50);
|
|
|
|
if((broke_mfib || broke_ema14) && held && stoch_ok)
|
|
{
|
|
setup_label = "STRUCTURAL BREAK & HOLD";
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CheckSetup3_MagnetSnapback(bool is_buy, string &setup_label)
|
|
{
|
|
if(!Allow_Magnet_Snapback) return false;
|
|
|
|
double current = (SymbolInfoDouble(_Symbol, SYMBOL_BID) + SymbolInfoDouble(_Symbol, SYMBOL_ASK)) / 2;
|
|
double ema14 = MA_Current[1];
|
|
|
|
bool extended = is_buy ? (current < ema14 * 0.99) : (current > ema14 * 1.01);
|
|
bool stoch_extreme = is_buy ? IsStochOversold() : IsStochOverbought();
|
|
bool returning = IsPriceAtEMA14(current) && IsPriceAtMFIB032(current);
|
|
|
|
if(extended && stoch_extreme && returning)
|
|
{
|
|
setup_label = "MAGNET SNAPBACK ENTRY";
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CheckSetup4_MFIBContinuation(bool is_buy, string &setup_label)
|
|
{
|
|
if(!Allow_MFIB_Continuation) return false;
|
|
|
|
bool mode_ok = is_buy ? MFIB_Bull_Mode : MFIB_Bear_Mode;
|
|
bool ema14_respected = IsPriceAtEMA14(iClose(_Symbol, PERIOD_CURRENT, 0));
|
|
bool micro_align = is_buy ? IsMicroBullAlign() : IsMicroBearAlign();
|
|
bool stoch_reset = IsStochReset(is_buy);
|
|
|
|
if(mode_ok && ema14_respected && micro_align && stoch_reset)
|
|
{
|
|
setup_label = "MFIB MODE CONTINUATION";
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CheckSetup5_FailedBreak(bool is_buy, string &setup_label)
|
|
{
|
|
if(!Allow_Failed_Break) return false;
|
|
|
|
double close_curr = iClose(_Symbol, PERIOD_CURRENT, 0);
|
|
double close_prev = iClose(_Symbol, PERIOD_CURRENT, 1);
|
|
double close_old = iClose(_Symbol, PERIOD_CURRENT, 2);
|
|
|
|
bool attempted_break = false;
|
|
bool failed = false;
|
|
bool stoch_crossed = false;
|
|
|
|
if(is_buy)
|
|
{
|
|
// Failed bearish break
|
|
attempted_break = (close_old > MFIB_032 && close_prev < MFIB_032);
|
|
failed = (close_curr > MFIB_032);
|
|
stoch_crossed = (Stoch_K_Previous < 50 && Stoch_K_Current > 50);
|
|
}
|
|
else
|
|
{
|
|
// Failed bullish break
|
|
attempted_break = (close_old < MFIB_032 && close_prev > MFIB_032);
|
|
failed = (close_curr < MFIB_032);
|
|
stoch_crossed = (Stoch_K_Previous > 50 && Stoch_K_Current < 50);
|
|
}
|
|
|
|
if(attempted_break && failed && stoch_crossed)
|
|
{
|
|
setup_label = "FAILED STRUCTURE BREAK";
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CheckSetup6_TripleConfluence(bool is_buy, string &setup_label)
|
|
{
|
|
if(!Allow_Triple_Confluence) return false;
|
|
|
|
double current = (SymbolInfoDouble(_Symbol, SYMBOL_BID) + SymbolInfoDouble(_Symbol, SYMBOL_ASK)) / 2;
|
|
|
|
bool at_mfib = IsPriceAtMFIB032(current);
|
|
bool at_ema14 = IsPriceAtEMA14(current);
|
|
bool stoch_extreme = is_buy ? (Stoch_K_Current <= 20) : (Stoch_K_Current >= 80);
|
|
|
|
// Check for rejection candle
|
|
double body_size = MathAbs(iClose(_Symbol, PERIOD_CURRENT, 1) - iOpen(_Symbol, PERIOD_CURRENT, 1));
|
|
double wick_size = is_buy ?
|
|
(iHigh(_Symbol, PERIOD_CURRENT, 1) - MathMax(iOpen(_Symbol, PERIOD_CURRENT, 1), iClose(_Symbol, PERIOD_CURRENT, 1))) :
|
|
(MathMin(iOpen(_Symbol, PERIOD_CURRENT, 1), iClose(_Symbol, PERIOD_CURRENT, 1)) - iLow(_Symbol, PERIOD_CURRENT, 1));
|
|
|
|
bool rejection_candle = (wick_size > body_size * 1.5);
|
|
|
|
if(at_mfib && at_ema14 && stoch_extreme && rejection_candle)
|
|
{
|
|
setup_label = "TRIPLE LEVEL REJECT";
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
bool IsPriceAtHigherMA(double price)
|
|
{
|
|
double buffer = MA_Touch_Buffer * _Point;
|
|
|
|
// Check MA50, MA140, MA230, MA500
|
|
int higher_mas[4] = {3, 4, 5, 6};
|
|
|
|
for(int i=0; i<4; i++)
|
|
{
|
|
int idx = higher_mas[i];
|
|
if(MathAbs(price - MA_Current[idx]) <= buffer)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void UpdateStatusLabel(string status, color clr)
|
|
{
|
|
ObjectDelete(0, "Label_Status");
|
|
ObjectCreate(0, "Label_Status", OBJ_LABEL, 0, 0, 0);
|
|
ObjectSetInteger(0, "Label_Status", OBJPROP_CORNER, CORNER_LEFT_UPPER);
|
|
ObjectSetInteger(0, "Label_Status", OBJPROP_XDISTANCE, 10);
|
|
ObjectSetInteger(0, "Label_Status", OBJPROP_YDISTANCE, 60);
|
|
ObjectSetString(0, "Label_Status", OBJPROP_TEXT, status);
|
|
ObjectSetInteger(0, "Label_Status", OBJPROP_COLOR, clr);
|
|
ObjectSetInteger(0, "Label_Status", OBJPROP_FONTSIZE, 11);
|
|
}
|
|
|
|
void UpdateMFIBModeLabel()
|
|
{
|
|
ObjectDelete(0, "Label_MFIB_Mode");
|
|
ObjectCreate(0, "Label_MFIB_Mode", OBJ_LABEL, 0, 0, 0);
|
|
ObjectSetInteger(0, "Label_MFIB_Mode", OBJPROP_CORNER, CORNER_LEFT_UPPER);
|
|
ObjectSetInteger(0, "Label_MFIB_Mode", OBJPROP_XDISTANCE, 10);
|
|
ObjectSetInteger(0, "Label_MFIB_Mode", OBJPROP_YDISTANCE, 30);
|
|
|
|
if(MFIB_Bull_Mode)
|
|
{
|
|
ObjectSetString(0, "Label_MFIB_Mode", OBJPROP_TEXT, "MFIB: BULL MODE ↑");
|
|
ObjectSetInteger(0, "Label_MFIB_Mode", OBJPROP_COLOR, clrLime);
|
|
}
|
|
else if(MFIB_Bear_Mode)
|
|
{
|
|
ObjectSetString(0, "Label_MFIB_Mode", OBJPROP_TEXT, "MFIB: BEAR MODE ↓");
|
|
ObjectSetInteger(0, "Label_MFIB_Mode", OBJPROP_COLOR, clrRed);
|
|
}
|
|
else
|
|
{
|
|
ObjectSetString(0, "Label_MFIB_Mode", OBJPROP_TEXT, "MFIB: TRANSITION");
|
|
ObjectSetInteger(0, "Label_MFIB_Mode", OBJPROP_COLOR, clrYellow);
|
|
}
|
|
|
|
ObjectSetInteger(0, "Label_MFIB_Mode", OBJPROP_FONTSIZE, 12);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void DetermineTrendBias()
|
|
{
|
|
UpdateMAs();
|
|
|
|
Previous_Trend_Bullish = Current_Trend_Bullish;
|
|
Previous_Trend_Bearish = Current_Trend_Bearish;
|
|
|
|
int bullish_alignment = 0;
|
|
int bearish_alignment = 0;
|
|
|
|
for(int i=0; i<6; i++)
|
|
{
|
|
if(i < 5 && MA_Current[i] > MA_Current[i+1])
|
|
bullish_alignment++;
|
|
if(i < 5 && MA_Current[i] < MA_Current[i+1])
|
|
bearish_alignment++;
|
|
}
|
|
|
|
bool ma14_above_ma50 = MA_Current[1] > MA_Current[3];
|
|
bool ma14_below_ma50 = MA_Current[1] < MA_Current[3];
|
|
|
|
if(bullish_alignment >= 3 && ma14_above_ma50)
|
|
{
|
|
Current_Trend_Bullish = true;
|
|
Current_Trend_Bearish = false;
|
|
}
|
|
else if(bearish_alignment >= 3 && ma14_below_ma50)
|
|
{
|
|
Current_Trend_Bullish = false;
|
|
Current_Trend_Bearish = true;
|
|
}
|
|
}
|
|
|
|
bool TrendReversed()
|
|
{
|
|
if(Previous_Trend_Bullish && Current_Trend_Bearish)
|
|
{
|
|
Print("===== TREND REVERSAL: BULL → BEAR =====");
|
|
return true;
|
|
}
|
|
if(Previous_Trend_Bearish && Current_Trend_Bullish)
|
|
{
|
|
Print("===== TREND REVERSAL: BEAR → BULL =====");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void CloseOppositeTrades(bool close_buys)
|
|
{
|
|
int closed = 0;
|
|
|
|
for(int i=PositionsTotal()-1; i>=0; i--)
|
|
{
|
|
ulong ticket = PositionGetTicket(i);
|
|
if(ticket == 0) continue;
|
|
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
|
|
if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
|
|
|
|
ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
|
|
|
if((close_buys && type == POSITION_TYPE_BUY) ||
|
|
(!close_buys && type == POSITION_TYPE_SELL))
|
|
{
|
|
Trade.PositionClose(ticket);
|
|
closed++;
|
|
}
|
|
}
|
|
|
|
if(closed > 0)
|
|
Print("Closed ", closed, " opposite trades on reversal");
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
double FindNearestFibLevel(double price, bool find_below)
|
|
{
|
|
double levels[] = {MFIB_ATL, MFIB_0236, MFIB_032, MFIB_05, MFIB_0618, MFIB_0786, MFIB_ATH};
|
|
double nearest = 0;
|
|
double min_distance = 999999;
|
|
|
|
for(int i=0; i<ArraySize(levels); i++)
|
|
{
|
|
double level = levels[i];
|
|
double distance = MathAbs(price - level);
|
|
|
|
if(find_below && level < price && distance < min_distance)
|
|
{
|
|
nearest = level;
|
|
min_distance = distance;
|
|
}
|
|
else if(!find_below && level > price && distance < min_distance)
|
|
{
|
|
nearest = level;
|
|
min_distance = distance;
|
|
}
|
|
}
|
|
|
|
return nearest;
|
|
}
|
|
|
|
void CalculateDynamicSLTP(double entry, bool is_buy, double &sl, double &tp)
|
|
{
|
|
if(Use_Fib_Based_SLTP)
|
|
{
|
|
sl = FindNearestFibLevel(entry, is_buy);
|
|
|
|
// If no Fib level found or too close, use symbol-specific SL
|
|
if(sl == 0 || MathAbs(entry - sl) / _Point < 100)
|
|
sl = is_buy ? entry - Symbol_SL_Points * _Point : entry + Symbol_SL_Points * _Point;
|
|
|
|
double sl_distance = MathAbs(entry - sl);
|
|
tp = is_buy ? entry + (sl_distance * Symbol_RR_Ratio)
|
|
: entry - (sl_distance * Symbol_RR_Ratio);
|
|
|
|
// Adjust TP to nearest Fib if close
|
|
double nearest_tp_fib = FindNearestFibLevel(entry, !is_buy);
|
|
if(nearest_tp_fib != 0)
|
|
{
|
|
double calculated_tp_dist = MathAbs(tp - entry);
|
|
double fib_tp_dist = MathAbs(nearest_tp_fib - entry);
|
|
|
|
// Only snap to Fib if within 15% and Fib level is further than minimum
|
|
if(MathAbs(calculated_tp_dist - fib_tp_dist) / calculated_tp_dist < 0.15 &&
|
|
fib_tp_dist >= Symbol_TP_Points * _Point * 0.8)
|
|
tp = nearest_tp_fib;
|
|
}
|
|
|
|
// Ensure minimum TP based on symbol
|
|
double min_tp_distance = Symbol_TP_Points * _Point;
|
|
if(MathAbs(tp - entry) < min_tp_distance)
|
|
tp = is_buy ? entry + min_tp_distance : entry - min_tp_distance;
|
|
}
|
|
else
|
|
{
|
|
// Fallback: use symbol-specific values
|
|
sl = is_buy ? entry - Symbol_SL_Points * _Point : entry + Symbol_SL_Points * _Point;
|
|
tp = is_buy ? entry + Symbol_TP_Points * _Point : entry - Symbol_TP_Points * _Point;
|
|
}
|
|
}
|
|
|
|
double GetLotSize(int sl_points)
|
|
{
|
|
double risk = AccountInfoDouble(ACCOUNT_BALANCE) * Risk_Per_Trade / 100.0;
|
|
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
|
|
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
|
|
|
|
double lot = risk / ((sl_points * _Point / tickSize) * tickValue);
|
|
|
|
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
|
|
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
|
|
double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
|
|
|
|
lot = MathMax(lot, minLot);
|
|
lot = MathMin(lot, maxLot);
|
|
lot = NormalizeDouble(lot / step, 0) * step;
|
|
|
|
return lot;
|
|
}
|
|
|
|
bool CheckLimits()
|
|
{
|
|
MqlDateTime dt;
|
|
TimeCurrent(dt);
|
|
dt.hour = 0; dt.min = 0; dt.sec = 0;
|
|
datetime today = StructToTime(dt);
|
|
|
|
if(today != LastDay)
|
|
{
|
|
DailyStart = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
TodayTrades = 0;
|
|
LastDay = today;
|
|
}
|
|
|
|
if(TodayTrades >= Max_Trades_Per_Day) return false;
|
|
|
|
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
double pl = ((balance - DailyStart) / DailyStart) * 100.0;
|
|
|
|
if(pl <= -Max_Daily_Loss_Percent || pl >= Max_Daily_Profit_Percent)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void OpenTrade(bool buy, double price, string setup_type, string details)
|
|
{
|
|
double sl, tp;
|
|
CalculateDynamicSLTP(price, buy, sl, tp);
|
|
|
|
int sl_points = (int)(MathAbs(price - sl) / _Point);
|
|
double lot = GetLotSize(sl_points);
|
|
|
|
if(lot < SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN)) return;
|
|
|
|
string comment = setup_type + " | " + details;
|
|
|
|
bool result = buy ? Trade.Buy(lot, _Symbol, price, sl, tp, comment)
|
|
: Trade.Sell(lot, _Symbol, price, sl, tp, comment);
|
|
|
|
if(result)
|
|
{
|
|
TodayTrades++;
|
|
ulong ticket = Trade.ResultOrder();
|
|
|
|
int size = ArraySize(OpenPositions);
|
|
ArrayResize(OpenPositions, size+1);
|
|
OpenPositions[size].ticket = ticket;
|
|
OpenPositions[size].entry = price;
|
|
OpenPositions[size].sl_level = sl;
|
|
OpenPositions[size].tp_level = tp;
|
|
OpenPositions[size].original_lot = lot;
|
|
OpenPositions[size].is_buy = buy;
|
|
OpenPositions[size].be_set = false;
|
|
OpenPositions[size].partials_closed = 0;
|
|
OpenPositions[size].setup_type = setup_type;
|
|
|
|
Print("========== ", setup_type, " ", TodayTrades, " ==========");
|
|
Print(buy ? "BUY" : "SELL", " @ ", price);
|
|
Print("Details: ", details);
|
|
Print("===================================");
|
|
|
|
string arrow_name = "Arrow_" + IntegerToString(ticket);
|
|
ObjectCreate(0, arrow_name, OBJ_ARROW, 0, TimeCurrent(), price);
|
|
ObjectSetInteger(0, arrow_name, OBJPROP_COLOR, buy ? clrLime : clrRed);
|
|
ObjectSetInteger(0, arrow_name, OBJPROP_ARROWCODE, buy ? 233 : 234);
|
|
ObjectSetInteger(0, arrow_name, OBJPROP_WIDTH, 3);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| ADD RE-ENTRY OPPORTUNITY TO QUEUE
|
|
//+------------------------------------------------------------------+
|
|
void AddReEntryOpportunity(ulong ticket, bool was_buy, double exit_price, double entry_price, string reason)
|
|
{
|
|
if(!Enable_ReEntry) return;
|
|
|
|
// Check if this trade already in queue
|
|
for(int i=0; i<ArraySize(ReEntryQueue); i++)
|
|
{
|
|
if(ReEntryQueue[i].original_ticket == ticket)
|
|
return; // Already queued
|
|
}
|
|
|
|
int size = ArraySize(ReEntryQueue);
|
|
ArrayResize(ReEntryQueue, size + 1);
|
|
|
|
ReEntryQueue[size].original_ticket = ticket;
|
|
ReEntryQueue[size].was_buy = was_buy;
|
|
ReEntryQueue[size].exit_price = exit_price;
|
|
ReEntryQueue[size].original_entry = entry_price;
|
|
ReEntryQueue[size].exit_time = TimeCurrent();
|
|
ReEntryQueue[size].exit_reason = reason;
|
|
ReEntryQueue[size].re_entered = false;
|
|
ReEntryQueue[size].re_entry_attempts = 0;
|
|
|
|
Print("📌 RE-ENTRY QUEUED: ", ticket, " | ", (was_buy ? "BUY" : "SELL"), " | Reason: ", reason);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| CHECK FOR STRONG CONFIRMATION (Re-entry validation)
|
|
//+------------------------------------------------------------------+
|
|
bool HasStrongConfirmation(bool check_bullish)
|
|
{
|
|
double current = (SymbolInfoDouble(_Symbol, SYMBOL_BID) + SymbolInfoDouble(_Symbol, SYMBOL_ASK)) / 2;
|
|
int confirmations = 0;
|
|
|
|
// 1. MFIB Confirmation
|
|
if(check_bullish && MFIB_Bull_Mode && current > MFIB_032)
|
|
confirmations++;
|
|
else if(!check_bullish && MFIB_Bear_Mode && current < MFIB_032)
|
|
confirmations++;
|
|
|
|
// 2. Strong MA Alignment (7-14-21 perfect stack)
|
|
if(check_bullish && MA_Current[0] > MA_Current[1] + 20 * _Point &&
|
|
MA_Current[1] > MA_Current[2] + 20 * _Point)
|
|
confirmations++;
|
|
else if(!check_bullish && MA_Current[0] < MA_Current[1] - 20 * _Point &&
|
|
MA_Current[1] < MA_Current[2] - 20 * _Point)
|
|
confirmations++;
|
|
|
|
// 3. Stoch Confirmation
|
|
if(check_bullish && Stoch_K_Current < 70 && Stoch_K_Current > Stoch_K_Previous)
|
|
confirmations++;
|
|
else if(!check_bullish && Stoch_K_Current > 30 && Stoch_K_Current < Stoch_K_Previous)
|
|
confirmations++;
|
|
|
|
// 4. Price at Key MA (retest setup)
|
|
if(IsPriceAtEMA14(current) || IsPriceAtMFIB032(current))
|
|
confirmations++;
|
|
|
|
// 5. Momentum (strong move in direction)
|
|
double close_curr = iClose(_Symbol, PERIOD_CURRENT, 0);
|
|
double close_prev = iClose(_Symbol, PERIOD_CURRENT, 1);
|
|
double move = MathAbs(close_curr - close_prev) / _Point;
|
|
|
|
if(check_bullish && close_curr > close_prev && move > 50)
|
|
confirmations++;
|
|
else if(!check_bullish && close_curr < close_prev && move > 50)
|
|
confirmations++;
|
|
|
|
// Need at least 3 confirmations for re-entry
|
|
return (confirmations >= 3);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| PROCESS RE-ENTRY OPPORTUNITIES
|
|
//+------------------------------------------------------------------+
|
|
void ProcessReEntries()
|
|
{
|
|
if(!Enable_ReEntry) return;
|
|
if(ArraySize(ReEntryQueue) == 0) return;
|
|
|
|
for(int i=ArraySize(ReEntryQueue)-1; i>=0; i--)
|
|
{
|
|
// Skip if already re-entered
|
|
if(ReEntryQueue[i].re_entered) continue;
|
|
|
|
// Skip if max attempts reached
|
|
if(ReEntryQueue[i].re_entry_attempts >= ReEntry_Max_Attempts)
|
|
{
|
|
// Remove from queue
|
|
ArrayRemove(ReEntryQueue, i, 1);
|
|
continue;
|
|
}
|
|
|
|
// Check cooldown
|
|
if(TimeCurrent() - ReEntryQueue[i].exit_time < ReEntry_Cooldown)
|
|
continue;
|
|
|
|
// Check if it was SL or BE exit
|
|
bool was_sl_exit = (StringFind(ReEntryQueue[i].exit_reason, "SL") >= 0);
|
|
bool was_be_exit = (StringFind(ReEntryQueue[i].exit_reason, "BE") >= 0);
|
|
|
|
if(was_sl_exit && !ReEntry_After_SL) continue;
|
|
if(was_be_exit && !ReEntry_After_BE) continue;
|
|
|
|
bool is_buy = ReEntryQueue[i].was_buy;
|
|
|
|
// Check if setup is still valid
|
|
bool setup_valid = false;
|
|
string validation = "";
|
|
|
|
if(Require_Stronger_Signal)
|
|
{
|
|
// Need STRONG confirmation for re-entry
|
|
if(HasStrongConfirmation(is_buy))
|
|
{
|
|
setup_valid = true;
|
|
validation = "STRONG CONFIRMATION";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Just need trend alignment
|
|
if(is_buy && (Current_Trend_Bullish || MFIB_Bull_Mode))
|
|
{
|
|
setup_valid = true;
|
|
validation = "TREND ALIGNED";
|
|
}
|
|
else if(!is_buy && (Current_Trend_Bearish || MFIB_Bear_Mode))
|
|
{
|
|
setup_valid = true;
|
|
validation = "TREND ALIGNED";
|
|
}
|
|
}
|
|
|
|
// Additional validation: Check if price has moved favorably since exit
|
|
double current = (SymbolInfoDouble(_Symbol, SYMBOL_BID) + SymbolInfoDouble(_Symbol, SYMBOL_ASK)) / 2;
|
|
double exit_price = ReEntryQueue[i].exit_price;
|
|
|
|
bool price_favorable = false;
|
|
if(is_buy && current > exit_price - 100 * _Point) // Not too far below exit
|
|
price_favorable = true;
|
|
else if(!is_buy && current < exit_price + 100 * _Point) // Not too far above exit
|
|
price_favorable = true;
|
|
|
|
if(setup_valid && price_favorable)
|
|
{
|
|
// Execute re-entry
|
|
double entry_price = is_buy ? SymbolInfoDouble(_Symbol, SYMBOL_ASK)
|
|
: SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
|
|
string reason = "RE-ENTRY " + IntegerToString(ReEntryQueue[i].re_entry_attempts + 1) +
|
|
" | " + validation + " | Original: " +
|
|
IntegerToString(ReEntryQueue[i].original_ticket);
|
|
|
|
OpenTrade(is_buy, entry_price, "RE-ENTRY", reason);
|
|
|
|
ReEntryQueue[i].re_entry_attempts++;
|
|
ReEntryQueue[i].exit_time = TimeCurrent(); // Reset cooldown
|
|
|
|
Print("🔄 RE-ENTRY EXECUTED: ", ReEntryQueue[i].original_ticket,
|
|
" | Attempt ", ReEntryQueue[i].re_entry_attempts, "/", ReEntry_Max_Attempts);
|
|
|
|
// If max attempts reached, remove from queue
|
|
if(ReEntryQueue[i].re_entry_attempts >= ReEntry_Max_Attempts)
|
|
ArrayRemove(ReEntryQueue, i, 1);
|
|
}
|
|
else
|
|
{
|
|
// Check if opportunity has expired (>10 minutes old)
|
|
if(TimeCurrent() - ReEntryQueue[i].exit_time > 600)
|
|
{
|
|
Print("⏰ RE-ENTRY EXPIRED: ", ReEntryQueue[i].original_ticket,
|
|
" | Setup no longer valid");
|
|
ArrayRemove(ReEntryQueue, i, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void ManagePositions()
|
|
{
|
|
UpdateMAs();
|
|
|
|
// Check for closed positions and queue re-entries
|
|
for(int i=0; i<ArraySize(OpenPositions); i++)
|
|
{
|
|
ulong ticket = OpenPositions[i].ticket;
|
|
|
|
// Check if position still exists
|
|
if(!PositionSelectByTicket(ticket))
|
|
{
|
|
// Position was closed - determine why
|
|
bool was_sl = false;
|
|
bool was_be = false;
|
|
|
|
double exit_price = 0;
|
|
|
|
// Try to get exit info from history
|
|
if(HistorySelectByPosition(ticket))
|
|
{
|
|
int deals = HistoryDealsTotal();
|
|
for(int d=deals-1; d>=0; d--)
|
|
{
|
|
ulong deal_ticket = HistoryDealGetTicket(d);
|
|
if(HistoryDealGetInteger(deal_ticket, DEAL_POSITION_ID) == ticket)
|
|
{
|
|
exit_price = HistoryDealGetDouble(deal_ticket, DEAL_PRICE);
|
|
|
|
// Check if hit SL or BE
|
|
double entry = OpenPositions[i].entry;
|
|
double sl = OpenPositions[i].sl_level;
|
|
|
|
bool is_buy = OpenPositions[i].is_buy;
|
|
|
|
// Was it at SL?
|
|
if(MathAbs(exit_price - sl) < 50 * _Point)
|
|
{
|
|
// Check if SL was at BE
|
|
if(MathAbs(sl - entry) < 50 * _Point)
|
|
was_be = true;
|
|
else
|
|
was_sl = true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Queue re-entry if appropriate
|
|
if(was_sl || was_be)
|
|
{
|
|
string reason = was_be ? "BE STOP" : "STOP LOSS";
|
|
AddReEntryOpportunity(ticket, OpenPositions[i].is_buy, exit_price,
|
|
OpenPositions[i].entry, reason);
|
|
}
|
|
|
|
// Remove from tracking
|
|
ArrayRemove(OpenPositions, i, 1);
|
|
i--;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Manage existing positions
|
|
for(int i=PositionsTotal()-1; i>=0; i--)
|
|
{
|
|
ulong ticket = PositionGetTicket(i);
|
|
if(ticket == 0) continue;
|
|
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
|
|
if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
|
|
|
|
int idx = -1;
|
|
for(int j=0; j<ArraySize(OpenPositions); j++)
|
|
{
|
|
if(OpenPositions[j].ticket == ticket)
|
|
{
|
|
idx = j;
|
|
break;
|
|
}
|
|
}
|
|
if(idx == -1) continue;
|
|
|
|
double entry = OpenPositions[idx].entry;
|
|
double sl = PositionGetDouble(POSITION_SL);
|
|
bool is_buy = OpenPositions[idx].is_buy;
|
|
|
|
double current = is_buy ? SymbolInfoDouble(_Symbol, SYMBOL_BID)
|
|
: SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
|
|
double profit_points = is_buy ? (current - entry) / _Point
|
|
: (entry - current) / _Point;
|
|
|
|
if(!OpenPositions[idx].be_set && profit_points >= Move_BE_At_Points)
|
|
{
|
|
if((is_buy && sl < entry) || (!is_buy && sl > entry))
|
|
{
|
|
Trade.PositionModify(ticket, entry, 0);
|
|
OpenPositions[idx].be_set = true;
|
|
Print("BE SET: ", ticket, " @ ", entry);
|
|
}
|
|
}
|
|
|
|
double lot = PositionGetDouble(POSITION_VOLUME);
|
|
|
|
if(IsPriceAtHigherMA(current))
|
|
{
|
|
if(OpenPositions[idx].partials_closed < 4)
|
|
{
|
|
double close_size = NormalizeDouble(OpenPositions[idx].original_lot * Partial_TP_Percent / 100.0, 2);
|
|
if(close_size > 0 && close_size <= lot)
|
|
{
|
|
Trade.PositionClosePartial(ticket, close_size);
|
|
OpenPositions[idx].partials_closed++;
|
|
Print("PARTIAL TP ", OpenPositions[idx].partials_closed, ": Closed ", Partial_TP_Percent, "%");
|
|
}
|
|
}
|
|
}
|
|
|
|
if(profit_points >= Trailing_SL_Points + 100)
|
|
{
|
|
double newSL = is_buy ? current - Trailing_SL_Points * _Point
|
|
: current + Trailing_SL_Points * _Point;
|
|
|
|
if((is_buy && newSL > sl + 50 * _Point) ||
|
|
(!is_buy && newSL < sl - 50 * _Point))
|
|
{
|
|
Trade.PositionModify(ticket, newSL, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
// Update MFIB every 30 minutes
|
|
if(TimeCurrent() - Last_MFIB_Calc >= 1800)
|
|
{
|
|
CalculateMFIB();
|
|
if(Show_MFIB_Levels) DrawMFIBLevels();
|
|
Last_MFIB_Calc = TimeCurrent();
|
|
}
|
|
|
|
if(TimeCurrent() - Last_Trend_Check >= 5)
|
|
{
|
|
DetermineTrendBias();
|
|
UpdateMFIBModeLabel();
|
|
|
|
if(TrendReversed())
|
|
{
|
|
if(Current_Trend_Bullish)
|
|
CloseOppositeTrades(false);
|
|
else if(Current_Trend_Bearish)
|
|
CloseOppositeTrades(true);
|
|
}
|
|
|
|
Last_Trend_Check = TimeCurrent();
|
|
}
|
|
|
|
ManagePositions();
|
|
|
|
// Process re-entry opportunities
|
|
ProcessReEntries();
|
|
|
|
if(!CheckLimits()) return;
|
|
|
|
// Check for dead zones
|
|
if(IsDeadZone()) return;
|
|
|
|
int buy_count = 0;
|
|
int sell_count = 0;
|
|
|
|
for(int i=0; i<PositionsTotal(); i++)
|
|
{
|
|
if(PositionGetTicket(i) == 0) continue;
|
|
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
|
|
PositionGetInteger(POSITION_MAGIC) == MagicNumber)
|
|
{
|
|
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
|
|
buy_count++;
|
|
else
|
|
sell_count++;
|
|
}
|
|
}
|
|
|
|
int total_open = buy_count + sell_count;
|
|
if(total_open >= Max_Simultaneous_Trades) return;
|
|
|
|
// AGGRESSIVE FORCE ENTRY - Ensure we hit minimum 4 trades
|
|
bool force_entry = (total_open < Min_Active_Entries);
|
|
bool force_entry_urgent = (total_open < 2); // Super aggressive below 2 trades
|
|
|
|
UpdateMAs();
|
|
UpdateStochastic();
|
|
|
|
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
double current = (bid + ask) / 2;
|
|
|
|
int ma14_crosses_bull = CountMA14Crosses(true);
|
|
int ma14_crosses_bear = CountMA14Crosses(false);
|
|
|
|
// Get labels for display
|
|
string mfib_label_bull = GetMFIBLabel(current, true);
|
|
string mfib_label_bear = GetMFIBLabel(current, false);
|
|
string ema14_label_bull = GetEMA14Label(current, true);
|
|
string ema14_label_bear = GetEMA14Label(current, false);
|
|
string stoch_label_bull = GetStochLabel(true);
|
|
string stoch_label_bear = GetStochLabel(false);
|
|
|
|
// MA RETEST DETECTION (KEY FOR MISSED OPPORTUNITIES!)
|
|
int retest_ma_idx = -1;
|
|
string retest_label_bull = "";
|
|
string retest_label_bear = "";
|
|
bool ma_retest_bull = DetectMARetest(true, retest_ma_idx, retest_label_bull);
|
|
bool ma_retest_bear = DetectMARetest(false, retest_ma_idx, retest_label_bear);
|
|
|
|
// MA REJECTION DETECTION
|
|
string reject_label_bull = "";
|
|
string reject_label_bear = "";
|
|
bool ma_reject_bull = DetectMAReject(true, reject_label_bull);
|
|
bool ma_reject_bear = DetectMAReject(false, reject_label_bear);
|
|
|
|
// Check MFIB interaction requirement (can be overridden by force entry or MA retest)
|
|
bool has_mfib_interaction = (mfib_label_bull != "" || mfib_label_bear != "");
|
|
if(Require_MFIB_Interaction && !has_mfib_interaction && !force_entry && !ma_retest_bull && !ma_retest_bear)
|
|
{
|
|
UpdateStatusLabel("No MFIB Interaction - Waiting", clrGray);
|
|
return;
|
|
}
|
|
|
|
string setup_label = "";
|
|
string details = "";
|
|
|
|
// BUY SETUPS
|
|
if(Current_Trend_Bullish || MFIB_Bull_Mode || force_entry)
|
|
{
|
|
bool buy_signal = false;
|
|
|
|
// PRIORITY 1: MA RETEST (Catches those circled opportunities!)
|
|
if(ma_retest_bull)
|
|
{
|
|
buy_signal = true;
|
|
setup_label = "MA RETEST";
|
|
details = retest_label_bull + " + " + stoch_label_bull;
|
|
}
|
|
// PRIORITY 2: MA REJECTION
|
|
else if(ma_reject_bull)
|
|
{
|
|
buy_signal = true;
|
|
setup_label = "MA REJECTION";
|
|
details = reject_label_bull + " + " + stoch_label_bull;
|
|
}
|
|
// Check all 6 standard setups
|
|
else if(CheckSetup1_StructuralBounce(true, setup_label))
|
|
{
|
|
buy_signal = true;
|
|
details = mfib_label_bull + " + " + ema14_label_bull + " + " + stoch_label_bull;
|
|
}
|
|
else if(CheckSetup2_StructuralBreak(true, setup_label))
|
|
{
|
|
buy_signal = true;
|
|
details = "Break & Hold + " + stoch_label_bull;
|
|
}
|
|
else if(CheckSetup3_MagnetSnapback(true, setup_label))
|
|
{
|
|
buy_signal = true;
|
|
details = ema14_label_bull + " + " + stoch_label_bull;
|
|
}
|
|
else if(CheckSetup4_MFIBContinuation(true, setup_label))
|
|
{
|
|
buy_signal = true;
|
|
details = "MFIB Bull Mode + Micro Align + " + stoch_label_bull;
|
|
}
|
|
else if(CheckSetup5_FailedBreak(true, setup_label))
|
|
{
|
|
buy_signal = true;
|
|
details = "Failed Bear Break + Stoch Cross";
|
|
}
|
|
else if(CheckSetup6_TripleConfluence(true, setup_label))
|
|
{
|
|
buy_signal = true;
|
|
details = mfib_label_bull + " + " + ema14_label_bull + " + Rejection";
|
|
}
|
|
|
|
// FORCE ENTRY LOGIC (More aggressive)
|
|
if(!buy_signal && force_entry_urgent)
|
|
{
|
|
// Super aggressive: just need any MA alignment
|
|
if(ma14_crosses_bull >= 1 || IsMicroBullAlign())
|
|
{
|
|
buy_signal = true;
|
|
setup_label = "FORCE ENTRY URGENT";
|
|
details = "Need " + IntegerToString(Min_Active_Entries) + " trades (" + IntegerToString(total_open) + " open)";
|
|
}
|
|
}
|
|
else if(!buy_signal && force_entry && ma14_crosses_bull >= Min_MA14_Crosses && buy_count < sell_count)
|
|
{
|
|
buy_signal = true;
|
|
setup_label = "FORCE ENTRY";
|
|
details = "Min trades " + IntegerToString(total_open) + "/" + IntegerToString(Min_Active_Entries);
|
|
}
|
|
|
|
if(buy_signal)
|
|
{
|
|
OpenTrade(true, ask, setup_label, details);
|
|
UpdateStatusLabel(setup_label + " LONG", clrLime);
|
|
}
|
|
}
|
|
|
|
// SELL SETUPS
|
|
if(Current_Trend_Bearish || MFIB_Bear_Mode || force_entry)
|
|
{
|
|
bool sell_signal = false;
|
|
|
|
// PRIORITY 1: MA RETEST (Catches those circled opportunities!)
|
|
if(ma_retest_bear)
|
|
{
|
|
sell_signal = true;
|
|
setup_label = "MA RETEST";
|
|
details = retest_label_bear + " + " + stoch_label_bear;
|
|
}
|
|
// PRIORITY 2: MA REJECTION
|
|
else if(ma_reject_bear)
|
|
{
|
|
sell_signal = true;
|
|
setup_label = "MA REJECTION";
|
|
details = reject_label_bear + " + " + stoch_label_bear;
|
|
}
|
|
// Check all 6 standard setups
|
|
else if(CheckSetup1_StructuralBounce(false, setup_label))
|
|
{
|
|
sell_signal = true;
|
|
details = mfib_label_bear + " + " + ema14_label_bear + " + " + stoch_label_bear;
|
|
}
|
|
else if(CheckSetup2_StructuralBreak(false, setup_label))
|
|
{
|
|
sell_signal = true;
|
|
details = "Break & Hold + " + stoch_label_bear;
|
|
}
|
|
else if(CheckSetup3_MagnetSnapback(false, setup_label))
|
|
{
|
|
sell_signal = true;
|
|
details = ema14_label_bear + " + " + stoch_label_bear;
|
|
}
|
|
else if(CheckSetup4_MFIBContinuation(false, setup_label))
|
|
{
|
|
sell_signal = true;
|
|
details = "MFIB Bear Mode + Micro Align + " + stoch_label_bear;
|
|
}
|
|
else if(CheckSetup5_FailedBreak(false, setup_label))
|
|
{
|
|
sell_signal = true;
|
|
details = "Failed Bull Break + Stoch Cross";
|
|
}
|
|
else if(CheckSetup6_TripleConfluence(false, setup_label))
|
|
{
|
|
sell_signal = true;
|
|
details = mfib_label_bear + " + " + ema14_label_bear + " + Rejection";
|
|
}
|
|
|
|
// FORCE ENTRY LOGIC (More aggressive)
|
|
if(!sell_signal && force_entry_urgent)
|
|
{
|
|
// Super aggressive: just need any MA alignment
|
|
if(ma14_crosses_bear >= 1 || IsMicroBearAlign())
|
|
{
|
|
sell_signal = true;
|
|
setup_label = "FORCE ENTRY URGENT";
|
|
details = "Need " + IntegerToString(Min_Active_Entries) + " trades (" + IntegerToString(total_open) + " open)";
|
|
}
|
|
}
|
|
else if(!sell_signal && force_entry && ma14_crosses_bear >= Min_MA14_Crosses && sell_count < buy_count)
|
|
{
|
|
sell_signal = true;
|
|
setup_label = "FORCE ENTRY";
|
|
details = "Min trades " + IntegerToString(total_open) + "/" + IntegerToString(Min_Active_Entries);
|
|
}
|
|
|
|
if(sell_signal)
|
|
{
|
|
OpenTrade(false, bid, setup_label, details);
|
|
UpdateStatusLabel(setup_label + " SHORT", clrRed);
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+ |