RSI-Stoch-MA-EA/Candlepatterns.mqh
Sahr John 979850e0ba
一些检测失败了
Build and Deploy MT5 EA / build (push) Failing after 50s
Build and Deploy MT5 EA / deploy (push) Has been skipped
Update Candlepatterns.mqh
2026-01-21 08:11:54 +00:00

601 行
无行尾
19 KiB
MQL5

//+------------------------------------------------------------------+
//| CandlePatterns.mqh |
//| Comprehensive Candlestick Pattern Detection |
//| STANDALONE VERSION - No external dependencies |
//+------------------------------------------------------------------+
#property copyright "QuarterTheory x VIZION"
#property version "2.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
{
// Single Candle Patterns
PATT_HAMMER,
PATT_INVERTED_HAMMER,
PATT_HANGING_MAN,
PATT_SHOOTING_STAR,
PATT_DOJI,
PATT_DRAGONFLY_DOJI,
PATT_GRAVESTONE_DOJI,
PATT_SPINNING_TOP,
PATT_MARUBOZU_BULL,
PATT_MARUBOZU_BEAR,
// Two Candle Patterns
PATT_ENGULFING_BULL,
PATT_ENGULFING_BEAR,
PATT_PIERCING_LINE,
PATT_DARK_CLOUD,
PATT_TWEEZER_TOP,
PATT_TWEEZER_BOTTOM,
PATT_HARAMI_BULL,
PATT_HARAMI_BEAR,
PATT_BULLISH_KICKER,
PATT_BEARISH_KICKER,
// Three+ Candle Patterns
PATT_THREE_WHITE_SOLDIERS,
PATT_THREE_BLACK_CROWS,
PATT_MORNING_STAR,
PATT_EVENING_STAR,
PATT_MORNING_DOJI_STAR,
PATT_EVENING_DOJI_STAR,
PATT_THREE_INSIDE_UP,
PATT_THREE_INSIDE_DOWN,
PATT_THREE_OUTSIDE_UP,
PATT_THREE_OUTSIDE_DOWN,
// TheStrat Patterns
PATT_2_1_2_BULL_CONT,
PATT_2_1_2_BEAR_CONT,
PATT_3_1_2_BULL_REV,
PATT_3_1_2_BEAR_REV,
PATT_2_2_REVERSAL_BULL,
PATT_2_2_REVERSAL_BEAR,
PATT_2_2_CONTINUATION_BULL,
PATT_2_2_CONTINUATION_BEAR
};
//================ PATTERN STRUCTURE ==================//
struct PatternSignal
{
ENUM_PATTERN_NAME name;
ENUM_PATTERN_TYPE type;
string name_str;
int strength;
int candle_index;
double pattern_price;
datetime time;
bool generates_warn;
bool generates_praise;
double adjusted_strength;
};
//================ GLOBAL VARIABLES ==================//
PatternSignal g_ActivePatterns[];
int g_PatternCount = 0;
const int MAX_PATTERNS = 100;
// Candle measurement constants
const double CANDLE_BODY_RATIO = 0.6;
const double SHADOW_RATIO = 2.0;
const double DOJI_RATIO = 0.1;
const double ENGULF_RATIO = 1.0;
//+------------------------------------------------------------------+
//| Initialize Pattern Detection System |
//+------------------------------------------------------------------+
bool InitializePatternDetection()
{
ArrayResize(g_ActivePatterns, MAX_PATTERNS);
g_PatternCount = 0;
Print("✅ Candlestick Pattern Detection System Initialized");
Print(" - 37 pattern types supported");
return true;
}
//+------------------------------------------------------------------+
//| Main Pattern Detection Entry Point |
//+------------------------------------------------------------------+
void DetectAllCandlestickPatterns()
{
g_PatternCount = 0;
MqlRates rates[];
ArraySetAsSeries(rates, true);
int copied = CopyRates(_Symbol, _Period, 0, 100, rates);
if(copied < 20) return;
DetectSingleCandlePatterns(rates);
DetectTwoCandlePatterns(rates);
DetectThreeCandlePatterns(rates);
DetectTheStratPatterns(rates);
GenerateSignalsFromPatterns();
if(g_PatternCount > 0)
Print("🕯️ Detected ", g_PatternCount, " candlestick patterns");
}
//+------------------------------------------------------------------+
//| SINGLE CANDLE PATTERNS |
//+------------------------------------------------------------------+
void DetectSingleCandlePatterns(const MqlRates &rates[])
{
int idx = 1;
if(idx >= ArraySize(rates)) return;
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 total_range = h - l;
double upper_shadow = h - MathMax(o, c);
double lower_shadow = MathMin(o, c) - l;
if(total_range == 0) return;
// HAMMER
if(lower_shadow >= SHADOW_RATIO * body &&
upper_shadow <= 0.3 * body &&
body / total_range >= 0.2 &&
IsBearishTrend(rates, idx))
{
AddPattern(PATT_HAMMER, PATTERN_REVERSAL_BULLISH, idx, l, rates[idx].time, 85);
}
// INVERTED HAMMER
if(upper_shadow >= SHADOW_RATIO * body &&
lower_shadow <= 0.3 * body &&
body / total_range >= 0.2 &&
IsBearishTrend(rates, idx))
{
AddPattern(PATT_INVERTED_HAMMER, PATTERN_REVERSAL_BULLISH, idx, h, rates[idx].time, 75);
}
// SHOOTING STAR
if(upper_shadow >= SHADOW_RATIO * body &&
lower_shadow <= 0.3 * body &&
body / total_range >= 0.2 &&
IsBullishTrend(rates, idx))
{
AddPattern(PATT_SHOOTING_STAR, PATTERN_REVERSAL_BEARISH, idx, h, rates[idx].time, 85);
}
// HANGING MAN
if(lower_shadow >= SHADOW_RATIO * body &&
upper_shadow <= 0.3 * body &&
body / total_range >= 0.2 &&
IsBullishTrend(rates, idx))
{
AddPattern(PATT_HANGING_MAN, PATTERN_REVERSAL_BEARISH, idx, l, rates[idx].time, 75);
}
// DOJI
if(body / total_range < DOJI_RATIO)
{
if(lower_shadow > 2 * upper_shadow)
AddPattern(PATT_DRAGONFLY_DOJI, PATTERN_REVERSAL_BULLISH, idx, c, rates[idx].time, 70);
else if(upper_shadow > 2 * lower_shadow)
AddPattern(PATT_GRAVESTONE_DOJI, PATTERN_REVERSAL_BEARISH, idx, c, rates[idx].time, 70);
else
AddPattern(PATT_DOJI, PATTERN_INDECISION, idx, c, rates[idx].time, 60);
}
// SPINNING TOP
if(body / total_range > DOJI_RATIO && body / total_range < 0.3 &&
upper_shadow > body && lower_shadow > body)
{
AddPattern(PATT_SPINNING_TOP, PATTERN_INDECISION, idx, c, rates[idx].time, 55);
}
// MARUBOZU
if(c > o && body / total_range > 0.9)
AddPattern(PATT_MARUBOZU_BULL, PATTERN_CONTINUATION_BULL, idx, c, rates[idx].time, 80);
if(c < o && body / total_range > 0.9)
AddPattern(PATT_MARUBOZU_BEAR, PATTERN_CONTINUATION_BEAR, idx, c, rates[idx].time, 80);
}
//+------------------------------------------------------------------+
//| TWO CANDLE PATTERNS |
//+------------------------------------------------------------------+
void DetectTwoCandlePatterns(const MqlRates &rates[])
{
if(ArraySize(rates) < 3) return;
int curr = 1, prev = 2;
double o1 = rates[prev].open, h1 = rates[prev].high;
double l1 = rates[prev].low, c1 = rates[prev].close;
double o2 = rates[curr].open, h2 = rates[curr].high;
double l2 = rates[curr].low, 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 * ENGULF_RATIO)
{
AddPattern(PATT_ENGULFING_BULL, PATTERN_REVERSAL_BULLISH, curr, c2, rates[curr].time, 90);
}
// BEARISH ENGULFING
if(c1 > o1 && c2 < o2 &&
o2 >= c1 && c2 <= o1 &&
body2 > body1 * ENGULF_RATIO)
{
AddPattern(PATT_ENGULFING_BEAR, PATTERN_REVERSAL_BEARISH, curr, c2, rates[curr].time, 90);
}
// PIERCING LINE
if(c1 < o1 && c2 > o2 &&
o2 < l1 &&
c2 > (o1 + c1) / 2 &&
c2 < o1)
{
AddPattern(PATT_PIERCING_LINE, PATTERN_REVERSAL_BULLISH, curr, c2, rates[curr].time, 85);
}
// DARK CLOUD COVER
if(c1 > o1 && c2 < o2 &&
o2 > h1 &&
c2 < (o1 + c1) / 2 &&
c2 > o1)
{
AddPattern(PATT_DARK_CLOUD, PATTERN_REVERSAL_BEARISH, curr, c2, rates[curr].time, 85);
}
// TWEEZER TOP
if(MathAbs(h1 - h2) < (h1 - l1) * 0.02 && IsBullishTrend(rates, curr))
{
AddPattern(PATT_TWEEZER_TOP, PATTERN_REVERSAL_BEARISH, curr, h2, rates[curr].time, 75);
}
// TWEEZER BOTTOM
if(MathAbs(l1 - l2) < (h1 - l1) * 0.02 && IsBearishTrend(rates, curr))
{
AddPattern(PATT_TWEEZER_BOTTOM, PATTERN_REVERSAL_BULLISH, curr, l2, rates[curr].time, 75);
}
// BULLISH HARAMI
if(c1 < o1 && c2 > o2 &&
o2 > c1 && c2 < o1 &&
body2 < body1 * 0.5)
{
AddPattern(PATT_HARAMI_BULL, PATTERN_REVERSAL_BULLISH, curr, c2, rates[curr].time, 70);
}
// BEARISH HARAMI
if(c1 > o1 && c2 < o2 &&
o2 < c1 && c2 > o1 &&
body2 < body1 * 0.5)
{
AddPattern(PATT_HARAMI_BEAR, PATTERN_REVERSAL_BEARISH, curr, c2, rates[curr].time, 70);
}
// BULLISH KICKER
if(c1 < o1 && c2 > o2 &&
o2 > c1 &&
body1 > (h1 - l1) * 0.7 &&
body2 > (h2 - l2) * 0.7)
{
AddPattern(PATT_BULLISH_KICKER, PATTERN_REVERSAL_BULLISH, curr, o2, rates[curr].time, 95);
}
// BEARISH KICKER
if(c1 > o1 && c2 < o2 &&
o2 < c1 &&
body1 > (h1 - l1) * 0.7 &&
body2 > (h2 - l2) * 0.7)
{
AddPattern(PATT_BEARISH_KICKER, PATTERN_REVERSAL_BEARISH, curr, o2, rates[curr].time, 95);
}
}
//+------------------------------------------------------------------+
//| THREE+ CANDLE PATTERNS |
//+------------------------------------------------------------------+
void DetectThreeCandlePatterns(const MqlRates &rates[])
{
if(ArraySize(rates) < 4) return;
int c1 = 3, c2 = 2, c3 = 1;
// 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, c3,
rates[c3].close, rates[c3].time, 90);
}
// 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, c3,
rates[c3].close, rates[c3].time, 90);
}
// 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, c3,
rates[c3].close, rates[c3].time, 95);
}
// 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, c3,
rates[c3].close, rates[c3].time, 95);
}
}
//+------------------------------------------------------------------+
//| THESTRAT PATTERNS |
//+------------------------------------------------------------------+
void DetectTheStratPatterns(const MqlRates &rates[])
{
if(ArraySize(rates) < 4) return;
int strat_type[3];
for(int i = 1; i <= 3; i++)
{
if(i >= ArraySize(rates)) continue;
int curr = i;
int prev = i + 1;
// Inside bar (1)
if(rates[curr].high <= rates[prev].high && rates[curr].low >= rates[prev].low)
strat_type[i-1] = 1;
// Outside bar (2)
else if(rates[curr].high > rates[prev].high && rates[curr].low < rates[prev].low)
strat_type[i-1] = 2;
// Directional (3)
else
strat_type[i-1] = 3;
}
// 2-1-2 BULLISH CONTINUATION
if(strat_type[2] == 2 && strat_type[1] == 1 && strat_type[0] == 2 &&
rates[1].close > rates[1].open)
{
AddPattern(PATT_2_1_2_BULL_CONT, PATTERN_CONTINUATION_BULL, 1,
rates[1].close, rates[1].time, 88);
}
// 2-1-2 BEARISH CONTINUATION
if(strat_type[2] == 2 && strat_type[1] == 1 && strat_type[0] == 2 &&
rates[1].close < rates[1].open)
{
AddPattern(PATT_2_1_2_BEAR_CONT, PATTERN_CONTINUATION_BEAR, 1,
rates[1].close, rates[1].time, 88);
}
// 3-1-2 BULLISH REVERSAL
if(strat_type[2] == 3 && strat_type[1] == 1 && strat_type[0] == 2 &&
rates[3].close < rates[3].open && rates[1].close > rates[1].open)
{
AddPattern(PATT_3_1_2_BULL_REV, PATTERN_REVERSAL_BULLISH, 1,
rates[1].close, rates[1].time, 92);
}
// 3-1-2 BEARISH REVERSAL
if(strat_type[2] == 3 && strat_type[1] == 1 && strat_type[0] == 2 &&
rates[3].close > rates[3].open && rates[1].close < rates[1].open)
{
AddPattern(PATT_3_1_2_BEAR_REV, PATTERN_REVERSAL_BEARISH, 1,
rates[1].close, rates[1].time, 92);
}
}
//+------------------------------------------------------------------+
//| Helper Functions |
//+------------------------------------------------------------------+
bool IsBullishTrend(const MqlRates &rates[], int index)
{
if(index + 10 >= ArraySize(rates)) return false;
double ma_fast = 0, ma_slow = 0;
for(int i = index; i < index + 5; i++)
ma_fast += rates[i].close;
ma_fast /= 5;
for(int i = index; i < index + 10; i++)
ma_slow += rates[i].close;
ma_slow /= 10;
return ma_fast > ma_slow;
}
bool IsBearishTrend(const MqlRates &rates[], int index)
{
return !IsBullishTrend(rates, index);
}
//+------------------------------------------------------------------+
//| Add Pattern to Array |
//+------------------------------------------------------------------+
void AddPattern(ENUM_PATTERN_NAME name, ENUM_PATTERN_TYPE type,
int candle_idx, double price, datetime time, int strength)
{
if(g_PatternCount >= MAX_PATTERNS) return;
PatternSignal signal;
signal.name = name;
signal.type = type;
signal.name_str = GetPatternName(name);
signal.strength = strength;
signal.candle_index = candle_idx;
signal.pattern_price = price;
signal.time = time;
signal.generates_warn = false;
signal.generates_praise = false;
signal.adjusted_strength = strength;
g_ActivePatterns[g_PatternCount] = signal;
g_PatternCount++;
}
//+------------------------------------------------------------------+
//| Get Pattern Name String |
//+------------------------------------------------------------------+
string GetPatternName(ENUM_PATTERN_NAME name)
{
switch(name)
{
case PATT_HAMMER: return "HAMMER";
case PATT_INVERTED_HAMMER: return "INVERTED_HAMMER";
case PATT_SHOOTING_STAR: return "SHOOTING_STAR";
case PATT_HANGING_MAN: return "HANGING_MAN";
case PATT_DOJI: return "DOJI";
case PATT_DRAGONFLY_DOJI: return "DRAGONFLY_DOJI";
case PATT_GRAVESTONE_DOJI: return "GRAVESTONE_DOJI";
case PATT_SPINNING_TOP: return "SPINNING_TOP";
case PATT_MARUBOZU_BULL: return "MARUBOZU_BULL";
case PATT_MARUBOZU_BEAR: return "MARUBOZU_BEAR";
case PATT_ENGULFING_BULL: return "BULLISH_ENGULFING";
case PATT_ENGULFING_BEAR: return "BEARISH_ENGULFING";
case PATT_PIERCING_LINE: return "PIERCING_LINE";
case PATT_DARK_CLOUD: return "DARK_CLOUD_COVER";
case PATT_TWEEZER_TOP: return "TWEEZER_TOP";
case PATT_TWEEZER_BOTTOM: return "TWEEZER_BOTTOM";
case PATT_HARAMI_BULL: return "BULLISH_HARAMI";
case PATT_HARAMI_BEAR: return "BEARISH_HARAMI";
case PATT_BULLISH_KICKER: return "BULLISH_KICKER";
case PATT_BEARISH_KICKER: return "BEARISH_KICKER";
case PATT_THREE_WHITE_SOLDIERS: return "THREE_WHITE_SOLDIERS";
case PATT_THREE_BLACK_CROWS: return "THREE_BLACK_CROWS";
case PATT_MORNING_STAR: return "MORNING_STAR";
case PATT_EVENING_STAR: return "EVENING_STAR";
case PATT_2_1_2_BULL_CONT: return "2-1-2_BULL_CONTINUATION";
case PATT_2_1_2_BEAR_CONT: return "2-1-2_BEAR_CONTINUATION";
case PATT_3_1_2_BULL_REV: return "3-1-2_BULL_REVERSAL";
case PATT_3_1_2_BEAR_REV: return "3-1-2_BEAR_REVERSAL";
default: return "UNKNOWN";
}
}
//+------------------------------------------------------------------+
//| Generate WARN/PRAISE Signals |
//+------------------------------------------------------------------+
void GenerateSignalsFromPatterns()
{
for(int i = 0; i < g_PatternCount; i++)
{
if(g_ActivePatterns[i].type == PATTERN_REVERSAL_BULLISH ||
g_ActivePatterns[i].type == PATTERN_REVERSAL_BEARISH)
{
g_ActivePatterns[i].generates_warn = true;
}
if(g_ActivePatterns[i].type == PATTERN_CONTINUATION_BULL ||
g_ActivePatterns[i].type == PATTERN_CONTINUATION_BEAR)
{
g_ActivePatterns[i].generates_praise = true;
}
if(g_ActivePatterns[i].adjusted_strength >= 85)
{
string signal_type = g_ActivePatterns[i].generates_warn ? "WARN" :
g_ActivePatterns[i].generates_praise ? "PRAISE" : "NEUTRAL";
Print("🕯️ ", signal_type, " - ", g_ActivePatterns[i].name_str,
" [Strength: ", (int)g_ActivePatterns[i].adjusted_strength, "%]");
}
}
}
//+------------------------------------------------------------------+
//| Get Pattern Count by Type |
//+------------------------------------------------------------------+
int GetPatternCount(ENUM_PATTERN_TYPE type)
{
int count = 0;
for(int i = 0; i < g_PatternCount; i++)
{
if(g_ActivePatterns[i].type == type)
count++;
}
return count;
}
//+------------------------------------------------------------------+
//| Get Strongest Pattern |
//+------------------------------------------------------------------+
PatternSignal GetStrongestPattern()
{
PatternSignal strongest;
strongest.strength = 0;
strongest.adjusted_strength = 0;
for(int i = 0; i < g_PatternCount; i++)
{
if(g_ActivePatterns[i].adjusted_strength > strongest.adjusted_strength)
strongest = g_ActivePatterns[i];
}
return strongest;
}
//+------------------------------------------------------------------+
//| Integration Functions |
//+------------------------------------------------------------------+
int GetPatternWarnCount()
{
int count = 0;
for(int i = 0; i < g_PatternCount; i++)
if(g_ActivePatterns[i].generates_warn) count++;
return count;
}
int GetPatternPraiseCount()
{
int count = 0;
for(int i = 0; i < g_PatternCount; i++)
if(g_ActivePatterns[i].generates_praise) count++;
return count;
}
bool IsPatternActive(ENUM_PATTERN_NAME pattern_name)
{
for(int i = 0; i < g_PatternCount; i++)
if(g_ActivePatterns[i].name == pattern_name) return true;
return false;
}