Vizion-Trading-EA/CandlePatterns.mqh

283 lines
8.8 KiB
MQL5
Raw Permalink Normal View History

#ifndef CANDLE_PATTERNS_MQH
#define CANDLE_PATTERNS_MQH
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_INVERTED_HAMMER,
PATT_HANGING_MAN,
PATT_SHOOTING_STAR,
PATT_DOJI,
PATT_SPINNING_TOP,
PATT_MARUBOZU_BULL,
PATT_MARUBOZU_BEAR,
PATT_ENGULFING_BULL,
PATT_ENGULFING_BEAR,
PATT_TWEEZER_TOP,
PATT_TWEEZER_BOTTOM,
PATT_THREE_WHITE_SOLDIERS,
PATT_THREE_BLACK_CROWS,
PATT_MORNING_STAR,
PATT_EVENING_STAR,
PATT_2_1_2_BULL_CONT,
PATT_2_1_2_BEAR_CONT,
PATT_3_1_2_BULL_REV,
PATT_3_1_2_BEAR_REV
};
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;
};
PatternSignal g_ActivePatterns[];
int g_PatternCount = 0;
const int MAX_PATTERNS = 100;
const double SHADOW_RATIO = 2.0;
const double DOJI_RATIO = 0.1;
const double ENGULF_RATIO = 1.0;
string GetPatternName(const ENUM_PATTERN_NAME name)
{
switch(name)
{
case PATT_HAMMER: return "HAMMER";
case PATT_INVERTED_HAMMER: return "INVERTED_HAMMER";
case PATT_HANGING_MAN: return "HANGING_MAN";
case PATT_SHOOTING_STAR: return "SHOOTING_STAR";
case PATT_DOJI: return "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 "ENGULFING_BULL";
case PATT_ENGULFING_BEAR: return "ENGULFING_BEAR";
case PATT_TWEEZER_TOP: return "TWEEZER_TOP";
case PATT_TWEEZER_BOTTOM: return "TWEEZER_BOTTOM";
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_CONT";
case PATT_2_1_2_BEAR_CONT: return "2-1-2_BEAR_CONT";
case PATT_3_1_2_BULL_REV: return "3-1-2_BULL_REV";
case PATT_3_1_2_BEAR_REV: return "3-1-2_BEAR_REV";
default: return "UNKNOWN";
}
}
bool IsBullishTrend(const MqlRates &rates[], const int index)
{
if(index + 10 >= ArraySize(rates)) return false;
double ma_fast = 0.0, ma_slow = 0.0;
for(int i = index; i < index + 5; ++i) ma_fast += rates[i].close;
for(int i = index; i < index + 10; ++i) ma_slow += rates[i].close;
ma_fast /= 5.0;
ma_slow /= 10.0;
return (ma_fast > ma_slow);
}
bool IsBearishTrend(const MqlRates &rates[], const int index)
{
return !IsBullishTrend(rates, index);
}
void AddPattern(const ENUM_PATTERN_NAME name,
const ENUM_PATTERN_TYPE type,
const int candle_idx,
const double price,
const datetime time,
const 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 = (double)strength;
g_ActivePatterns[g_PatternCount++] = signal;
}
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 range = h - l;
if(range <= 0.0) return;
double up_shadow = h - MathMax(o, c);
double lo_shadow = MathMin(o, c) - l;
if(lo_shadow >= SHADOW_RATIO * body && up_shadow <= 0.3 * body && IsBearishTrend(rates, idx))
AddPattern(PATT_HAMMER, PATTERN_REVERSAL_BULLISH, idx, l, rates[idx].time, 85);
if(up_shadow >= SHADOW_RATIO * body && lo_shadow <= 0.3 * body && IsBullishTrend(rates, idx))
AddPattern(PATT_SHOOTING_STAR, PATTERN_REVERSAL_BEARISH, idx, h, rates[idx].time, 85);
if(body / range < DOJI_RATIO)
AddPattern(PATT_DOJI, PATTERN_INDECISION, idx, c, rates[idx].time, 60);
if(body / range > 0.9)
{
if(c > o) AddPattern(PATT_MARUBOZU_BULL, PATTERN_CONTINUATION_BULL, idx, c, rates[idx].time, 80);
if(c < o) AddPattern(PATT_MARUBOZU_BEAR, PATTERN_CONTINUATION_BEAR, idx, c, rates[idx].time, 80);
}
}
void DetectTwoCandlePatterns(const MqlRates &rates[])
{
if(ArraySize(rates) < 3) return;
int curr = 1, prev = 2;
double o1 = rates[prev].open, c1 = rates[prev].close;
double o2 = rates[curr].open, c2 = rates[curr].close;
double b1 = MathAbs(c1 - o1), b2 = MathAbs(c2 - o2);
if(c1 < o1 && c2 > o2 && o2 <= c1 && c2 >= o1 && b2 > b1 * ENGULF_RATIO)
AddPattern(PATT_ENGULFING_BULL, PATTERN_REVERSAL_BULLISH, curr, c2, rates[curr].time, 90);
if(c1 > o1 && c2 < o2 && o2 >= c1 && c2 <= o1 && b2 > b1 * ENGULF_RATIO)
AddPattern(PATT_ENGULFING_BEAR, PATTERN_REVERSAL_BEARISH, curr, c2, rates[curr].time, 90);
if(MathAbs(rates[prev].high - rates[curr].high) <= (rates[prev].high - rates[prev].low) * 0.02)
AddPattern(PATT_TWEEZER_TOP, PATTERN_REVERSAL_BEARISH, curr, rates[curr].high, rates[curr].time, 75);
if(MathAbs(rates[prev].low - rates[curr].low) <= (rates[prev].high - rates[prev].low) * 0.02)
AddPattern(PATT_TWEEZER_BOTTOM, PATTERN_REVERSAL_BULLISH, curr, rates[curr].low, rates[curr].time, 75);
}
void DetectThreeCandlePatterns(const MqlRates &rates[])
{
if(ArraySize(rates) < 4) return;
int c1 = 3, c2 = 2, c3 = 1;
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);
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);
}
void DetectTheStratPatterns(const MqlRates &rates[])
{
if(ArraySize(rates) < 4) return;
int st[3] = {0, 0, 0};
for(int i = 1; i <= 3; ++i)
{
int curr = i;
int prev = i + 1;
if(rates[curr].high <= rates[prev].high && rates[curr].low >= rates[prev].low) st[i - 1] = 1;
else if(rates[curr].high > rates[prev].high && rates[curr].low < rates[prev].low) st[i - 1] = 2;
else st[i - 1] = 3;
}
if(st[2] == 2 && st[1] == 1 && st[0] == 2)
{
if(rates[1].close > rates[1].open)
AddPattern(PATT_2_1_2_BULL_CONT, PATTERN_CONTINUATION_BULL, 1, rates[1].close, rates[1].time, 88);
if(rates[1].close < rates[1].open)
AddPattern(PATT_2_1_2_BEAR_CONT, PATTERN_CONTINUATION_BEAR, 1, rates[1].close, rates[1].time, 88);
}
if(st[2] == 3 && st[1] == 1 && st[0] == 2)
{
if(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);
if(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);
}
}
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;
}
}
bool InitializePatternDetection()
{
ArrayResize(g_ActivePatterns, MAX_PATTERNS);
g_PatternCount = 0;
return true;
}
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();
}
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;
}
#endif