Vizion-Trading-EA/Experts/copus2.6.mq5
2026-02-19 23:19:25 -06:00

1254 lines
No EOL
109 KiB
MQL5

//+------------------------------------------------------------------+
//| QuarterTheory_VIZION_v7_PATTERNS.mq5 |
//| + CANDLESTICK PATTERNS: Confirmation for Structure Signals |
//| PRAISE SYSTEM: 8 Trend Signals | WAR SURVIVOR: MFIB Partials |
//+------------------------------------------------------------------+
#property copyright "QuarterTheory x VIZION"
#property version "7.00"
#property strict
#include <Trade/Trade.mqh>
CTrade Trade;
//================ CORE STRUCTURES ==================//
struct SignalParams {
int sl_points, be_points, trail_points, tp_points;
int partial_tp;
double partial_pct;
};
struct IndicatorData {
double ma[10], ma_prev[10], ma_prev2[10];
double stoch_k, stoch_k_prev, stoch_k_prev2;
double stoch_d;
double atr, adx;
};
struct MFIBLevels {
double high, low;
double level_236, level_382, level_050, level_618, level_786;
};
struct PositionRecord {
ulong ticket;
double entry, original_lot, close_price, last_mfib_partial_price;
bool is_buy, partial_tp_hit, be_set, trailing_active, is_runner;
bool closed_at_sl, closed_at_be;
int setup_type, category, entry_family, entry_bias, entry_strength;
int mfib_partials_taken;
double distance_from_current;
string setup_name;
};
struct ClosureRecord {
int setup_type, category;
bool was_buy, closed_at_sl, closed_at_be;
double close_price;
datetime close_time;
};
struct CandlePatterns {
// Bullish Patterns
bool bull_engulfing, bull_hammer, bull_morning_star;
bool bull_piercing, bull_three_white;
// Bearish Patterns
bool bear_engulfing, bear_shooting_star, bear_evening_star;
bool bear_dark_cloud, bear_three_black;
// Reversal Indicators
bool doji, spinning_top, harami;
// Counts
int bullish_count, bearish_count, reversal_count;
// Pattern Strength
bool strong_bullish_pattern, strong_bearish_pattern;
bool reversal_warning;
};
struct Warnings {
bool stoch_extreme, stoch_reject, stoch_level_cross;
bool ma7_cross_14, ma7_cross_21, ma50_break;
bool fib_reject, fib_reclaim, fib_break;
bool mfib_reject, mfib_reclaim, mfib_break;
bool ma_reject, ma_reclaim, ma_break;
bool band_snap, ma50, ma140, ma230, ma500;
bool pullback, retracement;
bool ma14_magnet, fib_break_confirmed, mfib_break_confirmed;
bool strong_ma_bounce, trend_resumption;
// Pattern-enhanced warnings
bool pattern_reversal_warn;
bool pattern_rejection_confirm;
int confluence_count;
bool confluence_3plus;
};
struct Praise {
bool triple_magnet, power_couple;
bool mfib_staircase, mfib_express, mfib_breakout;
bool ma_stack, clean_reclaim, multi_breakout;
// Pattern-enhanced praise
bool pattern_confirmation;
bool pattern_momentum_align;
int count;
};
//================ ENUMS ==================//
enum MODE_FAMILY { FAMILY_TRENDING = 0, FAMILY_RANGING = 1, FAMILY_CHOP = 2, FAMILY_TRANSITIONAL = 3 };
enum TREND_BIAS { BIAS_NEUTRAL = 0, BIAS_BULL = 1, BIAS_BEAR = -1 };
enum TREND_STRENGTH { STRENGTH_WEAK = 0, STRENGTH_CONFIRMED = 1, STRENGTH_STRONG = 2 };
enum PRICE_STATE {
STATE_CONTINUATION = 0, STATE_PULLBACK = 1, STATE_DEEP_RETRACEMENT = 2, STATE_REVERSAL_ATTEMPT = 3, STATE_REVERSAL_CONFIRMED = 4,
STATE_RANGE_MID_DRIFT = 10, STATE_RANGE_EDGE_TEST = 11, STATE_RANGE_REJECTION = 12, STATE_RANGE_BREAK_ATTEMPT = 13, STATE_RANGE_BREAK_CONFIRMED = 14,
STATE_CHOP_NOISE = 20, STATE_CHOP_VOL_SPIKE = 21, STATE_CHOP_SQUEEZE = 22, STATE_CHOP_FAKEOUT_LOOP = 23, STATE_UNKNOWN = 99
};
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, SETUP_PULLBACK_COUNTER = 17, SETUP_RETRACEMENT_COUNTER = 18
};
enum TRADE_CATEGORY { CATEGORY_CONTINUATION = 0, CATEGORY_COUNTER_TREND = 1 };
//================ 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 "=== CANDLESTICK PATTERNS ==="
input bool Use_Pattern_Detection = true;
input bool Pattern_Boost_Praise = true;
input bool Pattern_Enhance_Warnings = true;
input double Pattern_Praise_Multiplier = 1.3;
input double Pattern_Size_Threshold = 0.3; // Min body size vs ATR for pattern validity
input group "=== REVERSAL CONFIRMATION ==="
input bool Only_Close_On_Full_Reversal = true;
input group "=== MA SYSTEM ==="
input int MA_1 = 7, MA_2 = 14, MA_3 = 21, MA_4 = 50, MA_5 = 140;
input int MA_6 = 230, MA_7 = 500, MA_8 = 1000, MA_9 = 1100, 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;
input double Stoch_Extreme_Low = 15.0;
input double Stoch_High = 70.0;
input double Stoch_Low = 30.0;
input group "=== MOVING FIBONACCI ==="
input int MFIB_Lookback = 500;
input bool Use_MFIB_382_Bias = true;
input group "=== FIBONACCI ==="
input int Lookback_Bars = 200;
input bool Show_Levels = true;
input group "=== SIGNAL PARAMETERS ==="
input int Continuation_SL_Points = 150;
input int Continuation_BreakEven = 300;
input int Continuation_Trail = 300;
input int Continuation_TP = 4000;
input int Continuation_Partial_TP = 900;
input double Continuation_Partial_Pct = 33.0;
input int Counter_SL_Points = 50;
input int Counter_BreakEven = 25;
input int Counter_Trail = 150;
input int Counter_TP = 3000;
input int Counter_Partial_TP = 100;
input double Counter_Partial_Pct = 50.0;
input group "=== WAR SURVIVOR & PRAISE ==="
input bool Use_MFIB_Partials = true;
input double MFIB_Partial_Percent = 25.0;
input int MFIB_Partial_Min_Profit = 30;
input double War_Survivor_Multiplier = 2.5;
input bool Use_Praise_System = true;
input double Praise_Multiplier_Strong = 1.5;
input double Praise_Multiplier_Supreme = 2.0;
input int Praise_Tight_Trail = 100;
input bool Pause_Counter_On_Praise = true;
input bool Reduce_Continuation_Warn = true;
input bool Max_Aggression_Mode = true;
input group "=== OTHER SETTINGS ==="
input double Band_Snap_ATR_Multiplier = 2.0;
input bool Allow_Re_Entry = true;
input int Re_Entry_Cooldown_Bars = 5;
//================ GLOBALS ==================//
int Stoch_Handle, ATR_Handle, ADX_Handle;
int MA_Handles[10];
double PriceLevels[7];
IndicatorData Indicators;
MFIBLevels MFIB;
PositionRecord OpenPositions[];
ClosureRecord RecentClosures[10];
int ClosureIndex = 0;
Warnings Warn;
Praise PraiseSignals;
CandlePatterns Patterns;
MODE_FAMILY Current_Family, Prev_Family;
TREND_BIAS Current_Bias, Prev_Bias, MFIB_Bias;
TREND_STRENGTH Current_Strength, Prev_Strength;
PRICE_STATE Current_State;
int Mode_Confirmation_Count, Reversal_Confirm_Counter;
int TodayTrades = 0, BuyTrades = 0, SellTrades = 0, ClosedByReversal = 0;
int SetupCount[19];
datetime LastEntryTime[19];
double Stoch_Levels[5] = {20.0, 35.0, 50.0, 65.0, 80.0};
int MA_Periods[10] = {7, 14, 21, 50, 140, 230, 500, 1000, 1100, 1300};
//================ HELPERS ==================//
double Mid() { return (SymbolInfoDouble(_Symbol, SYMBOL_BID) + SymbolInfoDouble(_Symbol, SYMBOL_ASK)) / 2.0; }
bool Near(double price, double level, double tolPts) { return MathAbs(price - level) <= tolPts * _Point; }
bool StochUp() { return (Indicators.stoch_k_prev < Indicators.stoch_d && Indicators.stoch_k >= Indicators.stoch_d); }
bool StochDn() { return (Indicators.stoch_k_prev > Indicators.stoch_d && Indicators.stoch_k <= Indicators.stoch_d); }
bool IsBull() { return (Current_Bias == BIAS_BULL); }
bool IsBear() { return (Current_Bias == BIAS_BEAR); }
bool BullMA50Reclaim() {
bool rec = (Indicators.ma_prev[0] <= Indicators.ma_prev[3]) && (Indicators.ma[0] > Indicators.ma[3]);
double low0 = iLow(_Symbol, PERIOD_CURRENT, 0), close0 = iClose(_Symbol, PERIOD_CURRENT, 0);
bool rej = (low0 <= Indicators.ma[3] && close0 > Indicators.ma[3] && (StochUp() || Indicators.stoch_k > 50));
return (rec || rej);
}
bool BearMA50Reclaim() {
bool rec = (Indicators.ma_prev[0] >= Indicators.ma_prev[3]) && (Indicators.ma[0] < Indicators.ma[3]);
double high0 = iHigh(_Symbol, PERIOD_CURRENT, 0), close0 = iClose(_Symbol, PERIOD_CURRENT, 0);
bool rej = (high0 >= Indicators.ma[3] && close0 < Indicators.ma[3] && (StochDn() || Indicators.stoch_k < 50));
return (rec || rej);
}
void RecordClosure(int setup, int cat, bool was_buy, double close_price, bool at_sl, bool at_be) {
RecentClosures[ClosureIndex].setup_type = setup;
RecentClosures[ClosureIndex].category = cat;
RecentClosures[ClosureIndex].was_buy = was_buy;
RecentClosures[ClosureIndex].close_price = close_price;
RecentClosures[ClosureIndex].close_time = TimeCurrent();
RecentClosures[ClosureIndex].closed_at_sl = at_sl;
RecentClosures[ClosureIndex].closed_at_be = at_be;
ClosureIndex = (ClosureIndex + 1) % 10;
}
bool RecentlyStopped(int setup) {
datetime cutoff = TimeCurrent() - 10 * PeriodSeconds(PERIOD_CURRENT);
for(int i=0; i<10; i++) {
if(RecentClosures[i].setup_type == setup && RecentClosures[i].close_time > cutoff &&
(RecentClosures[i].closed_at_sl || RecentClosures[i].closed_at_be)) return true;
}
return false;
}
//+------------------------------------------------------------------+
//| CANDLESTICK PATTERN DETECTION
//+------------------------------------------------------------------+
double CandleBody(int shift) {
double open = iOpen(_Symbol, PERIOD_CURRENT, shift);
double close = iClose(_Symbol, PERIOD_CURRENT, shift);
return MathAbs(close - open);
}
double CandleRange(int shift) {
return iHigh(_Symbol, PERIOD_CURRENT, shift) - iLow(_Symbol, PERIOD_CURRENT, shift);
}
bool IsBullishCandle(int shift) {
return iClose(_Symbol, PERIOD_CURRENT, shift) > iOpen(_Symbol, PERIOD_CURRENT, shift);
}
bool IsBearishCandle(int shift) {
return iClose(_Symbol, PERIOD_CURRENT, shift) < iOpen(_Symbol, PERIOD_CURRENT, shift);
}
double UpperWick(int shift) {
double high = iHigh(_Symbol, PERIOD_CURRENT, shift);
double close = iClose(_Symbol, PERIOD_CURRENT, shift);
double open = iOpen(_Symbol, PERIOD_CURRENT, shift);
return high - MathMax(close, open);
}
double LowerWick(int shift) {
double low = iLow(_Symbol, PERIOD_CURRENT, shift);
double close = iClose(_Symbol, PERIOD_CURRENT, shift);
double open = iOpen(_Symbol, PERIOD_CURRENT, shift);
return MathMin(close, open) - low;
}
void DetectCandlePatterns() {
if(!Use_Pattern_Detection) {
ZeroMemory(Patterns);
return;
}
ZeroMemory(Patterns);
double atr = Indicators.atr;
if(atr <= 0) return;
// Get candle data
double o0 = iOpen(_Symbol, PERIOD_CURRENT, 0);
double h0 = iHigh(_Symbol, PERIOD_CURRENT, 0);
double l0 = iLow(_Symbol, PERIOD_CURRENT, 0);
double c0 = iClose(_Symbol, PERIOD_CURRENT, 0);
double o1 = iOpen(_Symbol, PERIOD_CURRENT, 1);
double h1 = iHigh(_Symbol, PERIOD_CURRENT, 1);
double l1 = iLow(_Symbol, PERIOD_CURRENT, 1);
double c1 = iClose(_Symbol, PERIOD_CURRENT, 1);
double o2 = iOpen(_Symbol, PERIOD_CURRENT, 2);
double h2 = iHigh(_Symbol, PERIOD_CURRENT, 2);
double l2 = iLow(_Symbol, PERIOD_CURRENT, 2);
double c2 = iClose(_Symbol, PERIOD_CURRENT, 2);
double body0 = CandleBody(0);
double body1 = CandleBody(1);
double body2 = CandleBody(2);
double range1 = CandleRange(1);
// Minimum body size requirement
double min_body = atr * Pattern_Size_Threshold;
//=== BULLISH ENGULFING ===
if(IsBearishCandle(1) && IsBullishCandle(0)) {
if(c0 > o1 && o0 < c1 && body0 > body1 * 1.2 && body0 > min_body) {
Patterns.bull_engulfing = true;
Patterns.bullish_count++;
}
}
//=== BEARISH ENGULFING ===
if(IsBullishCandle(1) && IsBearishCandle(0)) {
if(c0 < o1 && o0 > c1 && body0 > body1 * 1.2 && body0 > min_body) {
Patterns.bear_engulfing = true;
Patterns.bearish_count++;
}
}
//=== HAMMER (Bullish) ===
if(IsBullishCandle(1)) {
double lower_wick = LowerWick(1);
double upper_wick = UpperWick(1);
if(lower_wick > body1 * 2.0 && upper_wick < body1 * 0.5 && body1 > min_body) {
Patterns.bull_hammer = true;
Patterns.bullish_count++;
}
}
//=== SHOOTING STAR (Bearish) ===
if(IsBearishCandle(1)) {
double upper_wick = UpperWick(1);
double lower_wick = LowerWick(1);
if(upper_wick > body1 * 2.0 && lower_wick < body1 * 0.5 && body1 > min_body) {
Patterns.bear_shooting_star = true;
Patterns.bearish_count++;
}
}
//=== MORNING STAR (Bullish) ===
if(IsBearishCandle(2) && IsBullishCandle(0)) {
if(body1 < body2 * 0.3 && body1 < body0 * 0.3 && c0 > (o2 + c2) / 2 && body0 > min_body) {
Patterns.bull_morning_star = true;
Patterns.bullish_count += 2; // Strong pattern
}
}
//=== EVENING STAR (Bearish) ===
if(IsBullishCandle(2) && IsBearishCandle(0)) {
if(body1 < body2 * 0.3 && body1 < body0 * 0.3 && c0 < (o2 + c2) / 2 && body0 > min_body) {
Patterns.bear_evening_star = true;
Patterns.bearish_count += 2; // Strong pattern
}
}
//=== PIERCING PATTERN (Bullish) ===
if(IsBearishCandle(1) && IsBullishCandle(0)) {
double midpoint = c1 + (o1 - c1) * 0.5;
if(c0 > midpoint && c0 < o1 && o0 < c1 && body0 > min_body) {
Patterns.bull_piercing = true;
Patterns.bullish_count++;
}
}
//=== DARK CLOUD COVER (Bearish) ===
if(IsBullishCandle(1) && IsBearishCandle(0)) {
double midpoint = o1 + (c1 - o1) * 0.5;
if(c0 < midpoint && c0 > o1 && o0 > c1 && body0 > min_body) {
Patterns.bear_dark_cloud = true;
Patterns.bearish_count++;
}
}
//=== THREE WHITE SOLDIERS (Bullish) ===
if(IsBullishCandle(2) && IsBullishCandle(1) && IsBullishCandle(0)) {
if(c1 > c2 && c0 > c1 && o1 > o2 && o1 < c2 && o0 > o1 && o0 < c1) {
if(body0 > min_body && body1 > min_body && body2 > min_body) {
Patterns.bull_three_white = true;
Patterns.bullish_count += 2; // Very strong
}
}
}
//=== THREE BLACK CROWS (Bearish) ===
if(IsBearishCandle(2) && IsBearishCandle(1) && IsBearishCandle(0)) {
if(c1 < c2 && c0 < c1 && o1 < o2 && o1 > c2 && o0 < o1 && o0 > c1) {
if(body0 > min_body && body1 > min_body && body2 > min_body) {
Patterns.bear_three_black = true;
Patterns.bearish_count += 2; // Very strong
}
}
}
//=== DOJI (Reversal Warning) ===
if(body1 < range1 * 0.1 && range1 > min_body) {
Patterns.doji = true;
Patterns.reversal_count++;
}
//=== SPINNING TOP (Indecision) ===
if(body1 < range1 * 0.3 && body1 > range1 * 0.1) {
double upper_wick = UpperWick(1);
double lower_wick = LowerWick(1);
if(upper_wick > body1 && lower_wick > body1) {
Patterns.spinning_top = true;
Patterns.reversal_count++;
}
}
//=== HARAMI (Reversal) ===
if(body0 < body1 * 0.5) {
if(IsBearishCandle(1) && IsBullishCandle(0) && o0 > c1 && c0 < o1) {
Patterns.harami = true;
Patterns.reversal_count++;
}
if(IsBullishCandle(1) && IsBearishCandle(0) && o0 < c1 && c0 > o1) {
Patterns.harami = true;
Patterns.reversal_count++;
}
}
// Pattern Strength Assessment
Patterns.strong_bullish_pattern = (Patterns.bullish_count >= 2) ||
Patterns.bull_morning_star ||
Patterns.bull_three_white;
Patterns.strong_bearish_pattern = (Patterns.bearish_count >= 2) ||
Patterns.bear_evening_star ||
Patterns.bear_three_black;
Patterns.reversal_warning = (Patterns.reversal_count >= 1) ||
Patterns.doji ||
Patterns.harami;
}
//+------------------------------------------------------------------+
int OnInit() {
Print("========== QuarterTheory VIZION v7 (PATTERNS) ==========");
Print("CANDLESTICK PATTERNS: Structure + Pattern Confirmation");
Print("WAR SURVIVOR: 2.5x size + 25% MFIB partials");
Print("PRAISE SYSTEM: 8 Trend Signals + Pattern Boost");
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);
for(int i=0; i<10; i++) MA_Handles[i] = iMA(_Symbol, PERIOD_CURRENT, MA_Periods[i], 0, MODE_EMA, PRICE_CLOSE);
ArrayInitialize(SetupCount, 0);
ArrayInitialize(LastEntryTime, 0);
CalculateLevels();
if(Show_Levels) DrawLevels();
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, "MFIB_");
Print("Final: B:", BuyTrades, " | S:", SellTrades, " | Reversed:", ClosedByReversal);
}
//+------------------------------------------------------------------+
void CalculateLevels() {
double high = iHigh(_Symbol, PERIOD_CURRENT, 0), low = iLow(_Symbol, PERIOD_CURRENT, 0);
for(int i=1; i<=Lookback_Bars; i++) {
double h = iHigh(_Symbol, PERIOD_CURRENT, i), l = iLow(_Symbol, PERIOD_CURRENT, i);
if(h > high) high = h;
if(l < low) low = l;
}
double range = high - low;
PriceLevels[0] = low;
for(int i=1; i<6; i++) PriceLevels[i] = low + range * (i==1 ? 0.236 : i==2 ? 0.382 : i==3 ? 0.5 : i==4 ? 0.618 : 0.786);
PriceLevels[6] = high;
double ath = iHigh(_Symbol, PERIOD_CURRENT, 0), atl = iLow(_Symbol, PERIOD_CURRENT, 0);
for(int i=1; i<=MFIB_Lookback; i++) {
double h = iHigh(_Symbol, PERIOD_CURRENT, i), l = iLow(_Symbol, PERIOD_CURRENT, i);
if(h > ath) ath = h;
if(l < atl) atl = l;
}
MFIB.high = ath;
MFIB.low = atl;
double mfib_range = ath - atl;
MFIB.level_236 = ath - (mfib_range * 0.236);
MFIB.level_382 = ath - (mfib_range * 0.382);
MFIB.level_050 = ath - (mfib_range * 0.500);
MFIB.level_618 = ath - (mfib_range * 0.618);
MFIB.level_786 = ath - (mfib_range * 0.786);
if(Use_MFIB_382_Bias) {
double current = Mid();
if(current > MFIB.level_382) MFIB_Bias = BIAS_BULL;
else if(current < MFIB.level_382) MFIB_Bias = BIAS_BEAR;
else MFIB_Bias = BIAS_NEUTRAL;
} else MFIB_Bias = BIAS_NEUTRAL;
}
void DrawLevels() {
ObjectsDeleteAll(0, "Level_");
ObjectsDeleteAll(0, "MFIB_");
color level_colors[7] = {clrRed, clrOrange, clrYellow, clrLime, clrCyan, clrBlue, clrMagenta};
for(int i=0; i<7; i++) {
ObjectCreate(0, "Level_" + IntegerToString(i), OBJ_HLINE, 0, 0, PriceLevels[i]);
ObjectSetInteger(0, "Level_" + IntegerToString(i), OBJPROP_COLOR, level_colors[i]);
ObjectSetInteger(0, "Level_" + IntegerToString(i), OBJPROP_STYLE, STYLE_DOT);
}
ObjectCreate(0, "MFIB_382", OBJ_HLINE, 0, 0, MFIB.level_382);
ObjectSetInteger(0, "MFIB_382", OBJPROP_COLOR, clrYellow);
ObjectSetInteger(0, "MFIB_382", OBJPROP_WIDTH, 2);
ObjectCreate(0, "MFIB_618", OBJ_HLINE, 0, 0, MFIB.level_618);
ObjectSetInteger(0, "MFIB_618", OBJPROP_COLOR, clrCyan);
ObjectSetInteger(0, "MFIB_618", OBJPROP_WIDTH, 2);
}
//+------------------------------------------------------------------+
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) Indicators.ma[i] = curr[0];
if(CopyBuffer(MA_Handles[i], 0, 1, 1, prev) > 0) Indicators.ma_prev[i] = prev[0];
if(CopyBuffer(MA_Handles[i], 0, 2, 1, prev2) > 0) Indicators.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) Indicators.stoch_k = k_curr[0];
if(CopyBuffer(Stoch_Handle, MAIN_LINE, 1, 1, k_prev) > 0) Indicators.stoch_k_prev = k_prev[0];
if(CopyBuffer(Stoch_Handle, MAIN_LINE, 2, 1, k_prev2) > 0) Indicators.stoch_k_prev2 = k_prev2[0];
if(CopyBuffer(Stoch_Handle, SIGNAL_LINE, 0, 1, d_curr) > 0) Indicators.stoch_d = d_curr[0];
double atr[1], adx[1];
if(CopyBuffer(ATR_Handle, 0, 0, 1, atr) > 0) Indicators.atr = atr[0];
if(CopyBuffer(ADX_Handle, 0, 0, 1, adx) > 0) Indicators.adx = adx[0];
}
//+------------------------------------------------------------------+
void DetectWarnings() {
double current = Mid(), prev = iClose(_Symbol, PERIOD_CURRENT, 1), bufPts = (double)MA_Touch_Buffer;
double mfib_levels[5] = {MFIB.level_236, MFIB.level_382, MFIB.level_050, MFIB.level_618, MFIB.level_786};
ZeroMemory(Warn);
if(Indicators.stoch_k <= Stoch_Extreme_Low || Indicators.stoch_k >= Stoch_Extreme_High) Warn.stoch_extreme = true;
bool k_crossed_d = (Indicators.stoch_k_prev < Indicators.stoch_d && Indicators.stoch_k >= Indicators.stoch_d) ||
(Indicators.stoch_k_prev > Indicators.stoch_d && Indicators.stoch_k <= Indicators.stoch_d);
bool near_key = false;
for(int i=0; i<5; i++) if(MathAbs(Indicators.stoch_k - Stoch_Levels[i]) <= 5.0) { near_key = true; break; }
if(k_crossed_d && near_key) Warn.stoch_level_cross = true;
bool stoch_reject_dn = (StochDn() && Indicators.stoch_k > 50);
bool stoch_reject_up = (StochUp() && Indicators.stoch_k < 50);
if(stoch_reject_dn || stoch_reject_up || Warn.stoch_level_cross) Warn.stoch_reject = true;
bool ma7_crossed_14_dn = (Indicators.ma_prev[0] > Indicators.ma_prev[1]) && (Indicators.ma[0] <= Indicators.ma[1]);
bool ma7_crossed_14_up = (Indicators.ma_prev[0] < Indicators.ma_prev[1]) && (Indicators.ma[0] >= Indicators.ma[1]);
if(ma7_crossed_14_dn || ma7_crossed_14_up) { Warn.ma7_cross_14 = true; Warn.pullback = true; }
bool ma7_crossed_21_dn = (Indicators.ma_prev[0] > Indicators.ma_prev[2]) && (Indicators.ma[0] <= Indicators.ma[2]);
bool ma7_crossed_21_up = (Indicators.ma_prev[0] < Indicators.ma_prev[2]) && (Indicators.ma[0] >= Indicators.ma[2]);
if(ma7_crossed_21_dn || ma7_crossed_21_up) { Warn.ma7_cross_21 = true; Warn.retracement = true; }
bool ma7_broke_50_dn = (Indicators.ma_prev[0] > Indicators.ma_prev[3]) && (Indicators.ma[0] <= Indicators.ma[3]);
bool ma7_broke_50_up = (Indicators.ma_prev[0] < Indicators.ma_prev[3]) && (Indicators.ma[0] >= Indicators.ma[3]);
if(ma7_broke_50_dn || ma7_broke_50_up) Warn.ma50_break = true;
if(Indicators.atr > 0.0) {
double distance = MathAbs(current - Indicators.ma[0]);
if(distance >= Indicators.atr * Band_Snap_ATR_Multiplier) Warn.band_snap = true;
}
bool at_fib = false;
int fib_idx = -1;
for(int i=1; i<6; i++) if(Near(current, PriceLevels[i], bufPts)) { at_fib = true; fib_idx = i; break; }
if(at_fib) {
if(Warn.stoch_extreme || Warn.stoch_reject || Warn.stoch_level_cross) Warn.fib_reject = true;
if((prev < PriceLevels[fib_idx] && current > PriceLevels[fib_idx]) ||
(prev > PriceLevels[fib_idx] && current < PriceLevels[fib_idx])) Warn.fib_reclaim = true;
if(MathAbs(current - PriceLevels[fib_idx]) > bufPts * 1.5) Warn.fib_break = true;
}
bool at_mfib = false;
double mfib_level = 0;
for(int i=0; i<5; i++) if(Near(current, mfib_levels[i], bufPts)) { at_mfib = true; mfib_level = mfib_levels[i]; break; }
if(at_mfib) {
if(Warn.stoch_extreme || Warn.stoch_reject || Warn.stoch_level_cross) Warn.mfib_reject = true;
if((prev < mfib_level && current > mfib_level) || (prev > mfib_level && current < mfib_level)) Warn.mfib_reclaim = true;
if(MathAbs(current - mfib_level) > bufPts * 1.5) Warn.mfib_break = true;
}
if(Near(current, Indicators.ma[3], bufPts)) Warn.ma50 = true;
if(Near(current, Indicators.ma[4], bufPts)) Warn.ma140 = true;
if(Near(current, Indicators.ma[5], bufPts)) Warn.ma230 = true;
if(Near(current, Indicators.ma[6], bufPts)) Warn.ma500 = true;
if((Warn.ma50 || Warn.ma140 || Warn.ma230 || Warn.ma500) &&
(Warn.stoch_extreme || Warn.stoch_reject || Warn.stoch_level_cross)) Warn.ma_reject = true;
if(Warn.ma50 && ((prev < Indicators.ma[3] && current > Indicators.ma[3]) || (prev > Indicators.ma[3] && current < Indicators.ma[3]))) Warn.ma_reclaim = true;
if(Warn.ma140 && ((prev < Indicators.ma[4] && current > Indicators.ma[4]) || (prev > Indicators.ma[4] && current < Indicators.ma[4]))) Warn.ma_reclaim = true;
if((Warn.ma50 || Warn.ma140 || Warn.ma230) && MathAbs(current - Indicators.ma[3]) > bufPts * 2) Warn.ma_break = true;
// PATTERN-ENHANCED WARNINGS
if(Pattern_Enhance_Warnings && Use_Pattern_Detection) {
// Reversal patterns confirm warning signals
if(Patterns.reversal_warning && (Warn.stoch_extreme || Warn.ma_reject || Warn.fib_reject)) {
Warn.pattern_reversal_warn = true;
}
// Bearish patterns confirm bullish rejections
if(IsBull() && Patterns.strong_bearish_pattern && (Warn.ma_reject || Warn.fib_reject || Warn.mfib_reject)) {
Warn.pattern_rejection_confirm = true;
}
// Bullish patterns confirm bearish rejections
if(IsBear() && Patterns.strong_bullish_pattern && (Warn.ma_reject || Warn.fib_reject || Warn.mfib_reject)) {
Warn.pattern_rejection_confirm = true;
}
}
Warn.confluence_count = 0;
if(Warn.stoch_extreme) Warn.confluence_count++;
if(Warn.stoch_reject) Warn.confluence_count++;
if(Warn.stoch_level_cross) Warn.confluence_count++;
if(Warn.ma7_cross_14) Warn.confluence_count++;
if(Warn.ma7_cross_21) Warn.confluence_count++;
if(Warn.ma50_break) Warn.confluence_count++;
if(Warn.fib_reject) Warn.confluence_count++;
if(Warn.mfib_reject) Warn.confluence_count++;
if(Warn.ma_reject) Warn.confluence_count++;
if(Warn.fib_reclaim) Warn.confluence_count++;
if(Warn.mfib_reclaim) Warn.confluence_count++;
if(Warn.ma_reclaim) Warn.confluence_count++;
if(Warn.band_snap) Warn.confluence_count++;
if(Warn.ma50) Warn.confluence_count++;
if(Warn.ma140) Warn.confluence_count++;
if(Warn.ma230) Warn.confluence_count++;
if(Warn.ma500) Warn.confluence_count++;
if(Warn.pattern_reversal_warn) Warn.confluence_count++;
if(Warn.pattern_rejection_confirm) Warn.confluence_count++;
Warn.confluence_3plus = (Warn.confluence_count >= 3);
if(Indicators.atr > 0.0) {
double dist_ma14 = MathAbs(current - Indicators.ma[1]) / Indicators.atr;
Warn.ma14_magnet = (dist_ma14 < 0.7);
}
for(int i=1; i<6; i++) {
if(MathAbs(prev - PriceLevels[i]) < bufPts * 0.5 && MathAbs(current - PriceLevels[i]) > bufPts * 2.0) {
Warn.fib_break_confirmed = true;
break;
}
}
for(int i=0; i<5; i++) {
if(MathAbs(prev - mfib_levels[i]) < bufPts * 0.5 && MathAbs(current - mfib_levels[i]) > bufPts * 2.0) {
Warn.mfib_break_confirmed = true;
break;
}
}
bool at_strong_ma = (Warn.ma140 || Warn.ma230 || Warn.ma500);
if(at_strong_ma) {
bool ma140_bounce = Warn.ma140 && ((prev < Indicators.ma[4] && current > Indicators.ma[4]) || (prev > Indicators.ma[4] && current < Indicators.ma[4]));
bool ma230_bounce = Warn.ma230 && ((prev < Indicators.ma[5] && current > Indicators.ma[5]) || (prev > Indicators.ma[5] && current < Indicators.ma[5]));
bool ma500_bounce = Warn.ma500 && ((prev < Indicators.ma[6] && current > Indicators.ma[6]) || (prev > Indicators.ma[6] && current < Indicators.ma[6]));
if((ma140_bounce || ma230_bounce || ma500_bounce) &&
(Warn.stoch_level_cross || Warn.stoch_reject)) Warn.strong_ma_bounce = true;
}
Warn.trend_resumption = (IsBull() && BullMA50Reclaim()) || (IsBear() && BearMA50Reclaim());
}
void DetectPraiseSignals() {
if(!Use_Praise_System) { PraiseSignals.count = 0; return; }
double current = Mid(), bufPts = (double)MA_Touch_Buffer;
ZeroMemory(PraiseSignals);
if(Indicators.atr > 0.0) {
double d7 = MathAbs(current - Indicators.ma[0]) / Indicators.atr;
double d14 = MathAbs(current - Indicators.ma[1]) / Indicators.atr;
double d21 = MathAbs(current - Indicators.ma[2]) / Indicators.atr;
bool all_close = (d7 < 0.5) && (d14 < 0.7) && (d21 < 0.9);
bool trending = (Indicators.ma[0] > Indicators.ma_prev[0] && Indicators.ma[1] > Indicators.ma_prev[1] && Indicators.ma[2] > Indicators.ma_prev[2]) ||
(Indicators.ma[0] < Indicators.ma_prev[0] && Indicators.ma[1] < Indicators.ma_prev[1] && Indicators.ma[2] < Indicators.ma_prev[2]);
if(all_close && trending && !Warn.band_snap) PraiseSignals.triple_magnet = true;
}
if(Indicators.atr > 0.0) {
double dist = MathAbs(Indicators.ma[1] - Indicators.ma[2]) / Indicators.atr;
bool close = (dist < 0.3);
bool same_dir = (Indicators.ma[1] > Indicators.ma_prev[1] && Indicators.ma[2] > Indicators.ma_prev[2]) ||
(Indicators.ma[1] < Indicators.ma_prev[1] && Indicators.ma[2] < Indicators.ma_prev[2]);
bool side = (IsBull() && Indicators.ma[0] > Indicators.ma[1]) || (IsBear() && Indicators.ma[0] < Indicators.ma[1]);
bool hugging = MathAbs(current - Indicators.ma[1]) / Indicators.atr < 0.8 || MathAbs(current - Indicators.ma[2]) / Indicators.atr < 0.8;
if(close && same_dir && side && hugging) PraiseSignals.power_couple = true;
}
bool stack_bull = (Indicators.ma[0] > Indicators.ma[1]) && (Indicators.ma[1] > Indicators.ma[2]) && (Indicators.ma[2] > Indicators.ma[3]) && (Indicators.ma[3] > Indicators.ma[4]);
bool stack_bear = (Indicators.ma[0] < Indicators.ma[1]) && (Indicators.ma[1] < Indicators.ma[2]) && (Indicators.ma[2] < Indicators.ma[3]) && (Indicators.ma[3] < Indicators.ma[4]);
bool properly_spaced = true;
if(Indicators.atr > 0.0) {
for(int i=0; i<4; i++) {
double spacing = MathAbs(Indicators.ma[i] - Indicators.ma[i+1]) / Indicators.atr;
if(spacing < 0.1) { properly_spaced = false; break; }
}
}
bool all_trending = true;
for(int i=0; i<5; i++) if(MathAbs(Indicators.ma[i] - Indicators.ma_prev[i]) / _Point < 5) { all_trending = false; break; }
if((stack_bull || stack_bear) && properly_spaced && all_trending) PraiseSignals.ma_stack = true;
if(Warn.mfib_break_confirmed && Indicators.adx > 25) PraiseSignals.mfib_breakout = true;
if(Warn.fib_break_confirmed && Indicators.adx > 25) PraiseSignals.multi_breakout = true;
// PATTERN-ENHANCED PRAISE
if(Pattern_Boost_Praise && Use_Pattern_Detection) {
// Bullish patterns align with bullish structure
if(IsBull() && Patterns.strong_bullish_pattern &&
(PraiseSignals.ma_stack || PraiseSignals.triple_magnet || PraiseSignals.power_couple)) {
PraiseSignals.pattern_confirmation = true;
}
// Bearish patterns align with bearish structure
if(IsBear() && Patterns.strong_bearish_pattern &&
(PraiseSignals.ma_stack || PraiseSignals.triple_magnet || PraiseSignals.power_couple)) {
PraiseSignals.pattern_confirmation = true;
}
// Multiple bullish patterns with trend momentum
if(IsBull() && Patterns.bullish_count >= 2 && Indicators.adx > 25 && !Warn.band_snap) {
PraiseSignals.pattern_momentum_align = true;
}
// Multiple bearish patterns with trend momentum
if(IsBear() && Patterns.bearish_count >= 2 && Indicators.adx > 25 && !Warn.band_snap) {
PraiseSignals.pattern_momentum_align = true;
}
}
PraiseSignals.count = 0;
if(PraiseSignals.triple_magnet) PraiseSignals.count++;
if(PraiseSignals.power_couple) PraiseSignals.count++;
if(PraiseSignals.mfib_staircase) PraiseSignals.count++;
if(PraiseSignals.mfib_express) PraiseSignals.count++;
if(PraiseSignals.mfib_breakout) PraiseSignals.count++;
if(PraiseSignals.ma_stack) PraiseSignals.count++;
if(PraiseSignals.clean_reclaim) PraiseSignals.count++;
if(PraiseSignals.multi_breakout) PraiseSignals.count++;
if(PraiseSignals.pattern_confirmation) PraiseSignals.count++;
if(PraiseSignals.pattern_momentum_align) PraiseSignals.count++;
}
void DetectFamilyBiasStrength(MODE_FAMILY &family, TREND_BIAS &bias, TREND_STRENGTH &strength) {
double current = Mid();
bool mas_bull = (Indicators.ma[0] > Indicators.ma[1]) && (Indicators.ma[1] > Indicators.ma[2]) && (Indicators.ma[2] > Indicators.ma[3]);
bool mas_bear = (Indicators.ma[0] < Indicators.ma[1]) && (Indicators.ma[1] < Indicators.ma[2]) && (Indicators.ma[2] < Indicators.ma[3]);
double recent_high = iHigh(_Symbol, PERIOD_CURRENT, 0), 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 = false;
if(Indicators.atr > 0.0) ma_clustered = ((MathAbs(Indicators.ma[0] - Indicators.ma[3]) / Indicators.atr) < Chop_ATR_Threshold);
bool is_choppy = (ma_clustered || Indicators.adx < 15);
if(mas_bull && (MFIB_Bias == BIAS_BULL || !Use_MFIB_382_Bias)) bias = BIAS_BULL;
else if(mas_bear && (MFIB_Bias == BIAS_BEAR || !Use_MFIB_382_Bias)) bias = BIAS_BEAR;
else if(MFIB_Bias == BIAS_BULL && Indicators.ma[0] > Indicators.ma[3]) bias = BIAS_BULL;
else if(MFIB_Bias == BIAS_BEAR && Indicators.ma[0] < Indicators.ma[3]) bias = BIAS_BEAR;
else if(Indicators.ma[0] > Indicators.ma[3]) bias = BIAS_BULL;
else if(Indicators.ma[0] < Indicators.ma[3]) bias = BIAS_BEAR;
else bias = BIAS_NEUTRAL;
if(is_choppy && !(mas_bull || mas_bear)) family = FAMILY_CHOP;
else if(is_ranging && !(mas_bull || mas_bear)) family = FAMILY_RANGING;
else if(bias != BIAS_NEUTRAL) family = FAMILY_TRENDING;
else family = FAMILY_TRANSITIONAL;
if(Indicators.adx > 25 && (mas_bull || mas_bear)) strength = STRENGTH_STRONG;
else if(Indicators.adx > 18 && (mas_bull || mas_bear)) strength = STRENGTH_CONFIRMED;
else strength = STRENGTH_WEAK;
}
PRICE_STATE DetermineState() {
if(Current_Family == FAMILY_RANGING) {
double current = Mid(), bufPts = (double)MA_Touch_Buffer;
bool near_low = Near(current, PriceLevels[1], bufPts) || Near(current, PriceLevels[0], bufPts);
bool near_high = Near(current, PriceLevels[5], bufPts) || Near(current, PriceLevels[6], bufPts);
if(near_low || near_high) return STATE_RANGE_EDGE_TEST;
if(Warn.stoch_reject || Warn.stoch_extreme || Warn.fib_reject || Warn.mfib_reject) return STATE_RANGE_REJECTION;
return STATE_RANGE_MID_DRIFT;
}
if(Current_Family == FAMILY_CHOP) {
if(Indicators.adx < 12 && !Warn.stoch_reject) return STATE_CHOP_NOISE;
if(Warn.stoch_reject) return STATE_CHOP_FAKEOUT_LOOP;
return STATE_CHOP_NOISE;
}
bool ma7_above_50 = (Indicators.ma[0] > Indicators.ma[3]);
bool ma7_below_50 = (Indicators.ma[0] < Indicators.ma[3]);
bool ma14_above_50 = (Indicators.ma[1] > Indicators.ma[3]);
bool ma14_below_50 = (Indicators.ma[1] < Indicators.ma[3]);
bool pullback_sig = (Warn.pullback || Warn.mfib_reject || Warn.fib_reject || Warn.stoch_reject || Warn.band_snap || Warn.stoch_level_cross);
bool retrace_sig = (Warn.ma7_cross_21 || Warn.retracement || Warn.ma140 || Warn.ma230 || Warn.ma500);
bool strong_ma_pressure = (Warn.ma140 || Warn.ma230 || Warn.ma500 || Warn.ma50);
if(IsBull()) {
if(ma7_below_50 && !ma14_above_50) return STATE_REVERSAL_CONFIRMED;
if(Warn.ma50_break && (retrace_sig || strong_ma_pressure || Warn.stoch_extreme || Warn.confluence_3plus)) return STATE_REVERSAL_ATTEMPT;
if(Warn.ma7_cross_21 || strong_ma_pressure || (!Indicators.ma[0] > Indicators.ma[2] && (pullback_sig || retrace_sig))) return STATE_DEEP_RETRACEMENT;
if(Warn.ma7_cross_14 || (ma14_above_50 && pullback_sig)) return STATE_PULLBACK;
return STATE_CONTINUATION;
}
if(IsBear()) {
if(ma7_above_50 && !ma14_below_50) return STATE_REVERSAL_CONFIRMED;
if(Warn.ma50_break && (retrace_sig || strong_ma_pressure || Warn.stoch_extreme || Warn.confluence_3plus)) return STATE_REVERSAL_ATTEMPT;
if(Warn.ma7_cross_21 || strong_ma_pressure || (!Indicators.ma[0] < Indicators.ma[2] && (pullback_sig || retrace_sig))) return STATE_DEEP_RETRACEMENT;
if(Warn.ma7_cross_14 || (ma14_below_50 && pullback_sig)) return STATE_PULLBACK;
return STATE_CONTINUATION;
}
return STATE_UNKNOWN;
}
string StateStr(PRICE_STATE s) {
if(s == STATE_CONTINUATION) return "CONT";
if(s == STATE_PULLBACK) return "PULLBACK";
if(s == STATE_DEEP_RETRACEMENT) return "RETRACE";
if(s == STATE_REVERSAL_CONFIRMED) return "REV-CONF";
if(s == STATE_RANGE_EDGE_TEST) return "RANGE-EDGE";
if(s == STATE_CHOP_NOISE) return "CHOP";
return "UNKNOWN";
}
string BiasStr(TREND_BIAS b) { return (b == BIAS_BULL ? "BULL" : (b == BIAS_BEAR ? "BEAR" : "NEUTRAL")); }
string FamilyStr(MODE_FAMILY f) { return (f == FAMILY_TRENDING ? "TREND" : (f == FAMILY_RANGING ? "RANGE" : (f == FAMILY_CHOP ? "CHOP" : "TRANS"))); }
void UpdateLabels() {
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, 20);
string mode_text = FamilyStr(Current_Family) + " | " + BiasStr(Current_Bias) + " | " + StateStr(Current_State);
mode_text += " | P:" + IntegerToString(PraiseSignals.count) + " W:" + IntegerToString(Warn.confluence_count);
// Add pattern info
if(Use_Pattern_Detection) {
mode_text += " | Bull:" + IntegerToString(Patterns.bullish_count) + " Bear:" + IntegerToString(Patterns.bearish_count);
}
color txt_color = clrWhite;
if(Current_Family == FAMILY_TRENDING && IsBull()) txt_color = clrLime;
else if(Current_Family == FAMILY_TRENDING && IsBear()) txt_color = clrRed;
else if(Current_Family == FAMILY_RANGING) txt_color = clrCyan;
else if(Current_Family == FAMILY_CHOP) txt_color = clrViolet;
ObjectSetString(0, "StateLabel", OBJPROP_TEXT, mode_text);
ObjectSetInteger(0, "StateLabel", OBJPROP_COLOR, txt_color);
ObjectSetInteger(0, "StateLabel", OBJPROP_FONTSIZE, 11);
}
void UpdateModeAndState() {
MODE_FAMILY detected_family;
TREND_BIAS detected_bias;
TREND_STRENGTH detected_strength;
DetectFamilyBiasStrength(detected_family, detected_bias, detected_strength);
Current_Family = detected_family;
Current_Bias = detected_bias;
Current_Strength = detected_strength;
Current_State = DetermineState();
UpdateLabels();
}
void MarkRunners() {
double current = Mid();
for(int i=0; i<ArraySize(OpenPositions); i++) {
if(PositionSelectByTicket(OpenPositions[i].ticket)) {
OpenPositions[i].distance_from_current = MathAbs(current - OpenPositions[i].entry) / _Point;
}
}
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) {
PositionRecord tmp = OpenPositions[i];
OpenPositions[i] = OpenPositions[j];
OpenPositions[j] = tmp;
}
}
}
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("REVERSAL - Closing opposing positions");
for(int i=PositionsTotal()-1; i>=0; i--) {
if(!PositionGetTicket(i)) 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);
int idx = -1;
for(int j=0; j<ArraySize(OpenPositions); j++) if(OpenPositions[j].ticket == ticket) { idx = j; break; }
if(idx >= 0 && OpenPositions[idx].is_runner) continue;
bool should_close = (is_buy && IsBear()) || (!is_buy && IsBull());
if(should_close) { if(Trade.PositionClose(ticket)) ClosedByReversal++; }
}
}
bool IsDirectionAllowed(bool is_buy) {
if(!Use_Market_Mode_Filter) return true;
if(Current_Family == FAMILY_TRENDING) {
if(Current_State == STATE_REVERSAL_CONFIRMED) {
if(IsBull() && !is_buy) return false;
if(IsBear() && is_buy) return false;
return true;
}
if(Current_State == STATE_PULLBACK || Current_State == STATE_DEEP_RETRACEMENT) {
if(IsBull()) return (!is_buy && !BullMA50Reclaim()) || (is_buy && BullMA50Reclaim());
if(IsBear()) return (is_buy && !BearMA50Reclaim()) || (!is_buy && BearMA50Reclaim());
}
if(Current_State == STATE_CONTINUATION) {
if(IsBull() && !is_buy) return false;
if(IsBear() && is_buy) return false;
}
}
return true;
}
int CountSetupTrades(int setup) {
int count = 0;
for(int i=0; i<PositionsTotal(); i++) {
if(!PositionGetTicket(i)) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
ulong t = PositionGetTicket(i);
for(int j=0; j<ArraySize(OpenPositions); j++) {
if(OpenPositions[j].ticket == t && OpenPositions[j].setup_type == setup) count++;
}
}
return count;
}
SignalParams GetSignalParams(int category) {
SignalParams p;
if(category == CATEGORY_COUNTER_TREND) {
p.sl_points = Counter_SL_Points;
p.be_points = Counter_BreakEven;
p.trail_points = Counter_Trail;
p.tp_points = Counter_TP;
p.partial_tp = Counter_Partial_TP;
p.partial_pct = Counter_Partial_Pct;
} else {
p.sl_points = Continuation_SL_Points;
p.be_points = Continuation_BreakEven;
p.trail_points = Continuation_Trail;
p.tp_points = Continuation_TP;
p.partial_tp = Continuation_Partial_TP;
p.partial_pct = Continuation_Partial_Pct;
}
return p;
}
double GetLotSize(int category) {
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);
SignalParams p = GetSignalParams(category);
double lot = risk / ((p.sl_points * _Point / tickSize) * tickValue);
if(Use_MFIB_Partials) lot = lot * War_Survivor_Multiplier;
if(Use_Praise_System) {
if(category == CATEGORY_CONTINUATION) {
// Pattern boost for continuation trades
if(Pattern_Boost_Praise && (PraiseSignals.pattern_confirmation || PraiseSignals.pattern_momentum_align)) {
lot = lot * Pattern_Praise_Multiplier;
}
if(PraiseSignals.count >= 4) lot = lot * Praise_Multiplier_Supreme;
else if(PraiseSignals.count == 3) lot = lot * Praise_Multiplier_Strong;
if(Reduce_Continuation_Warn && Warn.confluence_count >= 3) lot = lot * 0.5;
} else if(category == CATEGORY_COUNTER_TREND) {
if(Pause_Counter_On_Praise && PraiseSignals.count >= 3) lot = lot * 0.25;
}
}
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, int setup_type, int category) {
if(!IsDirectionAllowed(buy)) return;
if(!Allow_Re_Entry || (TimeCurrent() - LastEntryTime[setup_type] >= 1)) {
if(CountSetupTrades(setup_type) >= Max_Trades_Per_Setup) return;
if(PositionsTotal() >= Max_Total_Trades) return;
double lot = GetLotSize(category);
if(lot < SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN)) return;
SignalParams p = GetSignalParams(category);
double sl = buy ? price - p.sl_points * _Point : price + p.sl_points * _Point;
double tp = buy ? price + p.tp_points * _Point : price - p.tp_points * _Point;
string comment = setup_name + "|" + (category == CATEGORY_COUNTER_TREND ? "CTR" : "CONT");
bool result = buy ? Trade.Buy(lot, _Symbol, 0, sl, tp, comment) : Trade.Sell(lot, _Symbol, 0, sl, tp, comment);
if(result) {
LastEntryTime[setup_type] = TimeCurrent();
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].setup_type = setup_type;
OpenPositions[size].category = category;
OpenPositions[size].setup_name = setup_name;
OpenPositions[size].entry_family = Current_Family;
OpenPositions[size].entry_bias = Current_Bias;
OpenPositions[size].entry_strength = Current_Strength;
}
}
}
void ManagePositions() {
for(int i=PositionsTotal()-1; i>=0; i--) {
ulong ticket = PositionGetTicket(i);
if(!ticket) 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;
int cat = OpenPositions[idx].category;
double current = is_buy ? SymbolInfoDouble(_Symbol, SYMBOL_BID) : SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double profit_points = is_buy ? (current - entry) / _Point : (entry - current) / _Point;
SignalParams p = GetSignalParams(cat);
int trail = p.trail_points;
if(Use_Praise_System && cat == CATEGORY_CONTINUATION && PraiseSignals.count >= 4) trail = Praise_Tight_Trail;
if(!OpenPositions[idx].partial_tp_hit && profit_points >= p.partial_tp) {
double current_lot = PositionGetDouble(POSITION_VOLUME);
double close_size = NormalizeDouble(OpenPositions[idx].original_lot * p.partial_pct / 100.0, 2);
if(close_size > 0 && close_size <= current_lot) {
if(Trade.PositionClosePartial(ticket, close_size)) OpenPositions[idx].partial_tp_hit = true;
}
}
if(Use_MFIB_Partials && profit_points >= MFIB_Partial_Min_Profit && OpenPositions[idx].mfib_partials_taken < 4) {
double mfib_levels[5] = {MFIB.level_236, MFIB.level_382, MFIB.level_050, MFIB.level_618, MFIB.level_786};
bool at_mfib = false;
double mfib_price = 0;
for(int m=0; m<5; m++) {
if(MathAbs(current - mfib_levels[m]) / _Point <= 50) {
if((Warn.mfib_reject || Warn.stoch_reject || Warn.stoch_extreme || Warn.confluence_3plus) &&
(OpenPositions[idx].last_mfib_partial_price == 0 || MathAbs(current - OpenPositions[idx].last_mfib_partial_price) / _Point > 100)) {
at_mfib = true;
mfib_price = mfib_levels[m];
break;
}
}
}
if(at_mfib) {
double current_lot = PositionGetDouble(POSITION_VOLUME);
double close_size = NormalizeDouble(OpenPositions[idx].original_lot * MFIB_Partial_Percent / 100.0, 2);
if(close_size > current_lot) close_size = current_lot * 0.25;
if(close_size > 0 && close_size >= SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN)) {
if(Trade.PositionClosePartial(ticket, close_size)) {
OpenPositions[idx].mfib_partials_taken++;
OpenPositions[idx].last_mfib_partial_price = mfib_price;
}
}
}
}
if(!OpenPositions[idx].be_set && profit_points >= p.be_points) {
if((is_buy && current_sl < entry) || (!is_buy && current_sl > entry)) {
if(Trade.PositionModify(ticket, entry, current_tp)) OpenPositions[idx].be_set = true;
}
}
if(profit_points >= p.be_points + 50) {
OpenPositions[idx].trailing_active = true;
double newSL = is_buy ? current - trail * _Point : current + trail * _Point;
bool should_modify = is_buy ? (newSL > current_sl + 30 * _Point) : (newSL < current_sl - 30 * _Point);
if(should_modify) Trade.PositionModify(ticket, newSL, current_tp);
}
OpenPositions[idx].close_price = current;
}
for(int i=ArraySize(OpenPositions)-1; i>=0; i--) {
if(!PositionSelectByTicket(OpenPositions[i].ticket)) {
double entry = OpenPositions[i].entry;
double close_price = OpenPositions[i].close_price;
bool is_buy = OpenPositions[i].is_buy;
bool at_be = (MathAbs(close_price - entry) / _Point < 10);
bool at_sl = !at_be && ((is_buy && close_price < entry) || (!is_buy && close_price > entry));
RecordClosure(OpenPositions[i].setup_type, OpenPositions[i].category, OpenPositions[i].is_buy, close_price, at_sl, at_be);
for(int j=i; j<ArraySize(OpenPositions)-1; j++) OpenPositions[j] = OpenPositions[j+1];
ArrayResize(OpenPositions, ArraySize(OpenPositions)-1);
}
}
}
void OnTick() {
UpdateIndicators();
DetectCandlePatterns(); // NEW: Pattern detection
DetectWarnings();
DetectPraiseSignals();
static int tick_count = 0;
tick_count++;
if(tick_count >= 100) {
CalculateLevels();
if(Show_Levels) DrawLevels();
tick_count = 0;
}
UpdateModeAndState();
ManagePositions();
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double current = (bid + ask) / 2.0;
double buffer = MA_Touch_Buffer * _Point;
if(Current_Family == FAMILY_TRENDING && Current_State == STATE_CONTINUATION) {
if(IsBull()) {
if(Indicators.ma[0] > Indicators.ma[1]) OpenTrade(true, ask, "MA-CROSS↑", SETUP_MA14_CROSS, CATEGORY_CONTINUATION);
if(Near(current, Indicators.ma[3], buffer)) OpenTrade(true, ask, "MA50-BOUNCE↑", SETUP_MA50_BOUNCE, CATEGORY_CONTINUATION);
if(Near(current, Indicators.ma[4], buffer)) OpenTrade(true, ask, "MA140-BOUNCE↑", SETUP_MA140_BOUNCE, CATEGORY_CONTINUATION);
if(Near(current, Indicators.ma[5], buffer)) OpenTrade(true, ask, "MA230-BOUNCE↑", SETUP_MA230_BOUNCE, CATEGORY_CONTINUATION);
bool stack = (Indicators.ma[0] > Indicators.ma[1]) && (Indicators.ma[1] > Indicators.ma[2]) && (Indicators.ma[2] > Indicators.ma[3]) && (Indicators.ma[3] > Indicators.ma[4]);
if(stack && Indicators.adx > 25 && !Warn.band_snap) OpenTrade(true, ask, "STAIRCASE↑", SETUP_STAIRCASE_ADV, CATEGORY_CONTINUATION);
} else if(IsBear()) {
if(Indicators.ma[0] < Indicators.ma[1]) OpenTrade(false, bid, "MA-CROSS↓", SETUP_MA14_CROSS, CATEGORY_CONTINUATION);
if(Near(current, Indicators.ma[3], buffer)) OpenTrade(false, bid, "MA50-BOUNCE↓", SETUP_MA50_BOUNCE, CATEGORY_CONTINUATION);
if(Near(current, Indicators.ma[4], buffer)) OpenTrade(false, bid, "MA140-BOUNCE↓", SETUP_MA140_BOUNCE, CATEGORY_CONTINUATION);
bool stack = (Indicators.ma[0] < Indicators.ma[1]) && (Indicators.ma[1] < Indicators.ma[2]) && (Indicators.ma[2] < Indicators.ma[3]) && (Indicators.ma[3] < Indicators.ma[4]);
if(stack && Indicators.adx > 25 && !Warn.band_snap) OpenTrade(false, bid, "STAIRCASE↓", SETUP_STAIRCASE_ADV, CATEGORY_CONTINUATION);
}
}
if(Current_Family == FAMILY_RANGING) {
if(Near(current, PriceLevels[1], buffer) && Indicators.stoch_k < 35) OpenTrade(true, ask, "RANGE-BUY", SETUP_RANGE_ENGINE, CATEGORY_COUNTER_TREND);
if(Near(current, PriceLevels[5], buffer) && Indicators.stoch_k > 65) OpenTrade(false, bid, "RANGE-SELL", SETUP_RANGE_ENGINE, CATEGORY_COUNTER_TREND);
}
if(Current_Family == FAMILY_CHOP) {
if(Warn.stoch_extreme || Warn.stoch_reject || Warn.confluence_3plus) {
if(Indicators.stoch_k <= Stoch_Low) OpenTrade(true, ask, "CHOP-REV-BUY", SETUP_MEAN_REV, CATEGORY_COUNTER_TREND);
if(Indicators.stoch_k >= Stoch_High) OpenTrade(false, bid, "CHOP-REV-SELL", SETUP_MEAN_REV, CATEGORY_COUNTER_TREND);
}
}
}
//+------------------------------------------------------------------+