155 lines
5 KiB
MQL5
155 lines
5 KiB
MQL5
#include "..\IStrategy.mqh"
|
|
#include "..\KnowledgeBase.mqh"
|
|
#include "..\TradeManager.mqh"
|
|
|
|
class CGoldVolatilityStrategy : public IStrategy
|
|
{
|
|
private:
|
|
// Gold-specific parameters
|
|
int m_atrPeriod;
|
|
int m_bollingerPeriod;
|
|
double m_bollingerDeviation;
|
|
int m_volumeMAPeriod;
|
|
|
|
// Cached values
|
|
double m_atr, m_bb_upper, m_bb_lower, m_bb_middle;
|
|
double m_volume, m_volume_ma;
|
|
double m_close0, m_close1;
|
|
|
|
public:
|
|
CGoldVolatilityStrategy(const string symbol, const ENUM_TIMEFRAMES tf) : IStrategy("GoldVolatilityStrategy", symbol, tf)
|
|
{
|
|
m_atrPeriod = 14;
|
|
m_bollingerPeriod = 20;
|
|
m_bollingerDeviation = 2.0;
|
|
m_volumeMAPeriod = 20;
|
|
|
|
ResetValues();
|
|
}
|
|
|
|
virtual string Name() { return "GoldVolatilityStrategy"; }
|
|
|
|
void ResetValues()
|
|
{
|
|
m_atr = m_bb_upper = m_bb_lower = m_bb_middle = 0;
|
|
m_volume = m_volume_ma = 0;
|
|
m_close0 = m_close1 = 0;
|
|
}
|
|
|
|
virtual void Refresh()
|
|
{
|
|
ResetValues();
|
|
m_close0 = iClose(m_symbol, m_timeframe, 0);
|
|
m_close1 = iClose(m_symbol, m_timeframe, 1);
|
|
|
|
// ATR for volatility measurement
|
|
double atr_buffer[];
|
|
int atr_handle = iATR(m_symbol, m_timeframe, m_atrPeriod);
|
|
if(atr_handle > 0 && CopyBuffer(atr_handle, 0, 0, 1, atr_buffer) == 1)
|
|
m_atr = atr_buffer[0];
|
|
|
|
// Bollinger Bands
|
|
double bb_upper[], bb_middle[], bb_lower[];
|
|
int period_bb = (int)m_bollingerPeriod;
|
|
int deviation_bb = (int)MathRound(m_bollingerDeviation); // align with iBands signature in this terminal build
|
|
int shift_bb = 0;
|
|
int price_bb = (int)PRICE_CLOSE;
|
|
int bb_handle = iBands(m_symbol, m_timeframe, period_bb, deviation_bb, shift_bb, price_bb);
|
|
if(bb_handle > 0)
|
|
{
|
|
CopyBuffer(bb_handle, 0, 0, 1, bb_upper);
|
|
CopyBuffer(bb_handle, 1, 0, 1, bb_middle);
|
|
CopyBuffer(bb_handle, 2, 0, 1, bb_lower);
|
|
|
|
m_bb_upper = bb_upper[0];
|
|
m_bb_middle = bb_middle[0];
|
|
m_bb_lower = bb_lower[0];
|
|
}
|
|
|
|
// Volume analysis
|
|
double volume_buffer[];
|
|
m_volume = (double)iVolume(m_symbol, m_timeframe, 0);
|
|
|
|
// Simple volume MA
|
|
double volume_ma_buffer[];
|
|
int volume_ma_handle = iMA(m_symbol, m_timeframe, m_volumeMAPeriod, 0, MODE_SMA, VOLUME_TICK);
|
|
if(volume_ma_handle > 0 && CopyBuffer(volume_ma_handle, 0, 0, 1, volume_ma_buffer) == 1)
|
|
m_volume_ma = volume_ma_buffer[0];
|
|
}
|
|
|
|
virtual TradeOrder CheckSignal()
|
|
{
|
|
TradeOrder ord; ord.strategy_name = Name();
|
|
|
|
// Skip if insufficient data
|
|
if(m_atr <= 0 || m_bb_upper <= 0) return ord;
|
|
|
|
// Gold-specific volatility breakout strategy
|
|
double bb_width = m_bb_upper - m_bb_lower;
|
|
double bb_position = (m_close0 - m_bb_lower) / bb_width;
|
|
|
|
// Volume confirmation
|
|
bool high_volume = m_volume > m_volume_ma * 1.5;
|
|
|
|
// Bollinger Band squeeze breakout
|
|
bool squeeze_condition = bb_width < m_atr * 2.0;
|
|
|
|
// Long setup: breakout above upper band with volume
|
|
if(m_close0 > m_bb_upper && high_volume && !squeeze_condition)
|
|
{
|
|
ord.action = ACTION_BUY;
|
|
ord.order_type = ORDER_TYPE_BUY;
|
|
ord.stop_loss = m_bb_middle;
|
|
ord.take_profit = m_close0 + m_atr * 2;
|
|
ord.trailing_enabled = true;
|
|
ord.trailing_type = TRAIL_ATR;
|
|
ord.atr_period = m_atrPeriod;
|
|
ord.atr_multiplier = 1.5;
|
|
return ord;
|
|
}
|
|
|
|
// Short setup: breakdown below lower band with volume
|
|
else if(m_close0 < m_bb_lower && high_volume && !squeeze_condition)
|
|
{
|
|
ord.action = ACTION_SELL;
|
|
ord.order_type = ORDER_TYPE_SELL;
|
|
ord.stop_loss = m_bb_middle;
|
|
ord.take_profit = m_close0 - m_atr * 2;
|
|
ord.trailing_enabled = true;
|
|
ord.trailing_type = TRAIL_ATR;
|
|
ord.atr_period = m_atrPeriod;
|
|
ord.atr_multiplier = 1.5;
|
|
return ord;
|
|
}
|
|
|
|
// Mean reversion: oversold bounce from lower band
|
|
else if(bb_position < 0.1 && m_close0 > m_close1)
|
|
{
|
|
ord.action = ACTION_BUY;
|
|
ord.order_type = ORDER_TYPE_BUY;
|
|
ord.stop_loss = m_close0 - m_atr * 0.5;
|
|
ord.take_profit = m_bb_middle;
|
|
return ord;
|
|
}
|
|
|
|
// Mean reversion: overbought pullback from upper band
|
|
else if(bb_position > 0.9 && m_close0 < m_close1)
|
|
{
|
|
ord.action = ACTION_SELL;
|
|
ord.order_type = ORDER_TYPE_SELL;
|
|
ord.stop_loss = m_close0 + m_atr * 0.5;
|
|
ord.take_profit = m_bb_middle;
|
|
return ord;
|
|
}
|
|
|
|
return ord;
|
|
}
|
|
|
|
virtual void ExportFeatures(CFeaturesKB* kb, const datetime ts)
|
|
{
|
|
if(CheckPointer(kb)==POINTER_INVALID) return;
|
|
(*kb).WriteKV(ts, m_symbol, Name(), "atr", m_atr);
|
|
(*kb).WriteKV(ts, m_symbol, Name(), "bb_position", (m_close0 - m_bb_lower) / (m_bb_upper - m_bb_lower));
|
|
(*kb).WriteKV(ts, m_symbol, Name(), "volume_ratio", m_volume / (m_volume_ma + 0.00001));
|
|
}
|
|
};
|