Chọn FVG gần nhất chưa used làm POI

This commit is contained in:
Bell
2026-05-25 01:59:57 +07:00
parent cddec2320e
commit 68c1f864e4
9 changed files with 551 additions and 294 deletions
+10 -2
View File
@@ -3,7 +3,7 @@
//| BOS = Continue | CHoCH = Reversal |
//+------------------------------------------------------------------+
#property copyright "ICT 2026"
#property version "1.130"
#property version "1.138"
#property description "ICT2026 MSS limit entry + SL swing CHoCH + TP intraday"
#include <ICT2026/Config.mqh>
@@ -29,7 +29,9 @@ int OnInit()
if(biasOk || intraOk)
{
PrintFormat("[ICT2026] Init — Bias=%s | Intraday=%s | Allow=%s | FVG=%d",
IctEaState_Refresh(_Symbol);
PrintFormat("[ICT2026] Init — EA=%s | Bias=%s | H1=%s | Allow=%s | FVG=%d",
IctEaState_Code(IctEaState_Current()),
IctBiasDisplayShort(g_ictDailyBias.bias),
IctTrendDisplayShort(g_ictIntraday.trend),
g_ictIntraday.isAllowTrade ? "true" : "false",
@@ -98,4 +100,10 @@ ENUM_ICT_MSS_PHASE ICT2026_GetMssPhase() { return g_ictLowTf.mss.phase; }
string ICT2026_GetMssReason() { return g_ictLowTf.mss.displayReason; }
ENUM_ICT_EA_STATE ICT2026_GetEaState() { return IctEaState_Current(); }
string ICT2026_GetEaStateCode() { return IctEaState_Code(IctEaState_Current()); }
string ICT2026_GetEaStateDetail() { return g_ictEaState.detail; }
//+------------------------------------------------------------------+
+4 -4
View File
@@ -48,7 +48,7 @@ input int InpFvgAtrPeriod = 14; // ATR cho lọc k
input double InpFvgMinGapATRPct = 12.0; // H1 only: gap tối thiểu (% ATR, 0=tắt)
input double InpFvgMinGapPoints = 0.0; // H1 only: gap tối thiểu (giá)
input double InpFvgMinGapVsBarPct = 25.0; // H1 only: gap >= % range nến B (0=tắt)
input double InpFvgUsedFillPct = 38.2; // % lấp FVG → Used
input double InpFvgUsedFillPct = 25.0; // % lấp FVG → Used
input int InpFvgExpireDays = 3; // Xóa Available sau N ngày
input int InpFvgMaxZones = 24; // Số FVG tối đa trên chart
input bool InpDrawFvgZones = true; // Vẽ FVG + Premium/Discount
@@ -59,9 +59,9 @@ input color InpPdPremiumColor = clrMaroon;
input color InpPdDiscountColor = clrDarkGreen;
input group "══ MSS / Entry (Confirm TF) ══"
input bool InpMssH1RetestWickOnly = true; // Retest FVG H1: chỉ cần râu chạm (không bắt thân nến lấp %)
input double InpMssH1MinFillPct = 38.2; // Nếu tắt wick-only: % lấp tối thiểu trên H1
input double InpMssEntryFillPct = 38.2; // M5 FVG: % lấp để sẵn sàng entry
input bool InpMssH1RetestWickOnly = true; // (legacy, bỏ qua) Retest = giá chạm FVG
input double InpMssH1MinFillPct = 25.0; // Vẽ mức % tham khảo trên chart (không chặn retest)
input double InpMssEntryFillPct = 25.0; // M5 FVG: % lấp để sẵn sàng entry
input int InpMssConfirmLookback = 80; // Lookback pivot CHoCH trên Confirm TF
input int InpMssConfirmFvgBars = 40; // Quét M5 FVG sau CHoCH
input double InpMssMaxDistGapPct = 75.0; // MSS: buffer quanh H1 FVG (% chiều cao gap)
+6 -3
View File
@@ -702,9 +702,12 @@ void IctFvg_UpdateZoneState(const string sym, const ENUM_TIMEFRAMES tf, IctFvgZo
IctFvg_UpdateTouchAndFill(sym, tf, zone);
const double usedPct = InpFvgUsedFillPct / 100.0;
if(zone.maxFillRatio >= usedPct || zone.maxFillRatio >= 0.999)
zone.state = ICT_FVG_USED;
if(tf != InpFvgTf)
{
const double usedPct = InpFvgUsedFillPct / 100.0;
if(zone.maxFillRatio >= usedPct || zone.maxFillRatio >= 0.999)
zone.state = ICT_FVG_USED;
}
if(zone.state == ICT_FVG_USED && prevState == ICT_FVG_AVAILABLE && zone.fvgUsedTime == 0)
zone.fvgUsedTime = iTime(sym, tf, 0);
+7 -4
View File
@@ -11,6 +11,7 @@
#include <ICT2026/MssEntry.mqh>
#include <ICT2026/FvgDraw.mqh>
#include <ICT2026/MssDraw.mqh>
#include <ICT2026/EaState.mqh>
void IctLowTfTrend_Reset()
{
@@ -57,9 +58,9 @@ bool IctLowTfTrend_Update(const string sym, const bool force = false)
{
const ENUM_ICT_FVG_SIDE side = IctFvgSideFromBias(g_ictDailyBias.bias);
IctFvg_ScanNew(sym, tf, side, force || allowJustOn);
g_ictLowTf.displayReason = StringFormat("Scan iTF FVG %s | %d avail / %d total",
IctFvgSideText(side),
IctFvg_CountAvailable(), g_ictFvgCount);
g_ictLowTf.displayReason = StringFormat("H1 POI %d avail / %d FVG | scan %s",
IctMss_CountH1PoiEligible(), g_ictFvgCount,
IctFvgSideText(side));
}
else
{
@@ -77,6 +78,7 @@ bool IctLowTfTrend_Update(const string sym, const bool force = false)
IctConfirmFvg_UpdateAll(sym, InpConfirmTf);
IctMss_Update(sym);
IctMssEntry_Update(sym);
IctEaState_Refresh(sym);
g_ictLowTf.confirmFvgCount = g_ictConfirmFvgCount;
}
@@ -127,6 +129,7 @@ void IctLowTfTrend_TickRefresh(const string sym)
const ENUM_ICT_MSS_PHASE prevMss = g_ictLowTf.mss.phase;
IctMss_Update(sym);
IctMssEntry_Update(sym);
IctEaState_Refresh(sym);
if(prevMss != g_ictLowTf.mss.phase)
dirty = true;
}
@@ -139,7 +142,7 @@ void IctLowTfTrend_TickRefresh(const string sym)
if(dirty)
IctFvgDraw_Render(sym);
if(g_ictLowTf.mss.phase >= ICT_MSS_CHOCH)
if(g_ictLowTf.mss.phase >= ICT_MSS_H1_TOUCH)
IctMssDraw_Render(sym);
else if(!InpDrawMssChoch)
IctMssDraw_DeleteAll();
+21 -6
View File
@@ -143,22 +143,32 @@ void IctMssDraw_Render(const string sym)
datetime keyT = 0, chochT = 0;
IctMssDraw_ResolveChoch(mss, keyLv, keyT, slSwing, chochT);
const bool mssPending = (mss.phase == ICT_MSS_H1_TOUCH && !mss.chochLocked);
if(mssPending && mss.liveL0Price > 0.0)
{
keyLv = isBear ? mss.liveL0Price : mss.liveH0Price;
keyT = isBear ? mss.liveL0Time : mss.liveH0Time;
slSwing = isBear ? mss.liveH0Price : mss.liveL0Price;
chochT = 0;
}
if(keyLv > 0.0)
{
if(keyT <= 0)
keyT = tTouch;
if(chochT <= 0)
chochT = keyT;
chochT = mss.chochTime > 0 ? mss.chochTime : keyT;
const color clrChoch = clrGold;
const string chochLbl = isBear ? " MSS↓ L0 " : " MSS↑ H0 ";
const string chochLbl = mssPending ?
(isBear ? " L0 live " : " H0 live ") :
(isBear ? " MSS↓ L0 " : " MSS↑ H0 ");
const bool chochAbove = !isBear;
const datetime tLineStart = (keyT > 0) ? keyT : tTouch;
const datetime tChoch = (chochT > 0) ? chochT : tLineStart;
const bool chochPending = (mss.phase == ICT_MSS_H1_TOUCH && !mss.chochLocked);
IctMssDraw_HLine("CHOCH", tLineStart, tEnd, keyLv, clrChoch,
chochPending ? STYLE_DASH : STYLE_SOLID, 2);
mssPending ? STYLE_DOT : STYLE_SOLID, 2);
IctMssDraw_Label("CHOCH_LBL", chochLbl, tChoch, keyLv, chochAbove, clrChoch);
}
@@ -166,9 +176,14 @@ void IctMssDraw_Render(const string sym)
{
const string swTag = isBear ? " H0 " : " L0 ";
const color clrSw = clrYellow;
datetime tSw = (keyT > 0) ? keyT : tTouch;
datetime tSw = isBear ?
(mss.liveH0Time > 0 ? mss.liveH0Time : keyT) :
(mss.liveL0Time > 0 ? mss.liveL0Time : keyT);
if(tSw <= 0)
tSw = tTouch;
IctMssDraw_HLine("MSS_SW", tSw, tEnd, slSwing, clrSw, STYLE_DASH, 1);
IctMssDraw_HLine("MSS_SW", tSw, tEnd, slSwing, clrSw,
mssPending ? STYLE_DOT : STYLE_DASH, 1);
IctMssDraw_Label("MSS_SW_LBL", swTag, tSw, slSwing, true, clrSw);
}
+372 -260
View File
@@ -7,6 +7,8 @@
#include <ICT2026/ConfirmFvg.mqh>
#include <ICT2026/Journal.mqh>
#include <ICT2026/LowTfApi.mqh>
#include <ICT2026/StructureCore.mqh>
#include <ICT2026/Swing.mqh>
string IctMssPhaseText(const ENUM_ICT_MSS_PHASE ph)
{
@@ -15,7 +17,7 @@ string IctMssPhaseText(const ENUM_ICT_MSS_PHASE ph)
case ICT_MSS_H1_TOUCH: return "Retest FVG H1 OK";
case ICT_MSS_CHOCH: return "MSS OK";
case ICT_MSS_M5_FVG: return "M5 FVG";
case ICT_MSS_ENTRY_FILL: return "M5 fill 38.2%";
case ICT_MSS_ENTRY_FILL: return "M5 fill entry";
case ICT_MSS_READY: return "READY entry";
default: return "Idle";
}
@@ -29,51 +31,121 @@ int IctMss_FindH1FvgById(const ulong id)
return -1;
}
// H1 FVG mục tiêu: Bear → Premium cao nhất; Bull → Discount thấp nhất (chờ hồi chạm, chưa cần fill)
int IctMss_SelectTargetH1Fvg()
// POI H1: FVG chưa Used, gần giá nhất (không phải Premium cao nhất / Discount thấp nhất)
double IctMss_DistancePriceToFvg(const double price, const IctFvgZone &z)
{
int bestIdx = -1;
if(price >= z.lower - _Point && price <= z.upper + _Point)
return 0.0;
if(price > z.upper)
return price - z.upper;
return z.lower - price;
}
bool IctMss_IsH1PoiEligible(const IctFvgZone &z)
{
if(!IctFvg_MatchesBias(z))
return false;
if(!IctFvg_IsEntryRepPd(z))
return false;
if(z.state == ICT_FVG_USED)
return false;
return true;
}
int IctMss_CountH1PoiEligible()
{
int n = 0;
for(int i = 0; i < g_ictFvgCount; i++)
if(IctMss_IsH1PoiEligible(g_ictFvgZones[i]))
n++;
return n;
}
int IctMss_SelectNearestH1Poi(const string sym)
{
const double px = SymbolInfoDouble(sym, SYMBOL_BID);
int bestIdx = -1;
double bestDist = DBL_MAX;
for(int i = 0; i < g_ictFvgCount; i++)
{
if(!IctFvg_MatchesBias(g_ictFvgZones[i]))
continue;
if(!IctFvg_IsEntryRepPd(g_ictFvgZones[i]))
continue;
if(g_ictFvgZones[i].state == ICT_FVG_USED && g_ictFvgZones[i].maxFillRatio < 0.01)
if(!IctMss_IsH1PoiEligible(g_ictFvgZones[i]))
continue;
if(g_ictDailyBias.bias == ICT_BIAS_BEAR)
const double d = IctMss_DistancePriceToFvg(px, g_ictFvgZones[i]);
if(d < bestDist - _Point)
{
if(bestIdx < 0 || g_ictFvgZones[i].upper > g_ictFvgZones[bestIdx].upper)
bestIdx = i;
bestDist = d;
bestIdx = i;
}
else if(g_ictDailyBias.bias == ICT_BIAS_BULL)
else if(MathAbs(d - bestDist) <= _Point && bestIdx >= 0)
{
if(bestIdx < 0 || g_ictFvgZones[i].lower < g_ictFvgZones[bestIdx].lower)
if(g_ictFvgZones[i].createdTime > g_ictFvgZones[bestIdx].createdTime)
bestIdx = i;
}
}
return bestIdx;
}
// Retest FVG H1 (POI): râu H1 chạm gap (InpMssH1RetestWickOnly) hoặc thêm % lấp thân/râu
bool IctMss_HasH1FvgRetest(const string sym, IctFvgZone &h1)
bool IctMss_PriceInsideFvg(const IctFvgZone &h1, const double price)
{
return (price >= h1.lower - _Point && price <= h1.upper + _Point);
}
bool IctMss_BarOverlapsFvg(const IctFvgZone &h1, const double barHi, const double barLo)
{
return (barHi >= h1.lower - _Point && barLo <= h1.upper + _Point);
}
bool IctMss_LivePriceTouchesFvg(const string sym, const IctFvgZone &h1)
{
const double bid = SymbolInfoDouble(sym, SYMBOL_BID);
const double ask = SymbolInfoDouble(sym, SYMBOL_ASK);
return IctMss_PriceInsideFvg(h1, bid) || IctMss_PriceInsideFvg(h1, ask);
}
datetime IctMss_FirstM5TouchInFvg(const string sym, const IctFvgZone &h1)
{
const ENUM_TIMEFRAMES tf = InpConfirmTf;
const int lim = MathMin(InpMssConfirmLookback, iBars(sym, tf) - 2);
datetime best = 0;
for(int sh = lim; sh >= 1; sh--)
{
const datetime t = iTime(sym, tf, sh);
if(t <= h1.createdTime)
break;
if(!IctMss_BarOverlapsFvg(h1, iHigh(sym, tf, sh), iLow(sym, tf, sh)))
continue;
if(best == 0 || t < best)
best = t;
}
return best;
}
datetime IctMss_GetFvgTouchTime(const string sym, IctFvgZone &h1)
{
IctFvg_UpdateZoneState(sym, InpFvgTf, h1);
if(h1.firstTouchTime <= 0)
return false;
if(InpMssH1RetestWickOnly)
{
h1.mssH1Touch382 = true;
return true;
}
datetime t = h1.firstTouchTime;
const datetime tM5 = IctMss_FirstM5TouchInFvg(sym, h1);
if(tM5 > 0 && (t <= 0 || tM5 < t))
t = tM5;
if(!IctFvg_HasFillAtLeast(h1, InpMssH1MinFillPct))
return false;
h1.mssH1Touch382 = true;
return true;
if(t <= 0 && IctMss_LivePriceTouchesFvg(sym, h1))
t = iTime(sym, InpConfirmTf, 0);
return t;
}
// Retest = giá chạm FVG (H1/M5/bid-ask). Râu H1 xuyên FVG vẫn OK; chỉ hủy khi H1 body đóng xuyên.
bool IctMss_HasFvgPriceTouch(const string sym, IctFvgZone &h1)
{
return (IctMss_GetFvgTouchTime(sym, h1) > 0);
}
bool IctMss_HasH1FvgRetest(const string sym, IctFvgZone &h1)
{
return IctMss_HasFvgPriceTouch(sym, h1);
}
double IctMss_H1Atr(const string sym)
@@ -178,234 +250,165 @@ bool IctMss_BodyBrokeLevelSince(const string sym, const ENUM_TIMEFRAMES tf,
return false;
}
bool IctMss_BarOverlapsFvg(const IctFvgZone &h1, const double barHi, const double barLo)
bool IctMss_HasM5BarInH1Fvg(const string sym, const IctFvgZone &h1,
const datetime since)
{
return (barHi >= h1.lower - _Point && barLo <= h1.upper + _Point);
}
IctSwingPoint IctMss_ProtectedLowBeforeHigh(const IctSwingPoint &lows[], const int nL,
const IctSwingPoint &h0,
const datetime tTouch)
{
IctSwingPoint empty;
empty.Clear();
if(!h0.Valid())
return empty;
int best = -1;
for(int i = 0; i < nL; i++)
const ENUM_TIMEFRAMES tf = InpConfirmTf;
const int lim = MathMin(InpMssConfirmLookback, iBars(sym, tf) - 2);
for(int sh = 1; sh <= lim; sh++)
{
if(lows[i].time < tTouch)
continue;
if(lows[i].shift <= h0.shift)
continue;
if(lows[i].price >= h0.price - _Point)
continue;
if(best < 0 || lows[i].shift < lows[best].shift)
best = i;
if(since > 0 && iTime(sym, tf, sh) < since)
break;
if(IctMss_BarOverlapsFvg(h1, iHigh(sym, tf, sh), iLow(sym, tf, sh)))
return true;
}
if(best < 0)
return empty;
return lows[best];
return false;
}
IctSwingPoint IctMss_ProtectedHighAfterLow(const IctSwingPoint &highs[], const int nH,
const IctSwingPoint &l0,
const datetime tTouch)
bool IctMss_UpdateLiveM5Swings(const string sym, const ENUM_ICT_BIAS bias,
const datetime tTouch)
{
IctSwingPoint empty;
empty.Clear();
if(!l0.Valid())
return empty;
g_ictLowTf.mss.liveL0Price = 0.0;
g_ictLowTf.mss.liveH0Price = 0.0;
g_ictLowTf.mss.liveL0Time = 0;
g_ictLowTf.mss.liveH0Time = 0;
int best = -1;
for(int i = 0; i < nH; i++)
{
if(highs[i].time < tTouch || highs[i].time < l0.time)
continue;
if(highs[i].shift >= l0.shift)
continue;
if(highs[i].price <= l0.price + _Point)
continue;
if(best < 0 || highs[i].shift < highs[best].shift)
best = i;
}
if(best < 0)
return empty;
return highs[best];
}
bool IctMss_ReactionHighAfterTouch(const string sym, const ENUM_TIMEFRAMES tf,
const IctFvgZone &h1, const datetime tTouch,
IctSwingPoint &outHi)
{
outHi.Clear();
IctSwingSet sw;
ENUM_ICT_STRUCT st = ICT_STRUCT_NONE;
if(IctBuildConfirmSwingSet(sym, sw, st) && sw.hasH0 && sw.h0.time >= tTouch)
{
outHi = sw.h0;
return true;
}
int touchSh = iBarShift(sym, tf, tTouch, true);
if(touchSh < 0)
touchSh = iBarShift(sym, tf, tTouch, false);
if(touchSh < 1)
if(!IctBuildConfirmSwingSet(sym, sw, st))
return false;
double bestP = -DBL_MAX;
for(int sh = touchSh; sh >= 1; sh--)
{
if(iTime(sym, tf, sh) < tTouch)
continue;
const double hi = iHigh(sym, tf, sh);
const double lo = iLow(sym, tf, sh);
if(!IctMss_BarOverlapsFvg(h1, hi, lo))
continue;
if(hi > bestP)
{
bestP = hi;
outHi.price = hi;
outHi.time = iTime(sym, tf, sh);
outHi.shift = sh;
}
}
return outHi.Valid();
}
bool IctMss_ReactionLowAfterTouch(const string sym, const ENUM_TIMEFRAMES tf,
const IctFvgZone &h1, const datetime tTouch,
IctSwingPoint &outLo)
{
outLo.Clear();
IctSwingSet sw;
ENUM_ICT_STRUCT st = ICT_STRUCT_NONE;
if(IctBuildConfirmSwingSet(sym, sw, st) && sw.hasL0 && sw.l0.time >= tTouch)
{
outLo = sw.l0;
return true;
}
int touchSh = iBarShift(sym, tf, tTouch, true);
if(touchSh < 0)
touchSh = iBarShift(sym, tf, tTouch, false);
if(touchSh < 1)
return false;
double bestP = DBL_MAX;
for(int sh = touchSh; sh >= 1; sh--)
{
if(iTime(sym, tf, sh) < tTouch)
continue;
const double hi = iHigh(sym, tf, sh);
const double lo = iLow(sym, tf, sh);
if(!IctMss_BarOverlapsFvg(h1, hi, lo))
continue;
if(lo < bestP)
{
bestP = lo;
outLo.price = lo;
outLo.time = iTime(sym, tf, sh);
outLo.shift = sh;
}
}
return outLo.Valid();
}
// MSS M5 sau retest FVG H1: pullback ngược cục bộ → phá L0 (bear HTF) hoặc H0 (bull HTF)
bool IctMss_FindMssAfterFvgRetest(const string sym, const ENUM_TIMEFRAMES tf,
const IctFvgZone &h1, const datetime tTouch,
const ENUM_ICT_BIAS bias,
double &keyLevelOut, datetime &keyTimeOut,
datetime &mssBarTimeOut, double &slSwingOut)
{
keyLevelOut = 0.0;
keyTimeOut = 0;
mssBarTimeOut = 0;
slSwingOut = 0.0;
IctSwingPoint highs[], lows[];
IctCollectSwings(sym, tf, InpConfirmSwingRange, InpConfirmSwingLookback, highs, lows);
const int nH = ArraySize(highs);
const int nL = ArraySize(lows);
if(bias == ICT_BIAS_BEAR)
{
IctSwingPoint h0;
if(!IctMss_ReactionHighAfterTouch(sym, tf, h1, tTouch, h0))
if(!sw.hasL0 || !sw.hasH0)
return false;
IctSwingPoint keyLo = IctMss_ProtectedLowBeforeHigh(lows, nL, h0, tTouch);
if(!keyLo.Valid())
if(sw.l0.time < tTouch && sw.h0.time < tTouch)
return false;
const int startSh = MathMax(1, h0.shift - 1);
for(int sh = startSh; sh >= 1; sh--)
{
if(iTime(sym, tf, sh) < h0.time)
continue;
if(!IctBodyBreakBelow(sym, tf, sh, keyLo.price))
continue;
keyLevelOut = keyLo.price;
keyTimeOut = keyLo.time;
mssBarTimeOut = iTime(sym, tf, sh);
slSwingOut = h0.price;
return true;
}
g_ictLowTf.mss.liveL0Price = sw.l0.price;
g_ictLowTf.mss.liveL0Time = sw.l0.time;
g_ictLowTf.mss.liveH0Price = sw.h0.price;
g_ictLowTf.mss.liveH0Time = sw.h0.time;
return true;
}
if(bias == ICT_BIAS_BULL)
{
IctSwingPoint l0;
if(!IctMss_ReactionLowAfterTouch(sym, tf, h1, tTouch, l0))
if(!sw.hasL0 || !sw.hasH0)
return false;
IctSwingPoint keyHi = IctMss_ProtectedHighAfterLow(highs, nH, l0, tTouch);
if(!keyHi.Valid())
if(sw.l0.time < tTouch && sw.h0.time < tTouch)
return false;
const int startSh = MathMax(1, l0.shift - 1);
for(int sh = startSh; sh >= 1; sh--)
{
if(iTime(sym, tf, sh) < l0.time)
continue;
if(!IctBodyBreakAbove(sym, tf, sh, keyHi.price))
continue;
keyLevelOut = keyHi.price;
keyTimeOut = keyHi.time;
mssBarTimeOut = iTime(sym, tf, sh);
slSwingOut = l0.price;
return true;
}
g_ictLowTf.mss.liveL0Price = sw.l0.price;
g_ictLowTf.mss.liveL0Time = sw.l0.time;
g_ictLowTf.mss.liveH0Price = sw.h0.price;
g_ictLowTf.mss.liveH0Time = sw.h0.time;
return true;
}
return false;
}
// Hủy setup: H1 đóng (shift=1) — thân xuyên FVG (không giữ giá). Râu xuyên vẫn tiếp tục MSS.
bool IctMss_H1BodyInvalidatedSetup(const string sym, const IctFvgZone &h1,
const ENUM_ICT_BIAS bias)
{
if(h1.upper <= h1.lower)
return false;
const double cls = iClose(sym, InpFvgTf, 1);
if(bias == ICT_BIAS_BEAR)
return (cls > h1.upper + _Point);
if(bias == ICT_BIAS_BULL)
return (cls < h1.lower - _Point);
return false;
}
bool IctMss_CheckH1InvalidationOnNewBar(const string sym, const IctFvgZone &h1,
const ENUM_ICT_BIAS bias)
{
const datetime h1Bar1 = iTime(sym, InpFvgTf, 1);
if(h1Bar1 <= 0)
return false;
if(h1Bar1 == g_ictLowTf.mss.h1LastInvalidBarTime)
return false;
g_ictLowTf.mss.h1LastInvalidBarTime = h1Bar1;
return IctMss_H1BodyInvalidatedSetup(sym, h1, bias);
}
bool IctMss_FindMssBreakBar(const string sym, const ENUM_TIMEFRAMES tf,
const double keyLevel, const datetime keyTime,
const bool wantBreakBelow,
datetime &breakTimeOut)
{
breakTimeOut = 0;
if(keyLevel <= 0.0 || keyTime <= 0)
return false;
const int lim = MathMin(InpMssConfirmLookback, iBars(sym, tf) - 2);
for(int sh = 1; sh <= lim; sh++)
{
if(iTime(sym, tf, sh) < keyTime)
break;
const bool broke = wantBreakBelow ?
IctBodyBreakBelow(sym, tf, sh, keyLevel) :
IctBodyBreakAbove(sym, tf, sh, keyLevel);
if(!broke)
continue;
breakTimeOut = iTime(sym, tf, sh);
return true;
}
return false;
}
bool IctMss_TryLockMss(const string sym, const ENUM_TIMEFRAMES tf,
const IctFvgZone &h1, const ENUM_ICT_BIAS bias)
{
if(g_ictLowTf.mss.chochLocked && g_ictLowTf.mss.chochKeyLevel > 0.0)
return true;
const datetime tTouch = h1.firstTouchTime;
const datetime tTouch = (g_ictLowTf.mss.h1TouchTime > 0) ?
g_ictLowTf.mss.h1TouchTime : h1.firstTouchTime;
if(tTouch <= 0)
return false;
double keyLv = 0.0, slSwing = 0.0;
datetime keyT = 0, mssBarT = 0;
if(!IctMss_FindMssAfterFvgRetest(sym, tf, h1, tTouch, bias,
keyLv, keyT, mssBarT, slSwing))
if(!IctMss_UpdateLiveM5Swings(sym, bias, tTouch))
return false;
g_ictLowTf.mss.chochKeyLevel = keyLv;
g_ictLowTf.mss.chochKeyTime = keyT;
g_ictLowTf.mss.slSwingPrice = slSwing;
g_ictLowTf.mss.chochTime = mssBarT;
g_ictLowTf.mss.chochLocked = true;
if(g_ictLowTf.mss.liveL0Time < tTouch && g_ictLowTf.mss.liveH0Time < tTouch)
return false;
datetime breakT = 0;
if(bias == ICT_BIAS_BEAR)
{
if(!IctMss_FindMssBreakBar(sym, tf, g_ictLowTf.mss.liveL0Price,
g_ictLowTf.mss.liveL0Time, true, breakT))
return false;
if(breakT < tTouch)
return false;
g_ictLowTf.mss.chochKeyLevel = g_ictLowTf.mss.liveL0Price;
g_ictLowTf.mss.chochKeyTime = g_ictLowTf.mss.liveL0Time;
g_ictLowTf.mss.slSwingPrice = g_ictLowTf.mss.liveH0Price;
}
else if(bias == ICT_BIAS_BULL)
{
if(!IctMss_FindMssBreakBar(sym, tf, g_ictLowTf.mss.liveH0Price,
g_ictLowTf.mss.liveH0Time, false, breakT))
return false;
if(breakT < tTouch)
return false;
g_ictLowTf.mss.chochKeyLevel = g_ictLowTf.mss.liveH0Price;
g_ictLowTf.mss.chochKeyTime = g_ictLowTf.mss.liveH0Time;
g_ictLowTf.mss.slSwingPrice = g_ictLowTf.mss.liveL0Price;
}
else
return false;
g_ictLowTf.mss.chochTime = breakT;
g_ictLowTf.mss.chochLocked = true;
return true;
}
@@ -572,6 +575,96 @@ bool IctMss_PriceInEntryZone(const string sym, const ENUM_TIMEFRAMES tf,
return false;
}
void IctMss_MarkFvgUsed(IctFvgZone &zone, const string sym)
{
if(zone.id == 0)
return;
zone.state = ICT_FVG_USED;
if(zone.fvgUsedTime == 0)
zone.fvgUsedTime = iTime(sym, InpFvgTf, 0);
zone.timeEnd = IctFvg_GetFvgDrawTimeEnd(sym, InpFvgTf, zone);
}
void IctMss_MarkFvgUsedOnMssSuccess(const string sym, const ulong fvgId)
{
if(fvgId == 0)
return;
const int idx = IctMss_FindH1FvgById(fvgId);
if(idx < 0)
return;
const bool fresh = (g_ictFvgZones[idx].state != ICT_FVG_USED);
if(fresh)
IctMss_MarkFvgUsed(g_ictFvgZones[idx], sym);
if(g_ictLowTf.mss.h1WatchFvgId == fvgId)
g_ictLowTf.mss.h1WatchFvgId = 0;
if(fresh && InpMssLogJournal)
PrintFormat("[ICT2026/MSS] FVG #%I64u → Used (giữ giá + MSS M5 OK)", fvgId);
}
void IctMss_FailFvgH1Body(const string sym, const ulong fvgId, const string reason)
{
if(fvgId > 0)
{
const int idx = IctMss_FindH1FvgById(fvgId);
if(idx >= 0)
IctMss_MarkFvgUsed(g_ictFvgZones[idx], sym);
}
IctMss_ResetState();
g_ictLowTf.mss.displayReason = reason;
if(InpMssLogJournal)
PrintFormat("[ICT2026/MSS] FVG #%I64u → Used (H1 body xuyên) | %s", fvgId, reason);
g_ictMssJournalLast = "";
}
void IctMss_ResetPipelineKeepWatch()
{
const ulong watch = g_ictLowTf.mss.h1WatchFvgId;
const datetime inv = g_ictLowTf.mss.h1LastInvalidBarTime;
g_ictLowTf.mss.Clear();
g_ictLowTf.mss.h1WatchFvgId = watch;
g_ictLowTf.mss.h1LastInvalidBarTime = inv;
IctMss_JournalReset();
}
void IctMss_CheckH1WatchInvalidation(const string sym)
{
const ulong watchId = g_ictLowTf.mss.h1WatchFvgId;
if(watchId == 0)
return;
const int idx = IctMss_FindH1FvgById(watchId);
if(idx < 0)
{
g_ictLowTf.mss.h1WatchFvgId = 0;
return;
}
if(g_ictFvgZones[idx].state == ICT_FVG_USED)
{
g_ictLowTf.mss.h1WatchFvgId = 0;
return;
}
const ENUM_ICT_BIAS bias = g_ictDailyBias.bias;
if(bias != ICT_BIAS_BEAR && bias != ICT_BIAS_BULL)
return;
if(!IctMss_CheckH1InvalidationOnNewBar(sym, g_ictFvgZones[idx], bias))
return;
IctMss_FailFvgH1Body(sym, watchId,
(bias == ICT_BIAS_BEAR) ?
"FVG Used: H1 đóng thân trên Premium — không giữ giá" :
"FVG Used: H1 đóng thân dưới Discount — không giữ giá");
}
void IctMss_ResetState()
{
g_ictLowTf.mss.Clear();
@@ -582,11 +675,18 @@ void IctMss_Update(const string sym)
{
g_ictLowTf.mss.displayReason = IctMssPhaseText(g_ictLowTf.mss.phase);
IctMss_CheckH1WatchInvalidation(sym);
if(!g_ictIntraday.isAllowTrade)
{
if(g_ictLowTf.mss.phase != ICT_MSS_IDLE)
IctMss_ResetState();
g_ictLowTf.mss.displayReason = "AllowTrade=false";
{
if(g_ictLowTf.mss.h1WatchFvgId == 0 && g_ictLowTf.mss.h1FvgId > 0)
g_ictLowTf.mss.h1WatchFvgId = g_ictLowTf.mss.h1FvgId;
IctMss_ResetPipelineKeepWatch();
}
if(StringFind(g_ictLowTf.mss.displayReason, "FVG Used") != 0)
g_ictLowTf.mss.displayReason = "AllowTrade=false (H1 lệch Bias — MSS tạm dừng)";
return;
}
@@ -599,37 +699,41 @@ void IctMss_Update(const string sym)
return;
}
if(g_ictLowTf.mss.phase == ICT_MSS_IDLE || g_ictLowTf.mss.h1FvgId == 0)
if(g_ictLowTf.mss.phase == ICT_MSS_IDLE)
{
const int hIdx = IctMss_SelectTargetH1Fvg();
const int hIdx = IctMss_SelectNearestH1Poi(sym);
if(hIdx < 0)
{
g_ictLowTf.mss.displayReason = StringFormat("Chờ H1 %s FVG",
(wantSide == ICT_FVG_BEAR) ? "Premium" : "Discount");
g_ictLowTf.mss.h1FvgId = 0;
g_ictLowTf.mss.displayReason = StringFormat(
"Chờ H1 %s FVG gần giá (%d POI / %d FVG)",
(wantSide == ICT_FVG_BEAR) ? "Premium" : "Discount",
IctMss_CountH1PoiEligible(), g_ictFvgCount);
return;
}
g_ictLowTf.mss.h1FvgId = g_ictFvgZones[hIdx].id;
if(!IctMss_HasH1FvgRetest(sym, g_ictFvgZones[hIdx]))
if(!IctMss_HasFvgPriceTouch(sym, g_ictFvgZones[hIdx]))
{
g_ictLowTf.mss.displayReason = InpMssH1RetestWickOnly ?
StringFormat("Chờ râu H1 chạm FVG %s [%.0f%.0f]",
IctPdZoneText(IctFvg_GetRepPd(g_ictFvgZones[hIdx])),
g_ictFvgZones[hIdx].lower, g_ictFvgZones[hIdx].upper) :
StringFormat("Chờ retest FVG H1 %s [%.0f%.0f] (%.0f%% lấp)",
IctPdZoneText(IctFvg_GetRepPd(g_ictFvgZones[hIdx])),
g_ictFvgZones[hIdx].lower, g_ictFvgZones[hIdx].upper,
InpMssH1MinFillPct);
const double px = SymbolInfoDouble(sym, SYMBOL_BID);
const double dist = IctMss_DistancePriceToFvg(px, g_ictFvgZones[hIdx]);
g_ictLowTf.mss.displayReason = StringFormat(
"POI #%I64u [%.0f%.0f] dist %.0f pts — chờ chạm",
g_ictFvgZones[hIdx].id,
g_ictFvgZones[hIdx].lower, g_ictFvgZones[hIdx].upper, dist / _Point);
return;
}
const datetime tTouch = IctMss_GetFvgTouchTime(sym, g_ictFvgZones[hIdx]);
g_ictLowTf.mss.phase = ICT_MSS_H1_TOUCH;
g_ictLowTf.mss.h1TouchTime = g_ictFvgZones[hIdx].firstTouchTime;
g_ictLowTf.mss.displayReason = InpMssH1RetestWickOnly ?
"Retest FVG H1 OK | râu chạm POI" :
StringFormat("Retest FVG H1 OK | lấp %.0f%% (H1)",
g_ictFvgZones[hIdx].maxFillRatio * 100.0);
g_ictLowTf.mss.h1FvgId = g_ictFvgZones[hIdx].id;
g_ictLowTf.mss.h1WatchFvgId = g_ictFvgZones[hIdx].id;
g_ictLowTf.mss.h1TouchTime = tTouch;
g_ictLowTf.mss.h1LastInvalidBarTime = 0;
g_ictLowTf.mss.displayReason = StringFormat(
"Giá đã chạm FVG — theo dõi MSS M5 [%.0f%.0f]",
g_ictFvgZones[hIdx].lower, g_ictFvgZones[hIdx].upper);
}
const int h1Idx = IctMss_FindH1FvgById(g_ictLowTf.mss.h1FvgId);
@@ -640,44 +744,52 @@ void IctMss_Update(const string sym)
return;
}
if(g_ictLowTf.mss.phase >= ICT_MSS_H1_TOUCH &&
!IctMss_HasH1FvgRetest(sym, g_ictFvgZones[h1Idx]))
if(g_ictFvgZones[h1Idx].state == ICT_FVG_USED &&
g_ictLowTf.mss.phase <= ICT_MSS_H1_TOUCH &&
!g_ictLowTf.mss.chochLocked)
{
IctMss_ResetState();
g_ictLowTf.mss.displayReason = "FVG H1 chưa retest đủ % — reset MSS";
g_ictLowTf.mss.displayReason = "FVG POI Used — chọn FVG gần giá tiếp theo";
return;
}
if(g_ictLowTf.mss.phase >= ICT_MSS_H1_TOUCH && g_ictLowTf.mss.h1TouchTime <= 0)
g_ictLowTf.mss.h1TouchTime = g_ictFvgZones[h1Idx].firstTouchTime;
if(g_ictLowTf.mss.phase == ICT_MSS_H1_TOUCH)
{
if(!IctMss_TryLockMss(sym, cTf, g_ictFvgZones[h1Idx], g_ictDailyBias.bias))
const datetime t = IctMss_GetFvgTouchTime(sym, g_ictFvgZones[h1Idx]);
if(t > 0)
g_ictLowTf.mss.h1TouchTime = t;
}
if(g_ictLowTf.mss.phase == ICT_MSS_H1_TOUCH && !g_ictLowTf.mss.chochLocked)
{
const datetime tTouch = g_ictLowTf.mss.h1TouchTime;
if(IctMss_UpdateLiveM5Swings(sym, g_ictDailyBias.bias, tTouch))
{
g_ictLowTf.mss.displayReason = (g_ictDailyBias.bias == ICT_BIAS_BEAR) ?
"Retest FVG H1 OK — chờ MSS↓ phá L0 M5" :
"Retest FVG H1 OK — chờ MSS phá H0 M5";
return;
if(g_ictDailyBias.bias == ICT_BIAS_BEAR)
g_ictLowTf.mss.displayReason = StringFormat(
"Chờ MSS phá L0=%.2f | H0=%.2f (M5 bull)",
g_ictLowTf.mss.liveL0Price, g_ictLowTf.mss.liveH0Price);
else
g_ictLowTf.mss.displayReason = StringFormat(
"Chờ MSS↑ phá H0=%.2f | L0=%.2f (M5 bear)",
g_ictLowTf.mss.liveH0Price, g_ictLowTf.mss.liveL0Price);
}
else
g_ictLowTf.mss.displayReason = "M5 trong FVG — chờ pivot L0/H0";
if(!IctMss_TryLockMss(sym, cTf, g_ictFvgZones[h1Idx], g_ictDailyBias.bias))
return;
IctMss_MarkFvgUsedOnMssSuccess(sym, g_ictLowTf.mss.h1FvgId);
const double keyLv = g_ictLowTf.mss.chochKeyLevel;
const double slSwing = g_ictLowTf.mss.slSwingPrice;
const datetime mssT = g_ictLowTf.mss.chochTime;
if(!IctMss_IsChochNearH1Fvg(sym, g_ictFvgZones[h1Idx], g_ictDailyBias.bias,
keyLv, slSwing, mssT))
{
g_ictLowTf.mss.displayReason = StringFormat(
"MSS khóa @ %.2f — xa H1 FVG, chờ gần hơn", keyLv);
return;
}
g_ictLowTf.mss.phase = ICT_MSS_CHOCH;
IctConfirmFvg_ScanNew(sym, cTf, wantSide, g_ictLowTf.mss.chochTime, true);
g_ictLowTf.mss.displayReason = (g_ictDailyBias.bias == ICT_BIAS_BEAR) ?
StringFormat("MSS↓ khóa L0=%.2f | H0=%.2f — quét M5 FVG", keyLv, slSwing) :
StringFormat("MSS↑ khóa H0=%.2f | L0=%.2f — quét M5 FVG", keyLv, slSwing);
StringFormat("MSS↓ @ L0=%.2f | SL H0=%.2f — quét M5 FVG", keyLv, slSwing) :
StringFormat("MSS↑ @ H0=%.2f | SL L0=%.2f — quét M5 FVG", keyLv, slSwing);
}
if(g_ictLowTf.mss.phase == ICT_MSS_CHOCH)
+39 -10
View File
@@ -9,10 +9,11 @@
#include <ICT2026/DailyBias.mqh>
#include <ICT2026/IntradayStructure.mqh>
#include <ICT2026/LowTfTrend.mqh>
#include <ICT2026/EaState.mqh>
const string ICT26_PANEL_PFX = "ICT26_PNL_";
const string ICT26_PANEL_LEGACY = "ICT26_BIAS_PANEL";
const int ICT26_PANEL_MAXLINE = 14;
const int ICT26_PANEL_MAXLINE = 16;
const color ICT_PANEL_CLR_UP = clrLime;
const color ICT_PANEL_CLR_DOWN = clrOrangeRed;
@@ -59,6 +60,16 @@ color IctPanelAllowTradeColor()
return ICT_PANEL_CLR_NEUTRAL;
}
color IctPanelEaStateColor()
{
switch(g_ictEaState.category)
{
case ICT_EA_CAT_TRADE: return clrAqua;
case ICT_EA_CAT_SETUP: return clrGold;
default: return ICT_PANEL_CLR_MUTED;
}
}
void IctPanel_Clear()
{
const long ch = ChartID();
@@ -98,6 +109,7 @@ void IctPanel_Render(const string sym)
}
IctIntraday_UpdateAllowTrade();
IctEaState_Refresh(sym);
const long ch = ChartID();
ObjectDelete(ch, ICT26_PANEL_LEGACY);
@@ -108,6 +120,7 @@ void IctPanel_Render(const string sym)
const color clrBias = IctPanelBiasDirectionColor(g_ictDailyBias.bias);
const color clrIntra = IctPanelIntradayDirectionColor(g_ictIntraday.trend);
const color clrAllow = IctPanelAllowTradeColor();
const color clrEa = IctPanelEaStateColor();
string lines[];
color colors[];
@@ -116,6 +129,27 @@ void IctPanel_Render(const string sym)
int n = 0;
ArrayResize(lines, n + 1);
ArrayResize(colors, n + 1);
lines[n] = StringFormat("[%s] %s", IctEaState_CategoryText(g_ictEaState.category),
IctEaState_Code(g_ictEaState.state));
colors[n++] = clrEa;
ArrayResize(lines, n + 1);
ArrayResize(colors, n + 1);
lines[n] = IctEaState_TitleVi(g_ictEaState.state);
colors[n++] = clrEa;
ArrayResize(lines, n + 1);
ArrayResize(colors, n + 1);
lines[n] = StringFormat("Chi tiet: %s", g_ictEaState.detail);
colors[n++] = clrEa;
ArrayResize(lines, n + 1);
ArrayResize(colors, n + 1);
lines[n] = "-------------------------";
colors[n++] = ICT_PANEL_CLR_NEUTRAL;
ArrayResize(lines, n + 1);
ArrayResize(colors, n + 1);
lines[n] = StringFormat("ICT2026 %s | %s[0] chua dong", EnumToString(InpBiasTf), dTag);
@@ -153,21 +187,16 @@ void IctPanel_Render(const string sym)
ArrayResize(lines, n + 1);
ArrayResize(colors, n + 1);
lines[n] = StringFormat("IsAllowTrade: %s",
g_ictIntraday.isAllowTrade ? "true" : "false");
lines[n] = StringFormat("AllowTrade: %s | MSS phase: %s",
g_ictIntraday.isAllowTrade ? "YES" : "NO",
IctMssPhaseText(g_ictLowTf.mss.phase));
colors[n++] = clrAllow;
ArrayResize(lines, n + 1);
ArrayResize(colors, n + 1);
lines[n] = StringFormat("iTF FVG: %s", g_ictLowTf.displayReason);
lines[n] = StringFormat("H1 FVG: %s", g_ictLowTf.displayReason);
colors[n++] = (g_ictLowTf.availableCount > 0) ? ICT_PANEL_CLR_ALLOW : ICT_PANEL_CLR_MUTED;
ArrayResize(lines, n + 1);
ArrayResize(colors, n + 1);
lines[n] = StringFormat("MSS: %s", g_ictLowTf.mss.displayReason);
colors[n++] = (g_ictLowTf.mss.phase >= ICT_MSS_READY) ? ICT_PANEL_CLR_ALLOW :
(g_ictLowTf.mss.phase > ICT_MSS_IDLE) ? clrGold : ICT_PANEL_CLR_MUTED;
for(int i = 0; i < n; i++)
IctPanel_SetLine(ch, i, i * lh, lines[i], colors[i]);
+80 -5
View File
@@ -49,7 +49,8 @@ MQL5/
├── LowTfTrend.mqh ← iTF FVG khi IsAllowTrade
├── Fvg.mqh ← detect / Available-Used
├── FvgDraw.mqh ← vẽ FVG + Premium/Discount
├── Panel.mqh ← bias + intraday + IsAllowTrade (góc trên)
├── EaState.mqh ← state machine STOP / SETUP / TRADE
├── Panel.mqh ← bias + intraday + EA state (góc trên)
└── Draw.mqh ← label b*/i*/H0L1 trên chart
```
@@ -216,9 +217,13 @@ FVG Used **không** kéo dài P/D thêm; P/D độc lập với Used (theo swing
| | |
|--|--|
| **Mặc định (`InpMssH1RetestWickOnly`)** | **Râu H1** chạm `[lower … upper]` là đủ — không cần thân nến xuyên FVG |
| **Tùy chọn** | `InpMssH1RetestWickOnly=false` → thêm lấp ≥ `InpMssH1MinFillPct` |
| **MSS M5** | Sau râu chạm POI → M5 pullback ngược cục bộ → **phá L0** (bear HTF) hoặc **phá H0** (bull HTF) |
| **Retest** | **Giá chạm** FVG (H1/M5/bid-ask) — không cần râu H1 riêng |
| **Giữ giá H1** | Râu xuyên FVG → tiếp tục chờ MSS M5 |
| **AllowTrade** | H1 trend đồng thuận Bias — **không** đánh dấu FVG Used |
| **FVG Used (fail)** | H1 body đóng xuyên FVG — không giữ giá |
| **FVG Used (OK)** | Giữ giá + **MSS M5** khóa → Used, tiếp tục M5 FVG / entry trên cùng setup |
| **AllowTrade=false** | Tạm dừng MSS pipeline; vẫn **watch** FVG cho H1 body fail |
| **MSS M5** | Sau chạm FVG → M5 pullback → **phá L0** (bear) / **phá H0** (bull) |
**Định nghĩa MSS vs CHoCH (cùng rule Key H0/L0):**
@@ -234,6 +239,28 @@ CHoCH trên D/H1 = phá key level **ngược** xu hướng HTF (bull→bear phá
Sau retest FVG H1 OK → arm MSS trên M5.
### EA state machine (`EaState.mqh`, v1.131)
Panel luôn hiển thị 3 dòng đầu: **`[CATEGORY] CODE`**, tiêu đề, chi tiết.
| Category | State `CODE` | Khi nào |
|----------|--------------|---------|
| **STOP** | `STOP_NO_BIAS` | Daily bias = None |
| **STOP** | `STOP_BIAS_RANGE` | Bias = Range |
| **STOP** | `STOP_INTRADAY_NONE` | Bias Bull/Bear nhưng H1 trend = None |
| **STOP** | `STOP_BIAS_INTRADAY_MISMATCH` | Bias ≠ H1 (vd Bull + H1 Down) |
| **SETUP** | `WAIT_FVG_TOUCH` | AllowTrade, chờ retest FVG H1 |
| **SETUP** | `FVG_TOUCHED_WAIT_MSS` | H1 retest + M5 trong FVG; live L0/H0 M5, chờ body phá L0 (bear) |
| **SETUP** | `MSS_OK_WAIT_M5_FVG` | MSS khóa, chờ M5 FVG |
| **SETUP** | `M5_FVG_WAIT_RETRACE` | Có M5 FVG, chờ hồi fill entry |
| **SETUP** | `READY_FOR_LIMIT` | Giá trong vùng entry, sắp đặt limit |
| **TRADE** | `LIMIT_ORDER_PENDING` | Có lệnh limit MSS magic |
| **TRADE** | `ON_TRADE` | Có position MSS magic |
`ENUM_ICT_MSS_PHASE` (nội bộ) vẫn giữ; `IctEaState_Refresh()` map sang state trên sau mỗi `IctMss_Update` / `IctMssEntry_Update`.
API: `ICT2026_GetEaState()`, `ICT2026_GetEaStateCode()`, `ICT2026_GetEaStateDetail()`.
### MSS entry (Confirm TF, v1.115)
Khi `IsAllowTrade`, state machine `g_ictLowTf.mss`:
@@ -539,6 +566,54 @@ ENUM_ICT_BIAS ICT2026_GetDailyBias();
## Changelog
### v1.138 — POI H1 = FVG chưa Used **gần giá nhất**
- `IctMss_SelectNearestH1Poi`: khoảng cách bid → FVG; bỏ qua Used; tie → FVG mới hơn
- H1 FVG **không** auto-Used theo % fill (chỉ MSS fail/OK đánh dấu Used)
- IDLE: luôn chọn lại POI gần nhất; chạm → `FVG_TOUCHED_WAIT_MSS`
### v1.137 — Fill FVG mặc định 25% (thay 38.2%)
- `InpFvgUsedFillPct`, `InpMssEntryFillPct`, `InpMssH1MinFillPct` = 25
### v1.136 — FVG Used khi MSS OK (giữ giá)
- MSS khóa → `IctMss_MarkFvgUsedOnMssSuccess` (POI đã phục vụ, tiếp M5 FVG/entry)
- Used fail vs Used OK: cùng `ICT_FVG_USED`, journal khác nhau
- Pipeline MSS/entry vẫn chạy sau Used nếu `chochLocked`
### v1.135 — Tách AllowTrade vs FVG Used
- `AllowTrade=false`: pause MSS (`ResetPipelineKeepWatch`), **không** Used FVG
- `FVG Used`: chỉ khi H1 **body đóng xuyên** FVG (`IctMss_FailFvgH1Body`)
- `h1WatchFvgId`: theo dõi invalidation kể cả khi H1 lệch Bias
### v1.134 — FVG Used khi H1 body xuyên; skip FVG Used trong target
- `IctMss_SelectTargetH1Fvg`: bỏ qua mọi FVG Used
- MSS chỉ khóa nếu break sau `h1TouchTime`
### v1.133 — Retest = giá chạm FVG; H1 chỉ hủy khi body đóng xuyên
- Retest: `IctMss_HasFvgPriceTouch` (H1 touch / M5 overlap / giá live trong gap)
- Không còn “chờ râu H1”; `InpMssH1RetestWickOnly` legacy (bỏ qua)
- Hủy: `iClose` H1[1] xuyên FVG — râu xuyên vẫn chờ MSS
### v1.132 — MSS đơn giản: live L0/H0 M5 + hủy H1 body phá FVG
- `FVG_TOUCHED_WAIT_MSS`: cập nhật liên tục `liveL0`/`liveH0` từ `IctBuildConfirmSwingSet` (M5 bull khi bear HTF)
- MSS bear: body phá **L0** hiện tại → vẽ MSS tại L0, SL tại H0
- Hủy setup: mỗi nến H1 mới, body đóng **trên** FVG (bear) / **dưới** FVG (bull)
- Vào setup: H1 retest + ít nhất một nến M5 overlap H1 FVG
- Bỏ gate “MSS xa H1 FVG”; vẽ L0 live (nét chấm) trước khi khóa MSS
### v1.131 — EA state machine (STOP / SETUP / TRADE)
- `EaState.mqh`: `IctEaState_Refresh()`, panel 3 dòng state đầu
- STOP: no bias, range, H1 none, bias≠H1
- SETUP: WAIT_FVG_TOUCH → … → READY_FOR_LIMIT
- TRADE: LIMIT_ORDER_PENDING, ON_TRADE
### v1.130 — MSS = phá L0/H0 M5 (định nghĩa CHoCH đúng)
- Bear HTF: hồi Bearish H1 FVG → M5 pullback (bull cục bộ) → **MSS↓ = body phá L0** (đáy tạo H0)
@@ -564,7 +639,7 @@ ENUM_ICT_BIAS ICT2026_GetDailyBias();
### v1.126 — Thuật ngữ: Retest FVG H1 (POI), không ghi chung “H1 retest”
- Panel/journal: “Retest FVG H1”, “Chờ retest FVG H1 … (lấp trên H1)”
- `IctMss_HasH1FvgRetest`, `IctMss_TryLockMss`, `chochLocked`
- `IctMss_FailFvgH1Body`, `IctMss_CheckH1WatchInvalidation`, `chochLocked`
|
### v1.125 — MSS = phá swing M5 (confirm), build structure như chart
+12
View File
@@ -228,6 +228,12 @@ struct IctMssState
double pendingEntry;
double pendingSl;
double pendingTp;
double liveL0Price;
double liveH0Price;
datetime liveL0Time;
datetime liveH0Time;
datetime h1LastInvalidBarTime;
ulong h1WatchFvgId;
string displayReason;
void Clear()
@@ -246,6 +252,12 @@ struct IctMssState
pendingEntry = 0.0;
pendingSl = 0.0;
pendingTp = 0.0;
liveL0Price = 0.0;
liveH0Price = 0.0;
liveL0Time = 0;
liveH0Time = 0;
h1LastInvalidBarTime = 0;
h1WatchFvgId = 0;
displayReason = "";
}
};