2026-07-13 15:59:35 -04:00
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
//| ADWyckoffFailedStructure.mq5|
|
|
|
|
|
//| Wyckoff Failed Structure / Break family |
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
|
|
|
#property copyright "AD Institutional Indicators"
|
|
|
|
|
#property link ""
|
|
|
|
|
#property version "1.00"
|
|
|
|
|
#property description "Wyckoff Failed Structure — bullish/bearish structural failure"
|
|
|
|
|
#property indicator_separate_window
|
|
|
|
|
#property indicator_buffers 5
|
|
|
|
|
#property indicator_plots 5
|
|
|
|
|
|
|
|
|
|
#property indicator_minimum -2.5
|
|
|
|
|
#property indicator_maximum 2.5
|
|
|
|
|
#property indicator_level1 0
|
|
|
|
|
|
|
|
|
|
#property indicator_label1 "Value"
|
|
|
|
|
#property indicator_type1 DRAW_LINE
|
|
|
|
|
#property indicator_color1 clrWhite
|
|
|
|
|
#property indicator_width1 1
|
|
|
|
|
|
|
|
|
|
#property indicator_label2 "BullishStructuralFailure"
|
|
|
|
|
#property indicator_type2 DRAW_LINE
|
|
|
|
|
#property indicator_color2 clrLime
|
|
|
|
|
#property indicator_width2 1
|
|
|
|
|
|
|
|
|
|
#property indicator_label3 "BearishStructuralFailure"
|
|
|
|
|
#property indicator_type3 DRAW_LINE
|
|
|
|
|
#property indicator_color3 clrRed
|
|
|
|
|
#property indicator_width3 1
|
|
|
|
|
|
|
|
|
|
#property indicator_label4 "FailedAccumulation"
|
|
|
|
|
#property indicator_type4 DRAW_LINE
|
|
|
|
|
#property indicator_color4 clrAqua
|
|
|
|
|
#property indicator_width4 1
|
|
|
|
|
|
|
|
|
|
#property indicator_label5 "FailedDistribution"
|
|
|
|
|
#property indicator_type5 DRAW_LINE
|
|
|
|
|
#property indicator_color5 clrOrange
|
|
|
|
|
#property indicator_width5 1
|
|
|
|
|
|
|
|
|
|
input int InpLookbackPeriod = 50;
|
|
|
|
|
input int InpZigZagStrength = 3;
|
|
|
|
|
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 ExtValueBuffer[];
|
|
|
|
|
double ExtBullishFailureBuffer[];
|
|
|
|
|
double ExtBearishFailureBuffer[];
|
|
|
|
|
double ExtFailedAccumulationBuffer[];
|
|
|
|
|
double ExtFailedDistributionBuffer[];
|
|
|
|
|
|
|
|
|
|
double H[];
|
|
|
|
|
double L[];
|
|
|
|
|
double C[];
|
|
|
|
|
double V[];
|
|
|
|
|
datetime T[];
|
|
|
|
|
|
|
|
|
|
int ExtLookbackPeriod;
|
|
|
|
|
int ExtZigZagStrength;
|
|
|
|
|
double ExtVolumeClimaxMultiplier;
|
|
|
|
|
double ExtVolumeHighMultiplier;
|
|
|
|
|
double ExtRangeClimaxMultiplier;
|
|
|
|
|
double ExtRangeSignificantMult;
|
|
|
|
|
double ExtSTVolumeRatio;
|
|
|
|
|
double ExtATRMultiplier;
|
|
|
|
|
int ExtContextMode;
|
|
|
|
|
int ExtSessionType;
|
|
|
|
|
int ExtSessionCount;
|
|
|
|
|
|
|
|
|
|
double lastBullHigh = 0.0;
|
|
|
|
|
double lastBullLow = 0.0;
|
|
|
|
|
double lastBearHigh = 0.0;
|
|
|
|
|
double lastBearLow = 0.0;
|
|
|
|
|
|
|
|
|
|
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 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);
|
|
|
|
|
if(baseType == 1) return currentStart + (datetime)(shift * 86400);
|
|
|
|
|
if(baseType == 2) return currentStart + (datetime)(shift * 7 * 86400);
|
|
|
|
|
if(baseType == 3) return AddMonthsSafeMT5(currentStart, shift);
|
|
|
|
|
return AddMonthsSafeMT5(currentStart, shift * 12);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ResetState()
|
|
|
|
|
{
|
|
|
|
|
lastBullHigh = 0.0;
|
|
|
|
|
lastBullLow = 0.0;
|
|
|
|
|
lastBearHigh = 0.0;
|
|
|
|
|
lastBearLow = 0.0;
|
|
|
|
|
ArrayInitialize(ExtValueBuffer, 0);
|
|
|
|
|
ArrayInitialize(ExtBullishFailureBuffer, 0);
|
|
|
|
|
ArrayInitialize(ExtBearishFailureBuffer, 0);
|
|
|
|
|
ArrayInitialize(ExtFailedAccumulationBuffer, 0);
|
|
|
|
|
ArrayInitialize(ExtFailedDistributionBuffer, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SetOutputs(const int outIndex, const double value, const double bull, const double bear, const double failedAccum, const double failedDist)
|
|
|
|
|
{
|
|
|
|
|
ExtValueBuffer[outIndex] = value;
|
|
|
|
|
ExtBullishFailureBuffer[outIndex] = bull;
|
|
|
|
|
ExtBearishFailureBuffer[outIndex] = bear;
|
|
|
|
|
ExtFailedAccumulationBuffer[outIndex] = failedAccum;
|
|
|
|
|
ExtFailedDistributionBuffer[outIndex] = failedDist;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ResolveMaxShift(const int currentBar, const int rates_total, const datetime &time[])
|
|
|
|
|
{
|
|
|
|
|
int lookback = MathMax(5, MathMin(200, ExtLookbackPeriod));
|
|
|
|
|
int available = currentBar;
|
|
|
|
|
if(ExtContextMode != 1)
|
|
|
|
|
return MathMin(available, lookback - 1);
|
|
|
|
|
|
|
|
|
|
if(IsZigZagSessionTypeMT5(ExtSessionType))
|
|
|
|
|
return MathMin(available, (lookback * ExtSessionCount) - 1);
|
|
|
|
|
|
|
|
|
|
datetime start = ResolveCalendarContextStartMT5(time[currentBar]);
|
|
|
|
|
int lower = 0;
|
|
|
|
|
for(int j = 0; j <= currentBar; j++)
|
|
|
|
|
{
|
|
|
|
|
if(time[j] >= start)
|
|
|
|
|
{
|
|
|
|
|
lower = j;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return MathMax(0, currentBar - lower);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 OnInit()
|
|
|
|
|
{
|
|
|
|
|
ExtLookbackPeriod = ClampInt(InpLookbackPeriod, 5, 200);
|
|
|
|
|
ExtZigZagStrength = ClampInt(InpZigZagStrength, 1, 10);
|
|
|
|
|
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, ExtValueBuffer, INDICATOR_DATA);
|
|
|
|
|
SetIndexBuffer(1, ExtBullishFailureBuffer, INDICATOR_DATA);
|
|
|
|
|
SetIndexBuffer(2, ExtBearishFailureBuffer, INDICATOR_DATA);
|
|
|
|
|
SetIndexBuffer(3, ExtFailedAccumulationBuffer, INDICATOR_DATA);
|
|
|
|
|
SetIndexBuffer(4, ExtFailedDistributionBuffer, INDICATOR_DATA);
|
|
|
|
|
|
|
|
|
|
ArraySetAsSeries(ExtValueBuffer, true);
|
|
|
|
|
ArraySetAsSeries(ExtBullishFailureBuffer, true);
|
|
|
|
|
ArraySetAsSeries(ExtBearishFailureBuffer, true);
|
|
|
|
|
ArraySetAsSeries(ExtFailedAccumulationBuffer, true);
|
|
|
|
|
ArraySetAsSeries(ExtFailedDistributionBuffer, true);
|
|
|
|
|
|
|
|
|
|
IndicatorSetInteger(INDICATOR_DIGITS, 3);
|
|
|
|
|
IndicatorSetString(INDICATOR_SHORTNAME,
|
|
|
|
|
"WFS(" + IntegerToString(ExtLookbackPeriod) + "," + IntegerToString(ExtZigZagStrength) + "," +
|
|
|
|
|
DoubleToString(ExtRangeSignificantMult, 2) + "," + DoubleToString(ExtVolumeHighMultiplier, 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);
|
|
|
|
|
ResetState();
|
|
|
|
|
return(INIT_SUCCEEDED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnDeinit(const int reason) {}
|
|
|
|
|
|
|
|
|
|
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);
|
2026-07-17 23:21:12 -04:00
|
|
|
// open was missing here: it's read directly (not through the chronological H/L/C/V/T cache
|
|
|
|
|
// below) at `open[si]` using the series-space index `si`, while open itself stayed in its
|
|
|
|
|
// default chronological orientation - a genuine future-data leak (worst at the oldest processed
|
|
|
|
|
// bar, which read the NEWEST bar's open) into bullSig/bearSig and, from there, every output
|
|
|
|
|
// buffer (Value/BullishStructuralFailure/BearishStructuralFailure/FailedAccumulation/
|
|
|
|
|
// FailedDistribution). Flipping it here makes it consistent with every other array below.
|
|
|
|
|
ArraySetAsSeries(open, true);
|
2026-07-13 15:59:35 -04:00
|
|
|
ArraySetAsSeries(high, true);
|
|
|
|
|
ArraySetAsSeries(low, true);
|
|
|
|
|
ArraySetAsSeries(close, true);
|
|
|
|
|
ArraySetAsSeries(tick_volume, true);
|
|
|
|
|
ArraySetAsSeries(volume, true);
|
|
|
|
|
|
|
|
|
|
ArrayResize(H, rates_total);
|
|
|
|
|
ArrayResize(L, 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];
|
|
|
|
|
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 maxShift = ResolveMaxShift(chrono, rates_total, T);
|
|
|
|
|
|
|
|
|
|
double sumRange = 0.0;
|
|
|
|
|
double sumVolume = 0.0;
|
|
|
|
|
int n = 0;
|
|
|
|
|
int from = MathMax(0, chrono - maxShift);
|
|
|
|
|
for(int k = from; k <= chrono; k++)
|
|
|
|
|
{
|
|
|
|
|
sumRange += MathMax(H[k] - L[k], 0.000001);
|
|
|
|
|
sumVolume += MathMax(V[k], 1.0);
|
|
|
|
|
n++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(n <= 0)
|
|
|
|
|
{
|
|
|
|
|
SetOutputs(si, 0.0, 0.0, 0.0, 0.0, 0.0);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double avgRange = sumRange / n;
|
|
|
|
|
double avgVolume = sumVolume / n;
|
|
|
|
|
if(!MathIsValidNumber(avgRange) || !MathIsValidNumber(avgVolume) || avgRange <= 0 || avgVolume <= 0)
|
|
|
|
|
{
|
|
|
|
|
SetOutputs(si, 0.0, 0.0, 0.0, 0.0, 0.0);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double hi = H[chrono];
|
|
|
|
|
double lo = L[chrono];
|
|
|
|
|
double op = open[si];
|
|
|
|
|
double cl = C[chrono];
|
|
|
|
|
double vol = MathMax(V[chrono], 1.0);
|
|
|
|
|
double prevClose = (chrono > 0) ? C[chrono - 1] : cl;
|
|
|
|
|
double barRange = MathMax(hi - lo, 0.000001);
|
|
|
|
|
|
|
|
|
|
double closePos = (cl - lo) / barRange;
|
|
|
|
|
closePos = ClampDouble(closePos, 0.0, 1.0);
|
|
|
|
|
|
|
|
|
|
double rangeRatio = barRange / avgRange;
|
|
|
|
|
double volRatio = vol / avgVolume;
|
|
|
|
|
double rangeGate = ClampDouble(ExtRangeSignificantMult, 0.5, 3.0);
|
|
|
|
|
double volGate = ClampDouble(ExtVolumeHighMultiplier, 0.5, 3.0);
|
|
|
|
|
double climaxRangeGate = ClampDouble(ExtRangeClimaxMultiplier, 0.5, 5.0);
|
|
|
|
|
double climaxVolGate = ClampDouble(ExtVolumeClimaxMultiplier, 0.5, 5.0);
|
|
|
|
|
double atrNow = ComputeATRChrono(chrono, 14);
|
|
|
|
|
double atrRatio = barRange / MathMax(atrNow * ExtATRMultiplier, 0.000001);
|
|
|
|
|
double breakBuffer = MathMax(atrNow * 0.05, barRange * 0.02) * MathMax(1.0, (double)ExtZigZagStrength);
|
|
|
|
|
double stGate = ExtSTVolumeRatio;
|
|
|
|
|
|
|
|
|
|
bool bullSig = rangeRatio >= rangeGate && volRatio >= volGate && closePos >= 0.70 && cl > op && atrRatio >= 1.0 && volRatio >= stGate;
|
|
|
|
|
bool bearSig = rangeRatio >= rangeGate && volRatio >= volGate && closePos <= 0.30 && cl < op && atrRatio >= 1.0 && volRatio >= stGate;
|
|
|
|
|
bool climaxBull = rangeRatio >= climaxRangeGate && volRatio >= climaxVolGate && closePos >= 0.80 && cl > op;
|
|
|
|
|
bool climaxBear = rangeRatio >= climaxRangeGate && volRatio >= climaxVolGate && closePos <= 0.20 && cl < op;
|
|
|
|
|
|
|
|
|
|
double qualityBase = MathMax(rangeRatio / MathMax(rangeGate, 0.000001), volRatio / MathMax(volGate, 0.000001));
|
|
|
|
|
double quality = ClampDouble(qualityBase + ((climaxBull || climaxBear) ? 0.5 : 0.0), 0.0, 2.5);
|
|
|
|
|
|
|
|
|
|
double resistance = (lastBearHigh > 0.0) ? lastBearHigh : 0.0;
|
|
|
|
|
double support = (lastBullLow > 0.0) ? lastBullLow : 0.0;
|
|
|
|
|
bool bullishContext = cl > op || closePos >= 0.55;
|
|
|
|
|
bool bearishContext = cl < op || closePos <= 0.45;
|
|
|
|
|
|
|
|
|
|
bool bullishFailure = false;
|
|
|
|
|
bool bearishFailure = false;
|
|
|
|
|
|
|
|
|
|
if(bearishContext && bullSig && resistance > 0.0)
|
|
|
|
|
bullishFailure = (prevClose <= resistance + breakBuffer && cl > resistance + breakBuffer);
|
|
|
|
|
|
|
|
|
|
if(bullishContext && bearSig && support > 0.0)
|
|
|
|
|
bearishFailure = (prevClose >= support - breakBuffer && cl < support - breakBuffer);
|
|
|
|
|
|
|
|
|
|
double signedValue = 0.0;
|
|
|
|
|
if(bullishFailure)
|
|
|
|
|
signedValue = quality;
|
|
|
|
|
else if(bearishFailure)
|
|
|
|
|
signedValue = -quality;
|
|
|
|
|
|
|
|
|
|
if(bullSig)
|
|
|
|
|
{
|
|
|
|
|
lastBullHigh = hi;
|
|
|
|
|
lastBullLow = lo;
|
|
|
|
|
}
|
|
|
|
|
if(bearSig)
|
|
|
|
|
{
|
|
|
|
|
lastBearHigh = hi;
|
|
|
|
|
lastBearLow = lo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Normalize: guard against NaN/Inf from edge-case inputs
|
|
|
|
|
if(!MathIsValidNumber(signedValue)) signedValue = 0.0;
|
|
|
|
|
|
|
|
|
|
SetOutputs(si, signedValue, bullishFailure ? 1.0 : 0.0, bearishFailure ? 1.0 : 0.0, bearishFailure ? 1.0 : 0.0, bullishFailure ? 1.0 : 0.0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return(rates_total);
|
|
|
|
|
}
|
|
|
|
|
//+------------------------------------------------------------------+
|