Vizion-Trading-EA/Scripts/catalystv1.2.mq5
2026-02-19 23:19:25 -06:00

1128 lines
No EOL
77 KiB
MQL5

//+------------------------------------------------------------------+
//| QuarterTheory_VIZION_FINAL_v5.0.mq5 |
//| PULLBACK DETECTION | RUNNERS PROTECTED | STOCH EXTREMES |
//| Never Close Runners on Pullbacks | Only on Full Reversal |
//+------------------------------------------------------------------+
#property copyright "QuarterTheory x VIZION - Final v5.0"
#property version "5.00"
#property strict
#include <Trade/Trade.mqh>
CTrade Trade;
//================ INPUT PARAMETERS ==================//
input group "=== CORE SETTINGS ==="
input int MagicNumber = 456789;
input double Risk_Per_Trade = 1.2;
input int Max_Trades_Per_Setup = 10;
input int Max_Total_Trades = 100;
input int Min_Runners_To_Keep = 4;
input group "=== MARKET MODE SYSTEM ==="
input bool Use_Market_Mode_Filter = true;
input int Mode_Confirmation_Bars = 2;
input double Chop_ATR_Threshold = 0.5;
input double Range_Price_Threshold = 0.3;
input group "=== REVERSAL CONFIRMATION ==="
input bool Only_Close_On_Full_Reversal = true; // Protect runners from pullbacks
input int Reversal_Confirmation_Bars = 3; // Bars needed for full reversal
input group "=== MA SYSTEM ==="
input int MA_1 = 7;
input int MA_2 = 14;
input int MA_3 = 21;
input int MA_4 = 50;
input int MA_5 = 140;
input int MA_6 = 230;
input int MA_7 = 500;
input int MA_8 = 1000;
input int MA_9 = 1100;
input int MA_10 = 1300;
input int MA_Touch_Buffer = 100;
input group "=== STOCHASTIC ==="
input int Stoch_K_Period = 5;
input int Stoch_D_Period = 3;
input int Stoch_Slowing = 3;
input double Stoch_Extreme_High = 85.0; // Extreme overbought
input double Stoch_Extreme_Low = 15.0; // Extreme oversold
input double Stoch_High = 70.0;
input double Stoch_Low = 30.0;
input group "=== MFIB SYSTEM ==="
input int MFIB_Lookback = 500;
input group "=== FIBONACCI ==="
input int Lookback_Bars = 200;
input bool Show_Levels = true;
input group "=== 300 RULE EXIT SYSTEM ==="
input int Initial_SL_Points = 300;
input int BreakEven_Points = 300;
input int Trailing_Distance_Points = 300;
input int TP_Points = 1500;
input int Partial_TP_Points = 900;
input double Partial_TP_Percent = 33.0;
//================ ENUMS ==================//
enum MARKET_MODE {
MODE_STRONG_BULL_TREND,
MODE_BULL_TREND,
MODE_BEAR_TREND,
MODE_STRONG_BEAR_TREND,
MODE_CHOPPY,
MODE_RANGING,
MODE_TRANSITIONAL
};
enum PRICE_STATE {
STATE_TREND_CONTINUATION, // Clean trend
STATE_PULLBACK, // Healthy pullback (7 dip, 14/21 hold)
STATE_RETRACEMENT, // Deeper retracement (7 crosses 14, but 21/50 hold)
STATE_REVERSAL_FORMING, // Early reversal signs (50 pressure)
STATE_FULL_REVERSAL, // Confirmed reversal (50 broken, trend changed)
STATE_CONSOLIDATION,
STATE_UNKNOWN
};
enum SETUP_TYPE {
SETUP_MA14_CROSS = 1,
SETUP_MA50_BOUNCE = 2,
SETUP_MA140_BOUNCE = 3,
SETUP_MA230_BOUNCE = 4,
SETUP_MA500_TOUCH = 5,
SETUP_FIB_BREAK = 6,
SETUP_FIB_RECLAIM = 7,
SETUP_FIB_REJECT = 8,
SETUP_MAGNET_WALK = 9,
SETUP_STAIRCASE_ADV = 10,
SETUP_CTRL_PULLBACK = 11,
SETUP_TF_RESET = 12,
SETUP_MFIB_LADDER = 13,
SETUP_MFIB_PRESS = 14,
SETUP_MEAN_REV = 15,
SETUP_RANGE_ENGINE = 16
};
//================ GLOBALS ==================//
int Stoch_Handle, ATR_Handle, ADX_Handle;
double Stoch_K_Current = 0, Stoch_K_Previous = 0, Stoch_K_Prev2 = 0;
double Stoch_D_Current = 0;
double Current_ATR = 0;
double Current_ADX = 0;
double PriceLevels[7];
int MA_Handles[10];
double MA_Current[10];
double MA_Previous[10];
double MA_Prev2[10];
double MFIB_High, MFIB_Low;
double MFIB_Level_236, MFIB_Level_382, MFIB_Level_050;
double MFIB_Level_618, MFIB_Level_786;
MARKET_MODE Current_Mode = MODE_TRANSITIONAL;
MARKET_MODE Previous_Mode = MODE_TRANSITIONAL;
PRICE_STATE Current_State = STATE_UNKNOWN;
int Mode_Confirmation_Count = 0;
int Reversal_Confirm_Counter = 0;
// Warning flags
bool MA7_Cross_14_Warning = false;
bool MA7_Cross_21_Warning = false;
bool MA50_Break_Warning = false;
bool Fib_Reject_Warning = false;
bool MA_Reject_Warning = false;
bool Stoch_Extreme_Warning = false;
bool Pullback_Warning = false;
bool Retracement_Warning = false;
struct Position {
ulong ticket;
double entry;
double original_lot;
bool is_buy;
bool partial_tp_hit;
bool be_set;
bool trailing_active;
bool is_runner;
SETUP_TYPE setup_type;
string setup_name;
MARKET_MODE entry_mode;
double distance_from_current;
};
Position OpenPositions[];
int TodayTrades = 0;
int BuyTrades = 0;
int SellTrades = 0;
int ClosedByReversal = 0;
int SetupCount[17];
datetime LastEntryTime[17];
//+------------------------------------------------------------------+
int OnInit()
{
Print("========================================");
Print("FINAL SYSTEM v5.0");
Print("PULLBACK DETECTION | STOCH EXTREMES");
Print("RUNNERS PROTECTED FROM PULLBACKS");
Print("========================================");
Trade.SetExpertMagicNumber(MagicNumber);
Trade.SetDeviationInPoints(50);
Trade.SetTypeFilling(ORDER_FILLING_FOK);
Stoch_Handle = iStochastic(_Symbol, PERIOD_CURRENT, Stoch_K_Period, Stoch_D_Period,
Stoch_Slowing, MODE_SMA, STO_LOWHIGH);
ATR_Handle = iATR(_Symbol, PERIOD_CURRENT, 14);
ADX_Handle = iADX(_Symbol, PERIOD_CURRENT, 14);
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);
}
ArrayInitialize(SetupCount, 0);
ArrayInitialize(LastEntryTime, 0);
CalculateLevels();
if(Show_Levels) DrawLevels();
Print("Stoch Extremes: ", Stoch_Extreme_Low, " / ", Stoch_Extreme_High);
Print("Runners: ", Min_Runners_To_Keep, " protected from pullbacks");
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);
if(ATR_Handle != INVALID_HANDLE) IndicatorRelease(ATR_Handle);
if(ADX_Handle != INVALID_HANDLE) IndicatorRelease(ADX_Handle);
ObjectsDeleteAll(0, "Level_");
ObjectsDeleteAll(0, "ModeLabel");
ObjectsDeleteAll(0, "StateLabel");
ObjectsDeleteAll(0, "WarningLabel");
Print("Final: B:", BuyTrades, " | S:", SellTrades, " | Reversed:", ClosedByReversal);
}
//+------------------------------------------------------------------+
void CalculateLevels()
{
double high = iHigh(_Symbol, PERIOD_CURRENT, 0);
double low = iLow(_Symbol, PERIOD_CURRENT, 0);
for(int i=1; i<=Lookback_Bars; i++)
{
double h = iHigh(_Symbol, PERIOD_CURRENT, i);
double l = iLow(_Symbol, PERIOD_CURRENT, i);
if(h > high) high = h;
if(l < low) low = l;
}
double range = high - low;
PriceLevels[0] = low;
PriceLevels[1] = low + range * 0.236;
PriceLevels[2] = low + range * 0.382;
PriceLevels[3] = low + range * 0.5;
PriceLevels[4] = low + range * 0.618;
PriceLevels[5] = low + range * 0.786;
PriceLevels[6] = high;
MFIB_High = high;
MFIB_Low = low;
MFIB_Level_236 = low + range * 0.236;
MFIB_Level_382 = low + range * 0.382;
MFIB_Level_050 = low + range * 0.5;
MFIB_Level_618 = low + range * 0.618;
MFIB_Level_786 = low + range * 0.786;
}
void DrawLevels()
{
ObjectsDeleteAll(0, "Level_");
color level_colors[7] = {clrRed, clrOrange, clrYellow, clrLime, clrCyan, clrBlue, clrMagenta};
for(int i=0; i<7; i++)
{
string name = "Level_" + IntegerToString(i);
ObjectCreate(0, name, OBJ_HLINE, 0, 0, PriceLevels[i]);
ObjectSetInteger(0, name, OBJPROP_COLOR, level_colors[i]);
ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, name, OBJPROP_WIDTH, 2);
}
}
//+------------------------------------------------------------------+
void DetectWarnings()
{
double current = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double buffer = MA_Touch_Buffer * _Point;
// Reset warnings
MA7_Cross_14_Warning = false;
MA7_Cross_21_Warning = false;
MA50_Break_Warning = false;
Fib_Reject_Warning = false;
MA_Reject_Warning = false;
Stoch_Extreme_Warning = false;
Pullback_Warning = false;
Retracement_Warning = false;
// 1. STOCH EXTREME LEVELS (15/85)
if(Stoch_K_Current <= Stoch_Extreme_Low || Stoch_K_Current >= Stoch_Extreme_High)
{
Stoch_Extreme_Warning = true;
if(Stoch_K_Current <= Stoch_Extreme_Low)
Print("📊 STOCH EXTREME LOW: ", DoubleToString(Stoch_K_Current, 1), " - Pullback/Reversal");
else
Print("📊 STOCH EXTREME HIGH: ", DoubleToString(Stoch_K_Current, 1), " - Pullback/Reversal");
}
// 2. MA7 x MA14 CROSS (Early warning)
bool ma7_crossed_14_down = (MA_Previous[0] > MA_Previous[1]) && (MA_Current[0] <= MA_Current[1]);
bool ma7_crossed_14_up = (MA_Previous[0] < MA_Previous[1]) && (MA_Current[0] >= MA_Current[1]);
if(ma7_crossed_14_down || ma7_crossed_14_up)
{
MA7_Cross_14_Warning = true;
Retracement_Warning = true;
Print("⚠️ MA7 x MA14: ", ma7_crossed_14_down ? "BEAR RETRACEMENT" : "BULL RETRACEMENT");
}
// 3. MA7 x MA21 CROSS (Deeper retracement)
bool ma7_crossed_21_down = (MA_Previous[0] > MA_Previous[2]) && (MA_Current[0] <= MA_Current[2]);
bool ma7_crossed_21_up = (MA_Previous[0] < MA_Previous[2]) && (MA_Current[0] >= MA_Current[2]);
if(ma7_crossed_21_down || ma7_crossed_21_up)
{
MA7_Cross_21_Warning = true;
Retracement_Warning = true;
Print("⚠️ MA7 x MA21: DEEPER RETRACEMENT");
}
// 4. MA50 BREAK (Reversal warning)
bool ma7_broke_50_down = (MA_Previous[0] > MA_Previous[3]) && (MA_Current[0] <= MA_Current[3]);
bool ma7_broke_50_up = (MA_Previous[0] < MA_Previous[3]) && (MA_Current[0] >= MA_Current[3]);
if(ma7_broke_50_down || ma7_broke_50_up)
{
MA50_Break_Warning = true;
Print("🚨 MA50 BREAK: REVERSAL FORMING");
}
// 5. FIB REJECT at extremes with stoch
bool at_fib = false;
for(int i=1; i<6; i++)
{
if(MathAbs(current - PriceLevels[i]) <= buffer)
{
at_fib = true;
break;
}
}
if(at_fib && Stoch_Extreme_Warning)
{
Fib_Reject_Warning = true;
Pullback_Warning = true;
Print("📍 FIB REJECT + STOCH EXTREME");
}
// 6. MA REJECT at key levels with stoch
bool at_ma50 = MathAbs(current - MA_Current[3]) <= buffer;
bool at_ma140 = MathAbs(current - MA_Current[4]) <= buffer;
bool at_ma230 = MathAbs(current - MA_Current[5]) <= buffer;
if((at_ma50 || at_ma140 || at_ma230) && Stoch_Extreme_Warning)
{
MA_Reject_Warning = true;
Pullback_Warning = true;
Print("🔄 MA REJECT + STOCH EXTREME");
}
}
//+------------------------------------------------------------------+
PRICE_STATE DeterminePriceState()
{
double current = SymbolInfoDouble(_Symbol, SYMBOL_BID);
// Check MA structure
bool ma7_above_14 = MA_Current[0] > MA_Current[1];
bool ma7_above_21 = MA_Current[0] > MA_Current[2];
bool ma7_above_50 = MA_Current[0] > MA_Current[3];
bool ma14_above_50 = MA_Current[1] > MA_Current[3];
bool ma21_above_50 = MA_Current[2] > MA_Current[3];
// Bullish structure
if(Current_Mode == MODE_BULL_TREND || Current_Mode == MODE_STRONG_BULL_TREND)
{
// PULLBACK: 7 dips but 14/21 hold above 50
if(!ma7_above_21 && ma14_above_50 && ma21_above_50 && Stoch_Extreme_Warning)
{
return STATE_PULLBACK;
}
// RETRACEMENT: 7 crosses 14 but 21 still above 50
if(!ma7_above_14 && !ma21_above_50 && ma14_above_50)
{
return STATE_RETRACEMENT;
}
// REVERSAL FORMING: 7 approaching 50, pressure building
if(!ma7_above_50 && MA50_Break_Warning)
{
return STATE_REVERSAL_FORMING;
}
// FULL REVERSAL: 50 broken, trend changed
if(!ma7_above_50 && !ma14_above_50 && !ma21_above_50)
{
return STATE_FULL_REVERSAL;
}
// CONTINUATION: Clean structure
if(ma7_above_21 && ma21_above_50)
{
return STATE_TREND_CONTINUATION;
}
}
// Bearish structure
if(Current_Mode == MODE_BEAR_TREND || Current_Mode == MODE_STRONG_BEAR_TREND)
{
bool ma7_below_14 = MA_Current[0] < MA_Current[1];
bool ma7_below_21 = MA_Current[0] < MA_Current[2];
bool ma7_below_50 = MA_Current[0] < MA_Current[3];
bool ma14_below_50 = MA_Current[1] < MA_Current[3];
bool ma21_below_50 = MA_Current[2] < MA_Current[3];
// PULLBACK: 7 rises but 14/21 hold below 50
if(!ma7_below_21 && ma14_below_50 && ma21_below_50 && Stoch_Extreme_Warning)
{
return STATE_PULLBACK;
}
// RETRACEMENT: 7 crosses 14 but 21 still below 50
if(!ma7_below_14 && !ma21_below_50 && ma14_below_50)
{
return STATE_RETRACEMENT;
}
// REVERSAL FORMING: 7 approaching 50, pressure building
if(!ma7_below_50 && MA50_Break_Warning)
{
return STATE_REVERSAL_FORMING;
}
// FULL REVERSAL: 50 broken, trend changed
if(!ma7_below_50 && !ma14_below_50 && !ma21_below_50)
{
return STATE_FULL_REVERSAL;
}
// CONTINUATION: Clean structure
if(ma7_below_21 && ma21_below_50)
{
return STATE_TREND_CONTINUATION;
}
}
return STATE_UNKNOWN;
}
//+------------------------------------------------------------------+
MARKET_MODE DetermineMarketMode()
{
double current = SymbolInfoDouble(_Symbol, SYMBOL_BID);
// Don't flip mode on pullbacks/retracements
if(Current_State == STATE_PULLBACK || Current_State == STATE_RETRACEMENT)
{
// Keep current trend mode during pullbacks
return Current_Mode;
}
// Only flip on FULL REVERSAL or strong signals
bool force_flip = false;
if(Current_State == STATE_FULL_REVERSAL)
{
force_flip = true;
Print("🔄 FULL REVERSAL DETECTED - MODE FLIP INITIATED");
}
if(MA50_Break_Warning && MA7_Cross_21_Warning && Stoch_Extreme_Warning)
{
force_flip = true;
Print("🔄 STRONG REVERSAL SIGNALS - MODE FLIP INITIATED");
}
// Standard trend detection
bool ma7_above_50 = MA_Current[0] > MA_Current[3];
bool ma7_above_140 = MA_Current[0] > MA_Current[4];
bool ma7_above_230 = MA_Current[0] > MA_Current[5];
bool ma7_below_50 = MA_Current[0] < MA_Current[3];
bool ma7_below_140 = MA_Current[0] < MA_Current[4];
bool ma7_below_230 = MA_Current[0] < MA_Current[5];
bool mas_aligned_bull = (MA_Current[0] > MA_Current[1]) && (MA_Current[1] > MA_Current[2]) && (MA_Current[2] > MA_Current[3]);
bool mas_aligned_bear = (MA_Current[0] < MA_Current[1]) && (MA_Current[1] < MA_Current[2]) && (MA_Current[2] < MA_Current[3]);
bool above_mfib_618 = current > MFIB_Level_618;
bool below_mfib_382 = current < MFIB_Level_382;
bool stoch_trending_up = (Stoch_K_Current > Stoch_D_Current) && (Stoch_K_Current > 50);
bool stoch_trending_down = (Stoch_K_Current < Stoch_D_Current) && (Stoch_K_Current < 50);
// Chop/range detection (only if no clear trend)
double recent_high = iHigh(_Symbol, PERIOD_CURRENT, 0);
double recent_low = iLow(_Symbol, PERIOD_CURRENT, 0);
for(int i=1; i<20; i++)
{
recent_high = MathMax(recent_high, iHigh(_Symbol, PERIOD_CURRENT, i));
recent_low = MathMin(recent_low, iLow(_Symbol, PERIOD_CURRENT, i));
}
double range_size = (recent_high - recent_low) / current;
bool is_ranging = range_size < Range_Price_Threshold;
bool ma_clustered = (MathAbs(MA_Current[0] - MA_Current[3]) / Current_ATR < Chop_ATR_Threshold);
bool is_choppy = (ma_clustered || Current_ADX < 15); // Stricter chop detection
// Priority: Trends > Chop/Range (don't flip to chop/range during pullbacks)
// Strong trends
if(mas_aligned_bull && ma7_above_230 && above_mfib_618 && Current_ADX > 25)
return MODE_STRONG_BULL_TREND;
if(mas_aligned_bear && ma7_below_230 && below_mfib_382 && Current_ADX > 25)
return MODE_STRONG_BEAR_TREND;
// Regular trends (main detection)
if(mas_aligned_bull && ma7_above_140 && Current_ADX > 18)
return MODE_BULL_TREND;
if(mas_aligned_bear && ma7_below_140 && Current_ADX > 18)
return MODE_BEAR_TREND;
// Weaker bull trend (still trending, just weaker)
if(ma7_above_50 && Current_ADX > 15 && !is_choppy)
return MODE_BULL_TREND;
// Weaker bear trend
if(ma7_below_50 && Current_ADX > 15 && !is_choppy)
return MODE_BEAR_TREND;
// Only label chop/range if truly directionless
if(is_choppy && !force_flip)
return MODE_CHOPPY;
if(is_ranging && !mas_aligned_bull && !mas_aligned_bear && !force_flip)
return MODE_RANGING;
return MODE_TRANSITIONAL;
}
//+------------------------------------------------------------------+
void UpdateMarketMode()
{
// First determine state
Current_State = DeterminePriceState();
MARKET_MODE detected_mode = DetermineMarketMode();
// Fast flip on full reversal
int required_confirms = Mode_Confirmation_Bars;
if(Current_State == STATE_FULL_REVERSAL)
{
required_confirms = 1;
}
// Don't flip mode during pullbacks/retracements
if(Current_State == STATE_PULLBACK || Current_State == STATE_RETRACEMENT)
{
// Keep current mode, just update labels
UpdateLabels();
return;
}
if(detected_mode != Current_Mode)
{
if(detected_mode == Previous_Mode)
{
Mode_Confirmation_Count++;
if(Mode_Confirmation_Count >= required_confirms)
{
MARKET_MODE old_mode = Current_Mode;
Current_Mode = detected_mode;
Mode_Confirmation_Count = 0;
Reversal_Confirm_Counter = 0;
Print(">>> MODE FLIP: ", EnumToString(old_mode), "", EnumToString(Current_Mode));
// Only close on FULL REVERSAL
if(Current_State == STATE_FULL_REVERSAL)
{
CloseOnFullReversal();
}
}
}
else
{
Previous_Mode = detected_mode;
Mode_Confirmation_Count = 1;
}
}
else
{
Mode_Confirmation_Count = 0;
}
UpdateLabels();
}
//+------------------------------------------------------------------+
void UpdateLabels()
{
// Mode Label
ObjectDelete(0, "ModeLabel");
ObjectCreate(0, "ModeLabel", OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, "ModeLabel", OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, "ModeLabel", OBJPROP_XDISTANCE, 10);
ObjectSetInteger(0, "ModeLabel", OBJPROP_YDISTANCE, 30);
string mode_text = "";
color mode_color = clrYellow;
switch(Current_Mode)
{
case MODE_STRONG_BULL_TREND: mode_text = "MODE: STRONG BULL ↑↑"; mode_color = clrLime; break;
case MODE_BULL_TREND: mode_text = "MODE: BULL TREND ↑"; mode_color = clrGreenYellow; break;
case MODE_BEAR_TREND: mode_text = "MODE: BEAR TREND ↓"; mode_color = clrOrange; break;
case MODE_STRONG_BEAR_TREND: mode_text = "MODE: STRONG BEAR ↓↓"; mode_color = clrRed; break;
case MODE_CHOPPY: mode_text = "MODE: CHOPPY ⚡"; mode_color = clrViolet; break;
case MODE_RANGING: mode_text = "MODE: RANGING ↔"; mode_color = clrAqua; break;
case MODE_TRANSITIONAL: mode_text = "MODE: TRANSITIONAL ~"; mode_color = clrYellow; break;
}
ObjectSetString(0, "ModeLabel", OBJPROP_TEXT, mode_text);
ObjectSetInteger(0, "ModeLabel", OBJPROP_COLOR, mode_color);
ObjectSetInteger(0, "ModeLabel", OBJPROP_FONTSIZE, 12);
// State Label
ObjectDelete(0, "StateLabel");
ObjectCreate(0, "StateLabel", OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, "StateLabel", OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, "StateLabel", OBJPROP_XDISTANCE, 10);
ObjectSetInteger(0, "StateLabel", OBJPROP_YDISTANCE, 50);
string state_text = "STATE: ";
color state_color = clrWhite;
switch(Current_State)
{
case STATE_TREND_CONTINUATION: state_text += "CONTINUATION ✓"; state_color = clrLime; break;
case STATE_PULLBACK: state_text += "PULLBACK ↩ (RUNNERS SAFE)"; state_color = clrYellow; break;
case STATE_RETRACEMENT: state_text += "RETRACEMENT ↪ (RUNNERS SAFE)"; state_color = clrOrange; break;
case STATE_REVERSAL_FORMING: state_text += "REVERSAL FORMING ⚠"; state_color = clrOrangeRed; break;
case STATE_FULL_REVERSAL: state_text += "FULL REVERSAL 🔄"; state_color = clrRed; break;
case STATE_CONSOLIDATION: state_text += "CONSOLIDATION 📊"; state_color = clrAqua; break;
case STATE_UNKNOWN: state_text += "UNKNOWN"; break;
}
ObjectSetString(0, "StateLabel", OBJPROP_TEXT, state_text);
ObjectSetInteger(0, "StateLabel", OBJPROP_COLOR, state_color);
ObjectSetInteger(0, "StateLabel", OBJPROP_FONTSIZE, 11);
// Warning Label
if(MA7_Cross_14_Warning || MA7_Cross_21_Warning || MA50_Break_Warning ||
Fib_Reject_Warning || MA_Reject_Warning || Stoch_Extreme_Warning)
{
ObjectDelete(0, "WarningLabel");
ObjectCreate(0, "WarningLabel", OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, "WarningLabel", OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, "WarningLabel", OBJPROP_XDISTANCE, 10);
ObjectSetInteger(0, "WarningLabel", OBJPROP_YDISTANCE, 70);
string warn_text = "";
if(Stoch_Extreme_Warning) warn_text += "📊 STOCH EXTREME | ";
if(MA7_Cross_14_Warning) warn_text += "MA7x14 | ";
if(MA7_Cross_21_Warning) warn_text += "MA7x21 | ";
if(MA50_Break_Warning) warn_text += "🚨 MA50 BREAK | ";
if(Fib_Reject_Warning) warn_text += "FIB REJECT | ";
if(MA_Reject_Warning) warn_text += "MA REJECT";
ObjectSetString(0, "WarningLabel", OBJPROP_TEXT, warn_text);
ObjectSetInteger(0, "WarningLabel", OBJPROP_COLOR, clrRed);
ObjectSetInteger(0, "WarningLabel", OBJPROP_FONTSIZE, 10);
}
else
{
ObjectDelete(0, "WarningLabel");
}
}
//+------------------------------------------------------------------+
void MarkRunners()
{
double current = SymbolInfoDouble(_Symbol, SYMBOL_BID);
// Update distances
for(int i=0; i<ArraySize(OpenPositions); i++)
{
if(PositionSelectByTicket(OpenPositions[i].ticket))
{
double entry = OpenPositions[i].entry;
OpenPositions[i].distance_from_current = MathAbs(current - entry) / _Point;
}
}
// Sort by distance (far entries first)
for(int i=0; i<ArraySize(OpenPositions)-1; i++)
{
for(int j=i+1; j<ArraySize(OpenPositions); j++)
{
if(OpenPositions[j].distance_from_current > OpenPositions[i].distance_from_current)
{
Position temp = OpenPositions[i];
OpenPositions[i] = OpenPositions[j];
OpenPositions[j] = temp;
}
}
}
// Mark top N as runners
for(int i=0; i<ArraySize(OpenPositions); i++)
{
OpenPositions[i].is_runner = (i < Min_Runners_To_Keep);
}
}
//+------------------------------------------------------------------+
void CloseOnFullReversal()
{
if(!Only_Close_On_Full_Reversal) return;
MarkRunners();
Print("🔄 FULL REVERSAL - Closing opposing positions (protecting runners)");
for(int i=PositionsTotal()-1; i>=0; i--)
{
if(PositionGetTicket(i) == 0) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
ulong ticket = PositionGetTicket(i);
bool is_buy = PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY;
// Find in array
int idx = -1;
for(int j=0; j<ArraySize(OpenPositions); j++)
{
if(OpenPositions[j].ticket == ticket) { idx = j; break; }
}
// ALWAYS PROTECT RUNNERS (even in full reversal, keep 4 best)
if(idx >= 0 && OpenPositions[idx].is_runner)
{
Print("🏃 RUNNER PROTECTED: ", OpenPositions[idx].setup_name, " | Distance: ",
(int)OpenPositions[idx].distance_from_current);
continue;
}
bool should_close = false;
// Close opposing trades
if(is_buy && (Current_Mode == MODE_BEAR_TREND || Current_Mode == MODE_STRONG_BEAR_TREND))
should_close = true;
if(!is_buy && (Current_Mode == MODE_BULL_TREND || Current_Mode == MODE_STRONG_BULL_TREND))
should_close = true;
if(should_close)
{
if(Trade.PositionClose(ticket))
{
ClosedByReversal++;
Print("✂ FULL REVERSAL CLOSE: ", is_buy ? "BUY" : "SELL");
}
}
}
}
//+------------------------------------------------------------------+
void UpdateIndicators()
{
for(int i=0; i<10; i++)
{
double curr[1], prev[1], prev2[1];
if(CopyBuffer(MA_Handles[i], 0, 0, 1, curr) > 0) MA_Current[i] = curr[0];
if(CopyBuffer(MA_Handles[i], 0, 1, 1, prev) > 0) MA_Previous[i] = prev[0];
if(CopyBuffer(MA_Handles[i], 0, 2, 1, prev2) > 0) MA_Prev2[i] = prev2[0];
}
double k_curr[1], k_prev[1], k_prev2[1], d_curr[1];
if(CopyBuffer(Stoch_Handle, MAIN_LINE, 0, 1, k_curr) > 0) Stoch_K_Current = k_curr[0];
if(CopyBuffer(Stoch_Handle, MAIN_LINE, 1, 1, k_prev) > 0) Stoch_K_Previous = k_prev[0];
if(CopyBuffer(Stoch_Handle, MAIN_LINE, 2, 1, k_prev2) > 0) Stoch_K_Prev2 = k_prev2[0];
if(CopyBuffer(Stoch_Handle, SIGNAL_LINE, 0, 1, d_curr) > 0) Stoch_D_Current = d_curr[0];
double atr[1], adx[1];
if(CopyBuffer(ATR_Handle, 0, 0, 1, atr) > 0) Current_ATR = atr[0];
if(CopyBuffer(ADX_Handle, 0, 0, 1, adx) > 0) Current_ADX = adx[0];
}
//+------------------------------------------------------------------+
bool IsSetupValidForMode(SETUP_TYPE setup, bool is_buy)
{
if(!Use_Market_Mode_Filter) return true;
// During PULLBACK - allow pullback entries
if(Current_State == STATE_PULLBACK)
{
if(setup == SETUP_CTRL_PULLBACK || setup == SETUP_MEAN_REV || setup == SETUP_FIB_REJECT)
return true;
return false; // Only pullback setups during pullback
}
// During RETRACEMENT - wait for reclaim
if(Current_State == STATE_RETRACEMENT)
{
if(setup == SETUP_CTRL_PULLBACK || setup == SETUP_MEAN_REV)
return true;
return false;
}
// During REVERSAL FORMING - reduce aggression
if(Current_State == STATE_REVERSAL_FORMING)
{
// Only conservative setups
if(setup == SETUP_MA50_BOUNCE || setup == SETUP_MEAN_REV)
return true;
return false;
}
// MODE-BASED FILTERING
switch(Current_Mode)
{
case MODE_STRONG_BULL_TREND:
if(!is_buy) return false;
break;
case MODE_STRONG_BEAR_TREND:
if(is_buy) return false;
break;
case MODE_CHOPPY:
if(setup != SETUP_MEAN_REV && setup != SETUP_CTRL_PULLBACK && setup != SETUP_FIB_REJECT)
return false;
break;
case MODE_RANGING:
if(setup != SETUP_RANGE_ENGINE && setup != SETUP_MEAN_REV && setup != SETUP_FIB_REJECT)
return false;
break;
}
return true;
}
//+------------------------------------------------------------------+
int CountSetupTrades(SETUP_TYPE setup)
{
int count = 0;
for(int i=0; i<PositionsTotal(); i++)
{
if(PositionGetTicket(i) == 0) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
for(int j=0; j<ArraySize(OpenPositions); j++)
{
if(OpenPositions[j].ticket == PositionGetTicket(i))
{
if(OpenPositions[j].setup_type == setup)
count++;
break;
}
}
}
return count;
}
//+------------------------------------------------------------------+
double GetLotSize()
{
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 / ((Initial_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;
}
//+------------------------------------------------------------------+
void OpenTrade(bool buy, double price, string setup_name, SETUP_TYPE setup_type)
{
if(!IsSetupValidForMode(setup_type, buy)) return;
if(CountSetupTrades(setup_type) >= Max_Trades_Per_Setup) return;
if(PositionsTotal() >= Max_Total_Trades) return;
datetime now = TimeCurrent();
if(now - LastEntryTime[setup_type] < 1) return;
LastEntryTime[setup_type] = now;
double lot = GetLotSize();
if(lot < SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN)) return;
double sl = buy ? price - Initial_SL_Points * _Point : price + Initial_SL_Points * _Point;
double tp = buy ? price + TP_Points * _Point : price - TP_Points * _Point;
string comment = setup_name + "|" + EnumToString(Current_Mode) + "|" + EnumToString(Current_State);
bool result = false;
if(buy) result = Trade.Buy(lot, _Symbol, 0, sl, tp, comment);
else result = Trade.Sell(lot, _Symbol, 0, sl, tp, comment);
if(result)
{
TodayTrades++;
if(buy) BuyTrades++; else SellTrades++;
SetupCount[setup_type]++;
ulong ticket = Trade.ResultOrder();
int size = ArraySize(OpenPositions);
ArrayResize(OpenPositions, size+1);
OpenPositions[size].ticket = ticket;
OpenPositions[size].entry = price;
OpenPositions[size].original_lot = lot;
OpenPositions[size].is_buy = buy;
OpenPositions[size].partial_tp_hit = false;
OpenPositions[size].be_set = false;
OpenPositions[size].trailing_active = false;
OpenPositions[size].is_runner = false;
OpenPositions[size].setup_type = setup_type;
OpenPositions[size].setup_name = setup_name;
OpenPositions[size].entry_mode = Current_Mode;
OpenPositions[size].distance_from_current = 0;
Print("", setup_name, " ", buy ? "BUY" : "SELL", " | State: ", EnumToString(Current_State));
}
}
//+------------------------------------------------------------------+
void ManagePositions()
{
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 = PositionGetDouble(POSITION_PRICE_OPEN);
double current_sl = PositionGetDouble(POSITION_SL);
double current_tp = PositionGetDouble(POSITION_TP);
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;
// Partial TP
if(!OpenPositions[idx].partial_tp_hit && profit_points >= Partial_TP_Points)
{
double current_lot = PositionGetDouble(POSITION_VOLUME);
double close_size = NormalizeDouble(OpenPositions[idx].original_lot * Partial_TP_Percent / 100.0, 2);
if(close_size > 0 && close_size <= current_lot)
{
if(Trade.PositionClosePartial(ticket, close_size))
{
OpenPositions[idx].partial_tp_hit = true;
}
}
}
// Break Even
if(!OpenPositions[idx].be_set && profit_points >= BreakEven_Points)
{
if((is_buy && current_sl < entry) || (!is_buy && current_sl > entry))
{
if(Trade.PositionModify(ticket, entry, current_tp))
{
OpenPositions[idx].be_set = true;
}
}
}
// Trailing
if(profit_points >= BreakEven_Points + 100)
{
OpenPositions[idx].trailing_active = true;
double newSL = 0;
bool should_modify = false;
if(is_buy)
{
newSL = current - Trailing_Distance_Points * _Point;
if(newSL > current_sl + 30 * _Point) should_modify = true;
}
else
{
newSL = current + Trailing_Distance_Points * _Point;
if(newSL < current_sl - 30 * _Point) should_modify = true;
}
if(should_modify) Trade.PositionModify(ticket, newSL, current_tp);
}
}
}
//+------------------------------------------------------------------+
void OnTick()
{
UpdateIndicators();
DetectWarnings();
UpdateMarketMode();
ManagePositions();
static int tick_count = 0;
tick_count++;
if(tick_count >= 100)
{
CalculateLevels();
tick_count = 0;
}
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double current = (bid + ask) / 2;
double previous = iClose(_Symbol, PERIOD_CURRENT, 1);
double buffer = MA_Touch_Buffer * _Point;
//=================================================================
// SETUPS - filtered by state and mode
//=================================================================
// During pullbacks, focus on counter-pullback entries
if(Current_State == STATE_PULLBACK || Current_State == STATE_RETRACEMENT)
{
// CTRL PULLBACK entries when stoch extreme hit
if(Stoch_Extreme_Warning)
{
bool near_ma = MathAbs(current - MA_Current[3]) / Current_ATR < 1.5;
if(near_ma)
{
if(Current_Mode == MODE_BULL_TREND || Current_Mode == MODE_STRONG_BULL_TREND)
OpenTrade(true, ask, "PULLBACK-BUY", SETUP_CTRL_PULLBACK);
if(Current_Mode == MODE_BEAR_TREND || Current_Mode == MODE_STRONG_BEAR_TREND)
OpenTrade(false, bid, "PULLBACK-SELL", SETUP_CTRL_PULLBACK);
}
}
// MEAN REV at extremes
if(Stoch_K_Current <= Stoch_Extreme_Low)
OpenTrade(true, ask, "EXTREME-REV-BUY", SETUP_MEAN_REV);
if(Stoch_K_Current >= Stoch_Extreme_High)
OpenTrade(false, bid, "EXTREME-REV-SELL", SETUP_MEAN_REV);
// FIB REJECT during pullback
if(Fib_Reject_Warning)
{
if(Stoch_K_Current >= Stoch_Extreme_High)
OpenTrade(false, bid, "FIB-REJECT↓", SETUP_FIB_REJECT);
if(Stoch_K_Current <= Stoch_Extreme_Low)
OpenTrade(true, ask, "FIB-REJECT↑", SETUP_FIB_REJECT);
}
}
// Normal trend continuation setups
if(Current_State == STATE_TREND_CONTINUATION)
{
// MA14 CROSS
if(Current_Mode != MODE_CHOPPY && Current_Mode != MODE_RANGING)
{
int ma14_crosses = 0;
for(int i=0; i<10; i++) if(i != 1 && MA_Current[1] > MA_Current[i]) ma14_crosses++;
if(ma14_crosses >= 2) OpenTrade(true, ask, "MA14-CROSS↑", SETUP_MA14_CROSS);
ma14_crosses = 0;
for(int i=0; i<10; i++) if(i != 1 && MA_Current[1] < MA_Current[i]) ma14_crosses++;
if(ma14_crosses >= 2) OpenTrade(false, bid, "MA14-CROSS↓", SETUP_MA14_CROSS);
}
// MA BOUNCES
if(MathAbs(current - MA_Current[3]) <= buffer)
{
OpenTrade(true, ask, "MA50-BOUNCE↑", SETUP_MA50_BOUNCE);
OpenTrade(false, bid, "MA50-BOUNCE↓", SETUP_MA50_BOUNCE);
}
if(MathAbs(current - MA_Current[4]) <= buffer)
{
OpenTrade(true, ask, "MA140-BOUNCE↑", SETUP_MA140_BOUNCE);
OpenTrade(false, bid, "MA140-BOUNCE↓", SETUP_MA140_BOUNCE);
}
// FIB BREAKS
for(int i=1; i<6; i++)
{
if(MathAbs(current - PriceLevels[i]) <= buffer)
{
if(previous < PriceLevels[i])
OpenTrade(true, ask, "FIB-BREAK↑", SETUP_FIB_BREAK);
if(previous > PriceLevels[i])
OpenTrade(false, bid, "FIB-BREAK↓", SETUP_FIB_BREAK);
}
}
// MAGNET WALK
bool hugging = (MathAbs(current - MA_Current[2]) / Current_ATR < 0.7);
if(hugging && MA_Current[0] > MA_Current[3])
OpenTrade(true, ask, "MAGNET-WALK↑", SETUP_MAGNET_WALK);
if(hugging && MA_Current[0] < MA_Current[3])
OpenTrade(false, bid, "MAGNET-WALK↓", SETUP_MAGNET_WALK);
}
// Range setups
if(Current_Mode == MODE_RANGING)
{
if(MathAbs(current - PriceLevels[1]) < buffer && Stoch_K_Current < 35)
OpenTrade(true, ask, "RANGE-BUY", SETUP_RANGE_ENGINE);
if(MathAbs(current - PriceLevels[5]) < buffer && Stoch_K_Current > 65)
OpenTrade(false, bid, "RANGE-SELL", SETUP_RANGE_ENGINE);
}
}
//+------------------------------------------------------------------+