mql5/Experts/Advisors/Modules_optimised/Entrysystem_Optimised.mqh

1053 lines
37 KiB
MQL5
Raw Permalink Normal View History

//+------------------------------------------------------------------+
//| EntrySystem.mqh v2.0 |
//| Optimized Entry Signal Generation |
//| Enhanced with signal caching |
//+------------------------------------------------------------------+
#ifndef ENTRY_SYSTEM_MQH
#define ENTRY_SYSTEM_MQH
#include "Datatypes_Optimised.mqh"
#include <Indicators/Indicators.mqh>
//+------------------------------------------------------------------+
//| Entry System Class - Optimized Version |
//+------------------------------------------------------------------+
class CEntrySystem
{
private:
//--- Configuration
EntrySystemConfig m_config;
//--- Indicator handles (persistent)
int m_ma_fast_handle;
int m_ma_slow_handle;
int m_ma_filter_handle;
int m_rsi_handle;
int m_adx_handle;
int m_bb_handle;
int m_macd_handle;
int m_stoch_handle;
int m_atr_handle; // Dedicated ATR handle
//--- Signal tracking
datetime m_last_signal_time;
ENUM_SIGNAL_TYPE m_last_signal_type;
int m_consecutive_signals;
//--- Performance metrics
int m_signals_generated;
int m_signals_filtered;
double m_signal_accuracy;
//--- Bar tracking
datetime m_last_bar_time;
bool m_new_bar;
//--- Signal cache
struct SignalCache
{
datetime time;
EntrySignal signal;
bool valid;
};
SignalCache m_signal_cache;
//--- ATR cache for efficiency
double m_cached_atr;
datetime m_atr_cache_time;
//--- Entry methods
EntrySignal CheckMACrossover(const MarketConditions &market);
EntrySignal CheckMAPullback(const MarketConditions &market);
EntrySignal CheckMomentum(const MarketConditions &market);
EntrySignal CheckContrarian(const MarketConditions &market);
EntrySignal CheckBreakout(const MarketConditions &market);
EntrySignal CheckMeanReversion(const MarketConditions &market);
EntrySignal CheckMultiStrategy(const MarketConditions &market);
//--- Helper methods
bool IsNewBar();
bool CheckFilter(ENUM_SIGNAL_TYPE signal_type, const MarketConditions &market);
double CalculateSignalStrength(const EntrySignal &signal, const MarketConditions &market);
void AddTechnicalContext(EntrySignal &signal, const MarketConditions &market);
double GetCachedATR();
bool ValidateMarketHours();
double ScoreSignalQuality(const EntrySignal &signal, const MarketConditions &market);
void OptimizeStopDistance(EntrySignal &signal, const MarketConditions &market);
//--- Indicator data buffers (reusable)
double m_ma_fast_buffer[3];
double m_ma_slow_buffer[3];
double m_rsi_buffer[3];
double m_adx_buffer[3];
double m_bb_upper_buffer[3];
double m_bb_lower_buffer[3];
double m_bb_middle_buffer[3];
public:
CEntrySystem();
~CEntrySystem();
//--- Initialization
bool Initialize(const EntrySystemConfig &config);
void UpdateConfiguration(const EntrySystemConfig &config);
//--- Main method
EntrySignal CheckSignal(const MarketConditions &market);
//--- Signal validation
bool ValidateSignal(const EntrySignal &signal, const MarketConditions &market);
//--- Performance tracking
void UpdateSignalPerformance(const EntrySignal &signal, bool success);
//--- Getters
int GetConsecutiveSignals() { return m_consecutive_signals; }
datetime GetLastSignalTime() { return m_last_signal_time; }
double GetSignalAccuracy() { return m_signal_accuracy; }
int GetSignalsGenerated() { return m_signals_generated; }
//--- Market timing
bool IsOptimalTradingTime();
bool ShouldAvoidNews(const MarketConditions &market);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CEntrySystem::CEntrySystem()
{
//--- Initialize handles
m_ma_fast_handle = INVALID_HANDLE;
m_ma_slow_handle = INVALID_HANDLE;
m_ma_filter_handle = INVALID_HANDLE;
m_rsi_handle = INVALID_HANDLE;
m_adx_handle = INVALID_HANDLE;
m_bb_handle = INVALID_HANDLE;
m_macd_handle = INVALID_HANDLE;
m_stoch_handle = INVALID_HANDLE;
m_atr_handle = INVALID_HANDLE;
//--- Initialize tracking
m_last_signal_time = 0;
m_last_signal_type = SIGNAL_NONE;
m_consecutive_signals = 0;
m_signals_generated = 0;
m_signals_filtered = 0;
m_signal_accuracy = 0;
//--- Initialize cache
m_signal_cache.valid = false;
m_cached_atr = 0;
m_atr_cache_time = 0;
m_last_bar_time = 0;
m_new_bar = false;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CEntrySystem::~CEntrySystem()
{
//--- Release all indicator handles
if(m_ma_fast_handle != INVALID_HANDLE) IndicatorRelease(m_ma_fast_handle);
if(m_ma_slow_handle != INVALID_HANDLE) IndicatorRelease(m_ma_slow_handle);
if(m_ma_filter_handle != INVALID_HANDLE) IndicatorRelease(m_ma_filter_handle);
if(m_rsi_handle != INVALID_HANDLE) IndicatorRelease(m_rsi_handle);
if(m_adx_handle != INVALID_HANDLE) IndicatorRelease(m_adx_handle);
if(m_bb_handle != INVALID_HANDLE) IndicatorRelease(m_bb_handle);
if(m_macd_handle != INVALID_HANDLE) IndicatorRelease(m_macd_handle);
if(m_stoch_handle != INVALID_HANDLE) IndicatorRelease(m_stoch_handle);
if(m_atr_handle != INVALID_HANDLE) IndicatorRelease(m_atr_handle);
}
//+------------------------------------------------------------------+
//| Initialize entry system - Optimized |
//+------------------------------------------------------------------+
bool CEntrySystem::Initialize(const EntrySystemConfig &config)
{
m_config = config;
//--- Always create ATR for stop calculations
m_atr_handle = iATR(_Symbol, PERIOD_CURRENT, 14);
if(m_atr_handle == INVALID_HANDLE)
{
Print("EntrySystem: Failed to create ATR indicator");
return false;
}
//--- Create indicators based on entry mode
bool init_success = true;
switch(m_config.entry_mode)
{
case ENTRY_MA_CROSS:
case ENTRY_MA_PULLBACK:
m_ma_fast_handle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE);
m_ma_slow_handle = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE);
m_ma_filter_handle = iMA(_Symbol, PERIOD_CURRENT, 200, 0, MODE_SMA, PRICE_CLOSE);
init_success = (m_ma_fast_handle != INVALID_HANDLE &&
m_ma_slow_handle != INVALID_HANDLE);
break;
case ENTRY_MOMENTUM:
m_rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
m_adx_handle = iADX(_Symbol, PERIOD_CURRENT, 14);
m_macd_handle = iMACD(_Symbol, PERIOD_CURRENT, 12, 26, 9, PRICE_CLOSE);
init_success = (m_rsi_handle != INVALID_HANDLE &&
m_adx_handle != INVALID_HANDLE &&
m_macd_handle != INVALID_HANDLE);
break;
case ENTRY_MEAN_REVERSION:
case ENTRY_BREAKOUT:
m_bb_handle = iBands(_Symbol, PERIOD_CURRENT, 20, 0, 2.0, PRICE_CLOSE);
m_rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
if(m_config.entry_mode == ENTRY_BREAKOUT)
m_adx_handle = iADX(_Symbol, PERIOD_CURRENT, 14);
init_success = (m_bb_handle != INVALID_HANDLE &&
m_rsi_handle != INVALID_HANDLE);
break;
case ENTRY_MULTI_STRATEGY:
//--- Create all indicators for multi-strategy
m_ma_fast_handle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE);
m_ma_slow_handle = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE);
m_ma_filter_handle = iMA(_Symbol, PERIOD_CURRENT, 200, 0, MODE_SMA, PRICE_CLOSE);
m_rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
m_adx_handle = iADX(_Symbol, PERIOD_CURRENT, 14);
m_bb_handle = iBands(_Symbol, PERIOD_CURRENT, 20, 0, 2.0, PRICE_CLOSE);
m_macd_handle = iMACD(_Symbol, PERIOD_CURRENT, 12, 26, 9, PRICE_CLOSE);
m_stoch_handle = iStochastic(_Symbol, PERIOD_CURRENT, 5, 3, 3, MODE_SMA, STO_LOWHIGH);
init_success = (m_ma_fast_handle != INVALID_HANDLE &&
m_rsi_handle != INVALID_HANDLE &&
m_bb_handle != INVALID_HANDLE);
break;
case ENTRY_CONTRARIAN:
m_rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
m_bb_handle = iBands(_Symbol, PERIOD_CURRENT, 20, 0, 2.0, PRICE_CLOSE);
m_stoch_handle = iStochastic(_Symbol, PERIOD_CURRENT, 5, 3, 3, MODE_SMA, STO_LOWHIGH);
init_success = (m_rsi_handle != INVALID_HANDLE &&
m_bb_handle != INVALID_HANDLE);
break;
}
if(!init_success)
{
Print("EntrySystem: Failed to create required indicators");
return false;
}
Print("EntrySystem initialized: Mode=", EnumToString(m_config.entry_mode));
return true;
}
//+------------------------------------------------------------------+
//| Check signal - Optimized main function |
//+------------------------------------------------------------------+
EntrySignal CEntrySystem::CheckSignal(const MarketConditions &market)
{
//--- Check if cached signal is still valid (within same bar)
if(m_signal_cache.valid && m_signal_cache.time == iTime(_Symbol, PERIOD_CURRENT, 0))
{
return m_signal_cache.signal;
}
//--- Initialize empty signal
EntrySignal signal;
signal.signal_type = SIGNAL_NONE;
signal.entry_price = 0;
signal.stop_loss_distance = 0;
signal.take_profit_distance = 0;
signal.confidence = 0;
signal.comment = "";
signal.signal_time = TimeCurrent();
signal.timeframe = Period();
//--- Validate market conditions
if(market.volatility <= 0)
{
Print("EntrySystem: Invalid market volatility");
return signal;
}
//--- Check time restrictions
if(!ValidateMarketHours())
{
return signal;
}
//--- Check if enough time passed since last signal
if(TimeCurrent() - m_last_signal_time < m_config.min_time_between * 60)
{
return signal;
}
//--- Check for new bar
m_new_bar = IsNewBar();
//--- Only check on new bar for most strategies (except breakout)
if(!m_new_bar && m_config.entry_mode != ENTRY_BREAKOUT)
{
return signal;
}
//--- Check signals based on entry mode
switch(m_config.entry_mode)
{
case ENTRY_MA_CROSS:
signal = CheckMACrossover(market);
break;
case ENTRY_MA_PULLBACK:
signal = CheckMAPullback(market);
break;
case ENTRY_MOMENTUM:
signal = CheckMomentum(market);
break;
case ENTRY_CONTRARIAN:
signal = CheckContrarian(market);
break;
case ENTRY_BREAKOUT:
signal = CheckBreakout(market);
break;
case ENTRY_MEAN_REVERSION:
signal = CheckMeanReversion(market);
break;
case ENTRY_MULTI_STRATEGY:
signal = CheckMultiStrategy(market);
break;
}
//--- Process valid signals
if(signal.signal_type != SIGNAL_NONE)
{
m_signals_generated++;
//--- Ensure valid stop distances
OptimizeStopDistance(signal, market);
//--- Add technical context
AddTechnicalContext(signal, market);
//--- Calculate final signal strength
signal.confidence = CalculateSignalStrength(signal, market);
//--- Apply signal threshold
if(signal.confidence < m_config.signal_threshold)
{
m_signals_filtered++;
signal.signal_type = SIGNAL_NONE;
return signal;
}
//--- Validate signal
if(ValidateSignal(signal, market))
{
//--- Update tracking
m_last_signal_time = TimeCurrent();
m_last_signal_type = signal.signal_type;
if(signal.signal_type == m_last_signal_type)
m_consecutive_signals++;
else
m_consecutive_signals = 1;
//--- Cache the signal
m_signal_cache.time = iTime(_Symbol, PERIOD_CURRENT, 0);
m_signal_cache.signal = signal;
m_signal_cache.valid = true;
//--- Log signal
Print("EntrySystem: ", signal.comment,
" | Confidence: ", DoubleToString(signal.confidence, 1), "%",
" | SL: ", DoubleToString(signal.stop_loss_distance / _Point, 1), " points",
" | TP: ", DoubleToString(signal.take_profit_distance / _Point, 1), " points");
}
else
{
m_signals_filtered++;
signal.signal_type = SIGNAL_NONE;
}
}
return signal;
}
//+------------------------------------------------------------------+
//| MA Crossover Strategy - Optimized |
//+------------------------------------------------------------------+
EntrySignal CEntrySystem::CheckMACrossover(const MarketConditions &market)
{
EntrySignal signal;
signal.signal_type = SIGNAL_NONE;
//--- Get MA values efficiently
if(CopyBuffer(m_ma_fast_handle, 0, 0, 3, m_ma_fast_buffer) < 3) return signal;
if(CopyBuffer(m_ma_slow_handle, 0, 0, 3, m_ma_slow_buffer) < 3) return signal;
//--- Optional filter
double ma_filter = 0;
if(m_ma_filter_handle != INVALID_HANDLE)
{
double filter_buffer[1];
if(CopyBuffer(m_ma_filter_handle, 0, 0, 1, filter_buffer) > 0)
ma_filter = filter_buffer[0];
}
//--- Check for crossover
bool bullish_cross = (m_ma_fast_buffer[2] <= m_ma_slow_buffer[2] &&
m_ma_fast_buffer[1] > m_ma_slow_buffer[1]);
bool bearish_cross = (m_ma_fast_buffer[2] >= m_ma_slow_buffer[2] &&
m_ma_fast_buffer[1] < m_ma_slow_buffer[1]);
//--- Apply filter
double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
bool above_filter = (ma_filter == 0) || (current_price > ma_filter);
bool below_filter = (ma_filter == 0) || (current_price < ma_filter);
//--- Generate signal
if(bullish_cross && above_filter)
{
signal.signal_type = SIGNAL_BUY;
signal.entry_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
signal.comment = "MA Bullish Cross";
signal.confidence = 70;
//--- Calculate crossover angle for confidence
double cross_angle = MathAbs(m_ma_fast_buffer[1] - m_ma_slow_buffer[1]) / _Point;
if(cross_angle > 20) signal.confidence += 10;
if(cross_angle > 50) signal.confidence += 10;
}
else if(bearish_cross && below_filter)
{
signal.signal_type = SIGNAL_SELL;
signal.entry_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
signal.comment = "MA Bearish Cross";
signal.confidence = 70;
//--- Calculate crossover angle
double cross_angle = MathAbs(m_ma_fast_buffer[1] - m_ma_slow_buffer[1]) / _Point;
if(cross_angle > 20) signal.confidence += 10;
if(cross_angle > 50) signal.confidence += 10;
}
//--- Set stop/target distances based on ATR
if(signal.signal_type != SIGNAL_NONE)
{
double atr = GetCachedATR();
signal.stop_loss_distance = atr * 2.0;
signal.take_profit_distance = atr * 3.0;
signal.atr_value = atr;
}
return signal;
}
//+------------------------------------------------------------------+
//| Momentum Strategy - Enhanced |
//+------------------------------------------------------------------+
EntrySignal CEntrySystem::CheckMomentum(const MarketConditions &market)
{
EntrySignal signal;
signal.signal_type = SIGNAL_NONE;
//--- Get indicator values
double rsi[2], adx[1], adx_di_plus[1], adx_di_minus[1];
double macd_main[2], macd_signal[2];
if(CopyBuffer(m_rsi_handle, 0, 0, 2, rsi) < 2) return signal;
if(CopyBuffer(m_adx_handle, 0, 0, 1, adx) < 1) return signal;
if(CopyBuffer(m_adx_handle, 1, 0, 1, adx_di_plus) < 1) return signal;
if(CopyBuffer(m_adx_handle, 2, 0, 1, adx_di_minus) < 1) return signal;
if(CopyBuffer(m_macd_handle, 0, 0, 2, macd_main) < 2) return signal;
if(CopyBuffer(m_macd_handle, 1, 0, 2, macd_signal) < 2) return signal;
//--- Strong trend requirement
if(adx[0] < 25) return signal;
//--- Bullish momentum
if(rsi[0] > 50 && rsi[0] < 70 && // Not overbought
rsi[0] > rsi[1] && // Rising RSI
adx_di_plus[0] > adx_di_minus[0] && // Bullish direction
macd_main[0] > macd_signal[0] && // MACD bullish
macd_main[0] > macd_main[1]) // MACD rising
{
signal.signal_type = SIGNAL_BUY;
signal.entry_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
signal.comment = "Momentum Buy";
//--- Dynamic confidence based on indicators
signal.confidence = 60;
signal.confidence += (adx[0] - 25) * 0.8; // ADX strength
signal.confidence += (rsi[0] - 50) * 0.3; // RSI momentum
signal.confidence = MathMin(signal.confidence, 95);
}
//--- Bearish momentum
else if(rsi[0] < 50 && rsi[0] > 30 && // Not oversold
rsi[0] < rsi[1] && // Falling RSI
adx_di_minus[0] > adx_di_plus[0] && // Bearish direction
macd_main[0] < macd_signal[0] && // MACD bearish
macd_main[0] < macd_main[1]) // MACD falling
{
signal.signal_type = SIGNAL_SELL;
signal.entry_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
signal.comment = "Momentum Sell";
//--- Dynamic confidence
signal.confidence = 60;
signal.confidence += (adx[0] - 25) * 0.8;
signal.confidence += (50 - rsi[0]) * 0.3;
signal.confidence = MathMin(signal.confidence, 95);
}
//--- Set stops based on volatility and momentum
if(signal.signal_type != SIGNAL_NONE)
{
double atr = GetCachedATR();
//--- Tighter stops in strong momentum
double stop_multiplier = (adx[0] > 40) ? 1.5 : 2.0;
signal.stop_loss_distance = atr * stop_multiplier;
//--- Wider targets in strong trends
double target_multiplier = (adx[0] > 40) ? 4.0 : 3.0;
signal.take_profit_distance = atr * target_multiplier;
signal.atr_value = atr;
}
return signal;
}
//+------------------------------------------------------------------+
//| Breakout Strategy - Enhanced with volume |
//+------------------------------------------------------------------+
EntrySignal CEntrySystem::CheckBreakout(const MarketConditions &market)
{
EntrySignal signal;
signal.signal_type = SIGNAL_NONE;
//--- Get Bollinger Bands
if(CopyBuffer(m_bb_handle, 1, 0, 2, m_bb_upper_buffer) < 2) return signal;
if(CopyBuffer(m_bb_handle, 2, 0, 2, m_bb_lower_buffer) < 2) return signal;
if(CopyBuffer(m_bb_handle, 0, 0, 1, m_bb_middle_buffer) < 1) return signal;
double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double prev_close = iClose(_Symbol, PERIOD_CURRENT, 1);
//--- Volume analysis
long current_volume = iVolume(_Symbol, PERIOD_CURRENT, 0);
long avg_volume = 0;
for(int i = 1; i <= 20; i++)
avg_volume += iVolume(_Symbol, PERIOD_CURRENT, i);
avg_volume /= 20;
double volume_ratio = (avg_volume > 0) ? (double)current_volume / avg_volume : 1.0;
bool volume_surge = volume_ratio > 1.5;
//--- Upper band breakout
if(current_price > m_bb_upper_buffer[0] &&
prev_close <= m_bb_upper_buffer[1])
{
signal.signal_type = SIGNAL_BUY;
signal.entry_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
signal.comment = "Bollinger Upper Breakout";
//--- Base confidence
signal.confidence = 60;
//--- Volume confirmation
if(volume_surge)
{
signal.confidence += 20;
signal.comment += " (Volume Confirmed)";
}
//--- Band width analysis
double band_width = (m_bb_upper_buffer[0] - m_bb_lower_buffer[0]) / m_bb_middle_buffer[0];
if(band_width < 0.02) // Squeeze breakout
{
signal.confidence += 15;
signal.comment += " (Squeeze)";
}
}
//--- Lower band breakout
else if(current_price < m_bb_lower_buffer[0] &&
prev_close >= m_bb_lower_buffer[1])
{
signal.signal_type = SIGNAL_SELL;
signal.entry_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
signal.comment = "Bollinger Lower Breakout";
signal.confidence = 60;
if(volume_surge)
{
signal.confidence += 20;
signal.comment += " (Volume Confirmed)";
}
double band_width = (m_bb_upper_buffer[0] - m_bb_lower_buffer[0]) / m_bb_middle_buffer[0];
if(band_width < 0.02)
{
signal.confidence += 15;
signal.comment += " (Squeeze)";
}
}
//--- Set stops for breakout
if(signal.signal_type != SIGNAL_NONE)
{
double atr = GetCachedATR();
//--- Use band structure for stops
if(signal.signal_type == SIGNAL_BUY)
{
signal.stop_loss_distance = MathMax(current_price - m_bb_middle_buffer[0], atr * 1.5);
signal.take_profit_distance = (m_bb_upper_buffer[0] - m_bb_middle_buffer[0]) * 2.5;
}
else
{
signal.stop_loss_distance = MathMax(m_bb_middle_buffer[0] - current_price, atr * 1.5);
signal.take_profit_distance = (m_bb_middle_buffer[0] - m_bb_lower_buffer[0]) * 2.5;
}
signal.atr_value = atr;
}
return signal;
}
//+------------------------------------------------------------------+
//| Multi-Strategy Consensus - Optimized |
//+------------------------------------------------------------------+
EntrySignal CEntrySystem::CheckMultiStrategy(const MarketConditions &market)
{
EntrySignal signal;
signal.signal_type = SIGNAL_NONE;
//--- Collect signals from strategies
EntrySignal signals[5];
double weights[5] = {1.0, 1.2, 1.5, 0.8, 1.0}; // Strategy weights
signals[0] = CheckMACrossover(market);
signals[1] = CheckMomentum(market);
signals[2] = CheckBreakout(market);
signals[3] = CheckMeanReversion(market);
signals[4] = CheckMAPullback(market);
//--- Weighted voting
double buy_score = 0, sell_score = 0;
double total_buy_confidence = 0, total_sell_confidence = 0;
int buy_count = 0, sell_count = 0;
for(int i = 0; i < 5; i++)
{
if(signals[i].signal_type == SIGNAL_BUY)
{
buy_count++;
buy_score += weights[i];
total_buy_confidence += signals[i].confidence * weights[i];
}
else if(signals[i].signal_type == SIGNAL_SELL)
{
sell_count++;
sell_score += weights[i];
total_sell_confidence += signals[i].confidence * weights[i];
}
}
//--- Need weighted majority (>2.5 weight score)
if(buy_score >= 2.5 && buy_score > sell_score)
{
signal.signal_type = SIGNAL_BUY;
signal.entry_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
signal.comment = StringFormat("Multi-Strategy Buy (%d/5 strategies)", buy_count);
signal.confidence = total_buy_confidence / buy_score;
//--- Bonus for unanimous decision
if(buy_count >= 4) signal.confidence += 10;
}
else if(sell_score >= 2.5 && sell_score > buy_score)
{
signal.signal_type = SIGNAL_SELL;
signal.entry_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
signal.comment = StringFormat("Multi-Strategy Sell (%d/5 strategies)", sell_count);
signal.confidence = total_sell_confidence / sell_score;
if(sell_count >= 4) signal.confidence += 10;
}
//--- Average stops from agreeing strategies
if(signal.signal_type != SIGNAL_NONE)
{
double avg_sl = 0, avg_tp = 0;
int count = 0;
for(int i = 0; i < 5; i++)
{
if(signals[i].signal_type == signal.signal_type)
{
avg_sl += signals[i].stop_loss_distance;
avg_tp += signals[i].take_profit_distance;
count++;
}
}
if(count > 0)
{
signal.stop_loss_distance = avg_sl / count;
signal.take_profit_distance = avg_tp / count;
}
else
{
//--- Fallback
double atr = GetCachedATR();
signal.stop_loss_distance = atr * 2.0;
signal.take_profit_distance = atr * 3.0;
}
signal.atr_value = GetCachedATR();
}
return signal;
}
//+------------------------------------------------------------------+
//| Get cached ATR value |
//+------------------------------------------------------------------+
double CEntrySystem::GetCachedATR()
{
//--- Check cache validity (5 seconds)
if(TimeCurrent() - m_atr_cache_time < 5 && m_cached_atr > 0)
return m_cached_atr;
//--- Update cache
double atr_buffer[1];
if(m_atr_handle != INVALID_HANDLE &&
CopyBuffer(m_atr_handle, 0, 0, 1, atr_buffer) > 0 &&
atr_buffer[0] > 0)
{
m_cached_atr = atr_buffer[0];
m_atr_cache_time = TimeCurrent();
return m_cached_atr;
}
//--- Fallback calculation
double sum = 0;
int period = 14;
for(int i = 1; i <= period; i++)
{
double high = iHigh(_Symbol, PERIOD_CURRENT, i);
double low = iLow(_Symbol, PERIOD_CURRENT, i);
double close_prev = iClose(_Symbol, PERIOD_CURRENT, i + 1);
double tr = MathMax(high - low, MathMax(MathAbs(high - close_prev), MathAbs(low - close_prev)));
sum += tr;
}
m_cached_atr = sum / period;
m_atr_cache_time = TimeCurrent();
//--- Final validation
if(m_cached_atr <= 0)
{
m_cached_atr = 50 * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
Print("EntrySystem: Using fallback ATR");
}
return m_cached_atr;
}
//+------------------------------------------------------------------+
//| Optimize stop distances based on market conditions |
//+------------------------------------------------------------------+
void CEntrySystem::OptimizeStopDistance(EntrySignal &signal, const MarketConditions &market)
{
//--- Ensure minimum stop distance
double min_stop = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) *
SymbolInfoDouble(_Symbol, SYMBOL_POINT) * 1.1;
//--- Adjust for market conditions
double volatility_factor = 1.0;
switch(market.condition)
{
case MARKET_VOLATILE:
volatility_factor = 1.3; // Wider stops in volatile markets
break;
case MARKET_QUIET:
volatility_factor = 0.8; // Tighter stops in quiet markets
break;
case MARKET_TRENDING_UP:
case MARKET_TRENDING_DOWN:
volatility_factor = 1.1; // Slightly wider in trends
break;
}
//--- Apply adjustments
signal.stop_loss_distance *= volatility_factor;
signal.take_profit_distance *= volatility_factor;
//--- Ensure minimum distances
signal.stop_loss_distance = MathMax(signal.stop_loss_distance, min_stop);
signal.take_profit_distance = MathMax(signal.take_profit_distance, min_stop);
//--- Ensure minimum R:R ratio
if(m_config.min_rr_ratio > 0)
{
double min_tp = signal.stop_loss_distance * m_config.min_rr_ratio;
signal.take_profit_distance = MathMax(signal.take_profit_distance, min_tp);
}
//--- Round to symbol point
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
signal.stop_loss_distance = NormalizeDouble(signal.stop_loss_distance, _Digits);
signal.take_profit_distance = NormalizeDouble(signal.take_profit_distance, _Digits);
}
//+------------------------------------------------------------------+
//| Validate signal quality |
//+------------------------------------------------------------------+
bool CEntrySystem::ValidateSignal(const EntrySignal &signal, const MarketConditions &market)
{
//--- Basic validation
if(signal.stop_loss_distance <= 0 || signal.take_profit_distance <= 0)
{
Print("EntrySystem: Invalid stop/target distances");
return false;
}
//--- Check spread
double max_spread = signal.stop_loss_distance * 0.2; // Max 20% of stop
if(market.spread > max_spread)
{
Print("EntrySystem: Spread too high - ",
DoubleToString(market.spread/_Point, 1), " points");
return false;
}
//--- Check news filter
if(m_config.filter_news && market.news_event)
{
Print("EntrySystem: Signal rejected - news event");
return false;
}
//--- Check R:R ratio
double rr_ratio = signal.take_profit_distance / signal.stop_loss_distance;
if(m_config.min_rr_ratio > 0 && rr_ratio < m_config.min_rr_ratio)
{
Print("EntrySystem: R:R ratio too low - ", DoubleToString(rr_ratio, 2));
return false;
}
//--- Market condition filter
if(m_config.entry_mode == ENTRY_MOMENTUM &&
(market.condition == MARKET_RANGING || market.condition == MARKET_QUIET))
{
Print("EntrySystem: Momentum signal rejected in ranging market");
return false;
}
if(m_config.entry_mode == ENTRY_MEAN_REVERSION &&
(market.condition == MARKET_TRENDING_UP || market.condition == MARKET_TRENDING_DOWN))
{
Print("EntrySystem: Mean reversion rejected in trending market");
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Check if new bar formed |
//+------------------------------------------------------------------+
bool CEntrySystem::IsNewBar()
{
datetime current_bar_time = iTime(_Symbol, PERIOD_CURRENT, 0);
if(current_bar_time != m_last_bar_time)
{
m_last_bar_time = current_bar_time;
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Validate market hours |
//+------------------------------------------------------------------+
bool CEntrySystem::ValidateMarketHours()
{
if(!m_config.use_market_hours)
return true;
MqlDateTime current_time;
TimeCurrent(current_time);
//--- Check day of week
if(current_time.day_of_week == 0 || current_time.day_of_week == 6)
return false;
//--- Friday close
if(m_config.friday_close && current_time.day_of_week == 5 && current_time.hour >= 20)
return false;
//--- Check trading hours
if(current_time.hour < m_config.start_hour || current_time.hour >= m_config.end_hour)
return false;
return true;
}
//+------------------------------------------------------------------+
//| Calculate signal strength with market context |
//+------------------------------------------------------------------+
double CEntrySystem::CalculateSignalStrength(const EntrySignal &signal, const MarketConditions &market)
{
double strength = signal.confidence;
//--- Market alignment bonus
if((signal.signal_type == SIGNAL_BUY && market.condition == MARKET_TRENDING_UP) ||
(signal.signal_type == SIGNAL_SELL && market.condition == MARKET_TRENDING_DOWN))
{
strength += 10;
}
//--- Trend strength bonus
if(market.trend_strength > 30)
strength += 5;
if(market.trend_strength > 50)
strength += 5;
//--- Volatility adjustment
if(market.volatility_percentile > 80) // High volatility
strength -= 5;
else if(market.volatility_percentile < 20) // Low volatility
strength += 5;
//--- Support/Resistance proximity
for(int i = 0; i < market.sr_count && i < 5; i++)
{
double distance = MathAbs(signal.entry_price - market.sr_levels[i].price);
if(distance < market.volatility * 0.5)
{
strength += market.sr_levels[i].strength / 20; // Max +5 from S/R
}
}
return MathMin(strength, 100);
}
//+------------------------------------------------------------------+
//| Add technical context to signal |
//+------------------------------------------------------------------+
void CEntrySystem::AddTechnicalContext(EntrySignal &signal, const MarketConditions &market)
{
signal.atr_value = GetCachedATR();
signal.spread_value = market.spread;
//--- Add nearest key levels
int levels_added = 0;
for(int i = 0; i < market.sr_count && levels_added < 5; i++)
{
double level_distance = MathAbs(signal.entry_price - market.sr_levels[i].price);
//--- Include levels within 2 ATR
if(level_distance < signal.atr_value * 2)
{
signal.key_levels[levels_added] = market.sr_levels[i];
levels_added++;
}
}
//--- Calculate expected R:R
signal.expected_rr = signal.take_profit_distance / signal.stop_loss_distance;
//--- Suggested risk based on signal quality
if(signal.confidence >= 80)
signal.suggested_risk = 2.0; // 2% for high confidence
else if(signal.confidence >= 60)
signal.suggested_risk = 1.0; // 1% for medium
else
signal.suggested_risk = 0.5; // 0.5% for low
}
//+------------------------------------------------------------------+
//| Update signal performance tracking |
//+------------------------------------------------------------------+
void CEntrySystem::UpdateSignalPerformance(const EntrySignal &signal, bool success)
{
//--- Simple exponential average of success rate
double alpha = 0.1; // Learning rate
if(success)
m_signal_accuracy = m_signal_accuracy * (1 - alpha) + 1.0 * alpha;
else
m_signal_accuracy = m_signal_accuracy * (1 - alpha) + 0.0 * alpha;
}
//+------------------------------------------------------------------+
//| Additional signal generation methods |
//+------------------------------------------------------------------+
//--- MA Pullback implementation
EntrySignal CEntrySystem::CheckMAPullback(const MarketConditions &market)
{
EntrySignal signal;
signal.signal_type = SIGNAL_NONE;
//--- Similar structure to other methods but checking for pullbacks
//--- Implementation details...
return signal;
}
//--- Mean Reversion implementation
EntrySignal CEntrySystem::CheckMeanReversion(const MarketConditions &market)
{
EntrySignal signal;
signal.signal_type = SIGNAL_NONE;
//--- Check if market is ranging
if(market.condition != MARKET_RANGING && market.condition != MARKET_QUIET)
return signal;
//--- Implementation details...
return signal;
}
//--- Contrarian implementation
EntrySignal CEntrySystem::CheckContrarian(const MarketConditions &market)
{
EntrySignal signal;
signal.signal_type = SIGNAL_NONE;
//--- Look for extreme moves to fade
//--- Implementation details...
return signal;
}
#endif // ENTRY_SYSTEM_MQH
2025-08-15 23:05:57 +01:00
//+------------------------------------------------------------------+