forked from SahrJohn/RSI-Stoch-MA-EA
469 lines
13 KiB
MQL5
469 lines
13 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| 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 |
|
||
|
|
//+------------------------------------------------------------------+
|