//+------------------------------------------------------------------+ //| PatternSystemComplete.mqh | //| ALL-IN-ONE Pattern Detection System | //| Single file - Guaranteed to compile with zero dependencies | //+------------------------------------------------------------------+ #property copyright "QuarterTheory x VIZION" #property version "1.00" #property strict //================ PATTERN ENUMS ==================// enum ENUM_PATTERN_TYPE { PATTERN_NONE, PATTERN_REVERSAL_BULLISH, PATTERN_REVERSAL_BEARISH, PATTERN_CONTINUATION_BULL, PATTERN_CONTINUATION_BEAR, PATTERN_INDECISION }; enum ENUM_PATTERN_NAME { PATT_HAMMER, PATT_SHOOTING_STAR, PATT_DOJI, PATT_ENGULFING_BULL, PATT_ENGULFING_BEAR, PATT_MORNING_STAR, PATT_EVENING_STAR, PATT_THREE_WHITE_SOLDIERS, PATT_THREE_BLACK_CROWS }; enum ENUM_MARKET_STRUCTURE { STRUCTURE_UPTREND, STRUCTURE_DOWNTREND, STRUCTURE_RANGING }; //================ STRUCTURES ==================// struct PatternSignal { ENUM_PATTERN_NAME name; ENUM_PATTERN_TYPE type; string name_str; int strength; bool generates_warn; bool generates_praise; }; struct SwingPoint { double price; datetime time; bool is_high; bool is_higher_high; bool is_lower_high; bool is_higher_low; bool is_lower_low; }; //================ GLOBAL VARIABLES ==================// PatternSignal g_Patterns[20]; int g_PatternCount = 0; SwingPoint g_Swings[30]; int g_SwingCount = 0; ENUM_MARKET_STRUCTURE g_Structure = STRUCTURE_RANGING; int g_StructureStrength = 0; int g_TotalWarns = 0; int g_TotalPraise = 0; bool g_ShowMarkers = true; //+------------------------------------------------------------------+ //| Initialize System | //+------------------------------------------------------------------+ bool InitializePatternSystem() { g_PatternCount = 0; g_SwingCount = 0; Print("✅ Pattern System Initialized"); Print(" - 9 core patterns"); Print(" - Market structure analysis"); return true; } //+------------------------------------------------------------------+ //| Main Update Function | //+------------------------------------------------------------------+ void UpdatePatternSystem() { DetectPatterns(); AnalyzeStructure(); GenerateSignals(); } //+------------------------------------------------------------------+ //| Detect Patterns | //+------------------------------------------------------------------+ void DetectPatterns() { g_PatternCount = 0; MqlRates rates[]; ArraySetAsSeries(rates, true); int copied = CopyRates(_Symbol, _Period, 0, 50, rates); if(copied < 10) return; // Check previous closed candle int idx = 1; double o = rates[idx].open; double h = rates[idx].high; double l = rates[idx].low; double c = rates[idx].close; double body = MathAbs(c - o); double range = h - l; double upper_shadow = h - MathMax(o, c); double lower_shadow = MathMin(o, c) - l; if(range == 0) return; // HAMMER - Bullish reversal if(lower_shadow >= 2 * body && upper_shadow <= 0.3 * body && IsBearTrend(rates, idx)) { AddPattern(PATT_HAMMER, PATTERN_REVERSAL_BULLISH, "HAMMER", 85, true, false); } // SHOOTING STAR - Bearish reversal if(upper_shadow >= 2 * body && lower_shadow <= 0.3 * body && IsBullTrend(rates, idx)) { AddPattern(PATT_SHOOTING_STAR, PATTERN_REVERSAL_BEARISH, "SHOOTING_STAR", 85, true, false); } // DOJI - Indecision if(body / range < 0.1) { AddPattern(PATT_DOJI, PATTERN_INDECISION, "DOJI", 60, false, false); } // Check two-candle patterns if(copied >= 3) { int curr = 1, prev = 2; double o1 = rates[prev].open, c1 = rates[prev].close; double o2 = rates[curr].open, c2 = rates[curr].close; double body1 = MathAbs(c1 - o1); double body2 = MathAbs(c2 - o2); // BULLISH ENGULFING if(c1 < o1 && c2 > o2 && o2 <= c1 && c2 >= o1 && body2 > body1) { AddPattern(PATT_ENGULFING_BULL, PATTERN_REVERSAL_BULLISH, "BULLISH_ENGULFING", 90, true, false); } // BEARISH ENGULFING if(c1 > o1 && c2 < o2 && o2 >= c1 && c2 <= o1 && body2 > body1) { AddPattern(PATT_ENGULFING_BEAR, PATTERN_REVERSAL_BEARISH, "BEARISH_ENGULFING", 90, true, false); } } // Check three-candle patterns if(copied >= 4) { int c1 = 3, c2 = 2, c3 = 1; // MORNING STAR if(rates[c1].close < rates[c1].open && MathAbs(rates[c2].close - rates[c2].open) < (rates[c1].high - rates[c1].low) * 0.3 && rates[c3].close > rates[c3].open && rates[c3].close > (rates[c1].open + rates[c1].close) / 2) { AddPattern(PATT_MORNING_STAR, PATTERN_REVERSAL_BULLISH, "MORNING_STAR", 95, true, false); } // EVENING STAR if(rates[c1].close > rates[c1].open && MathAbs(rates[c2].close - rates[c2].open) < (rates[c1].high - rates[c1].low) * 0.3 && rates[c3].close < rates[c3].open && rates[c3].close < (rates[c1].open + rates[c1].close) / 2) { AddPattern(PATT_EVENING_STAR, PATTERN_REVERSAL_BEARISH, "EVENING_STAR", 95, true, false); } // THREE WHITE SOLDIERS if(rates[c1].close > rates[c1].open && rates[c2].close > rates[c2].open && rates[c3].close > rates[c3].open && rates[c2].close > rates[c1].close && rates[c3].close > rates[c2].close) { AddPattern(PATT_THREE_WHITE_SOLDIERS, PATTERN_CONTINUATION_BULL, "THREE_WHITE_SOLDIERS", 90, false, true); } // THREE BLACK CROWS if(rates[c1].close < rates[c1].open && rates[c2].close < rates[c2].open && rates[c3].close < rates[c3].open && rates[c2].close < rates[c1].close && rates[c3].close < rates[c2].close) { AddPattern(PATT_THREE_BLACK_CROWS, PATTERN_CONTINUATION_BEAR, "THREE_BLACK_CROWS", 90, false, true); } } } //+------------------------------------------------------------------+ //| Analyze Market Structure | //+------------------------------------------------------------------+ void AnalyzeStructure() { MqlRates rates[]; ArraySetAsSeries(rates, true); int copied = CopyRates(_Symbol, _Period, 0, 100, rates); if(copied < 50) return; // Find swing points g_SwingCount = 0; for(int i = 5; i < 50; i++) { // Swing high bool is_high = true; for(int j = 1; j <= 5; j++) { if(rates[i].high <= rates[i-j].high || rates[i].high <= rates[i+j].high) { is_high = false; break; } } if(is_high && g_SwingCount < 30) { g_Swings[g_SwingCount].price = rates[i].high; g_Swings[g_SwingCount].time = rates[i].time; g_Swings[g_SwingCount].is_high = true; g_SwingCount++; } // Swing low bool is_low = true; for(int j = 1; j <= 5; j++) { if(rates[i].low >= rates[i-j].low || rates[i].low >= rates[i+j].low) { is_low = false; break; } } if(is_low && g_SwingCount < 30) { g_Swings[g_SwingCount].price = rates[i].low; g_Swings[g_SwingCount].time = rates[i].time; g_Swings[g_SwingCount].is_high = false; g_SwingCount++; } } // Classify structure int hh = 0, hl = 0, lh = 0, ll = 0; for(int i = 0; i < g_SwingCount - 1; i++) { for(int j = i + 1; j < g_SwingCount; j++) { if(g_Swings[i].is_high && g_Swings[j].is_high) { if(g_Swings[i].price > g_Swings[j].price) { hh++; g_Swings[i].is_higher_high = true; } else { lh++; g_Swings[i].is_lower_high = true; } break; } else if(!g_Swings[i].is_high && !g_Swings[j].is_high) { if(g_Swings[i].price > g_Swings[j].price) { hl++; g_Swings[i].is_higher_low = true; } else { ll++; g_Swings[i].is_lower_low = true; } break; } } } // Determine structure if(hh >= 2 && hl >= 1) { g_Structure = STRUCTURE_UPTREND; g_StructureStrength = MathMin((hh * 20) + (hl * 15), 100); } else if(lh >= 2 && ll >= 1) { g_Structure = STRUCTURE_DOWNTREND; g_StructureStrength = MathMin((lh * 20) + (ll * 15), 100); } else { g_Structure = STRUCTURE_RANGING; g_StructureStrength = 30; } } //+------------------------------------------------------------------+ //| Generate Signals | //+------------------------------------------------------------------+ void GenerateSignals() { g_TotalWarns = 0; g_TotalPraise = 0; for(int i = 0; i < g_PatternCount; i++) { if(g_Patterns[i].generates_warn) g_TotalWarns++; if(g_Patterns[i].generates_praise) g_TotalPraise++; if(g_Patterns[i].strength >= 85) { string type = g_Patterns[i].generates_warn ? "WARN" : g_Patterns[i].generates_praise ? "PRAISE" : "NEUTRAL"; Print("🕯️ ", type, " - ", g_Patterns[i].name_str, " [", g_Patterns[i].strength, "%]"); } } } //+------------------------------------------------------------------+ //| Helper Functions | //+------------------------------------------------------------------+ bool IsBullTrend(const MqlRates &rates[], int idx) { if(idx + 10 >= ArraySize(rates)) return false; double fast = 0, slow = 0; for(int i = idx; i < idx + 5; i++) fast += rates[i].close; for(int i = idx; i < idx + 10; i++) slow += rates[i].close; return (fast / 5) > (slow / 10); } bool IsBearTrend(const MqlRates &rates[], int idx) { return !IsBullTrend(rates, idx); } void AddPattern(ENUM_PATTERN_NAME name, ENUM_PATTERN_TYPE type, string name_str, int strength, bool warn, bool praise) { if(g_PatternCount >= 20) return; g_Patterns[g_PatternCount].name = name; g_Patterns[g_PatternCount].type = type; g_Patterns[g_PatternCount].name_str = name_str; g_Patterns[g_PatternCount].strength = strength; g_Patterns[g_PatternCount].generates_warn = warn; g_Patterns[g_PatternCount].generates_praise = praise; g_PatternCount++; } //+------------------------------------------------------------------+ //| Public Interface Functions | //+------------------------------------------------------------------+ int GetTotalWarnCount() { return g_TotalWarns; } int GetTotalPraiseCount() { return g_TotalPraise; } bool IsUptrend() { return g_Structure == STRUCTURE_UPTREND; } bool IsDowntrend() { return g_Structure == STRUCTURE_DOWNTREND; } bool IsRanging() { return g_Structure == STRUCTURE_RANGING; } int GetStructureStrength() { return g_StructureStrength; } string GetStructureString() { switch(g_Structure) { case STRUCTURE_UPTREND: return "UPTREND (HH+HL)"; case STRUCTURE_DOWNTREND: return "DOWNTREND (LH+LL)"; case STRUCTURE_RANGING: return "RANGING"; default: return "UNKNOWN"; } } bool HasCriticalWarnings() { return g_TotalWarns >= 2; } bool ShouldSizeUpTrade() { return g_TotalPraise >= 2 && g_StructureStrength > 70; } int GetStructureTradeDirection() { if(IsUptrend() && g_TotalPraise > g_TotalWarns) return 1; // Buy if(IsDowntrend() && g_TotalPraise > g_TotalWarns) return -1; // Sell return 0; } string GetSignalSummary() { string summary = ""; summary += "Structure: " + GetStructureString() + "\n"; summary += "Strength: " + IntegerToString(g_StructureStrength) + "%\n"; summary += "Warns: " + IntegerToString(g_TotalWarns) + "\n"; summary += "Praise: " + IntegerToString(g_TotalPraise) + "\n"; summary += "Patterns Detected: " + IntegerToString(g_PatternCount) + "\n"; return summary; } void CleanupPatternSystem() { ObjectsDeleteAll(0, "PATTERN_"); Print("🧹 Pattern System cleaned up"); } //+------------------------------------------------------------------+ //| END OF PATTERN SYSTEM | //+------------------------------------------------------------------+