New EA and Indi
This commit is contained in:
574
Buffer EA/Include/SignalDetector.mqh
Normal file
574
Buffer EA/Include/SignalDetector.mqh
Normal file
@@ -0,0 +1,574 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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);
|
||||
}
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
Reference in New Issue
Block a user