246 lines
7.3 KiB
Plaintext
246 lines
7.3 KiB
Plaintext
//+------------------------------------------------------------------+
|
|
//| Strategy.mqh - XAUUSD M15 EMA Pullback Continuation Strategy |
|
|
//| Trend direction on H1, pullback on M15, RSI and ATR confirmation |
|
|
//+------------------------------------------------------------------+
|
|
|
|
#ifndef __STRATEGY_MQH__
|
|
#define __STRATEGY_MQH__
|
|
|
|
#include "Signal.mqh"
|
|
#include "MarketData.mqh"
|
|
#include "Logger.mqh"
|
|
#include "Config.mqh"
|
|
#include "Utilities.mqh"
|
|
|
|
class CStrategy
|
|
{
|
|
private:
|
|
// Indicator handles
|
|
int m_ema_h1_fast_handle;
|
|
int m_ema_h1_slow_handle;
|
|
int m_ema_m15_fast_handle;
|
|
int m_rsi_m15_handle;
|
|
int m_atr_m15_handle;
|
|
|
|
// References
|
|
CMarketData *mp_market_data;
|
|
CLogger *mp_logger;
|
|
|
|
// Timeframes
|
|
ENUM_TIMEFRAMES m_entry_timeframe;
|
|
ENUM_TIMEFRAMES m_trend_timeframe;
|
|
|
|
// Parameters
|
|
int m_trend_fast_ema_period;
|
|
int m_trend_slow_ema_period;
|
|
int m_entry_fast_ema_period;
|
|
int m_entry_pullback_ema_period;
|
|
int m_rsi_period;
|
|
int m_rsi_buy_threshold;
|
|
int m_rsi_sell_threshold;
|
|
int m_atr_period;
|
|
double m_last_atr_value;
|
|
bool m_use_atr_stops;
|
|
double m_atr_sl_multiplier;
|
|
double m_atr_tp_multiplier;
|
|
|
|
public:
|
|
// Constructor
|
|
CStrategy(CMarketData *market_data, CLogger *logger)
|
|
{
|
|
mp_market_data = market_data;
|
|
mp_logger = logger;
|
|
|
|
m_ema_h1_fast_handle = INVALID_HANDLE;
|
|
m_ema_h1_slow_handle = INVALID_HANDLE;
|
|
m_ema_m15_fast_handle = INVALID_HANDLE;
|
|
m_rsi_m15_handle = INVALID_HANDLE;
|
|
m_atr_m15_handle = INVALID_HANDLE;
|
|
m_last_atr_value = 0.0;
|
|
|
|
m_entry_timeframe = g_strategy_entry_timeframe;
|
|
m_trend_timeframe = g_strategy_trend_timeframe;
|
|
m_trend_fast_ema_period = g_trend_fast_ema_period;
|
|
m_trend_slow_ema_period = g_trend_slow_ema_period;
|
|
m_entry_fast_ema_period = g_entry_fast_ema_period;
|
|
m_entry_pullback_ema_period = g_entry_pullback_ema_period;
|
|
m_rsi_period = g_rsi_period;
|
|
m_rsi_buy_threshold = g_rsi_buy_threshold;
|
|
m_rsi_sell_threshold = g_rsi_sell_threshold;
|
|
m_atr_period = g_atr_period;
|
|
m_use_atr_stops = g_use_atr_stops;
|
|
m_atr_sl_multiplier = g_atr_sl_multiplier;
|
|
m_atr_tp_multiplier = g_atr_tp_multiplier;
|
|
}
|
|
|
|
// Destructor - clean up indicator handles
|
|
~CStrategy()
|
|
{
|
|
Cleanup();
|
|
}
|
|
|
|
// Initialize strategy and create indicator handles
|
|
bool Init()
|
|
{
|
|
const string symbol = mp_market_data.GetSymbol();
|
|
|
|
m_ema_h1_fast_handle = iMA(symbol, m_trend_timeframe,
|
|
m_trend_fast_ema_period, 0, MODE_EMA, PRICE_CLOSE);
|
|
if(m_ema_h1_fast_handle == INVALID_HANDLE)
|
|
{
|
|
if(mp_logger)
|
|
mp_logger.Error("Failed to create H1 EMA fast indicator");
|
|
return false;
|
|
}
|
|
|
|
m_ema_h1_slow_handle = iMA(symbol, m_trend_timeframe,
|
|
m_trend_slow_ema_period, 0, MODE_EMA, PRICE_CLOSE);
|
|
if(m_ema_h1_slow_handle == INVALID_HANDLE)
|
|
{
|
|
if(mp_logger)
|
|
mp_logger.Error("Failed to create H1 EMA slow indicator");
|
|
IndicatorRelease(m_ema_h1_fast_handle);
|
|
m_ema_h1_fast_handle = INVALID_HANDLE;
|
|
return false;
|
|
}
|
|
|
|
m_ema_m15_fast_handle = iMA(symbol, m_entry_timeframe,
|
|
m_entry_fast_ema_period, 0, MODE_EMA, PRICE_CLOSE);
|
|
if(m_ema_m15_fast_handle == INVALID_HANDLE)
|
|
{
|
|
if(mp_logger)
|
|
mp_logger.Error("Failed to create M15 EMA fast indicator");
|
|
IndicatorRelease(m_ema_h1_fast_handle);
|
|
m_ema_h1_fast_handle = INVALID_HANDLE;
|
|
IndicatorRelease(m_ema_h1_slow_handle);
|
|
m_ema_h1_slow_handle = INVALID_HANDLE;
|
|
return false;
|
|
}
|
|
|
|
m_rsi_m15_handle = iRSI(symbol, m_entry_timeframe, m_rsi_period, PRICE_CLOSE);
|
|
if(m_rsi_m15_handle == INVALID_HANDLE)
|
|
{
|
|
if(mp_logger)
|
|
mp_logger.Error("Failed to create M15 RSI indicator");
|
|
ReleaseAllHandles();
|
|
return false;
|
|
}
|
|
|
|
m_atr_m15_handle = iATR(symbol, m_entry_timeframe, m_atr_period);
|
|
if(m_atr_m15_handle == INVALID_HANDLE)
|
|
{
|
|
if(mp_logger)
|
|
mp_logger.Error("Failed to create M15 ATR indicator");
|
|
ReleaseAllHandles();
|
|
return false;
|
|
}
|
|
|
|
if(mp_logger)
|
|
mp_logger.Info("Strategy (M15 EMA Pullback Continuation) initialized successfully");
|
|
|
|
return true;
|
|
}
|
|
|
|
// Generate trading signal based on H1 trend and M15 pullback continuation
|
|
E_SIGNAL GetSignal()
|
|
{
|
|
const string symbol = mp_market_data.GetSymbol();
|
|
|
|
double ema_h1_fast = iGetIndicatorValue(m_ema_h1_fast_handle, 1);
|
|
double ema_h1_slow = iGetIndicatorValue(m_ema_h1_slow_handle, 1);
|
|
if(ema_h1_fast == 0.0 || ema_h1_slow == 0.0)
|
|
return SIGNAL_NONE;
|
|
|
|
double ema_m15_fast_last = iGetIndicatorValue(m_ema_m15_fast_handle, 1);
|
|
if(ema_m15_fast_last == 0.0)
|
|
return SIGNAL_NONE;
|
|
|
|
double close_last = iClose(symbol, m_entry_timeframe, 1);
|
|
double open_last = iOpen(symbol, m_entry_timeframe, 1);
|
|
|
|
if(close_last <= 0.0 || open_last <= 0.0)
|
|
return SIGNAL_NONE;
|
|
|
|
if(ema_h1_fast > ema_h1_slow)
|
|
{
|
|
bool entry_condition = (close_last > ema_m15_fast_last && close_last > open_last);
|
|
|
|
if(entry_condition)
|
|
{
|
|
if(mp_logger && g_debug_mode)
|
|
mp_logger.Info(StringFormat("BUY Signal: H1 EMA50=%.5f > EMA200=%.5f, M15 close=%.5f > EMA20=%.5f",
|
|
ema_h1_fast, ema_h1_slow, close_last, ema_m15_fast_last));
|
|
return SIGNAL_BUY;
|
|
}
|
|
}
|
|
else if(ema_h1_fast < ema_h1_slow)
|
|
{
|
|
bool entry_condition = (close_last < ema_m15_fast_last && close_last < open_last);
|
|
|
|
if(entry_condition)
|
|
{
|
|
if(mp_logger && g_debug_mode)
|
|
mp_logger.Info(StringFormat("SELL Signal: H1 EMA50=%.5f < EMA200=%.5f, M15 close=%.5f < EMA20=%.5f",
|
|
ema_h1_fast, ema_h1_slow, close_last, ema_m15_fast_last));
|
|
return SIGNAL_SELL;
|
|
}
|
|
}
|
|
|
|
return SIGNAL_NONE;
|
|
}
|
|
|
|
double GetLastAtrValue() const
|
|
{
|
|
return m_last_atr_value;
|
|
}
|
|
|
|
void Cleanup()
|
|
{
|
|
ReleaseAllHandles();
|
|
}
|
|
|
|
private:
|
|
void ReleaseAllHandles()
|
|
{
|
|
if(m_ema_h1_fast_handle != INVALID_HANDLE)
|
|
{
|
|
IndicatorRelease(m_ema_h1_fast_handle);
|
|
m_ema_h1_fast_handle = INVALID_HANDLE;
|
|
}
|
|
if(m_ema_h1_slow_handle != INVALID_HANDLE)
|
|
{
|
|
IndicatorRelease(m_ema_h1_slow_handle);
|
|
m_ema_h1_slow_handle = INVALID_HANDLE;
|
|
}
|
|
if(m_ema_m15_fast_handle != INVALID_HANDLE)
|
|
{
|
|
IndicatorRelease(m_ema_m15_fast_handle);
|
|
m_ema_m15_fast_handle = INVALID_HANDLE;
|
|
}
|
|
if(m_rsi_m15_handle != INVALID_HANDLE)
|
|
{
|
|
IndicatorRelease(m_rsi_m15_handle);
|
|
m_rsi_m15_handle = INVALID_HANDLE;
|
|
}
|
|
if(m_atr_m15_handle != INVALID_HANDLE)
|
|
{
|
|
IndicatorRelease(m_atr_m15_handle);
|
|
m_atr_m15_handle = INVALID_HANDLE;
|
|
}
|
|
}
|
|
|
|
double iGetIndicatorValue(int handle, int shift)
|
|
{
|
|
if(handle == INVALID_HANDLE)
|
|
return 0.0;
|
|
|
|
double value[1];
|
|
ArraySetAsSeries(value, true);
|
|
if(CopyBuffer(handle, 0, shift, 1, value) <= 0)
|
|
return 0.0;
|
|
return value[0];
|
|
}
|
|
};
|
|
|
|
#endif //__STRATEGY_MQH__
|