323 lines
11 KiB
MQL5
323 lines
11 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| SignalGenerator.mqh |
| |||
//| Copyright 2025, EscapeEA |
| |||
//| https://www.escapeea.com |
| |||
//+------------------------------------------------------------------+
| |||
#property copyright "Copyright 2025, EscapeEA"
| |||
#property link "https://www.escapeea.com"
| |||
#property version "1.00"
| |||
#property strict
| |||
| |||
#include <Arrays\ArrayObj.mqh>
| |||
#include <Indicators\Trend.mqh>
| |||
#include <Indicators\Oscilators.mqh>
| |||
| |||
// Forward declarations
| |||
class CSymbolInfo;
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Signal types and enums |
| |||
//+------------------------------------------------------------------+
| |||
enum ENUM_SIGNAL_TYPE {
| |||
SIGNAL_TYPE_NONE = 0, // No signal
| |||
SIGNAL_TYPE_BUY = 1, // Buy signal
| |||
SIGNAL_TYPE_SELL = -1, // Sell signal
| |||
SIGNAL_TYPE_CLOSE = 2 // Close position signal
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Signal structure to hold signal details |
| |||
//+------------------------------------------------------------------+
| |||
struct SSignal {
| |||
ENUM_SIGNAL_TYPE type; // Signal type
| |||
double price; // Entry price
| |||
double sl; // Stop loss
| |||
double tp; // Take profit
| |||
double strength; // Signal strength (0.0 to 1.0)
| |||
string comment; // Signal comment/description
| |||
datetime time; // Signal time
| |||
| |||
// Default constructor
| |||
SSignal() {
| |||
type = SIGNAL_TYPE_NONE;
| |||
price = 0.0;
| |||
sl = 0.0;
| |||
tp = 0.0;
| |||
strength = 0.0;
| |||
comment = "";
| |||
time = 0;
| |||
}
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Signal Generator class |
| |||
//+------------------------------------------------------------------+
| |||
class CSignalGenerator {
| |||
private:
| |||
// Indicators
| |||
CiMA m_ma; // Moving Average
| |||
CiMA m_maFast; // Fast Moving Average
| |||
CiMA m_maSlow; // Slow Moving Average
| |||
CiATR m_atr; // Average True Range
| |||
| |||
// Configuration
| |||
int m_maPeriod; // MA Period
| |||
int m_maFastPeriod; // Fast MA Period
| |||
int m_maSlowPeriod; // Slow MA Period
| |||
int m_atrPeriod; // ATR Period
| |||
double m_atrMultiplier; // ATR Multiplier for SL/TP
| |||
| |||
// State
| |||
bool m_initialized; // Initialization flag
| |||
CSymbolInfo *m_symbol; // Symbol info
| |||
| |||
// Private methods
| |||
bool InitializeIndicators();
| |||
double CalculateATRMultiplier() const;
| |||
| |||
public:
| |||
// Constructor/Destructor
| |||
CSignalGenerator();
| |||
~CSignalGenerator();
| |||
| |||
// Initialization
| |||
bool Initialize(CSymbolInfo *symbol,
| |||
int maPeriod,
| |||
int maFastPeriod,
| |||
int maSlowPeriod,
| |||
int atrPeriod,
| |||
double atrMultiplier);
| |||
| |||
// Signal generation
| |||
bool GenerateSignal(SSignal &signal);
| |||
| |||
// Getters
| |||
bool IsInitialized() const { return m_initialized; }
| |||
| |||
// Utility
| |||
static string SignalTypeToString(ENUM_SIGNAL_TYPE type);
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Constructor |
| |||
//+------------------------------------------------------------------+
| |||
CSignalGenerator::CSignalGenerator() :
| |||
m_maPeriod(20),
| |||
m_maFastPeriod(10),
| |||
m_maSlowPeriod(50),
| |||
m_atrPeriod(14),
| |||
m_atrMultiplier(2.0),
| |||
m_initialized(false),
| |||
m_symbol(NULL)
| |||
{
| |||
// Initialize indicators
| |||
m_ma = CiMA();
| |||
m_maFast = CiMA();
| |||
m_maSlow = CiMA();
| |||
m_atr = CiATR();
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Destructor |
| |||
//+------------------------------------------------------------------+
| |||
CSignalGenerator::~CSignalGenerator() {
| |||
// Release indicators
| |||
m_ma.Release();
| |||
m_maFast.Release();
| |||
m_maSlow.Release();
| |||
m_atr.Release();
| |||
| |||
// Clear symbol reference
| |||
m_symbol = NULL;
| |||
m_initialized = false;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Initialize the signal generator |
| |||
//+------------------------------------------------------------------+
| |||
bool CSignalGenerator::Initialize(CSymbolInfo *symbol,
| |||
int maPeriod,
| |||
int maFastPeriod,
| |||
int maSlowPeriod,
| |||
int atrPeriod,
| |||
double atrMultiplier) {
| |||
// Validate inputs
| |||
if(symbol == NULL || !symbol.Name() == "") {
| |||
Print("Error: Invalid symbol info");
| |||
return false;
| |||
}
| |||
| |||
if(maPeriod <= 0 || maFastPeriod <= 0 || maSlowPeriod <= 0 || atrPeriod <= 0) {
| |||
Print("Error: Invalid indicator periods");
| |||
return false;
| |||
}
| |||
| |||
// Store configuration
| |||
m_symbol = symbol;
| |||
m_maPeriod = maPeriod;
| |||
m_maFastPeriod = maFastPeriod;
| |||
m_maSlowPeriod = maSlowPeriod;
| |||
m_atrPeriod = atrPeriod;
| |||
m_atrMultiplier = atrMultiplier;
| |||
| |||
// Initialize indicators
| |||
if(!InitializeIndicators()) {
| |||
Print("Error: Failed to initialize indicators");
| |||
return false;
| |||
}
| |||
| |||
m_initialized = true;
| |||
return true;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Initialize indicators |
| |||
//+------------------------------------------------------------------+
| |||
bool CSignalGenerator::InitializeIndicators() {
| |||
// Initialize MA
| |||
if(!m_ma.Create(m_symbol.Name(), PERIOD_CURRENT, m_maPeriod, 0, MODE_SMA, PRICE_CLOSE)) {
| |||
Print("Error creating MA indicator");
| |||
return false;
| |||
}
| |||
| |||
// Initialize Fast MA
| |||
if(!m_maFast.Create(m_symbol.Name(), PERIOD_CURRENT, m_maFastPeriod, 0, MODE_SMA, PRICE_CLOSE)) {
| |||
Print("Error creating Fast MA indicator");
| |||
return false;
| |||
}
| |||
| |||
// Initialize Slow MA
| |||
if(!m_maSlow.Create(m_symbol.Name(), PERIOD_CURRENT, m_maSlowPeriod, 0, MODE_SMA, PRICE_CLOSE)) {
| |||
Print("Error creating Slow MA indicator");
| |||
return false;
| |||
}
| |||
| |||
// Initialize ATR
| |||
if(!m_atr.Create(m_symbol.Name(), PERIOD_CURRENT, m_atrPeriod)) {
| |||
Print("Error creating ATR indicator");
| |||
return false;
| |||
}
| |||
| |||
return true;
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Generate trading signal |
| |||
//+------------------------------------------------------------------+
| |||
bool CSignalGenerator::GenerateSignal(SSignal &signal) {
| |||
// Reset signal
| |||
signal = SSignal();
| |||
| |||
// Check initialization
| |||
if(!m_initialized || m_symbol == NULL) {
| |||
signal.comment = "Signal generator not properly initialized";
| |||
return false;
| |||
}
| |||
| |||
// Update symbol rates
| |||
m_symbol.RefreshRates();
| |||
| |||
// Get current prices
| |||
double ask = m_symbol.Ask();
| |||
double bid = m_symbol.Bid();
| |||
double point = m_symbol.Point();
| |||
int digits = (int)m_symbol.Digits();
| |||
| |||
// Update indicators
| |||
m_ma.Refresh(-1);
| |||
m_maFast.Refresh(-1);
| |||
m_maSlow.Refresh(-1);
| |||
m_atr.Refresh(-1);
| |||
| |||
// Get indicator values
| |||
double ma[3], maFast[3], maSlow[3];
| |||
| |||
if(m_ma.GetData(1, 1, 0, 3, ma) != 3 ||
| |||
m_maFast.GetData(1, 1, 0, 3, maFast) != 3 ||
| |||
m_maSlow.GetData(1, 1, 0, 3, maSlow) != 3) {
| |||
signal.comment = "Failed to get indicator data";
| |||
return false;
| |||
}
| |||
| |||
// Get ATR value for volatility
| |||
double atr[1];
| |||
if(m_atr.GetData(1, 1, 0, 1, atr) != 1) {
| |||
signal.comment = "Failed to get ATR data";
| |||
return false;
| |||
}
| |||
| |||
// Calculate signal strength (0.0 to 1.0)
| |||
double strength = 0.0;
| |||
| |||
// Check for trend direction
| |||
bool uptrend = ma[0] > ma[1] && ma[1] > ma[2];
| |||
bool downtrend = ma[0] < ma[1] && ma[1] < ma[2];
| |||
| |||
// Check for MA cross
| |||
bool fastAboveSlow = maFast[0] > maSlow[0] && maFast[1] <= maSlow[1]; // Bullish cross
| |||
bool fastBelowSlow = maFast[0] < maSlow[0] && maFast[1] >= maSlow[1]; // Bearish cross
| |||
| |||
// Generate signals based on strategy
| |||
if(uptrend && fastAboveSlow) {
| |||
// Strong buy signal
| |||
signal.type = SIGNAL_TYPE_BUY;
| |||
signal.price = ask;
| |||
signal.strength = 0.8 + (MathRand() % 20) / 100.0; // 0.8-1.0
| |||
signal.comment = "Strong buy: Uptrend with bullish MA cross";
| |||
}
| |||
else if(downtrend && fastBelowSlow) {
| |||
// Strong sell signal
| |||
signal.type = SIGNAL_TYPE_SELL;
| |||
signal.price = bid;
| |||
signal.strength = 0.8 + (MathRand() % 20) / 100.0; // 0.8-1.0
| |||
signal.comment = "Strong sell: Downtrend with bearish MA cross";
| |||
}
| |||
else if(fastAboveSlow) {
| |||
// Weak buy signal
| |||
signal.type = SIGNAL_TYPE_BUY;
| |||
signal.price = ask;
| |||
signal.strength = 0.5 + (MathRand() % 30) / 100.0; // 0.5-0.8
| |||
signal.comment = "Buy: Bullish MA cross";
| |||
}
| |||
else if(fastBelowSlow) {
| |||
// Weak sell signal
| |||
signal.type = SIGNAL_TYPE_SELL;
| |||
signal.price = bid;
| |||
signal.strength = 0.5 + (MathRand() % 30) / 100.0; // 0.5-0.8
| |||
signal.comment = "Sell: Bearish MA cross";
| |||
}
| |||
| |||
// If we have a valid signal, calculate SL/TP
| |||
if(signal.type != SIGNAL_TYPE_NONE) {
| |||
double atrValue = atr[0];
| |||
| |||
if(signal.type == SIGNAL_TYPE_BUY) {
| |||
signal.sl = signal.price - (atrValue * m_atrMultiplier);
| |||
signal.tp = signal.price + (atrValue * m_atrMultiplier * 1.5); // 1.5:1 reward:risk
| |||
}
| |||
else if(signal.type == SIGNAL_TYPE_SELL) {
| |||
signal.sl = signal.price + (atrValue * m_atrMultiplier);
| |||
signal.tp = signal.price - (atrValue * m_atrMultiplier * 1.5); // 1.5:1 reward:risk
| |||
}
| |||
| |||
// Normalize prices
| |||
signal.sl = NormalizeDouble(signal.sl, digits);
| |||
signal.tp = NormalizeDouble(signal.tp, digits);
| |||
signal.time = TimeCurrent();
| |||
}
| |||
| |||
return (signal.type != SIGNAL_TYPE_NONE);
| |||
}
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Convert signal type to string |
| |||
//+------------------------------------------------------------------+
| |||
string CSignalGenerator::SignalTypeToString(ENUM_SIGNAL_TYPE type) {
| |||
switch(type) {
| |||
case SIGNAL_TYPE_BUY: return "BUY";
| |||
case SIGNAL_TYPE_SELL: return "SELL";
| |||
case SIGNAL_TYPE_CLOSE: return "CLOSE";
| |||
default: return "NONE";
| |||
}
| |||
}
| |||
//+------------------------------------------------------------------+
|