2026-01-14 16:17:00 -05:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 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;
|
2026-02-24 12:47:37 -05:00
|
|
|
signal.order_type = (type == 0) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL; // Set order_type based on type
|
2026-01-14 16:17:00 -05:00
|
|
|
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);
|
|
|
|
|
|
2026-02-24 12:47:37 -05:00
|
|
|
// 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;
|
|
|
|
|
|
2026-01-14 16:17:00 -05:00
|
|
|
if(type == 0) // Buy
|
|
|
|
|
{
|
2026-02-24 12:47:37 -05:00
|
|
|
signal.sl = price - atr * sl_mult;
|
|
|
|
|
signal.tp = price + atr * tp_mult;
|
2026-01-14 16:17:00 -05:00
|
|
|
}
|
|
|
|
|
else // Sell
|
|
|
|
|
{
|
2026-02-24 12:47:37 -05:00
|
|
|
signal.sl = price + atr * sl_mult;
|
|
|
|
|
signal.tp = price - atr * tp_mult;
|
2026-01-14 16:17:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Final safety check - ensure TP is never garbage
|
|
|
|
|
if(signal.tp <= 0.0 || signal.tp > 1e10 || MathIsValidNumber(signal.tp) == false)
|
|
|
|
|
{
|
2026-02-24 12:47:37 -05:00
|
|
|
signal.tp = (type == 0) ? price + atr * tp_mult : price - atr * tp_mult;
|
2026-01-14 16:17:00 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| 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__
|