Files
EA/Buffer EA/Include/SignalDetector.mqh
Kunthawat Greethong 04aa2eb2e6 New EA and Indi
2026-01-25 10:34:54 +07:00

574 lines
19 KiB
Plaintext

//+------------------------------------------------------------------+
//| SignalDetector.mqh |
//| Universal Buffer Reader EA v2.0 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025"
#property link ""
#property version "1.00"
#property strict
//+------------------------------------------------------------------+
//| CSignalDetector - Reads indicator buffers and detects signals |
//+------------------------------------------------------------------+
class CSignalDetector
{
private:
string m_indicator_name;
int m_indicator_handle;
// Signal buffers
int m_buy_signal_buffer;
int m_sell_signal_buffer;
// SL/TP buffers (separate for BUY/SELL)
int m_buy_sl_buffer;
int m_buy_tp_buffers[];
int m_sell_sl_buffer;
int m_sell_tp_buffers[];
// ATR settings
int m_sltp_mode;
int m_atr_period;
int m_atr_handle;
double m_sl_atr_multiplier;
double m_tp_atr_multiplier;
int m_min_tp_pips;
// Symbol info
string m_symbol;
double m_pip_value;
int m_digits;
// Logging
bool m_enable_debug;
public:
//+------------------------------------------------------------------+
//| Signal data structure with multiple TPs |
//+------------------------------------------------------------------+
struct SignalData
{
bool has_signal;
bool is_buy;
double signal_price;
double sl_price;
double tp_prices[];
int tp_count;
bool used_atr_fallback;
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CSignalDetector()
{
m_indicator_name = "";
m_indicator_handle = INVALID_HANDLE;
m_buy_signal_buffer = 0;
m_sell_signal_buffer = 1;
m_buy_sl_buffer = 2;
m_sell_sl_buffer = 6;
m_sltp_mode = 0;
m_atr_period = 14;
m_atr_handle = INVALID_HANDLE;
m_sl_atr_multiplier = 1.5;
m_tp_atr_multiplier = 3.0;
m_min_tp_pips = 300;
m_symbol = "";
m_pip_value = 0;
m_digits = 0;
m_enable_debug = false;
ArrayResize(m_buy_tp_buffers, 0);
ArrayResize(m_sell_tp_buffers, 0);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
~CSignalDetector()
{
Deinitialize();
}
//+------------------------------------------------------------------+
//| Initialize indicator handles |
//+------------------------------------------------------------------+
bool Initialize()
{
Print("[SignalDetector] Initializing...");
// Initialize custom indicator handle
if(m_indicator_name != "" && m_indicator_name != "My_Indicator")
{
m_indicator_handle = iCustom(m_symbol, PERIOD_CURRENT, m_indicator_name);
if(m_indicator_handle == INVALID_HANDLE)
{
int error = GetLastError();
Print("[ERROR] Failed to create indicator handle for: ", m_indicator_name,
" Error code: ", error);
return false;
}
Print("[SignalDetector] Custom indicator handle created: ", m_indicator_name);
}
else
{
Print("[SignalDetector] Using ATR mode only (no custom indicator)");
}
// Initialize ATR handle
m_atr_handle = iATR(m_symbol, PERIOD_CURRENT, m_atr_period);
if(m_atr_handle == INVALID_HANDLE)
{
int error = GetLastError();
Print("[ERROR] Failed to create ATR handle. Error code: ", error);
return false;
}
Print("[SignalDetector] ATR handle created (Period: ", m_atr_period, ")");
Print("[SignalDetector] Initialization complete");
return true;
}
//+------------------------------------------------------------------+
//| Deinitialize indicator handles |
//+------------------------------------------------------------------+
void Deinitialize()
{
Print("[SignalDetector] Deinitializing...");
if(m_indicator_handle != INVALID_HANDLE)
{
IndicatorRelease(m_indicator_handle);
m_indicator_handle = INVALID_HANDLE;
Print("[SignalDetector] Custom indicator handle released");
}
if(m_atr_handle != INVALID_HANDLE)
{
IndicatorRelease(m_atr_handle);
m_atr_handle = INVALID_HANDLE;
Print("[SignalDetector] ATR handle released");
}
ArrayResize(m_buy_tp_buffers, 0);
ArrayResize(m_sell_tp_buffers, 0);
Print("[SignalDetector] Deinitialization complete");
}
//+------------------------------------------------------------------+
//| Set parameters |
//+------------------------------------------------------------------+
void SetParameters(
string indicator_name,
int buy_signal_buffer, int sell_signal_buffer,
int buy_sl_buffer, int sell_sl_buffer,
int sltp_mode, int atr_period,
double sl_atr_multiplier, double tp_atr_multiplier,
int min_tp_pips, double pip_value, int digits,
string symbol,
bool enable_debug = false
)
{
m_indicator_name = indicator_name;
m_buy_signal_buffer = buy_signal_buffer;
m_sell_signal_buffer = sell_signal_buffer;
m_buy_sl_buffer = buy_sl_buffer;
m_sell_sl_buffer = sell_sl_buffer;
m_sltp_mode = sltp_mode;
m_atr_period = atr_period;
m_sl_atr_multiplier = sl_atr_multiplier;
m_tp_atr_multiplier = tp_atr_multiplier;
m_min_tp_pips = min_tp_pips;
m_pip_value = pip_value;
m_digits = digits;
m_symbol = symbol;
m_enable_debug = enable_debug;
}
//+------------------------------------------------------------------+
//| Set debug mode |
//+------------------------------------------------------------------+
void SetDebugMode(bool enable_debug)
{
m_enable_debug = enable_debug;
}
//+------------------------------------------------------------------+
//| Set TP buffers (can have multiple) |
//+------------------------------------------------------------------+
void SetBuyTPBuffers(int &buffers[])
{
ArrayCopy(m_buy_tp_buffers, buffers);
}
//+------------------------------------------------------------------+
//| Set TP buffers (can have multiple) |
//+------------------------------------------------------------------+
void SetSellTPBuffers(int &buffers[])
{
ArrayCopy(m_sell_tp_buffers, buffers);
}
//+------------------------------------------------------------------+
//| Detect signal from indicator buffers |
//+------------------------------------------------------------------+
SignalData DetectSignal(int bar_shift = 1)
{
SignalData result;
result.has_signal = false;
result.is_buy = false;
result.signal_price = 0;
result.sl_price = 0;
result.tp_count = 0;
result.used_atr_fallback = false;
ArrayResize(result.tp_prices, 0);
if(m_enable_debug)
{
Print("[SignalDetector] Detecting signal at bar shift: ", bar_shift);
}
// Read buy/sell signal buffers
double buy_signal = GetIndicatorBufferValue(m_buy_signal_buffer, bar_shift);
double sell_signal = GetIndicatorBufferValue(m_sell_signal_buffer, bar_shift);
// Determine signal type
bool has_buy = (buy_signal != EMPTY_VALUE && buy_signal != 0);
bool has_sell = (sell_signal != EMPTY_VALUE && sell_signal != 0);
if(!has_buy && !has_sell)
{
if(m_enable_debug)
{
Print("[SignalDetector] No signal detected");
}
return result;
}
// Validate: Both buy and sell signals should not be present
if(has_buy && has_sell)
{
Print("[WARNING] Both BUY and SELL signals detected. Using BUY signal.");
has_sell = false;
}
result.has_signal = true;
result.is_buy = has_buy;
result.signal_price = has_buy ? buy_signal : sell_signal;
if(m_enable_debug)
{
Print("[SignalDetector] ", (has_buy ? "BUY" : "SELL"), " signal detected at: ",
DoubleToString(result.signal_price, m_digits));
}
// Calculate SL/TP based on mode
if(m_sltp_mode == 1)
{
if(m_enable_debug)
{
Print("[SignalDetector] Using Mode 1: Indicator SL/TP buffers");
}
// Try indicator buffers first
double sl_buffer = has_buy ?
GetIndicatorBufferValue(m_buy_sl_buffer, bar_shift) :
GetIndicatorBufferValue(m_sell_sl_buffer, bar_shift);
if(IsValidPrice(sl_buffer))
{
result.sl_price = sl_buffer;
if(m_enable_debug)
{
Print("[SignalDetector] SL from indicator: ", DoubleToString(result.sl_price, m_digits));
}
}
else
{
if(m_enable_debug)
{
Print("[SignalDetector] SL buffer empty, will use ATR fallback");
}
}
// Read TP buffers
int tp_count;
if(has_buy)
tp_count = ArraySize(m_buy_tp_buffers);
else
tp_count = ArraySize(m_sell_tp_buffers);
if(tp_count > 0)
{
ArrayResize(result.tp_prices, tp_count);
result.tp_count = 0;
for(int i = 0; i < tp_count; i++)
{
int buffer_index;
if(has_buy)
buffer_index = m_buy_tp_buffers[i];
else
buffer_index = m_sell_tp_buffers[i];
double tp_buffer = GetIndicatorBufferValue(buffer_index, bar_shift);
if(IsValidPrice(tp_buffer))
{
result.tp_prices[result.tp_count] = tp_buffer;
result.tp_count++;
if(m_enable_debug)
{
Print("[SignalDetector] TP", (i + 1), " from indicator:",
DoubleToString(tp_buffer, m_digits));
}
}
}
}
}
else
{
if(m_enable_debug)
{
Print("[SignalDetector] Using Mode 0: ATR-based SL/TP");
}
}
// Fall back to ATR if SL/TP not set
if(result.sl_price == 0 || result.tp_count == 0)
{
if(m_enable_debug)
{
Print("[SignalDetector] SL or TP not set from indicator, using ATR fallback");
}
double atr = GetATRValue(bar_shift);
if(atr > 0)
{
double open_price = SymbolInfoDouble(m_symbol, SYMBOL_BID);
result.sl_price = CalculateATRSL(has_buy, atr, open_price);
CalculateATRTPs(has_buy, atr, open_price, result.tp_prices, result.tp_count);
result.used_atr_fallback = true;
if(m_enable_debug)
{
Print("[SignalDetector] ATR value: ", DoubleToString(atr, m_digits));
Print("[SignalDetector] SL from ATR: ", DoubleToString(result.sl_price, m_digits));
for(int i = 0; i < result.tp_count; i++)
{
Print("[SignalDetector] TP", (i + 1), " from ATR: ",
DoubleToString(result.tp_prices[i], m_digits));
}
}
}
else
{
Print("[ERROR] ATR value is 0, cannot calculate SL/TP");
}
}
// Apply minimum TP
ApplyMinimumTP(has_buy, result.tp_prices, result.tp_count, result.signal_price);
if(m_enable_debug)
{
Print("[SignalDetector] Signal detection complete. SL: ", DoubleToString(result.sl_price, m_digits),
", TPs: ", result.tp_count, ", ATR fallback: ", (result.used_atr_fallback ? "Yes" : "No"));
}
return result;
}
//+------------------------------------------------------------------+
//| Get ATR value |
//+------------------------------------------------------------------+
double GetATRValue(int bar_shift = 1)
{
if(m_atr_handle == INVALID_HANDLE)
{
Print("[ERROR] ATR handle is invalid");
return 0;
}
double atr[];
ArraySetAsSeries(atr, true);
int copied = CopyBuffer(m_atr_handle, 0, bar_shift, 1, atr);
if(copied <= 0)
{
int error = GetLastError();
Print("[ERROR] Failed to copy ATR buffer. Error code: ", error);
return 0;
}
if(atr[0] <= 0)
{
if(m_enable_debug)
{
Print("[SignalDetector] ATR value is 0 or negative: ", atr[0]);
}
return 0;
}
return atr[0];
}
private:
//+------------------------------------------------------------------+
//| Get indicator buffer value |
//+------------------------------------------------------------------+
double GetIndicatorBufferValue(int buffer_index, int bar_shift)
{
if(m_indicator_handle == INVALID_HANDLE)
{
if(m_enable_debug)
{
Print("[SignalDetector] Indicator handle is invalid");
}
return EMPTY_VALUE;
}
if(buffer_index < 0)
{
Print("[ERROR] Invalid buffer index: ", buffer_index);
return EMPTY_VALUE;
}
double buffer[];
ArraySetAsSeries(buffer, true);
int copied = CopyBuffer(m_indicator_handle, buffer_index, bar_shift, 1, buffer);
if(copied <= 0)
{
if(m_enable_debug)
{
int error = GetLastError();
Print("[SignalDetector] Failed to copy buffer ", buffer_index,
". Error code: ", error);
}
return EMPTY_VALUE;
}
return buffer[0];
}
//+------------------------------------------------------------------+
//| Calculate ATR-based SL |
//+------------------------------------------------------------------+
double CalculateATRSL(bool is_buy, double atr_value, double open_price)
{
if(atr_value <= 0) return 0;
if(is_buy)
{
return NormalizeDouble(open_price - atr_value * m_sl_atr_multiplier, m_digits);
}
else
{
return NormalizeDouble(open_price + atr_value * m_sl_atr_multiplier, m_digits);
}
}
//+------------------------------------------------------------------+
//| Calculate ATR-based TPs |
//+------------------------------------------------------------------+
void CalculateATRTPs(bool is_buy, double atr_value, double open_price, double &tp_prices[], int &tp_count)
{
if(atr_value <= 0) return;
// Default to 3 TPs if using ATR
int num_tps = 3;
ArrayResize(tp_prices, num_tps);
tp_count = num_tps;
for(int i = 0; i < num_tps; i++)
{
double multiplier = m_tp_atr_multiplier * (i + 1);
if(is_buy)
{
tp_prices[i] = NormalizeDouble(open_price + atr_value * multiplier, m_digits);
}
else
{
tp_prices[i] = NormalizeDouble(open_price - atr_value * multiplier, m_digits);
}
}
}
//+------------------------------------------------------------------+
//| Apply minimum TP to all TPs |
//+------------------------------------------------------------------+
void ApplyMinimumTP(bool is_buy, double &tp_prices[], int tp_count, double open_price)
{
if(m_min_tp_pips <= 0)
{
if(m_enable_debug)
{
Print("[SignalDetector] Minimum TP disabled (0 pips)");
}
return;
}
if(tp_count == 0)
{
if(m_enable_debug)
{
Print("[SignalDetector] No TPs to apply minimum TP");
}
return;
}
int adjusted_count = 0;
for(int i = 0; i < tp_count; i++)
{
if(is_buy)
{
double min_tp = NormalizeDouble(open_price + m_min_tp_pips * m_pip_value, m_digits);
if(tp_prices[i] < min_tp)
{
if(m_enable_debug)
{
Print("[SignalDetector] TP", (i + 1), " adjusted to minimum: ",
DoubleToString(tp_prices[i], m_digits), " -> ",
DoubleToString(min_tp, m_digits));
}
tp_prices[i] = min_tp;
adjusted_count++;
}
}
else
{
double min_tp = NormalizeDouble(open_price - m_min_tp_pips * m_pip_value, m_digits);
if(tp_prices[i] > min_tp)
{
if(m_enable_debug)
{
Print("[SignalDetector] TP", (i + 1), " adjusted to minimum: ",
DoubleToString(tp_prices[i], m_digits), " -> ",
DoubleToString(min_tp, m_digits));
}
tp_prices[i] = min_tp;
adjusted_count++;
}
}
}
if(m_enable_debug && adjusted_count > 0)
{
Print("[SignalDetector] Minimum TP applied to ", adjusted_count, " TP(s)");
}
}
//+------------------------------------------------------------------+
//| Check if price is valid |
//+------------------------------------------------------------------+
bool IsValidPrice(double price)
{
return (price != EMPTY_VALUE && price != 0 && price > 0);
}
};
//+------------------------------------------------------------------+