191 lines
7.5 KiB
MQL5
191 lines
7.5 KiB
MQL5
|
//+------------------------------------------------------------------+
|
||
|
//| SignalDTDB.mqh |
|
||
|
//+------------------------------------------------------------------+
|
||
|
#property copyright "AnimateDread"
|
||
|
#property version "1.0"
|
||
|
#property description "Double Tops and Bottoms Signal"
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Include files |
|
||
|
//+------------------------------------------------------------------+
|
||
|
#include "..\Expert\ExpertSignalCustom.mqh"
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| CSignalDTDB class. |
|
||
|
//| Purpose: Class for detecting double tops and bottoms. |
|
||
|
//| Inherits from CExpertSignalCustom. |
|
||
|
//+------------------------------------------------------------------+
|
||
|
class CSignalDTDB : public CExpertSignalCustom
|
||
|
{
|
||
|
protected:
|
||
|
// Pattern weights
|
||
|
int m_pattern_0;
|
||
|
// Variables for dynamic filtering
|
||
|
int m_lookback_period; // Lookback period to calculate average range
|
||
|
|
||
|
public:
|
||
|
CSignalDTDB();
|
||
|
~CSignalDTDB();
|
||
|
// Methods for adjusting pattern weights
|
||
|
void Pattern_0(int value) { m_pattern_0 = value; }
|
||
|
void LookBackPeriod(int value) { m_lookback_period = value; }
|
||
|
virtual void ApplyPatternWeight(int patternNumber, int weight);
|
||
|
// Method to validate parameters
|
||
|
virtual bool ValidationSettings();
|
||
|
// Methods to generate signals
|
||
|
virtual int LongCondition(void);
|
||
|
virtual int ShortCondition(void);
|
||
|
|
||
|
protected:
|
||
|
// Method to detect double tops
|
||
|
bool DetectDoubleTop(int startIdx);
|
||
|
// Method to detect double bottoms
|
||
|
bool DetectDoubleBottom(int startIdx);
|
||
|
// Helper method to detect peaks and troughs
|
||
|
bool IsExtreme(int idx, double prevExtreme1, double prevExtreme2, bool isPeak)
|
||
|
{
|
||
|
double currentValue = isPeak ? High(idx) : Low(idx);
|
||
|
return isPeak ? (currentValue > prevExtreme1 && currentValue > prevExtreme2)
|
||
|
: (currentValue < prevExtreme1 && currentValue < prevExtreme2);
|
||
|
}
|
||
|
// Common method to detect Double Top or Bottom
|
||
|
bool DetectDoubleExtreme(int startIdx, bool isTop, double threshold = 0.02, int symmetryThreshold = 2)
|
||
|
{
|
||
|
int extremesFound = 0;
|
||
|
double extreme1 = 0, extreme2 = 0;
|
||
|
int extreme1Idx = 0, extreme2Idx = 0;
|
||
|
double prevExtreme1 = isTop ? -DBL_MAX : DBL_MAX, prevExtreme2 = prevExtreme1;
|
||
|
int trendAnalysisStartIdx = MathMax(0, startIdx - m_lookback_period);
|
||
|
for(int i = startIdx; i >= trendAnalysisStartIdx; i--)
|
||
|
{
|
||
|
double value = isTop ? High(i) : Low(i);
|
||
|
if(extremesFound == 0 && IsExtreme(i, prevExtreme1, prevExtreme2, isTop))
|
||
|
{
|
||
|
extreme1 = value;
|
||
|
extreme1Idx = i;
|
||
|
extremesFound++;
|
||
|
}
|
||
|
else
|
||
|
if(extremesFound == 1 && IsExtreme(i, prevExtreme1, prevExtreme2, isTop))
|
||
|
{
|
||
|
extreme2 = value;
|
||
|
extreme2Idx = i;
|
||
|
extremesFound++;
|
||
|
if(fabs(extreme1 - extreme2) / fabs(extreme1) < threshold)
|
||
|
{
|
||
|
double extremeDistance = fabs(extreme2Idx - extreme1Idx);
|
||
|
double oppositeDuration = fabs(extreme1Idx - startIdx);
|
||
|
if(fabs(extremeDistance - oppositeDuration) < symmetryThreshold)
|
||
|
{
|
||
|
double neckline = (extreme1 + extreme2) / 2;
|
||
|
if((isTop && Low(startIdx) < neckline) || (!isTop && High(startIdx) > neckline))
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Reset extremesFound to 1 to check for another potential double top/bottom
|
||
|
extremesFound = 1;
|
||
|
extreme1 = extreme2;
|
||
|
extreme1Idx = extreme2Idx;
|
||
|
}
|
||
|
prevExtreme2 = prevExtreme1;
|
||
|
prevExtreme1 = value;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
};
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Constructor |
|
||
|
//+------------------------------------------------------------------+
|
||
|
CSignalDTDB::CSignalDTDB() :
|
||
|
m_pattern_0(30),
|
||
|
m_lookback_period(10)
|
||
|
{
|
||
|
m_id = "DTDB";
|
||
|
m_pattern_count = 1;
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Destructor |
|
||
|
//+------------------------------------------------------------------+
|
||
|
CSignalDTDB::~CSignalDTDB(void)
|
||
|
{
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Validation settings |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool CSignalDTDB::ValidationSettings()
|
||
|
{
|
||
|
if(!CExpertSignalCustom::ValidationSettings())
|
||
|
return false;
|
||
|
if(m_lookback_period <= 0 || m_lookback_period > 200)
|
||
|
{
|
||
|
Print("Lookback Period must be greater than 0 and smaller than 200");
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Detect Double Top |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool CSignalDTDB::DetectDoubleTop(int startIdx)
|
||
|
{
|
||
|
return DetectDoubleExtreme(startIdx, true);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Detect Double Bottom |
|
||
|
//+------------------------------------------------------------------+
|
||
|
bool CSignalDTDB::DetectDoubleBottom(int startIdx)
|
||
|
{
|
||
|
return DetectDoubleExtreme(startIdx, false);
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Long Condition |
|
||
|
//+------------------------------------------------------------------+
|
||
|
int CSignalDTDB::LongCondition(void)
|
||
|
{
|
||
|
int result = 0;
|
||
|
int idx = StartIndex();
|
||
|
if(IS_PATTERN_USAGE(0) && DetectDoubleBottom(idx))
|
||
|
{
|
||
|
result = m_pattern_0;
|
||
|
m_active_pattern = "Pattern_0";
|
||
|
}
|
||
|
if(result != 0)
|
||
|
{
|
||
|
m_active_direction = "Buy";
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Short Condition |
|
||
|
//+------------------------------------------------------------------+
|
||
|
int CSignalDTDB::ShortCondition(void)
|
||
|
{
|
||
|
int result = 0;
|
||
|
int idx = StartIndex();
|
||
|
if(IS_PATTERN_USAGE(0) && DetectDoubleTop(idx))
|
||
|
{
|
||
|
result = m_pattern_0;
|
||
|
m_active_pattern = "Pattern_0";
|
||
|
}
|
||
|
if(result != 0)
|
||
|
{
|
||
|
m_active_direction = "Sell";
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|
||
|
//| Apply Pattern Weight |
|
||
|
//+------------------------------------------------------------------+
|
||
|
void CSignalDTDB::ApplyPatternWeight(int patternNumber, int weight)
|
||
|
{
|
||
|
switch(patternNumber)
|
||
|
{
|
||
|
default:
|
||
|
break;
|
||
|
case 0:
|
||
|
Pattern_0(weight);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
//+------------------------------------------------------------------+
|