ICT 2026 Bias + intraday Trend, FVG, PD zone

This commit is contained in:
Bell
2026-05-24 19:46:14 +07:00
parent 4755c3dc9b
commit e173949468
16 changed files with 3444 additions and 0 deletions
+331
View File
@@ -0,0 +1,331 @@
//+------------------------------------------------------------------+
//| Swing.mqh — pivot & swing set H0L1 (tham khảo HyperICT) |
//+------------------------------------------------------------------+
#ifndef ICT2026_SWING_MQH
#define ICT2026_SWING_MQH
#include <ICT2026/Types.mqh>
bool IctIsSwingHigh(const string sym, const ENUM_TIMEFRAMES tf,
const int shift, const int range)
{
const int str = MathMax(1, range);
const double h = iHigh(sym, tf, shift);
for(int k = 1; k <= str; k++)
{
if(shift + k >= Bars(sym, tf) || shift - k < 0)
return false;
if(h <= iHigh(sym, tf, shift + k) || h <= iHigh(sym, tf, shift - k))
return false;
}
return true;
}
bool IctIsSwingLow(const string sym, const ENUM_TIMEFRAMES tf,
const int shift, const int range)
{
const int str = MathMax(1, range);
const double l = iLow(sym, tf, shift);
for(int k = 1; k <= str; k++)
{
if(shift + k >= Bars(sym, tf) || shift - k < 0)
return false;
if(l >= iLow(sym, tf, shift + k) || l >= iLow(sym, tf, shift - k))
return false;
}
return true;
}
void IctSortSwingsByTime(IctSwingPoint &pts[], const int count)
{
for(int i = 0; i < count - 1; i++)
for(int j = i + 1; j < count; j++)
if(pts[j].time < pts[i].time)
{
const IctSwingPoint t = pts[i];
pts[i] = pts[j];
pts[j] = t;
}
}
void IctCollectSwings(const string sym, const ENUM_TIMEFRAMES tf,
const int range, const int lookback,
IctSwingPoint &highs[], IctSwingPoint &lows[])
{
ArrayResize(highs, 0);
ArrayResize(lows, 0);
const int str = MathMax(1, range);
const int bars = Bars(sym, tf);
const int last = MathMin(lookback, bars - str - 1);
if(last < str + 5)
return;
int nH = 0, nL = 0;
for(int sh = last; sh >= 1; sh--)
{
if(IctIsSwingHigh(sym, tf, sh, range))
{
ArrayResize(highs, nH + 1);
highs[nH].price = iHigh(sym, tf, sh);
highs[nH].time = iTime(sym, tf, sh);
highs[nH].shift = sh;
nH++;
}
if(IctIsSwingLow(sym, tf, sh, range))
{
ArrayResize(lows, nL + 1);
lows[nL].price = iLow(sym, tf, sh);
lows[nL].time = iTime(sym, tf, sh);
lows[nL].shift = sh;
nL++;
}
}
IctSortSwingsByTime(highs, nH);
IctSortSwingsByTime(lows, nL);
}
IctSwingPoint IctFindMostRecentOlder(IctSwingPoint &pts[], const int count,
const int anchorShift)
{
IctSwingPoint empty;
empty.Clear();
int best = -1;
for(int i = 0; i < count; i++)
{
if(pts[i].shift <= anchorShift)
continue;
if(best < 0 || pts[i].shift < pts[best].shift)
best = i;
}
if(best < 0)
return empty;
return pts[best];
}
IctSwingSet IctPickStructuralBear(IctSwingPoint &highs[], const int nH,
IctSwingPoint &lows[], const int nL)
{
IctSwingSet out;
out.Clear();
if(nH < 2 || nL < 2)
return out;
out.l0 = lows[nL - 1];
out.hasL0 = true;
out.l1 = IctFindMostRecentOlder(lows, nL, out.l0.shift);
if(!out.l1.Valid())
return out;
out.hasL1 = true;
out.h0 = IctFindMostRecentOlder(highs, nH, out.l1.shift);
if(!out.h0.Valid())
return out;
out.hasH0 = true;
out.h1 = IctFindMostRecentOlder(highs, nH, out.h0.shift);
if(!out.h1.Valid())
return out;
out.hasH1 = true;
return out;
}
IctSwingSet IctPickStructuralBull(IctSwingPoint &highs[], const int nH,
IctSwingPoint &lows[], const int nL)
{
IctSwingSet out;
out.Clear();
if(nH < 2 || nL < 2)
return out;
out.h0 = highs[nH - 1];
out.hasH0 = true;
out.l0 = IctFindMostRecentOlder(lows, nL, out.h0.shift);
if(!out.l0.Valid())
return out;
out.hasL0 = true;
out.h1 = IctFindMostRecentOlder(highs, nH, out.l0.shift);
if(!out.h1.Valid())
return out;
out.hasH1 = true;
out.l1 = IctFindMostRecentOlder(lows, nL, out.h1.shift);
if(!out.l1.Valid())
return out;
out.hasL1 = true;
return out;
}
ENUM_ICT_STRUCT IctClassifyStructure(IctSwingSet &sw)
{
if(!sw.IsComplete())
return ICT_STRUCT_NONE;
if(sw.h0.price > sw.h1.price && sw.l0.price > sw.l1.price)
return ICT_STRUCT_BULL;
if(sw.h0.price < sw.h1.price && sw.l0.price < sw.l1.price)
return ICT_STRUCT_BEAR;
return ICT_STRUCT_NONE;
}
bool IctIsPullbackValid(IctSwingSet &sw, const double ratio)
{
if(!sw.IsComplete() || ratio <= 0.0)
return true;
const double impulse = MathAbs(sw.h1.price - sw.l1.price);
const double pullback = MathAbs(sw.h1.price - sw.l0.price);
if(impulse <= 0.0)
return false;
return pullback >= impulse * ratio;
}
IctSwingSet IctBuildSwingSet(const string sym, const ENUM_TIMEFRAMES tf,
const int range, const int lookback,
ENUM_ICT_STRUCT &biasOut)
{
IctSwingSet out;
out.Clear();
biasOut = ICT_STRUCT_NONE;
IctSwingPoint highs[], lows[];
IctCollectSwings(sym, tf, range, lookback, highs, lows);
const int nH = ArraySize(highs);
const int nL = ArraySize(lows);
IctSwingSet bear = IctPickStructuralBear(highs, nH, lows, nL);
IctSwingSet bull = IctPickStructuralBull(highs, nH, lows, nL);
const bool hasBear = bear.IsComplete();
const bool hasBull = bull.IsComplete();
const ENUM_ICT_STRUCT biasBear = hasBear ? IctClassifyStructure(bear) : ICT_STRUCT_NONE;
const ENUM_ICT_STRUCT biasBull = hasBull ? IctClassifyStructure(bull) : ICT_STRUCT_NONE;
if(biasBear == ICT_STRUCT_BEAR)
{
out = bear;
biasOut = ICT_STRUCT_BEAR;
}
else if(biasBull == ICT_STRUCT_BULL)
{
out = bull;
biasOut = ICT_STRUCT_BULL;
}
else if(hasBear)
{
out = bear;
biasOut = IctClassifyStructure(bear);
}
else if(hasBull)
{
out = bull;
biasOut = IctClassifyStructure(bull);
}
return out;
}
// Intraday: 2 đỉnh + 2 đáy gần nhất (mới hơn = phần tử cuối sau sort time)
bool IctTakeLastTwoSwings(IctSwingPoint &pts[], const int count,
IctSwingPoint &older, IctSwingPoint &newer)
{
older.Clear();
newer.Clear();
if(count < 2)
return false;
older = pts[count - 2];
newer = pts[count - 1];
return older.Valid() && newer.Valid();
}
int IctFilterSwingsByMaxShift(IctSwingPoint &pts[], const int count, const int maxShift)
{
if(maxShift <= 0 || count < 1)
return count;
int w = 0;
for(int i = 0; i < count; i++)
{
if(pts[i].shift > maxShift)
continue;
if(w != i)
pts[w] = pts[i];
w++;
}
if(w < count)
ArrayResize(pts, w);
return w;
}
// Phân loại HH-HL / LH-LL từ pivot gần nhất — tránh ghép leg 4 swing cũ (sai trên H1)
bool IctBuildSwingSetRecentPivots(const string sym, const ENUM_TIMEFRAMES tf,
const int range, const int lookback,
const int maxRecentShift,
IctSwingSet &out, ENUM_ICT_STRUCT &biasOut)
{
out.Clear();
biasOut = ICT_STRUCT_NONE;
IctSwingPoint highs[], lows[];
IctCollectSwings(sym, tf, range, lookback, highs, lows);
int nH = ArraySize(highs);
int nL = ArraySize(lows);
if(maxRecentShift > 0)
{
nH = IctFilterSwingsByMaxShift(highs, nH, maxRecentShift);
nL = IctFilterSwingsByMaxShift(lows, nL, maxRecentShift);
}
IctSwingPoint hOld, hNew, lOld, lNew;
if(!IctTakeLastTwoSwings(highs, nH, hOld, hNew))
return false;
if(!IctTakeLastTwoSwings(lows, nL, lOld, lNew))
return false;
out.h0 = hNew;
out.hasH0 = true;
out.h1 = hOld;
out.hasH1 = true;
out.l0 = lNew;
out.hasL0 = true;
out.l1 = lOld;
out.hasL1 = true;
const bool hh = hNew.price > hOld.price + _Point;
const bool hl = lNew.price > lOld.price + _Point;
const bool lh = hNew.price < hOld.price - _Point;
const bool ll = lNew.price < lOld.price - _Point;
if(hh && hl)
biasOut = ICT_STRUCT_BULL;
else if(lh && ll)
biasOut = ICT_STRUCT_BEAR;
else
biasOut = ICT_STRUCT_NONE;
return out.IsComplete();
}
void IctGetKeyLevels(const ENUM_ICT_STRUCT bias, IctSwingSet &sw,
double &keyLv1, double &keyLv2)
{
keyLv1 = 0.0;
keyLv2 = 0.0;
if(!sw.IsComplete())
return;
if(bias == ICT_STRUCT_BULL)
{
keyLv1 = sw.l0.price;
keyLv2 = sw.h0.price;
}
else if(bias == ICT_STRUCT_BEAR)
{
keyLv1 = sw.h0.price;
keyLv2 = sw.l0.price;
}
}
#endif