Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fff49ea9da | |||
| 6208bbd9c5 |
+15
-6
@@ -23,7 +23,7 @@ input double g_min_lot = 0.01; // Minimum Lot Si
|
||||
input int g_magic_number = 12345; // Magic Number for trades
|
||||
input int g_stop_loss_points = 100; // Stop Loss in points
|
||||
input int g_take_profit_points = 200; // Take Profit in points
|
||||
input int g_max_spread_points = 10; // Max Spread in points
|
||||
input int g_max_spread_points = 100; // Max Spread in points (1.00 USD for XAUUSD)
|
||||
input int g_max_positions = 1; // Max positions at once
|
||||
|
||||
// ==================== TRADING HOURS ====================
|
||||
@@ -39,11 +39,20 @@ input int g_break_even_profit = 10; // Break Even Tri
|
||||
input int g_break_even_sl = 2; // Break Even SL distance
|
||||
|
||||
// ==================== STRATEGY PARAMETERS ====================
|
||||
input int g_ma_fast_period = 10; // Fast MA Period
|
||||
input int g_ma_slow_period = 20; // Slow MA Period
|
||||
input int g_ma_shift = 0; // MA Shift
|
||||
input ENUM_MA_METHOD g_ma_method = MODE_SMA; // MA Method
|
||||
input ENUM_APPLIED_PRICE g_ma_price = PRICE_CLOSE; // MA Applied Price
|
||||
// XAUUSD M15 EMA Pullback Continuation Strategy
|
||||
input ENUM_TIMEFRAMES g_strategy_entry_timeframe = PERIOD_M15; // Entry signal timeframe
|
||||
input ENUM_TIMEFRAMES g_strategy_trend_timeframe = PERIOD_H1; // Trend filter timeframe
|
||||
input int g_trend_fast_ema_period = 50; // H1 EMA fast period
|
||||
input int g_trend_slow_ema_period = 200; // H1 EMA slow period
|
||||
input int g_entry_fast_ema_period = 20; // M15 EMA for entry confirmation
|
||||
input int g_entry_pullback_ema_period = 50; // M15 EMA for pullback touch
|
||||
input int g_rsi_period = 14; // RSI period on M15
|
||||
input int g_rsi_buy_threshold = 50; // RSI buy threshold
|
||||
input int g_rsi_sell_threshold = 50; // RSI sell threshold
|
||||
input int g_atr_period = 14; // ATR period on M15
|
||||
input double g_atr_sl_multiplier = 1.5; // ATR multiplier for SL (future use)
|
||||
input double g_atr_tp_multiplier = 2.0; // ATR multiplier for TP (future use)
|
||||
input bool g_use_atr_stops = false; // Use ATR-based SL/TP if supported
|
||||
|
||||
// ==================== DEBUG ====================
|
||||
input bool g_debug_mode = true; // Enable Debug Logging
|
||||
|
||||
+10
-1
@@ -83,7 +83,16 @@ public:
|
||||
// Check if spread is acceptable
|
||||
bool IsSpreadAcceptable()
|
||||
{
|
||||
return mp_market_data.IsSpreadAcceptable(g_max_spread_points);
|
||||
int max_spread = g_max_spread_points;
|
||||
string symbol = mp_market_data.GetSymbol();
|
||||
|
||||
// XAUUSD/gold normally trades with a much wider spread than forex
|
||||
if(StringFind(symbol, "XAU") >= 0 || StringFind(symbol, "GOLD") >= 0)
|
||||
{
|
||||
max_spread = MathMax(max_spread, 200);
|
||||
}
|
||||
|
||||
return mp_market_data.IsSpreadAcceptable(max_spread);
|
||||
}
|
||||
|
||||
// Check if trading is allowed by time filter
|
||||
|
||||
+166
-72
@@ -1,6 +1,6 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Strategy.mqh - Trading strategy implementation |
|
||||
//| Simple MA crossover: Buy when Fast MA > Slow MA, Sell opposite |
|
||||
//| Strategy.mqh - XAUUSD M15 EMA Pullback Continuation Strategy |
|
||||
//| Trend direction on H1, pullback on M15, RSI and ATR confirmation |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
#ifndef __STRATEGY_MQH__
|
||||
@@ -10,20 +10,39 @@
|
||||
#include "MarketData.mqh"
|
||||
#include "Logger.mqh"
|
||||
#include "Config.mqh"
|
||||
#include "Utilities.mqh"
|
||||
|
||||
class CStrategy
|
||||
{
|
||||
private:
|
||||
int m_ma_fast_handle;
|
||||
int m_ma_slow_handle;
|
||||
// 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;
|
||||
|
||||
int m_fast_period;
|
||||
int m_slow_period;
|
||||
int m_ma_shift;
|
||||
ENUM_MA_METHOD m_ma_method;
|
||||
ENUM_APPLIED_PRICE m_ma_price;
|
||||
|
||||
// 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
|
||||
@@ -31,15 +50,27 @@ public:
|
||||
{
|
||||
mp_market_data = market_data;
|
||||
mp_logger = logger;
|
||||
|
||||
m_fast_period = g_ma_fast_period;
|
||||
m_slow_period = g_ma_slow_period;
|
||||
m_ma_shift = g_ma_shift;
|
||||
m_ma_method = g_ma_method;
|
||||
m_ma_price = g_ma_price;
|
||||
|
||||
m_ma_fast_handle = INVALID_HANDLE;
|
||||
m_ma_slow_handle = INVALID_HANDLE;
|
||||
|
||||
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
|
||||
@@ -51,99 +82,162 @@ public:
|
||||
// Initialize strategy and create indicator handles
|
||||
bool Init()
|
||||
{
|
||||
// Create fast MA handle
|
||||
m_ma_fast_handle = iMA(mp_market_data.GetSymbol(), PERIOD_CURRENT,
|
||||
m_fast_period, m_ma_shift, m_ma_method, m_ma_price);
|
||||
|
||||
if(m_ma_fast_handle == INVALID_HANDLE)
|
||||
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 Fast MA indicator");
|
||||
mp_logger.Error("Failed to create H1 EMA fast indicator");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create slow MA handle
|
||||
m_ma_slow_handle = iMA(mp_market_data.GetSymbol(), PERIOD_CURRENT,
|
||||
m_slow_period, m_ma_shift, m_ma_method, m_ma_price);
|
||||
|
||||
if(m_ma_slow_handle == INVALID_HANDLE)
|
||||
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 Slow MA indicator");
|
||||
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 initialized successfully");
|
||||
|
||||
mp_logger.Info("Strategy (M15 EMA Pullback Continuation) initialized successfully");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Generate trading signal
|
||||
// Generate trading signal based on H1 trend and M15 pullback continuation
|
||||
E_SIGNAL GetSignal()
|
||||
{
|
||||
if(m_ma_fast_handle == INVALID_HANDLE || m_ma_slow_handle == INVALID_HANDLE)
|
||||
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 ma_fast = iGetMainValue(m_ma_fast_handle, 0);
|
||||
double ma_slow = iGetMainValue(m_ma_slow_handle, 0);
|
||||
|
||||
if(ma_fast == 0 || ma_slow == 0)
|
||||
double ema_m15_fast_last = iGetIndicatorValue(m_ema_m15_fast_handle, 1);
|
||||
if(ema_m15_fast_last == 0.0)
|
||||
return SIGNAL_NONE;
|
||||
|
||||
// Get previous values for confirmation
|
||||
double ma_fast_prev = iGetMainValue(m_ma_fast_handle, 1);
|
||||
double ma_slow_prev = iGetMainValue(m_ma_slow_handle, 1);
|
||||
double close_last = iClose(symbol, m_entry_timeframe, 1);
|
||||
double open_last = iOpen(symbol, m_entry_timeframe, 1);
|
||||
|
||||
if(ma_fast_prev == 0 || ma_slow_prev == 0)
|
||||
if(close_last <= 0.0 || open_last <= 0.0)
|
||||
return SIGNAL_NONE;
|
||||
|
||||
// Simple MA crossover logic
|
||||
// BUY: Fast MA crosses above Slow MA
|
||||
if(ma_fast_prev <= ma_slow_prev && ma_fast > ma_slow)
|
||||
if(ema_h1_fast > ema_h1_slow)
|
||||
{
|
||||
if(mp_logger && g_debug_mode)
|
||||
mp_logger.Info(StringFormat("BUY Signal: MA Fast=%.5f > MA Slow=%.5f", ma_fast, ma_slow));
|
||||
return SIGNAL_BUY;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// SELL: Fast MA crosses below Slow MA
|
||||
if(ma_fast_prev >= ma_slow_prev && ma_fast < ma_slow)
|
||||
else if(ema_h1_fast < ema_h1_slow)
|
||||
{
|
||||
if(mp_logger && g_debug_mode)
|
||||
mp_logger.Info(StringFormat("SELL Signal: MA Fast=%.5f < MA Slow=%.5f", ma_fast, ma_slow));
|
||||
return SIGNAL_SELL;
|
||||
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;
|
||||
}
|
||||
|
||||
// Clean up indicator handles
|
||||
double GetLastAtrValue() const
|
||||
{
|
||||
return m_last_atr_value;
|
||||
}
|
||||
|
||||
void Cleanup()
|
||||
{
|
||||
if(m_ma_fast_handle != INVALID_HANDLE)
|
||||
{
|
||||
IndicatorRelease(m_ma_fast_handle);
|
||||
m_ma_fast_handle = INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if(m_ma_slow_handle != INVALID_HANDLE)
|
||||
{
|
||||
IndicatorRelease(m_ma_slow_handle);
|
||||
m_ma_slow_handle = INVALID_HANDLE;
|
||||
}
|
||||
ReleaseAllHandles();
|
||||
}
|
||||
|
||||
private:
|
||||
// Safe way to get indicator value
|
||||
double iGetMainValue(int handle, int shift)
|
||||
void ReleaseAllHandles()
|
||||
{
|
||||
double value[];
|
||||
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];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -98,17 +98,32 @@ private:
|
||||
{
|
||||
double break_even_trigger = CUtilities::PointsToPrice(mp_market_data.GetSymbol(),
|
||||
g_break_even_profit);
|
||||
double break_even_distance = CUtilities::PointsToPrice(mp_market_data.GetSymbol(),
|
||||
double break_even_buffer = CUtilities::PointsToPrice(mp_market_data.GetSymbol(),
|
||||
g_break_even_sl);
|
||||
double current_price = (pos_type == POSITION_TYPE_BUY) ? mp_market_data.GetBid() : mp_market_data.GetAsk();
|
||||
double price_move = 0.0;
|
||||
|
||||
// Break-even only if profit threshold is reached
|
||||
if(profit < break_even_trigger)
|
||||
return false;
|
||||
|
||||
// For BUY: move SL to BE (open price + distance)
|
||||
if(pos_type == POSITION_TYPE_BUY)
|
||||
{
|
||||
double be_sl = open_price + break_even_distance;
|
||||
price_move = current_price - open_price;
|
||||
}
|
||||
else if(pos_type == POSITION_TYPE_SELL)
|
||||
{
|
||||
price_move = open_price - current_price;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Break-even only if price has moved enough from entry
|
||||
if(price_move < break_even_trigger)
|
||||
return false;
|
||||
|
||||
// For BUY: move SL to entry price plus optional buffer
|
||||
if(pos_type == POSITION_TYPE_BUY)
|
||||
{
|
||||
double be_sl = open_price + break_even_buffer;
|
||||
be_sl = CUtilities::NormalizePrice(mp_market_data.GetSymbol(), be_sl);
|
||||
|
||||
if(be_sl > current_sl)
|
||||
@@ -119,10 +134,10 @@ private:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// For SELL: move SL to BE (open price - distance)
|
||||
// For SELL: move SL to entry price minus optional buffer
|
||||
else if(pos_type == POSITION_TYPE_SELL)
|
||||
{
|
||||
double be_sl = open_price - break_even_distance;
|
||||
double be_sl = open_price - break_even_buffer;
|
||||
be_sl = CUtilities::NormalizePrice(mp_market_data.GetSymbol(), be_sl);
|
||||
|
||||
if(be_sl < current_sl)
|
||||
|
||||
@@ -23,6 +23,10 @@ public:
|
||||
double min_lot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
|
||||
double max_lot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
|
||||
double lot_step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
|
||||
|
||||
// Guard against invalid broker volume data
|
||||
if(min_lot <= 0.0 || max_lot <= 0.0 || lot_step <= 0.0 || max_lot < min_lot)
|
||||
return 0.0;
|
||||
|
||||
// Apply limits
|
||||
if(lot < min_lot) lot = min_lot;
|
||||
@@ -30,10 +34,13 @@ public:
|
||||
|
||||
// Round to step
|
||||
lot = MathFloor(lot / lot_step) * lot_step;
|
||||
|
||||
if(lot < min_lot)
|
||||
lot = min_lot;
|
||||
|
||||
return NormalizeDouble(lot, 2);
|
||||
}
|
||||
|
||||
|
||||
// Convert points to price distance
|
||||
static double PointsToPrice(const string symbol, int points)
|
||||
{
|
||||
|
||||
BIN
Binary file not shown.
+10
@@ -48,6 +48,10 @@ int OnInit()
|
||||
if(!g_market_data.IsTradingAllowed())
|
||||
{
|
||||
g_logger.Error("Trading not allowed for this symbol");
|
||||
delete g_market_data;
|
||||
g_market_data = NULL;
|
||||
delete g_logger;
|
||||
g_logger = NULL;
|
||||
return INIT_FAILED;
|
||||
}
|
||||
|
||||
@@ -56,6 +60,12 @@ int OnInit()
|
||||
if(!g_strategy.Init())
|
||||
{
|
||||
g_logger.Error("Failed to initialize strategy");
|
||||
delete g_strategy;
|
||||
g_strategy = NULL;
|
||||
delete g_market_data;
|
||||
g_market_data = NULL;
|
||||
delete g_logger;
|
||||
g_logger = NULL;
|
||||
return INIT_FAILED;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user