//+------------------------------------------------------------------+ //| StrategySignalGenerators.mqh - Extensible Signal Generator Framework | //| Provides actual indicator-based signal generation for all strategies | //+------------------------------------------------------------------+ #ifndef __STRATEGY_SIGNAL_GENERATORS_MQH__ #define __STRATEGY_SIGNAL_GENERATORS_MQH__ #include "GateManager.mqh" //+------------------------------------------------------------------+ //| Base Interface for Strategy Signal Generators | //+------------------------------------------------------------------+ class ISignalGenerator { public: virtual ~ISignalGenerator() {} virtual string GetName() = 0; virtual bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) = 0; virtual string GetDescription() { return ""; } }; //+------------------------------------------------------------------+ //| Helper Functions for All Strategies | //+------------------------------------------------------------------+ double GetATR(string symbol, ENUM_TIMEFRAMES tf, int period = 14) { int handle = iATR(symbol, tf, period); if(handle == INVALID_HANDLE) return 0.0; double buf[1]; if(CopyBuffer(handle, 0, 0, 1, buf) != 1) { IndicatorRelease(handle); return 0.0; } IndicatorRelease(handle); return buf[0]; } double GetCurrentPrice(string symbol, bool bid = true) { return bid ? SymbolInfoDouble(symbol, SYMBOL_BID) : SymbolInfoDouble(symbol, SYMBOL_ASK); } void SetSignalDefaults(TradingSignal &signal, string symbol, ENUM_TIMEFRAMES tf, string strategy, int type, double price) { // Initialize all fields first to prevent garbage values signal.Init(); signal.id = strategy + "_" + IntegerToString(TimeCurrent()); signal.symbol = symbol; signal.timeframe = tf; signal.timestamp = TimeCurrent(); signal.price = price; signal.type = type; signal.order_type = (type == 0) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL; // Set order_type based on type signal.strategy = strategy; signal.volume = 0.1; signal.confidence = 0.6; double atr = GetATR(symbol, tf, 14); if(atr <= 0) atr = 100 * SymbolInfoDouble(symbol, SYMBOL_POINT); // TIMEFRAME-BASED MULTIPLIER: Longer timeframes = wider SL/TP double tf_multiplier = 1.0; switch(tf) { case PERIOD_M1: tf_multiplier = 0.5; break; // Tightest stops case PERIOD_M5: tf_multiplier = 0.7; break; case PERIOD_M15: tf_multiplier = 0.85; break; case PERIOD_M30: tf_multiplier = 1.0; break; // Baseline case PERIOD_H1: tf_multiplier = 1.3; break; case PERIOD_H4: tf_multiplier = 1.6; break; case PERIOD_D1: tf_multiplier = 2.0; break; // Wider stops case PERIOD_W1: tf_multiplier = 2.5; break; case PERIOD_MN1: tf_multiplier = 3.0; break; // Widest stops default: tf_multiplier = 1.0; break; } // Set SL/TP based on signal type with timeframe adjustment double sl_mult = 1.5 * tf_multiplier; double tp_mult = 2.5 * tf_multiplier; if(type == 0) // Buy { signal.sl = price - atr * sl_mult; signal.tp = price + atr * tp_mult; } else // Sell { signal.sl = price + atr * sl_mult; signal.tp = price - atr * tp_mult; } // Final safety check - ensure TP is never garbage if(signal.tp <= 0.0 || signal.tp > 1e10 || MathIsValidNumber(signal.tp) == false) { signal.tp = (type == 0) ? price + atr * tp_mult : price - atr * tp_mult; } } //+------------------------------------------------------------------+ //| ADX Strategy - Trend Strength | //+------------------------------------------------------------------+ class CADXSignalGenerator : public ISignalGenerator { private: int m_period; double m_threshold; public: CADXSignalGenerator(int period = 14, double threshold = 25.0) { m_period = period; m_threshold = threshold; } string GetName() override { return "ADXStrategy"; } string GetDescription() override { return "ADX trend strength with DI+/DI- crossover"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iADX(symbol, tf, m_period); if(handle == INVALID_HANDLE) return false; double adx[2], di_plus[2], di_minus[2]; if(CopyBuffer(handle, 0, 0, 2, adx) != 2) { IndicatorRelease(handle); return false; } if(CopyBuffer(handle, 1, 0, 2, di_plus) != 2) { IndicatorRelease(handle); return false; } if(CopyBuffer(handle, 2, 0, 2, di_minus) != 2) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); if(adx[0] < m_threshold) return false; double price = GetCurrentPrice(symbol); // DI+ crosses above DI- = Buy if(di_plus[1] <= di_minus[1] && di_plus[0] > di_minus[0]) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.5 + (adx[0] / 100.0) * 0.3; return true; } // DI- crosses above DI+ = Sell if(di_minus[1] <= di_plus[1] && di_minus[0] > di_plus[0]) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.5 + (adx[0] / 100.0) * 0.3; return true; } return false; } }; //+------------------------------------------------------------------+ //| RSI Strategy - Overbought/Oversold | //+------------------------------------------------------------------+ class CRSISignalGenerator : public ISignalGenerator { private: int m_period; double m_overbought, m_oversold; public: CRSISignalGenerator(int period = 14, double ob = 70.0, double os = 30.0) { m_period = period; m_overbought = ob; m_oversold = os; } string GetName() override { return "RSIStrategy"; } string GetDescription() override { return "RSI overbought/oversold reversal"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iRSI(symbol, tf, m_period, PRICE_CLOSE); if(handle == INVALID_HANDLE) return false; double rsi[2]; if(CopyBuffer(handle, 0, 0, 2, rsi) != 2) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); double price = GetCurrentPrice(symbol); // RSI crosses above oversold = Buy if(rsi[1] < m_oversold && rsi[0] >= m_oversold) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.55 + (m_oversold - rsi[1]) / 100.0; return true; } // RSI crosses below overbought = Sell if(rsi[1] > m_overbought && rsi[0] <= m_overbought) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.55 + (rsi[1] - m_overbought) / 100.0; return true; } return false; } }; //+------------------------------------------------------------------+ //| MACD Strategy - Crossover | //+------------------------------------------------------------------+ class CMACDSignalGenerator : public ISignalGenerator { private: int m_fast, m_slow, m_signal; public: CMACDSignalGenerator(int fast = 12, int slow = 26, int sig = 9) { m_fast = fast; m_slow = slow; m_signal = sig; } string GetName() override { return "MACDStrategy"; } string GetDescription() override { return "MACD line/signal crossover"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iMACD(symbol, tf, m_fast, m_slow, m_signal, PRICE_CLOSE); if(handle == INVALID_HANDLE) return false; double macd[2], sig_line[2]; if(CopyBuffer(handle, 0, 0, 2, macd) != 2) { IndicatorRelease(handle); return false; } if(CopyBuffer(handle, 1, 0, 2, sig_line) != 2) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); double price = GetCurrentPrice(symbol); // MACD crosses above signal = Buy if(macd[1] <= sig_line[1] && macd[0] > sig_line[0]) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.6; return true; } // MACD crosses below signal = Sell if(macd[1] >= sig_line[1] && macd[0] < sig_line[0]) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.6; return true; } return false; } }; //+------------------------------------------------------------------+ //| Stochastic Strategy - Crossover in OB/OS zones | //+------------------------------------------------------------------+ class CStochasticSignalGenerator : public ISignalGenerator { private: int m_k, m_d, m_slowing; double m_overbought, m_oversold; public: CStochasticSignalGenerator(int k = 14, int d = 3, int slowing = 3, double ob = 80.0, double os = 20.0) { m_k = k; m_d = d; m_slowing = slowing; m_overbought = ob; m_oversold = os; } string GetName() override { return "StochasticStrategy"; } string GetDescription() override { return "Stochastic K/D crossover in OB/OS zones"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iStochastic(symbol, tf, m_k, m_d, m_slowing, MODE_SMA, STO_LOWHIGH); if(handle == INVALID_HANDLE) return false; double k_line[2], d_line[2]; if(CopyBuffer(handle, 0, 0, 2, k_line) != 2) { IndicatorRelease(handle); return false; } if(CopyBuffer(handle, 1, 0, 2, d_line) != 2) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); double price = GetCurrentPrice(symbol); // K crosses above D in oversold = Buy if(k_line[0] < m_oversold && k_line[1] <= d_line[1] && k_line[0] > d_line[0]) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.58; return true; } // K crosses below D in overbought = Sell if(k_line[0] > m_overbought && k_line[1] >= d_line[1] && k_line[0] < d_line[0]) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.58; return true; } return false; } }; //+------------------------------------------------------------------+ //| CCI Strategy - Commodity Channel Index | //+------------------------------------------------------------------+ class CCCISignalGenerator : public ISignalGenerator { private: int m_period; double m_overbought, m_oversold; public: CCCISignalGenerator(int period = 20, double ob = 100.0, double os = -100.0) { m_period = period; m_overbought = ob; m_oversold = os; } string GetName() override { return "CCIStrategy"; } string GetDescription() override { return "CCI overbought/oversold crossover"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iCCI(symbol, tf, m_period, PRICE_TYPICAL); if(handle == INVALID_HANDLE) return false; double cci[2]; if(CopyBuffer(handle, 0, 0, 2, cci) != 2) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); double price = GetCurrentPrice(symbol); // CCI crosses above oversold = Buy if(cci[1] < m_oversold && cci[0] >= m_oversold) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.55; return true; } // CCI crosses below overbought = Sell if(cci[1] > m_overbought && cci[0] <= m_overbought) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.55; return true; } return false; } }; //+------------------------------------------------------------------+ //| Momentum Strategy | //+------------------------------------------------------------------+ class CMomentumSignalGenerator : public ISignalGenerator { private: int m_period; public: CMomentumSignalGenerator(int period = 14) { m_period = period; } string GetName() override { return "MomentumStrategy"; } string GetDescription() override { return "Momentum zero-line crossover"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iMomentum(symbol, tf, m_period, PRICE_CLOSE); if(handle == INVALID_HANDLE) return false; double mom[2]; if(CopyBuffer(handle, 0, 0, 2, mom) != 2) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); double price = GetCurrentPrice(symbol); double zero_line = 100.0; // Momentum crosses above 100 = Buy if(mom[1] < zero_line && mom[0] >= zero_line) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.55; return true; } // Momentum crosses below 100 = Sell if(mom[1] > zero_line && mom[0] <= zero_line) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.55; return true; } return false; } }; //+------------------------------------------------------------------+ //| Williams %R Strategy | //+------------------------------------------------------------------+ class CWilliamsPercentRangeSignalGenerator : public ISignalGenerator { private: int m_period; double m_overbought, m_oversold; public: CWilliamsPercentRangeSignalGenerator(int period = 14, double ob = -20.0, double os = -80.0) { m_period = period; m_overbought = ob; m_oversold = os; } string GetName() override { return "WilliamsPercentRangeStrategy"; } string GetDescription() override { return "Williams %R overbought/oversold"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iWPR(symbol, tf, m_period); if(handle == INVALID_HANDLE) return false; double wpr[2]; if(CopyBuffer(handle, 0, 0, 2, wpr) != 2) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); double price = GetCurrentPrice(symbol); // WPR crosses above oversold = Buy if(wpr[1] < m_oversold && wpr[0] >= m_oversold) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.55; return true; } // WPR crosses below overbought = Sell if(wpr[1] > m_overbought && wpr[0] <= m_overbought) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.55; return true; } return false; } }; //+------------------------------------------------------------------+ //| DeMarker Strategy | //+------------------------------------------------------------------+ class CDeMarkerSignalGenerator : public ISignalGenerator { private: int m_period; double m_overbought, m_oversold; public: CDeMarkerSignalGenerator(int period = 14, double ob = 0.7, double os = 0.3) { m_period = period; m_overbought = ob; m_oversold = os; } string GetName() override { return "DeMarkerStrategy"; } string GetDescription() override { return "DeMarker overbought/oversold"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iDeMarker(symbol, tf, m_period); if(handle == INVALID_HANDLE) return false; double dem[2]; if(CopyBuffer(handle, 0, 0, 2, dem) != 2) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); double price = GetCurrentPrice(symbol); // DeMarker crosses above oversold = Buy if(dem[1] < m_oversold && dem[0] >= m_oversold) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.55; return true; } // DeMarker crosses below overbought = Sell if(dem[1] > m_overbought && dem[0] <= m_overbought) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.55; return true; } return false; } }; //+------------------------------------------------------------------+ //| Force Index Strategy | //+------------------------------------------------------------------+ class CForceIndexSignalGenerator : public ISignalGenerator { private: int m_period; public: CForceIndexSignalGenerator(int period = 13) { m_period = period; } string GetName() override { return "ForceIndexStrategy"; } string GetDescription() override { return "Force Index zero-line crossover"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iForce(symbol, tf, m_period, MODE_EMA, VOLUME_TICK); if(handle == INVALID_HANDLE) return false; double force[2]; if(CopyBuffer(handle, 0, 0, 2, force) != 2) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); double price = GetCurrentPrice(symbol); // Force crosses above 0 = Buy if(force[1] < 0 && force[0] >= 0) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.55; return true; } // Force crosses below 0 = Sell if(force[1] > 0 && force[0] <= 0) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.55; return true; } return false; } }; //+------------------------------------------------------------------+ //| Bears Power Strategy | //+------------------------------------------------------------------+ class CBearsPowerSignalGenerator : public ISignalGenerator { private: int m_period; public: CBearsPowerSignalGenerator(int period = 13) { m_period = period; } string GetName() override { return "BearsPowerStrategy"; } string GetDescription() override { return "Bears Power zero-line crossover with trend filter"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iBearsPower(symbol, tf, m_period); if(handle == INVALID_HANDLE) return false; double bears[2]; if(CopyBuffer(handle, 0, 0, 2, bears) != 2) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); // Get EMA for trend filter int ema_handle = iMA(symbol, tf, m_period, 0, MODE_EMA, PRICE_CLOSE); if(ema_handle == INVALID_HANDLE) return false; double ema[1], close[1]; CopyBuffer(ema_handle, 0, 0, 1, ema); IndicatorRelease(ema_handle); close[0] = GetCurrentPrice(symbol); double price = close[0]; // Bears Power rising from below 0 while price above EMA = Buy if(bears[1] < bears[0] && bears[0] < 0 && price > ema[0]) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.55; return true; } // Bears Power falling while price below EMA = Sell if(bears[1] > bears[0] && bears[0] > 0 && price < ema[0]) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.55; return true; } return false; } }; //+------------------------------------------------------------------+ //| Bulls Power Strategy | //+------------------------------------------------------------------+ class CBullsPowerSignalGenerator : public ISignalGenerator { private: int m_period; public: CBullsPowerSignalGenerator(int period = 13) { m_period = period; } string GetName() override { return "BullsPowerStrategy"; } string GetDescription() override { return "Bulls Power zero-line crossover with trend filter"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iBullsPower(symbol, tf, m_period); if(handle == INVALID_HANDLE) return false; double bulls[2]; if(CopyBuffer(handle, 0, 0, 2, bulls) != 2) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); // Get EMA for trend filter int ema_handle = iMA(symbol, tf, m_period, 0, MODE_EMA, PRICE_CLOSE); if(ema_handle == INVALID_HANDLE) return false; double ema[1]; CopyBuffer(ema_handle, 0, 0, 1, ema); IndicatorRelease(ema_handle); double price = GetCurrentPrice(symbol); // Bulls Power rising while price above EMA = Buy if(bulls[1] < bulls[0] && bulls[0] > 0 && price > ema[0]) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.55; return true; } // Bulls Power falling from above 0 while price below EMA = Sell if(bulls[1] > bulls[0] && bulls[0] < 0 && price < ema[0]) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.55; return true; } return false; } }; //+------------------------------------------------------------------+ //| RVI Strategy - Relative Vigor Index | //+------------------------------------------------------------------+ class CRVISignalGenerator : public ISignalGenerator { private: int m_period; public: CRVISignalGenerator(int period = 10) { m_period = period; } string GetName() override { return "RVIStrategy"; } string GetDescription() override { return "RVI signal line crossover"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iRVI(symbol, tf, m_period); if(handle == INVALID_HANDLE) return false; double rvi[2], sig_line[2]; if(CopyBuffer(handle, 0, 0, 2, rvi) != 2) { IndicatorRelease(handle); return false; } if(CopyBuffer(handle, 1, 0, 2, sig_line) != 2) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); double price = GetCurrentPrice(symbol); // RVI crosses above signal = Buy if(rvi[1] <= sig_line[1] && rvi[0] > sig_line[0]) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.55; return true; } // RVI crosses below signal = Sell if(rvi[1] >= sig_line[1] && rvi[0] < sig_line[0]) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.55; return true; } return false; } }; //+------------------------------------------------------------------+ //| OsMA Strategy - Moving Average of Oscillator | //+------------------------------------------------------------------+ class COsMASignalGenerator : public ISignalGenerator { private: int m_fast, m_slow, m_signal; public: COsMASignalGenerator(int fast = 12, int slow = 26, int sig = 9) { m_fast = fast; m_slow = slow; m_signal = sig; } string GetName() override { return "OsMAStrategy"; } string GetDescription() override { return "OsMA zero-line crossover"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iOsMA(symbol, tf, m_fast, m_slow, m_signal, PRICE_CLOSE); if(handle == INVALID_HANDLE) return false; double osma[2]; if(CopyBuffer(handle, 0, 0, 2, osma) != 2) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); double price = GetCurrentPrice(symbol); // OsMA crosses above 0 = Buy if(osma[1] < 0 && osma[0] >= 0) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.55; return true; } // OsMA crosses below 0 = Sell if(osma[1] > 0 && osma[0] <= 0) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.55; return true; } return false; } }; //+------------------------------------------------------------------+ //| TriX Strategy - Triple Exponential Average | //+------------------------------------------------------------------+ class CTriXSignalGenerator : public ISignalGenerator { private: int m_period; public: CTriXSignalGenerator(int period = 14) { m_period = period; } string GetName() override { return "TriXStrategy"; } string GetDescription() override { return "TriX zero-line crossover"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iTriX(symbol, tf, m_period, PRICE_CLOSE); if(handle == INVALID_HANDLE) return false; double trix[2]; if(CopyBuffer(handle, 0, 0, 2, trix) != 2) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); double price = GetCurrentPrice(symbol); // TriX crosses above 0 = Buy if(trix[1] < 0 && trix[0] >= 0) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.55; return true; } // TriX crosses below 0 = Sell if(trix[1] > 0 && trix[0] <= 0) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.55; return true; } return false; } }; //+------------------------------------------------------------------+ //| Accelerator Oscillator Strategy | //+------------------------------------------------------------------+ class CAcceleratorOscillatorSignalGenerator : public ISignalGenerator { public: string GetName() override { return "AcceleratorOscillatorStrategy"; } string GetDescription() override { return "AC zero-line crossover with color confirmation"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iAC(symbol, tf); if(handle == INVALID_HANDLE) return false; double ac[3]; if(CopyBuffer(handle, 0, 0, 3, ac) != 3) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); double price = GetCurrentPrice(symbol); // AC crosses above 0 with rising momentum = Buy if(ac[2] < 0 && ac[1] < 0 && ac[0] >= 0 && ac[0] > ac[1]) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.55; return true; } // AC crosses below 0 with falling momentum = Sell if(ac[2] > 0 && ac[1] > 0 && ac[0] <= 0 && ac[0] < ac[1]) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.55; return true; } return false; } }; //+------------------------------------------------------------------+ //| Awesome Oscillator Strategy | //+------------------------------------------------------------------+ class CAwesomeOscillatorSignalGenerator : public ISignalGenerator { public: string GetName() override { return "AwesomeOscillatorStrategy"; } string GetDescription() override { return "AO zero-line crossover"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iAO(symbol, tf); if(handle == INVALID_HANDLE) return false; double ao[2]; if(CopyBuffer(handle, 0, 0, 2, ao) != 2) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); double price = GetCurrentPrice(symbol); // AO crosses above 0 = Buy if(ao[1] < 0 && ao[0] >= 0) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.55; return true; } // AO crosses below 0 = Sell if(ao[1] > 0 && ao[0] <= 0) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.55; return true; } return false; } }; //+------------------------------------------------------------------+ //| Alligator Strategy | //+------------------------------------------------------------------+ class CAlligatorSignalGenerator : public ISignalGenerator { private: int m_jaw, m_teeth, m_lips; public: CAlligatorSignalGenerator(int jaw = 13, int teeth = 8, int lips = 5) { m_jaw = jaw; m_teeth = teeth; m_lips = lips; } string GetName() override { return "AlligatorStrategy"; } string GetDescription() override { return "Alligator awakening - lines spread apart"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iAlligator(symbol, tf, m_jaw, 8, m_teeth, 5, m_lips, 3, MODE_SMMA, PRICE_MEDIAN); if(handle == INVALID_HANDLE) return false; double jaw[2], teeth[2], lips[2]; if(CopyBuffer(handle, 0, 0, 2, jaw) != 2) { IndicatorRelease(handle); return false; } if(CopyBuffer(handle, 1, 0, 2, teeth) != 2) { IndicatorRelease(handle); return false; } if(CopyBuffer(handle, 2, 0, 2, lips) != 2) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); double price = GetCurrentPrice(symbol); // Bullish: Lips > Teeth > Jaw and spreading if(lips[0] > teeth[0] && teeth[0] > jaw[0] && (lips[0] - jaw[0]) > (lips[1] - jaw[1])) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.58; return true; } // Bearish: Lips < Teeth < Jaw and spreading if(lips[0] < teeth[0] && teeth[0] < jaw[0] && (jaw[0] - lips[0]) > (jaw[1] - lips[1])) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.58; return true; } return false; } }; //+------------------------------------------------------------------+ //| Gator Oscillator Strategy | //+------------------------------------------------------------------+ class CGatorSignalGenerator : public ISignalGenerator { public: string GetName() override { return "GatorStrategy"; } string GetDescription() override { return "Gator awakening - bars expanding"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iGator(symbol, tf, 13, 8, 8, 5, 5, 3, MODE_SMMA, PRICE_MEDIAN); if(handle == INVALID_HANDLE) return false; double upper[3], lower[3]; if(CopyBuffer(handle, 0, 0, 3, upper) != 3) { IndicatorRelease(handle); return false; } if(CopyBuffer(handle, 2, 0, 3, lower) != 3) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); double price = GetCurrentPrice(symbol); // Gator awakening (bars expanding) = trend starting double spread_now = MathAbs(upper[0]) + MathAbs(lower[0]); double spread_prev = MathAbs(upper[1]) + MathAbs(lower[1]); double spread_prev2 = MathAbs(upper[2]) + MathAbs(lower[2]); if(spread_now > spread_prev && spread_prev > spread_prev2) { // Determine direction from upper histogram if(upper[0] > 0) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.55; return true; } else { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.55; return true; } } return false; } }; //+------------------------------------------------------------------+ //| Ichimoku Strategy | //+------------------------------------------------------------------+ class CIchimokuSignalGenerator : public ISignalGenerator { private: int m_tenkan, m_kijun, m_senkou; public: CIchimokuSignalGenerator(int tenkan = 9, int kijun = 26, int senkou = 52) { m_tenkan = tenkan; m_kijun = kijun; m_senkou = senkou; } string GetName() override { return "IchimokuStrategy"; } string GetDescription() override { return "Ichimoku Tenkan/Kijun crossover with cloud filter"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iIchimoku(symbol, tf, m_tenkan, m_kijun, m_senkou); if(handle == INVALID_HANDLE) return false; double tenkan[2], kijun[2], senkou_a[1], senkou_b[1]; if(CopyBuffer(handle, 0, 0, 2, tenkan) != 2) { IndicatorRelease(handle); return false; } if(CopyBuffer(handle, 1, 0, 2, kijun) != 2) { IndicatorRelease(handle); return false; } if(CopyBuffer(handle, 2, 0, 1, senkou_a) != 1) { IndicatorRelease(handle); return false; } if(CopyBuffer(handle, 3, 0, 1, senkou_b) != 1) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); double price = GetCurrentPrice(symbol); double cloud_top = MathMax(senkou_a[0], senkou_b[0]); double cloud_bottom = MathMin(senkou_a[0], senkou_b[0]); // Tenkan crosses above Kijun, price above cloud = Buy if(tenkan[1] <= kijun[1] && tenkan[0] > kijun[0] && price > cloud_top) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.62; return true; } // Tenkan crosses below Kijun, price below cloud = Sell if(tenkan[1] >= kijun[1] && tenkan[0] < kijun[0] && price < cloud_bottom) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.62; return true; } return false; } }; //+------------------------------------------------------------------+ //| Fractals Strategy | //+------------------------------------------------------------------+ class CFractalsSignalGenerator : public ISignalGenerator { public: string GetName() override { return "FractalsStrategy"; } string GetDescription() override { return "Fractal breakout"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iFractals(symbol, tf); if(handle == INVALID_HANDLE) return false; double upper[10], lower[10]; if(CopyBuffer(handle, 0, 0, 10, upper) != 10) { IndicatorRelease(handle); return false; } if(CopyBuffer(handle, 1, 0, 10, lower) != 10) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); // Find last valid fractal double last_upper = 0, last_lower = 0; for(int i = 2; i < 10; i++) { if(upper[i] != EMPTY_VALUE && upper[i] > 0) { last_upper = upper[i]; break; } } for(int i = 2; i < 10; i++) { if(lower[i] != EMPTY_VALUE && lower[i] > 0) { last_lower = lower[i]; break; } } if(last_upper == 0 && last_lower == 0) return false; double price = GetCurrentPrice(symbol); // Price breaks above upper fractal = Buy if(last_upper > 0 && price > last_upper) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.55; return true; } // Price breaks below lower fractal = Sell if(last_lower > 0 && price < last_lower) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.55; return true; } return false; } }; //+------------------------------------------------------------------+ //| ZigZag Strategy | //+------------------------------------------------------------------+ class CZigZagSignalGenerator : public ISignalGenerator { private: int m_depth, m_deviation, m_backstep; public: CZigZagSignalGenerator(int depth = 12, int deviation = 5, int backstep = 3) { m_depth = depth; m_deviation = deviation; m_backstep = backstep; } string GetName() override { return "ZigZagStrategy"; } string GetDescription() override { return "ZigZag swing point breakout"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int handle = iCustom(symbol, tf, "Examples\\ZigZag", m_depth, m_deviation, m_backstep); if(handle == INVALID_HANDLE) return false; double zz[50]; if(CopyBuffer(handle, 0, 0, 50, zz) != 50) { IndicatorRelease(handle); return false; } IndicatorRelease(handle); // Find last two swing points double swing1 = 0, swing2 = 0; int swing1_idx = -1, swing2_idx = -1; for(int i = 0; i < 50; i++) { if(zz[i] != 0 && zz[i] != EMPTY_VALUE) { if(swing1 == 0) { swing1 = zz[i]; swing1_idx = i; } else if(swing2 == 0) { swing2 = zz[i]; swing2_idx = i; break; } } } if(swing1 == 0 || swing2 == 0) return false; double price = GetCurrentPrice(symbol); // Higher high = uptrend, buy on pullback if(swing1 > swing2 && price > swing2) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.55; return true; } // Lower low = downtrend, sell on pullback if(swing1 < swing2 && price < swing2) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.55; return true; } return false; } }; //+------------------------------------------------------------------+ //| Ultimate Oscillator Strategy | //+------------------------------------------------------------------+ class CUltimateOscillatorSignalGenerator : public ISignalGenerator { private: int m_fast, m_middle, m_slow; double m_overbought, m_oversold; public: CUltimateOscillatorSignalGenerator(int fast = 7, int middle = 14, int slow = 28, double ob = 70.0, double os = 30.0) { m_fast = fast; m_middle = middle; m_slow = slow; m_overbought = ob; m_oversold = os; } string GetName() override { return "UltimateOscillatorStrategy"; } string GetDescription() override { return "Ultimate Oscillator overbought/oversold with divergence"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { // Ultimate Oscillator is not a built-in indicator, calculate manually // Using a simplified approach with ATR and price action double close[30], high[30], low[30]; if(CopyClose(symbol, tf, 0, 30, close) != 30) return false; if(CopyHigh(symbol, tf, 0, 30, high) != 30) return false; if(CopyLow(symbol, tf, 0, 30, low) != 30) return false; // Calculate buying pressure and true range double bp_sum_fast = 0, tr_sum_fast = 0; double bp_sum_mid = 0, tr_sum_mid = 0; double bp_sum_slow = 0, tr_sum_slow = 0; for(int i = 1; i < 29; i++) { double true_low = MathMin(low[i], close[i+1]); double true_high = MathMax(high[i], close[i+1]); double bp = close[i] - true_low; double tr = true_high - true_low; if(i < m_fast) { bp_sum_fast += bp; tr_sum_fast += tr; } if(i < m_middle) { bp_sum_mid += bp; tr_sum_mid += tr; } if(i < m_slow) { bp_sum_slow += bp; tr_sum_slow += tr; } } if(tr_sum_fast == 0 || tr_sum_mid == 0 || tr_sum_slow == 0) return false; double avg_fast = bp_sum_fast / tr_sum_fast; double avg_mid = bp_sum_mid / tr_sum_mid; double avg_slow = bp_sum_slow / tr_sum_slow; double uo = 100.0 * ((4.0 * avg_fast) + (2.0 * avg_mid) + avg_slow) / 7.0; double price = GetCurrentPrice(symbol); // UO crosses above oversold = Buy if(uo < m_oversold + 5 && uo > m_oversold) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.55; return true; } // UO crosses below overbought = Sell if(uo > m_overbought - 5 && uo < m_overbought) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.55; return true; } return false; } }; //+------------------------------------------------------------------+ //| Moving Average Strategy (default fallback) | //+------------------------------------------------------------------+ class CMovingAverageSignalGenerator : public ISignalGenerator { private: int m_fast, m_slow; public: CMovingAverageSignalGenerator(int fast = 20, int slow = 50) { m_fast = fast; m_slow = slow; } string GetName() override { return "MovingAverageStrategy"; } string GetDescription() override { return "MA crossover"; } bool GenerateSignal(string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) override { int fast_handle = iMA(symbol, tf, m_fast, 0, MODE_SMA, PRICE_CLOSE); int slow_handle = iMA(symbol, tf, m_slow, 0, MODE_SMA, PRICE_CLOSE); if(fast_handle == INVALID_HANDLE || slow_handle == INVALID_HANDLE) return false; double fast_ma[2], slow_ma[2]; if(CopyBuffer(fast_handle, 0, 0, 2, fast_ma) != 2) { IndicatorRelease(fast_handle); IndicatorRelease(slow_handle); return false; } if(CopyBuffer(slow_handle, 0, 0, 2, slow_ma) != 2) { IndicatorRelease(fast_handle); IndicatorRelease(slow_handle); return false; } IndicatorRelease(fast_handle); IndicatorRelease(slow_handle); double price = GetCurrentPrice(symbol); // Fast MA crosses above Slow MA = Buy if(fast_ma[1] <= slow_ma[1] && fast_ma[0] > slow_ma[0]) { SetSignalDefaults(signal, symbol, tf, GetName(), 0, price); signal.confidence = 0.6; return true; } // Fast MA crosses below Slow MA = Sell if(fast_ma[1] >= slow_ma[1] && fast_ma[0] < slow_ma[0]) { SetSignalDefaults(signal, symbol, tf, GetName(), 1, price); signal.confidence = 0.6; return true; } return false; } }; //+------------------------------------------------------------------+ //| STRATEGY SIGNAL GENERATOR REGISTRY | //| Maps strategy names to their signal generators | //+------------------------------------------------------------------+ class CStrategySignalRegistry { private: ISignalGenerator* m_generators[]; int m_count; public: CStrategySignalRegistry() { m_count = 0; ArrayResize(m_generators, 0); } ~CStrategySignalRegistry() { for(int i = 0; i < m_count; i++) { if(m_generators[i] != NULL) delete m_generators[i]; } } void RegisterGenerator(ISignalGenerator* generator) { if(generator == NULL) return; ArrayResize(m_generators, m_count + 1); m_generators[m_count] = generator; m_count++; } ISignalGenerator* GetGenerator(const string &strategy_name) { for(int i = 0; i < m_count; i++) { if(m_generators[i] != NULL && m_generators[i].GetName() == strategy_name) return m_generators[i]; } return NULL; } bool GenerateSignal(const string &strategy_name, string symbol, ENUM_TIMEFRAMES tf, TradingSignal &signal) { // CRITICAL: Always initialize signal to safe defaults before generation signal.Init(); ISignalGenerator* gen = GetGenerator(strategy_name); if(gen == NULL) return false; return gen.GenerateSignal(symbol, tf, signal); } int GetCount() { return m_count; } void InitializeAllStrategies() { RegisterGenerator(new CADXSignalGenerator()); RegisterGenerator(new CRSISignalGenerator()); RegisterGenerator(new CMACDSignalGenerator()); RegisterGenerator(new CStochasticSignalGenerator()); RegisterGenerator(new CCCISignalGenerator()); RegisterGenerator(new CMomentumSignalGenerator()); RegisterGenerator(new CWilliamsPercentRangeSignalGenerator()); RegisterGenerator(new CDeMarkerSignalGenerator()); RegisterGenerator(new CForceIndexSignalGenerator()); RegisterGenerator(new CBearsPowerSignalGenerator()); RegisterGenerator(new CBullsPowerSignalGenerator()); RegisterGenerator(new CRVISignalGenerator()); RegisterGenerator(new COsMASignalGenerator()); RegisterGenerator(new CTriXSignalGenerator()); RegisterGenerator(new CAcceleratorOscillatorSignalGenerator()); RegisterGenerator(new CAwesomeOscillatorSignalGenerator()); RegisterGenerator(new CAlligatorSignalGenerator()); RegisterGenerator(new CGatorSignalGenerator()); RegisterGenerator(new CIchimokuSignalGenerator()); RegisterGenerator(new CFractalsSignalGenerator()); RegisterGenerator(new CZigZagSignalGenerator()); RegisterGenerator(new CUltimateOscillatorSignalGenerator()); RegisterGenerator(new CMovingAverageSignalGenerator()); } string GetRegisteredStrategies() { string result = ""; for(int i = 0; i < m_count; i++) { if(m_generators[i] != NULL) { if(result != "") result += ","; result += m_generators[i].GetName(); } } return result; } }; #endif // __STRATEGY_SIGNAL_GENERATORS_MQH__