forked from Princeec13/mql5
140 lines
4.9 KiB
MQL5
140 lines
4.9 KiB
MQL5
|
// MeanReversionBBStrategy.mqh
|
||
|
// A mean-reversion strategy based on Bollinger Bands with a long-term trend filter.
|
||
|
|
||
|
#property copyright "2025, Windsurf Engineering"
|
||
|
#property link "https://www.windsurf.ai"
|
||
|
|
||
|
#include "..\IStrategy.mqh"
|
||
|
// For CFeaturesKB
|
||
|
#include "..\KnowledgeBase.mqh"
|
||
|
|
||
|
class CMeanReversionBBStrategy : public IStrategy
|
||
|
{
|
||
|
private:
|
||
|
int m_bb_handle;
|
||
|
int m_ma_handle;
|
||
|
string m_symbol;
|
||
|
ENUM_TIMEFRAMES m_timeframe;
|
||
|
|
||
|
// --- Data arrays
|
||
|
double m_bb_upper[], m_bb_lower[];
|
||
|
double m_ma_trend[];
|
||
|
|
||
|
public:
|
||
|
CMeanReversionBBStrategy(string symbol, ENUM_TIMEFRAMES timeframe);
|
||
|
~CMeanReversionBBStrategy();
|
||
|
|
||
|
// --- IStrategy interface methods
|
||
|
virtual void Refresh() override;
|
||
|
virtual TradeOrder CheckSignal() override;
|
||
|
virtual string Name() override { return "MeanReversionBBStrategy"; }
|
||
|
virtual void ExportFeatures(CFeaturesKB* kb, const datetime ts) override
|
||
|
{
|
||
|
if(CheckPointer(kb)==POINTER_INVALID) return;
|
||
|
// latest price
|
||
|
MqlRates r[]; if(CopyRates(m_symbol, m_timeframe, 0, 1, r)==1)
|
||
|
(*kb).WriteKV(ts, m_symbol, Name(), "close", r[0].close);
|
||
|
// SMA trend value
|
||
|
double sma[1]; if(CopyBuffer(m_ma_handle, 0, 0, 1, sma)==1)
|
||
|
(*kb).WriteKV(ts, m_symbol, Name(), "sma_trend", sma[0]);
|
||
|
// BBands values
|
||
|
double up[1], lo[1];
|
||
|
if(CopyBuffer(m_bb_handle, 1, 0, 1, up)==1)
|
||
|
(*kb).WriteKV(ts, m_symbol, Name(), "bb_upper", up[0]);
|
||
|
if(CopyBuffer(m_bb_handle, 2, 0, 1, lo)==1)
|
||
|
(*kb).WriteKV(ts, m_symbol, Name(), "bb_lower", lo[0]);
|
||
|
if(CopyBuffer(m_bb_handle, 1, 0, 1, up)==1 && CopyBuffer(m_bb_handle, 2, 0, 1, lo)==1)
|
||
|
(*kb).WriteKV(ts, m_symbol, Name(), "bb_width", up[0]-lo[0]);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Constructor |
|
||
|
//+------------------------------------------------------------------+
|
||
|
CMeanReversionBBStrategy::CMeanReversionBBStrategy(string symbol, ENUM_TIMEFRAMES timeframe)
|
||
|
{
|
||
|
m_symbol = symbol;
|
||
|
m_timeframe = timeframe;
|
||
|
|
||
|
// --- Get indicator handles
|
||
|
m_bb_handle = iBands(m_symbol, m_timeframe, 20, 0, 2.0, PRICE_CLOSE);
|
||
|
m_ma_handle = iMA(m_symbol, PERIOD_D1, 100, 0, MODE_SMA, PRICE_CLOSE);
|
||
|
|
||
|
// --- Set buffers as series
|
||
|
ArraySetAsSeries(m_bb_upper, true);
|
||
|
ArraySetAsSeries(m_bb_lower, true);
|
||
|
ArraySetAsSeries(m_ma_trend, true);
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Destructor |
|
||
|
//+------------------------------------------------------------------+
|
||
|
CMeanReversionBBStrategy::~CMeanReversionBBStrategy()
|
||
|
{
|
||
|
IndicatorRelease(m_bb_handle);
|
||
|
IndicatorRelease(m_ma_handle);
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Refresh |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CMeanReversionBBStrategy::Refresh()
|
||
|
{
|
||
|
// Copy the last 2 bars of data
|
||
|
CopyBuffer(m_bb_handle, 1, 0, 2, m_bb_upper); // Upper Band
|
||
|
CopyBuffer(m_bb_handle, 2, 0, 2, m_bb_lower); // Lower Band
|
||
|
CopyBuffer(m_ma_handle, 0, 0, 1, m_ma_trend); // MA Trend
|
||
|
}
|
||
|
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Checks for a trading signal. |
|
||
|
//+------------------------------------------------------------------+
|
||
|
TradeOrder CMeanReversionBBStrategy::CheckSignal()
|
||
|
{
|
||
|
TradeOrder order;
|
||
|
order.strategy_name = Name();
|
||
|
|
||
|
// --- Get latest price data
|
||
|
MqlRates rates[];
|
||
|
if(CopyRates(m_symbol, m_timeframe, 0, 1, rates) != 1) return order;
|
||
|
double close_price = rates[0].close;
|
||
|
|
||
|
// --- Get latest indicator values
|
||
|
double sma_val[1];
|
||
|
double upper_band[1];
|
||
|
double lower_band[1];
|
||
|
|
||
|
if(CopyBuffer(m_ma_handle, 0, 0, 1, sma_val) != 1 ||
|
||
|
CopyBuffer(m_bb_handle, 1, 0, 1, upper_band) != 1 ||
|
||
|
CopyBuffer(m_bb_handle, 2, 0, 1, lower_band) != 1)
|
||
|
{
|
||
|
return order;
|
||
|
}
|
||
|
|
||
|
// --- Entry Logic
|
||
|
if(close_price > sma_val[0]) // Long-term trend is up
|
||
|
{
|
||
|
if(close_price < lower_band[0])
|
||
|
{
|
||
|
order.action = ACTION_BUY;
|
||
|
order.order_type = ORDER_TYPE_BUY;
|
||
|
order.stop_loss = close_price - 100 * _Point; // Example SL
|
||
|
order.take_profit = close_price + 200 * _Point; // Example TP
|
||
|
return order;
|
||
|
}
|
||
|
}
|
||
|
else if(close_price < sma_val[0]) // Long-term trend is down
|
||
|
{
|
||
|
if(close_price > upper_band[0])
|
||
|
{
|
||
|
order.action = ACTION_SELL;
|
||
|
order.order_type = ORDER_TYPE_SELL;
|
||
|
order.stop_loss = close_price + 100 * _Point; // Example SL
|
||
|
order.take_profit = close_price - 200 * _Point; // Example TP
|
||
|
return order;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return order;
|
||
|
}
|