2026-07-01 19:11:35 +02:00
//+------------------------------------------------------------------+
2026-02-17 09:45:13 +01:00
//| Stochastic_Adaptive_on_DMI_Calculator.mqh |
2026-07-01 19:11:35 +02:00
//| Copyright 2026, xxxxxxxx|
2026-02-17 09:45:13 +01:00
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, xxxxxxxx"
2026-07-01 19:53:24 +02:00
#property version "2.30" // Upgraded with dynamic volume-weighted (VWMA) smoothing support
2026-07-01 19:11:35 +02:00
#ifndef STOCHASTIC_ADAPTIVE_ON_DMI_CALCULATOR_MQH
#define STOCHASTIC_ADAPTIVE_ON_DMI_CALCULATOR_MQH
2026-02-17 09:45:13 +01:00
#include <MyIncludes\DMI_Engine.mqh>
#include <MyIncludes\MovingAverage_Engine.mqh>
2026-02-17 09:57:00 +01:00
//--- Enums Definitions
2026-02-17 09:45:13 +01:00
#ifndef ENUM_CANDLE_SOURCE_DEFINED
#define ENUM_CANDLE_SOURCE_DEFINED
2026-02-17 09:57:00 +01:00
enum ENUM_CANDLE_SOURCE { CANDLE_STANDARD, CANDLE_HEIKIN_ASHI };
2026-02-17 09:45:13 +01:00
#endif
2026-02-17 09:57:00 +01:00
enum ENUM_DMI_OSC_TYPE { OSC_PDI_MINUS_NDI, OSC_NDI_MINUS_PDI };
2026-02-17 09:45:13 +01:00
//+==================================================================+
//| CLASS: CStochAdaptiveOnDMICalculator |
2026-05-22 12:48:12 +02:00
//| PURPOSE: Calculates an adaptive stochastic oscillator based on |
//| DMI output, ensuring O(1) incremental performance. |
2026-02-17 09:45:13 +01:00
//+==================================================================+
class CStochAdaptiveOnDMICalculator
{
protected:
2026-02-17 09:57:00 +01:00
// Parameters
int m_dmi_p;
ENUM_DMI_OSC_TYPE m_osc_type;
int m_er_p;
int m_min_stoch_p;
int m_max_stoch_p;
2026-05-22 12:48:12 +02:00
// Mathematical Engines (Stateful for O(1) recursion)
2026-02-17 09:57:00 +01:00
CDMIEngine *m_dmi_engine;
2026-02-17 09:45:13 +01:00
CMovingAverageCalculator m_slowing_engine;
CMovingAverageCalculator m_signal_engine;
2026-05-22 12:48:12 +02:00
// Persistent Buffers for internal states
2026-02-17 09:57:00 +01:00
double m_pDI[], m_nDI[];
2026-07-01 19:53:24 +02:00
double m_volume[]; // Persistent volume buffer to support VWMA
2026-05-22 12:48:12 +02:00
double m_dmi_osc[]; // DMI Oscillator Data
2026-02-17 09:57:00 +01:00
double m_er_buffer[]; // Efficiency Ratio of DMI
2026-05-22 12:48:12 +02:00
double m_nsp_buffer[]; // Dynamic Stochastic Period (Lookback)
2026-02-17 09:57:00 +01:00
double m_raw_k[]; // Raw Adaptive %K
2026-02-17 09:45:13 +01:00
2026-05-22 12:48:12 +02:00
// Factory Method for Engine instantiation
2026-02-17 09:57:00 +01:00
virtual void CreateDMIEngine();
2026-02-17 09:45:13 +01:00
public:
CStochAdaptiveOnDMICalculator();
2026-02-17 09:57:00 +01:00
virtual ~CStochAdaptiveOnDMICalculator();
2026-02-17 09:45:13 +01:00
2026-07-01 19:11:35 +02:00
bool Init(double gamma, int dmi_p, ENUM_DMI_OSC_TYPE osc_type, int er_p, int min_p, int max_p, int slow_p, ENUM_MA_TYPE slow_ma, int d_p, ENUM_MA_TYPE d_ma);
2026-02-17 09:45:13 +01:00
2026-07-01 19:53:24 +02:00
//--- Standard Calculate (Without volume data) - Redirects to overloaded with dummy volume fallback
2026-02-17 09:57:00 +01:00
void Calculate(int rates_total, int prev_calculated,
const double &open[], const double &high[],
const double &low[], const double &close[],
double &out_k[], double &out_d[]);
2026-07-01 19:53:24 +02:00
//--- Overloaded Calculate with Volume (Specifically for VWMA support)
void Calculate(int rates_total, int prev_calculated,
const double &open[], const double &high[],
const double &low[], const double &close[],
const long &volume[],
double &out_k[], double &out_d[]);
2026-02-17 09:45:13 +01:00
};
//+------------------------------------------------------------------+
2026-05-22 12:48:12 +02:00
//| Constructor & Destructor |
2026-02-17 09:45:13 +01:00
//+------------------------------------------------------------------+
2026-02-17 09:57:00 +01:00
CStochAdaptiveOnDMICalculator::CStochAdaptiveOnDMICalculator() : m_dmi_engine(NULL) {}
2026-02-17 09:45:13 +01:00
//+------------------------------------------------------------------+
2026-02-17 09:57:00 +01:00
//| |
2026-02-17 09:45:13 +01:00
//+------------------------------------------------------------------+
CStochAdaptiveOnDMICalculator::~CStochAdaptiveOnDMICalculator()
{
2026-07-01 19:11:35 +02:00
if(CheckPointer(m_dmi_engine) != POINTER_INVALID)
2026-02-17 09:45:13 +01:00
delete m_dmi_engine;
}
//+------------------------------------------------------------------+
2026-02-17 09:57:00 +01:00
//| |
2026-02-17 09:45:13 +01:00
//+------------------------------------------------------------------+
void CStochAdaptiveOnDMICalculator::CreateDMIEngine()
{
m_dmi_engine = new CDMIEngine();
}
//+------------------------------------------------------------------+
2026-05-22 12:48:12 +02:00
//| Initialization phase |
2026-02-17 09:45:13 +01:00
//+------------------------------------------------------------------+
2026-07-01 19:11:35 +02:00
bool CStochAdaptiveOnDMICalculator::Init(double gamma, int dmi_p, ENUM_DMI_OSC_TYPE osc_type, int er_p, int min_p, int max_p, int slow_p, ENUM_MA_TYPE slow_ma, int d_p, ENUM_MA_TYPE d_ma)
2026-02-17 09:45:13 +01:00
{
2026-02-17 09:57:00 +01:00
m_dmi_p = dmi_p;
2026-02-17 09:45:13 +01:00
m_osc_type = osc_type;
2026-02-17 09:57:00 +01:00
m_er_p = er_p;
m_min_stoch_p = min_p;
m_max_stoch_p = max_p;
2026-02-17 09:45:13 +01:00
CreateDMIEngine();
2026-05-22 12:48:12 +02:00
2026-07-01 19:11:35 +02:00
if(CheckPointer(m_dmi_engine) == POINTER_INVALID || !m_dmi_engine.Init(m_dmi_p))
2026-02-17 09:45:13 +01:00
return false;
2026-02-17 09:57:00 +01:00
if(!m_slowing_engine.Init(slow_p, slow_ma))
2026-02-17 09:45:13 +01:00
return false;
if(!m_signal_engine.Init(d_p, d_ma))
return false;
return true;
}
//+------------------------------------------------------------------+
2026-07-01 19:53:24 +02:00
//| Standard Calculate (OHLC) - Dummy Volume Fallback Pattern |
2026-02-17 09:45:13 +01:00
//+------------------------------------------------------------------+
void CStochAdaptiveOnDMICalculator::Calculate(int rates_total, int prev_calculated,
const double &open[], const double &high[],
const double &low[], const double &close[],
double &out_k[], double &out_d[])
2026-07-01 19:53:24 +02:00
{
long dummy_vol[];
ArrayResize(dummy_vol, rates_total);
ArrayInitialize(dummy_vol, 1);
Calculate(rates_total, prev_calculated, open, high, low, close, dummy_vol, out_k, out_d);
}
//+------------------------------------------------------------------+
//| Overloaded Calculate (OHLC) with Volume |
//+------------------------------------------------------------------+
void CStochAdaptiveOnDMICalculator::Calculate(int rates_total, int prev_calculated,
const double &open[], const double &high[],
const double &low[], const double &close[],
const long &volume[],
double &out_k[], double &out_d[])
2026-02-17 09:45:13 +01:00
{
if(rates_total < m_dmi_p + m_er_p + m_max_stoch_p)
return;
2026-07-01 19:11:35 +02:00
if(CheckPointer(m_dmi_engine) == POINTER_INVALID)
return;
2026-05-22 12:48:12 +02:00
// O(1) Pointer
2026-02-17 09:45:13 +01:00
int start_index = (prev_calculated > 0) ? prev_calculated - 1 : 0;
2026-07-01 19:11:35 +02:00
// 1. Dynamic Buffer Resizing and chronological sorting safety kényszerítés
2026-02-17 09:45:13 +01:00
if(ArraySize(m_pDI) != rates_total)
{
ArrayResize(m_pDI, rates_total);
ArrayResize(m_nDI, rates_total);
2026-07-01 19:53:24 +02:00
ArrayResize(m_volume, rates_total);
2026-02-17 09:45:13 +01:00
ArrayResize(m_dmi_osc, rates_total);
ArrayResize(m_er_buffer, rates_total);
ArrayResize(m_nsp_buffer, rates_total);
ArrayResize(m_raw_k, rates_total);
2026-07-01 19:11:35 +02:00
ArraySetAsSeries(m_pDI, false);
ArraySetAsSeries(m_nDI, false);
2026-07-01 19:53:24 +02:00
ArraySetAsSeries(m_volume, false);
2026-07-01 19:11:35 +02:00
ArraySetAsSeries(m_dmi_osc, false);
ArraySetAsSeries(m_er_buffer, false);
ArraySetAsSeries(m_nsp_buffer, false);
ArraySetAsSeries(m_raw_k, false);
2026-02-17 09:45:13 +01:00
}
2026-05-22 12:48:12 +02:00
// 2. Base DMI Calculation via encapsulated Engine
2026-02-17 09:45:13 +01:00
m_dmi_engine.Calculate(rates_total, prev_calculated, open, high, low, close, m_pDI, m_nDI);
2026-05-22 12:48:12 +02:00
// 3. DMI Oscillator Line
2026-02-17 09:57:00 +01:00
int loop_start_dmi = MathMax(m_dmi_p, start_index);
for(int i = loop_start_dmi; i < rates_total; i++)
2026-02-17 09:45:13 +01:00
{
2026-07-01 19:53:24 +02:00
m_volume[i] = (double)volume[i]; // Copy and cast volume locally
2026-02-17 09:45:13 +01:00
if(m_osc_type == OSC_PDI_MINUS_NDI)
m_dmi_osc[i] = m_pDI[i] - m_nDI[i];
else
m_dmi_osc[i] = m_nDI[i] - m_pDI[i];
}
2026-05-22 12:48:12 +02:00
// 4. Efficiency Ratio (ER) based strictly on DMI volatility
2026-02-17 09:57:00 +01:00
int loop_start_er = MathMax(m_dmi_p + m_er_p, start_index);
for(int i = loop_start_er; i < rates_total; i++)
2026-02-17 09:45:13 +01:00
{
double direction = MathAbs(m_dmi_osc[i] - m_dmi_osc[i - m_er_p]);
double volatility = 0;
for(int j = 0; j < m_er_p; j++)
volatility += MathAbs(m_dmi_osc[i - j] - m_dmi_osc[i - j - 1]);
m_er_buffer[i] = (volatility > 1.0e-9) ? direction / volatility : 0.0;
}
2026-07-01 19:53:24 +02:00
// 5. Adaptive Period (NSP) Calculation
2026-05-22 12:48:12 +02:00
// Inverse logic: High ER (Trend) = Short Period; Low ER (Chop) = Long Period
2026-02-17 09:57:00 +01:00
for(int i = loop_start_er; i < rates_total; i++)
2026-02-17 09:45:13 +01:00
{
2026-05-22 12:48:12 +02:00
m_nsp_buffer[i] = MathRound(m_min_stoch_p + (1.0 - m_er_buffer[i]) * (m_max_stoch_p - m_min_stoch_p));
// Safety Limit: Stochastic mathematically breaks if period < 2 (Div by Zero)
2026-02-17 09:45:13 +01:00
if(m_nsp_buffer[i] < 2)
m_nsp_buffer[i] = 2;
}
2026-05-22 12:48:12 +02:00
// 6. Raw %K on DMI Oscillator using dynamic lookback (NSP)
2026-02-17 09:57:00 +01:00
int stoch_start = m_dmi_p + m_er_p + m_max_stoch_p - 1;
int loop_start_k = MathMax(stoch_start, start_index);
2026-02-17 09:45:13 +01:00
2026-02-17 09:57:00 +01:00
for(int i = loop_start_k; i < rates_total; i++)
2026-02-17 09:45:13 +01:00
{
int current_nsp = (int)m_nsp_buffer[i];
double highest = m_dmi_osc[i];
2026-02-17 09:57:00 +01:00
double lowest = m_dmi_osc[i];
2026-02-17 09:45:13 +01:00
for(int k = 1; k < current_nsp; k++)
{
2026-02-17 09:57:00 +01:00
if(i-k < 0)
2026-05-22 12:48:12 +02:00
break; // Safety
2026-02-17 09:57:00 +01:00
if(m_dmi_osc[i-k] > highest)
highest = m_dmi_osc[i-k];
if(m_dmi_osc[i-k] < lowest)
lowest = m_dmi_osc[i-k];
2026-02-17 09:45:13 +01:00
}
double range = highest - lowest;
if(range > 1.0e-9)
m_raw_k[i] = 100.0 * (m_dmi_osc[i] - lowest) / range;
else
2026-05-22 12:48:12 +02:00
m_raw_k[i] = (i > 0) ? m_raw_k[i-1] : 50.0; // Flatline prevention fallback
2026-02-17 09:45:13 +01:00
}
2026-07-01 19:53:24 +02:00
// 7. Final Smoothing (Engine handles volume-weighted (VWMA) O(1) natively if volume buffer is passed)
m_slowing_engine.CalculateOnArray(rates_total, prev_calculated, m_raw_k, m_volume, out_k, stoch_start);
2026-02-17 09:45:13 +01:00
int d_offset = stoch_start + m_slowing_engine.GetPeriod() - 1;
2026-07-01 19:53:24 +02:00
m_signal_engine.CalculateOnArray(rates_total, prev_calculated, out_k, m_volume, out_d, d_offset);
2026-02-17 09:45:13 +01:00
}
//+==================================================================+
2026-05-22 12:48:12 +02:00
//| CLASS: CStochAdaptiveOnDMICalculator_HA (Heikin Ashi Support) |
2026-02-17 09:45:13 +01:00
//+==================================================================+
class CStochAdaptiveOnDMICalculator_HA : public CStochAdaptiveOnDMICalculator
{
protected:
virtual void CreateDMIEngine() override
{
m_dmi_engine = new CDMIEngine_HA();
}
};
//+------------------------------------------------------------------+
2026-07-01 19:11:35 +02:00
#endif // STOCHASTIC_ADAPTIVE_ON_DMI_CALCULATOR_MQH