2026-07-13 15:59:35 -04:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| ADCumulativeDelta.mq5|
|
|
|
|
|
//| Wyckoff Cumulative Delta / Flow Pressure |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
#property copyright "AD Institutional Indicators"
|
|
|
|
|
#property link ""
|
|
|
|
|
#property version "1.00"
|
|
|
|
|
#property description "Wyckoff Cumulative Delta — tick-volume and price-flow order-flow proxy"
|
|
|
|
|
#property indicator_separate_window
|
|
|
|
|
#property indicator_buffers 6
|
|
|
|
|
#property indicator_plots 6
|
|
|
|
|
|
|
|
|
|
#property indicator_minimum -2.0
|
|
|
|
|
#property indicator_maximum 2.0
|
|
|
|
|
#property indicator_level1 0
|
|
|
|
|
|
|
|
|
|
#property indicator_label1 "Pressure"
|
|
|
|
|
#property indicator_type1 DRAW_LINE
|
|
|
|
|
#property indicator_color1 clrWhite
|
|
|
|
|
#property indicator_width1 1
|
|
|
|
|
|
|
|
|
|
#property indicator_label2 "CumulativeDelta"
|
|
|
|
|
#property indicator_type2 DRAW_LINE
|
|
|
|
|
#property indicator_color2 clrGold
|
|
|
|
|
#property indicator_width2 1
|
|
|
|
|
|
|
|
|
|
#property indicator_label3 "BullishPressure"
|
|
|
|
|
#property indicator_type3 DRAW_LINE
|
|
|
|
|
#property indicator_color3 clrLime
|
|
|
|
|
#property indicator_width3 1
|
|
|
|
|
|
|
|
|
|
#property indicator_label4 "BearishPressure"
|
|
|
|
|
#property indicator_type4 DRAW_LINE
|
|
|
|
|
#property indicator_color4 clrRed
|
|
|
|
|
#property indicator_width4 1
|
|
|
|
|
|
|
|
|
|
#property indicator_label5 "Absorption"
|
|
|
|
|
#property indicator_type5 DRAW_LINE
|
|
|
|
|
#property indicator_color5 clrAqua
|
|
|
|
|
#property indicator_width5 1
|
|
|
|
|
|
|
|
|
|
#property indicator_label6 "Initiative"
|
|
|
|
|
#property indicator_type6 DRAW_LINE
|
|
|
|
|
#property indicator_color6 clrMagenta
|
|
|
|
|
#property indicator_width6 1
|
|
|
|
|
|
|
|
|
|
input int InpLookbackPeriod = 50;
|
|
|
|
|
input double InpVolumeClimaxMultiplier = 2.5;
|
|
|
|
|
input double InpVolumeHighMultiplier = 1.5;
|
|
|
|
|
input double InpRangeClimaxMultiplier = 1.8;
|
|
|
|
|
input double InpRangeSignificantMult = 1.2;
|
|
|
|
|
input double InpSTVolumeRatio = 0.6;
|
|
|
|
|
input double InpATRMultiplier = 0.5;
|
|
|
|
|
input int InpContextMode = 0;
|
|
|
|
|
input int InpSessionType = 5;
|
|
|
|
|
input int InpSessionCount = 1;
|
|
|
|
|
|
|
|
|
|
double ExtPressureBuffer[];
|
|
|
|
|
double ExtCumulativeDeltaBuffer[];
|
|
|
|
|
double ExtBullishPressureBuffer[];
|
|
|
|
|
double ExtBearishPressureBuffer[];
|
|
|
|
|
double ExtAbsorptionBuffer[];
|
|
|
|
|
double ExtInitiativeBuffer[];
|
|
|
|
|
|
|
|
|
|
double H[];
|
|
|
|
|
double L[];
|
|
|
|
|
double O[];
|
|
|
|
|
double C[];
|
|
|
|
|
double V[];
|
|
|
|
|
datetime T[];
|
|
|
|
|
|
|
|
|
|
int ExtLookbackPeriod;
|
|
|
|
|
double ExtVolumeClimaxMultiplier;
|
|
|
|
|
double ExtVolumeHighMultiplier;
|
|
|
|
|
double ExtRangeClimaxMultiplier;
|
|
|
|
|
double ExtRangeSignificantMult;
|
|
|
|
|
double ExtSTVolumeRatio;
|
|
|
|
|
double ExtATRMultiplier;
|
|
|
|
|
int ExtContextMode;
|
|
|
|
|
int ExtSessionType;
|
|
|
|
|
int ExtSessionCount;
|
|
|
|
|
|
|
|
|
|
int ClampInt(const int value, const int minValue, const int maxValue) { return (int)MathMax(minValue, MathMin(maxValue, value)); }
|
|
|
|
|
double ClampDouble(const double value, const double minValue, const double maxValue) { return MathMax(minValue, MathMin(maxValue, value)); }
|
|
|
|
|
|
|
|
|
|
bool IsPreviousSessionTypeMT5(const int sessionType) { return (sessionType >= 1 && sessionType <= 4); }
|
|
|
|
|
bool IsZigZagSessionTypeMT5(const int sessionType) { return (sessionType == 9 || sessionType == 10); }
|
|
|
|
|
int MapBaseCalendarTypeMT5(const int sessionType)
|
|
|
|
|
{
|
|
|
|
|
if(sessionType == 1 || sessionType == 5) return 1;
|
|
|
|
|
if(sessionType == 2 || sessionType == 6) return 2;
|
|
|
|
|
if(sessionType == 3 || sessionType == 7) return 3;
|
|
|
|
|
if(sessionType == 4 || sessionType == 8) return 4;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
datetime DayStartMT5(const datetime t)
|
|
|
|
|
{
|
|
|
|
|
MqlDateTime dt;
|
|
|
|
|
TimeToStruct(t, dt);
|
|
|
|
|
dt.hour = 0; dt.min = 0; dt.sec = 0;
|
|
|
|
|
return StructToTime(dt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
datetime AddMonthsSafeMT5(const datetime t, const int months)
|
|
|
|
|
{
|
|
|
|
|
MqlDateTime dt;
|
|
|
|
|
TimeToStruct(t, dt);
|
|
|
|
|
int m = dt.mon + months;
|
|
|
|
|
while(m > 12) { m -= 12; dt.year++; }
|
|
|
|
|
while(m < 1) { m += 12; dt.year--; }
|
|
|
|
|
dt.mon = m; dt.day = 1; dt.hour = 0; dt.min = 0; dt.sec = 0;
|
|
|
|
|
return StructToTime(dt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
datetime ShiftCalendarStartMT5(const datetime start, const int baseType, const int shiftCount)
|
|
|
|
|
{
|
|
|
|
|
if(shiftCount == 0) return start;
|
|
|
|
|
if(baseType == 1) return start + (datetime)(shiftCount * 86400);
|
|
|
|
|
if(baseType == 2) return start + (datetime)(shiftCount * 7 * 86400);
|
|
|
|
|
if(baseType == 3) return AddMonthsSafeMT5(start, shiftCount);
|
|
|
|
|
return AddMonthsSafeMT5(start, shiftCount * 12);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
datetime ResolveCalendarContextStartMT5(const datetime currentTime)
|
|
|
|
|
{
|
|
|
|
|
int st = ExtSessionType;
|
|
|
|
|
int baseType = MapBaseCalendarTypeMT5(st);
|
|
|
|
|
datetime currentStart = DayStartMT5(currentTime);
|
|
|
|
|
if(baseType == 2)
|
|
|
|
|
{
|
|
|
|
|
MqlDateTime w; TimeToStruct(currentStart, w);
|
|
|
|
|
int dow = w.day_of_week;
|
|
|
|
|
int back = (dow == 0) ? 6 : (dow - 1);
|
|
|
|
|
currentStart -= (datetime)(back * 86400);
|
|
|
|
|
}
|
|
|
|
|
else if(baseType == 3)
|
|
|
|
|
{
|
|
|
|
|
MqlDateTime m; TimeToStruct(currentStart, m);
|
|
|
|
|
m.day = 1; m.hour = 0; m.min = 0; m.sec = 0;
|
|
|
|
|
currentStart = StructToTime(m);
|
|
|
|
|
}
|
|
|
|
|
else if(baseType == 4)
|
|
|
|
|
{
|
|
|
|
|
MqlDateTime y; TimeToStruct(currentStart, y);
|
|
|
|
|
y.mon = 1; y.day = 1; y.hour = 0; y.min = 0; y.sec = 0;
|
|
|
|
|
currentStart = StructToTime(y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int shift = IsPreviousSessionTypeMT5(st) ? -ExtSessionCount : -(ExtSessionCount - 1);
|
|
|
|
|
return ShiftCalendarStartMT5(currentStart, baseType, shift);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ResetState()
|
|
|
|
|
{
|
|
|
|
|
ArrayInitialize(ExtPressureBuffer, 0);
|
|
|
|
|
ArrayInitialize(ExtCumulativeDeltaBuffer, 0);
|
|
|
|
|
ArrayInitialize(ExtBullishPressureBuffer, 0);
|
|
|
|
|
ArrayInitialize(ExtBearishPressureBuffer, 0);
|
|
|
|
|
ArrayInitialize(ExtAbsorptionBuffer, 0);
|
|
|
|
|
ArrayInitialize(ExtInitiativeBuffer, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SetOutputs(const int outIndex, const double pressure, const double cumulativeDelta, const double bullishPressure, const double bearishPressure, const double absorption, const double initiative)
|
|
|
|
|
{
|
|
|
|
|
ExtPressureBuffer[outIndex] = pressure;
|
|
|
|
|
ExtCumulativeDeltaBuffer[outIndex] = cumulativeDelta;
|
|
|
|
|
ExtBullishPressureBuffer[outIndex] = bullishPressure;
|
|
|
|
|
ExtBearishPressureBuffer[outIndex] = bearishPressure;
|
|
|
|
|
ExtAbsorptionBuffer[outIndex] = absorption;
|
|
|
|
|
ExtInitiativeBuffer[outIndex] = initiative;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int OnInit()
|
|
|
|
|
{
|
|
|
|
|
ExtLookbackPeriod = ClampInt(InpLookbackPeriod, 5, 200);
|
|
|
|
|
ExtVolumeClimaxMultiplier = ClampDouble(InpVolumeClimaxMultiplier, 1.0, 5.0);
|
|
|
|
|
ExtVolumeHighMultiplier = ClampDouble(InpVolumeHighMultiplier, 0.5, 3.0);
|
|
|
|
|
ExtRangeClimaxMultiplier = ClampDouble(InpRangeClimaxMultiplier, 1.0, 5.0);
|
|
|
|
|
ExtRangeSignificantMult = ClampDouble(InpRangeSignificantMult, 0.5, 3.0);
|
|
|
|
|
ExtSTVolumeRatio = ClampDouble(InpSTVolumeRatio, 0.1, 1.0);
|
|
|
|
|
ExtATRMultiplier = ClampDouble(InpATRMultiplier, 0.1, 3.0);
|
|
|
|
|
ExtContextMode = (InpContextMode == 1) ? 1 : 0;
|
|
|
|
|
ExtSessionType = ClampInt(InpSessionType, 1, 10);
|
|
|
|
|
ExtSessionCount = ClampInt(InpSessionCount, 1, 20);
|
|
|
|
|
|
|
|
|
|
SetIndexBuffer(0, ExtPressureBuffer, INDICATOR_DATA);
|
|
|
|
|
SetIndexBuffer(1, ExtCumulativeDeltaBuffer, INDICATOR_DATA);
|
|
|
|
|
SetIndexBuffer(2, ExtBullishPressureBuffer, INDICATOR_DATA);
|
|
|
|
|
SetIndexBuffer(3, ExtBearishPressureBuffer, INDICATOR_DATA);
|
|
|
|
|
SetIndexBuffer(4, ExtAbsorptionBuffer, INDICATOR_DATA);
|
|
|
|
|
SetIndexBuffer(5, ExtInitiativeBuffer, INDICATOR_DATA);
|
|
|
|
|
|
|
|
|
|
ArraySetAsSeries(ExtPressureBuffer, true);
|
|
|
|
|
ArraySetAsSeries(ExtCumulativeDeltaBuffer, true);
|
|
|
|
|
ArraySetAsSeries(ExtBullishPressureBuffer, true);
|
|
|
|
|
ArraySetAsSeries(ExtBearishPressureBuffer, true);
|
|
|
|
|
ArraySetAsSeries(ExtAbsorptionBuffer, true);
|
|
|
|
|
ArraySetAsSeries(ExtInitiativeBuffer, true);
|
|
|
|
|
|
|
|
|
|
IndicatorSetInteger(INDICATOR_DIGITS, 3);
|
|
|
|
|
IndicatorSetString(INDICATOR_SHORTNAME,
|
|
|
|
|
"CVD(" + IntegerToString(ExtLookbackPeriod) + "," + DoubleToString(ExtVolumeClimaxMultiplier, 2) + "," + DoubleToString(ExtVolumeHighMultiplier, 2) + "," +
|
|
|
|
|
DoubleToString(ExtRangeClimaxMultiplier, 2) + "," + DoubleToString(ExtRangeSignificantMult, 2) + ")");
|
|
|
|
|
|
|
|
|
|
PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, ExtLookbackPeriod);
|
|
|
|
|
PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, ExtLookbackPeriod);
|
|
|
|
|
PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, ExtLookbackPeriod);
|
|
|
|
|
PlotIndexSetInteger(3, PLOT_DRAW_BEGIN, ExtLookbackPeriod);
|
|
|
|
|
PlotIndexSetInteger(4, PLOT_DRAW_BEGIN, ExtLookbackPeriod);
|
|
|
|
|
PlotIndexSetInteger(5, PLOT_DRAW_BEGIN, ExtLookbackPeriod);
|
|
|
|
|
ResetState();
|
|
|
|
|
return(INIT_SUCCEEDED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnDeinit(const int reason) {}
|
|
|
|
|
|
|
|
|
|
double ComputeATRChrono(const int i, const int period)
|
|
|
|
|
{
|
|
|
|
|
int available = MathMin(period, i);
|
|
|
|
|
if(available <= 0)
|
|
|
|
|
return H[i] - L[i];
|
|
|
|
|
|
|
|
|
|
double sum = 0.0;
|
|
|
|
|
for(int k = 0; k < available; k++)
|
|
|
|
|
{
|
|
|
|
|
int idx = i - k;
|
|
|
|
|
double hi = H[idx];
|
|
|
|
|
double lo = L[idx];
|
|
|
|
|
double prevClose = (idx > 0) ? C[idx - 1] : hi;
|
|
|
|
|
double tr = MathMax(hi - lo, MathMax(MathAbs(hi - prevClose), MathAbs(lo - prevClose)));
|
|
|
|
|
sum += tr;
|
|
|
|
|
}
|
|
|
|
|
return sum / available;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int OnCalculate(const int rates_total,
|
|
|
|
|
const int prev_calculated,
|
|
|
|
|
const datetime &time[],
|
|
|
|
|
const double &open[],
|
|
|
|
|
const double &high[],
|
|
|
|
|
const double &low[],
|
|
|
|
|
const double &close[],
|
|
|
|
|
const long &tick_volume[],
|
|
|
|
|
const long &volume[],
|
|
|
|
|
const int &spread[])
|
|
|
|
|
{
|
|
|
|
|
if(rates_total < ExtLookbackPeriod + 2)
|
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
|
|
ArraySetAsSeries(time, true);
|
|
|
|
|
ArraySetAsSeries(high, true);
|
|
|
|
|
ArraySetAsSeries(low, true);
|
|
|
|
|
ArraySetAsSeries(open, true);
|
|
|
|
|
ArraySetAsSeries(close, true);
|
|
|
|
|
ArraySetAsSeries(tick_volume, true);
|
|
|
|
|
ArraySetAsSeries(volume, true);
|
|
|
|
|
|
|
|
|
|
ArrayResize(H, rates_total);
|
|
|
|
|
ArrayResize(L, rates_total);
|
|
|
|
|
ArrayResize(O, rates_total);
|
|
|
|
|
ArrayResize(C, rates_total);
|
|
|
|
|
ArrayResize(V, rates_total);
|
|
|
|
|
ArrayResize(T, rates_total);
|
|
|
|
|
|
|
|
|
|
ResetState();
|
|
|
|
|
|
|
|
|
|
for(int chrono = 0; chrono < rates_total; chrono++)
|
|
|
|
|
{
|
|
|
|
|
int si = rates_total - 1 - chrono;
|
|
|
|
|
H[chrono] = high[si];
|
|
|
|
|
L[chrono] = low[si];
|
|
|
|
|
O[chrono] = open[si];
|
|
|
|
|
C[chrono] = close[si];
|
|
|
|
|
V[chrono] = (double)MathMax(tick_volume[si], 1);
|
|
|
|
|
T[chrono] = time[si];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(int chrono = 0; chrono < rates_total && !IsStopped(); chrono++)
|
|
|
|
|
{
|
|
|
|
|
int si = rates_total - 1 - chrono;
|
|
|
|
|
|
|
|
|
|
int start = 0;
|
|
|
|
|
if(ExtContextMode == 0)
|
|
|
|
|
{
|
|
|
|
|
start = MathMax(0, chrono - ExtLookbackPeriod + 1);
|
|
|
|
|
}
|
|
|
|
|
else if(IsZigZagSessionTypeMT5(ExtSessionType))
|
|
|
|
|
{
|
|
|
|
|
start = MathMax(0, chrono - (ExtLookbackPeriod * ExtSessionCount) + 1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
datetime sessionStart = ResolveCalendarContextStartMT5(T[chrono]);
|
|
|
|
|
for(int j = chrono; j >= 0; j--)
|
|
|
|
|
{
|
|
|
|
|
if(T[j] < sessionStart)
|
|
|
|
|
{
|
|
|
|
|
start = j + 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
start = j;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double sumRange = 0.0;
|
|
|
|
|
double sumVolume = 0.0;
|
|
|
|
|
double cumulativeDelta = 0.0;
|
|
|
|
|
double bullishDelta = 0.0;
|
|
|
|
|
double bearishDelta = 0.0;
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
|
|
for(int k = start; k <= chrono; k++)
|
|
|
|
|
{
|
|
|
|
|
double hi = H[k];
|
|
|
|
|
double lo = L[k];
|
|
|
|
|
double op = O[k];
|
|
|
|
|
double cl = C[k];
|
|
|
|
|
double vol = MathMax(V[k], 1.0);
|
|
|
|
|
double barRange = MathMax(hi - lo, 0.000001);
|
|
|
|
|
double closePos = ClampDouble((cl - lo) / barRange, 0.0, 1.0);
|
|
|
|
|
double bodyBias = ClampDouble((cl - op) / barRange, -1.0, 1.0);
|
|
|
|
|
double priceStep = (k > 0) ? (cl - C[k - 1]) : (cl - op);
|
|
|
|
|
double flowBias = ClampDouble(priceStep / barRange, -1.0, 1.0);
|
|
|
|
|
double signedDelta = vol * ClampDouble(0.7 * flowBias + 0.3 * bodyBias, -1.0, 1.0);
|
|
|
|
|
|
|
|
|
|
sumRange += barRange;
|
|
|
|
|
sumVolume += vol;
|
|
|
|
|
cumulativeDelta += signedDelta;
|
|
|
|
|
if(signedDelta >= 0.0)
|
|
|
|
|
bullishDelta += signedDelta;
|
|
|
|
|
else
|
|
|
|
|
bearishDelta += -signedDelta;
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(count <= 0 || !MathIsValidNumber(sumRange) || !MathIsValidNumber(sumVolume) || sumRange <= 0.0 || sumVolume <= 0.0)
|
|
|
|
|
{
|
|
|
|
|
SetOutputs(si, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double avgRange = sumRange / count;
|
|
|
|
|
double avgVolume = sumVolume / count;
|
|
|
|
|
if(!MathIsValidNumber(avgRange) || !MathIsValidNumber(avgVolume) || avgRange <= 0.0 || avgVolume <= 0.0)
|
|
|
|
|
{
|
|
|
|
|
SetOutputs(si, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double absorptionSum = 0.0;
|
|
|
|
|
double initiativeSum = 0.0;
|
|
|
|
|
double atrNow = ComputeATRChrono(chrono, 14);
|
|
|
|
|
double atrRatio = (H[chrono] - L[chrono]) / MathMax(atrNow * ExtATRMultiplier, 0.000001);
|
|
|
|
|
|
|
|
|
|
for(int k = start; k <= chrono; k++)
|
|
|
|
|
{
|
|
|
|
|
double hi = H[k];
|
|
|
|
|
double lo = L[k];
|
|
|
|
|
double op = O[k];
|
|
|
|
|
double cl = C[k];
|
|
|
|
|
double vol = MathMax(V[k], 1.0);
|
|
|
|
|
double barRange = MathMax(hi - lo, 0.000001);
|
|
|
|
|
double closePos = ClampDouble((cl - lo) / barRange, 0.0, 1.0);
|
|
|
|
|
double rangeRatio = barRange / avgRange;
|
|
|
|
|
double volRatio = vol / avgVolume;
|
|
|
|
|
double midpointDistance = MathAbs(closePos - 0.5) * 2.0;
|
|
|
|
|
|
|
|
|
|
bool absorptionHit = volRatio >= ExtVolumeHighMultiplier
|
|
|
|
|
&& rangeRatio <= ExtRangeSignificantMult
|
|
|
|
|
&& closePos >= 0.35 && closePos <= 0.65;
|
|
|
|
|
double absorptionScore = absorptionHit
|
|
|
|
|
? ClampDouble((volRatio / MathMax(rangeRatio, 0.000001)) / MathMax(ExtVolumeClimaxMultiplier, 0.000001), 0.0, 2.0)
|
|
|
|
|
: 0.0;
|
|
|
|
|
|
|
|
|
|
bool initiativeHit = volRatio >= ExtVolumeClimaxMultiplier
|
|
|
|
|
&& rangeRatio >= ExtRangeClimaxMultiplier
|
|
|
|
|
&& atrRatio >= 1.0
|
|
|
|
|
&& (closePos >= 0.70 || closePos <= 0.30);
|
|
|
|
|
double initiativeScore = initiativeHit
|
|
|
|
|
? ClampDouble((volRatio * rangeRatio) / MathMax(ExtVolumeHighMultiplier, 0.000001), 0.0, 2.0) * (closePos >= 0.5 ? 1.0 : -1.0)
|
|
|
|
|
: 0.0;
|
|
|
|
|
|
|
|
|
|
if(volRatio <= ExtSTVolumeRatio && rangeRatio <= ExtRangeSignificantMult && midpointDistance <= 0.5)
|
|
|
|
|
absorptionScore += 0.10 * (1.0 - midpointDistance);
|
|
|
|
|
|
|
|
|
|
absorptionSum += absorptionScore;
|
|
|
|
|
initiativeSum += initiativeScore;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-16 19:55:51 -04:00
|
|
|
double normalizedCumulativeDelta = ClampDouble((cumulativeDelta / MathMax(sumVolume, 0.000001)) * 2.0, -2.0, 2.0);
|
|
|
|
|
double pressure = ClampDouble(normalizedCumulativeDelta
|
2026-07-13 15:59:35 -04:00
|
|
|
+ (initiativeSum / count) * 0.25
|
|
|
|
|
- (absorptionSum / count) * 0.15,
|
|
|
|
|
-2.0, 2.0);
|
|
|
|
|
double bullishPressure = ClampDouble((bullishDelta / MathMax(sumVolume, 0.000001)) * 2.0, 0.0, 2.0);
|
|
|
|
|
double bearishPressure = ClampDouble((bearishDelta / MathMax(sumVolume, 0.000001)) * 2.0, 0.0, 2.0);
|
|
|
|
|
double absorption = ClampDouble(absorptionSum / count, 0.0, 2.0);
|
|
|
|
|
double initiative = ClampDouble(initiativeSum / count, -2.0, 2.0);
|
|
|
|
|
|
|
|
|
|
// Normalize: guard against NaN/Inf from edge-case inputs
|
|
|
|
|
if(!MathIsValidNumber(pressure)) pressure = 0.0;
|
2026-07-16 19:55:51 -04:00
|
|
|
if(!MathIsValidNumber(normalizedCumulativeDelta)) normalizedCumulativeDelta = 0.0;
|
2026-07-13 15:59:35 -04:00
|
|
|
if(!MathIsValidNumber(bullishPressure)) bullishPressure = 0.0;
|
|
|
|
|
if(!MathIsValidNumber(bearishPressure)) bearishPressure = 0.0;
|
|
|
|
|
if(!MathIsValidNumber(absorption)) absorption = 0.0;
|
|
|
|
|
if(!MathIsValidNumber(initiative)) initiative = 0.0;
|
|
|
|
|
|
2026-07-16 19:55:51 -04:00
|
|
|
SetOutputs(si, pressure, normalizedCumulativeDelta, bullishPressure, bearishPressure, absorption, initiative);
|
2026-07-13 15:59:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return(rates_total);
|
|
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|