From cddec2320e983e53465ea5afbc5c62e75939e80f Mon Sep 17 00:00:00 2001 From: Bell Date: Sun, 24 May 2026 23:28:13 +0700 Subject: [PATCH] =?UTF-8?q?Optimize=20logic=20mss=20lock=20=C4=91ang=20c?= =?UTF-8?q?=C3=B3=20v=E1=BA=A5n=20=C4=91=E1=BB=81:=20Sau=20khi=20used/xuy?= =?UTF-8?q?=C3=AAn=20fvg=20mss=20c=C3=B3=20v=E1=BA=BB=20ch=C6=B0a=20reset?= =?UTF-8?q?=20=C4=91=E1=BB=A3i=20FVG=20m=E1=BB=9Bi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Experts/ICT_2026.mq5 | 2 +- Include/ICT2026/Config.mqh | 11 +- Include/ICT2026/Fvg.mqh | 11 ++ Include/ICT2026/MssDraw.mqh | 13 +- Include/ICT2026/MssSetup.mqh | 274 ++++++++++++++++++++++------------- Include/ICT2026/README.md | 43 +++++- 6 files changed, 236 insertions(+), 118 deletions(-) diff --git a/Experts/ICT_2026.mq5 b/Experts/ICT_2026.mq5 index 080ef6e..8136de4 100644 --- a/Experts/ICT_2026.mq5 +++ b/Experts/ICT_2026.mq5 @@ -3,7 +3,7 @@ //| BOS = Continue | CHoCH = Reversal | //+------------------------------------------------------------------+ #property copyright "ICT 2026" -#property version "1.127" +#property version "1.130" #property description "ICT2026 MSS limit entry + SL swing CHoCH + TP intraday" #include diff --git a/Include/ICT2026/Config.mqh b/Include/ICT2026/Config.mqh index 8aa7bf2..7618abf 100644 --- a/Include/ICT2026/Config.mqh +++ b/Include/ICT2026/Config.mqh @@ -35,7 +35,7 @@ input int InpChartLabelFontSize = 9; input group "══ Confirm swing (M5) ══" input ENUM_TIMEFRAMES InpConfirmTf = PERIOD_M5; // TF confirmation (tương lai) -input int InpConfirmSwingRange = 2; +input int InpConfirmSwingRange = 1; input int InpConfirmSwingLookback = 80; input int InpConfirmRecentBars = 40; @@ -45,9 +45,9 @@ input ENUM_TIMEFRAMES InpFvgTf = PERIOD_H1; // Quét FVG (mặc input int InpFvgLookbackBars = 60; // Bar quét FVG (full / khi Allow bật) input int InpFvgScanBarsPerUpdate = 40; // Mỗi nến mới: quét lại N bar gần nhất input int InpFvgAtrPeriod = 14; // ATR cho lọc kích thước gap -input double InpFvgMinGapATRPct = 12.0; // Gap tối thiểu (% ATR, 0=tắt) -input double InpFvgMinGapPoints = 0.0; // Gap tối thiểu (giá, 0=chỉ ATR) -input double InpFvgMinGapVsBarPct = 25.0; // Gap >= % range nến giữa B (0=tắt) +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 int InpFvgExpireDays = 3; // Xóa Available sau N ngày input int InpFvgMaxZones = 24; // Số FVG tối đa trên chart @@ -59,7 +59,8 @@ input color InpPdPremiumColor = clrMaroon; input color InpPdDiscountColor = clrDarkGreen; input group "══ MSS / Entry (Confirm TF) ══" -input double InpMssH1MinFillPct = 38.2; // Retest FVG H1 (POI): % lấp tối thiểu trên H1 +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 int InpMssConfirmLookback = 80; // Lookback pivot CHoCH trên Confirm TF input int InpMssConfirmFvgBars = 40; // Quét M5 FVG sau CHoCH diff --git a/Include/ICT2026/Fvg.mqh b/Include/ICT2026/Fvg.mqh index adfaea8..1599bc5 100644 --- a/Include/ICT2026/Fvg.mqh +++ b/Include/ICT2026/Fvg.mqh @@ -47,10 +47,18 @@ string IctPdZoneText(const ENUM_ICT_PD_ZONE zone) } } +bool IctFvg_UseGapSizeFilter(const ENUM_TIMEFRAMES tf) +{ + return (tf == InpFvgTf); +} + double IctFvg_MinRequiredGapHeight(const string sym, const ENUM_TIMEFRAMES tf, const int shiftC) { double minH = 0.0; + if(!IctFvg_UseGapSizeFilter(tf)) + return 0.0; + if(InpFvgMinGapPoints > 0.0) minH = MathMax(minH, InpFvgMinGapPoints); @@ -77,6 +85,9 @@ bool IctFvg_IsValidGapSize(const string sym, const ENUM_TIMEFRAMES tf, const int if(height <= _Point) return false; + if(!IctFvg_UseGapSizeFilter(tf)) + return true; + const double minH = IctFvg_MinRequiredGapHeight(sym, tf, shiftC); if(minH > 0.0 && height + _Point * 0.5 < minH) return false; diff --git a/Include/ICT2026/MssDraw.mqh b/Include/ICT2026/MssDraw.mqh index e9a0f21..dee80e9 100644 --- a/Include/ICT2026/MssDraw.mqh +++ b/Include/ICT2026/MssDraw.mqh @@ -151,24 +151,25 @@ void IctMssDraw_Render(const string sym) chochT = keyT; const color clrChoch = clrGold; - const string chochLbl = isBear ? " CHoCH↓ " : " CHoCH↑ "; + const string chochLbl = isBear ? " MSS↓ L0 " : " MSS↑ H0 "; const bool chochAbove = !isBear; - const datetime tChoch = (chochT > 0) ? chochT : keyT; + 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", tChoch, tEnd, keyLv, clrChoch, + IctMssDraw_HLine("CHOCH", tLineStart, tEnd, keyLv, clrChoch, chochPending ? STYLE_DASH : STYLE_SOLID, 2); - IctMssDraw_Label("CHOCH_LBL", chochLbl, tEnd, keyLv, chochAbove, clrChoch); + IctMssDraw_Label("CHOCH_LBL", chochLbl, tChoch, keyLv, chochAbove, clrChoch); } if(slSwing > 0.0) { const string swTag = isBear ? " H0 " : " L0 "; const color clrSw = clrYellow; - datetime tSw = (chochT > 0) ? chochT : ((keyT > 0) ? keyT : tTouch); + datetime tSw = (keyT > 0) ? keyT : tTouch; IctMssDraw_HLine("MSS_SW", tSw, tEnd, slSwing, clrSw, STYLE_DASH, 1); - IctMssDraw_Label("MSS_SW_LBL", swTag, tEnd, slSwing, true, clrSw); + IctMssDraw_Label("MSS_SW_LBL", swTag, tSw, slSwing, true, clrSw); } if(mss.pendingEntry > 0.0 && mss.phase >= ICT_MSS_M5_FVG) diff --git a/Include/ICT2026/MssSetup.mqh b/Include/ICT2026/MssSetup.mqh index 1fa3f25..ed8b4b8 100644 --- a/Include/ICT2026/MssSetup.mqh +++ b/Include/ICT2026/MssSetup.mqh @@ -1,5 +1,5 @@ //+------------------------------------------------------------------+ -//| MssSetup.mqh — MSS: retest FVG H1 (POI) → CHoCH M5 → M5 FVG → entry | +//| MssSetup.mqh — MSS: retest FVG H1 → M5 MSS (phá L0/H0) → M5 FVG → entry | //+------------------------------------------------------------------+ #ifndef ICT2026_MSSSETUP_MQH #define ICT2026_MSSSETUP_MQH @@ -13,7 +13,7 @@ string IctMssPhaseText(const ENUM_ICT_MSS_PHASE ph) switch(ph) { case ICT_MSS_H1_TOUCH: return "Retest FVG H1 OK"; - case ICT_MSS_CHOCH: return "CHoCH 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_READY: return "READY entry"; @@ -57,12 +57,19 @@ int IctMss_SelectTargetH1Fvg() return bestIdx; } -// Retest FVG H1 (POI): giá chạm gap H1 + lấp ≥ InpMssH1MinFillPct (đo trên InpFvgTf, không phải M5) +// 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) { IctFvg_UpdateZoneState(sym, InpFvgTf, h1); if(h1.firstTouchTime <= 0) return false; + + if(InpMssH1RetestWickOnly) + { + h1.mssH1Touch382 = true; + return true; + } + if(!IctFvg_HasFillAtLeast(h1, InpMssH1MinFillPct)) return false; h1.mssH1Touch382 = true; @@ -171,17 +178,28 @@ bool IctMss_BodyBrokeLevelSince(const string sym, const ENUM_TIMEFRAMES tf, return false; } -IctSwingPoint IctMss_NewestSwingLowBefore(const IctSwingPoint &lows[], const int nL, - const int barShift, const datetime afterTime) +bool IctMss_BarOverlapsFvg(const IctFvgZone &h1, const double barHi, const double barLo) +{ + 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++) { - if(lows[i].shift <= barShift) + if(lows[i].time < tTouch) continue; - if(lows[i].time < afterTime) + 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; @@ -191,17 +209,23 @@ IctSwingPoint IctMss_NewestSwingLowBefore(const IctSwingPoint &lows[], const int return lows[best]; } -IctSwingPoint IctMss_NewestSwingHighBefore(const IctSwingPoint &highs[], const int nH, - const int barShift, const datetime afterTime) +IctSwingPoint IctMss_ProtectedHighAfterLow(const IctSwingPoint &highs[], const int nH, + const IctSwingPoint &l0, + const datetime tTouch) { IctSwingPoint empty; empty.Clear(); + if(!l0.Valid()) + return empty; + int best = -1; for(int i = 0; i < nH; i++) { - if(highs[i].shift <= barShift) + if(highs[i].time < tTouch || highs[i].time < l0.time) continue; - if(highs[i].time < afterTime) + 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; @@ -211,44 +235,18 @@ IctSwingPoint IctMss_NewestSwingHighBefore(const IctSwingPoint &highs[], const i return highs[best]; } -double IctMss_MaxHighSince(const string sym, const ENUM_TIMEFRAMES tf, - const int fromShift, const int toShift, - const datetime afterTime) +bool IctMss_ReactionHighAfterTouch(const string sym, const ENUM_TIMEFRAMES tf, + const IctFvgZone &h1, const datetime tTouch, + IctSwingPoint &outHi) { - double hi = -DBL_MAX; - for(int sh = fromShift; sh >= toShift; sh--) + outHi.Clear(); + IctSwingSet sw; + ENUM_ICT_STRUCT st = ICT_STRUCT_NONE; + if(IctBuildConfirmSwingSet(sym, sw, st) && sw.hasH0 && sw.h0.time >= tTouch) { - if(iTime(sym, tf, sh) < afterTime) - continue; - hi = MathMax(hi, iHigh(sym, tf, sh)); + outHi = sw.h0; + return true; } - return (hi > -DBL_MAX * 0.5) ? hi : 0.0; -} - -double IctMss_MinLowSince(const string sym, const ENUM_TIMEFRAMES tf, - const int fromShift, const int toShift, - const datetime afterTime) -{ - double lo = DBL_MAX; - for(int sh = fromShift; sh >= toShift; sh--) - { - if(iTime(sym, tf, sh) < afterTime) - continue; - lo = MathMin(lo, iLow(sym, tf, sh)); - } - return (lo < DBL_MAX * 0.5) ? lo : 0.0; -} - -// CHoCH/MSS thời điểm: nến M5 đầu tiên (sau retest FVG H1) body phá swing — khóa, không đổi khi pivot update -bool IctMss_FindFirstChochAfterFvgRetest(const string sym, const ENUM_TIMEFRAMES tf, - const datetime tTouch, const ENUM_ICT_BIAS bias, - double &keyLevelOut, datetime &keyTimeOut, - datetime &chochBarTimeOut, double &slSwingOut) -{ - keyLevelOut = 0.0; - keyTimeOut = 0; - chochBarTimeOut = 0; - slSwingOut = 0.0; int touchSh = iBarShift(sym, tf, tTouch, true); if(touchSh < 0) @@ -256,6 +254,77 @@ bool IctMss_FindFirstChochAfterFvgRetest(const string sym, const ENUM_TIMEFRAMES 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(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); @@ -263,52 +332,52 @@ bool IctMss_FindFirstChochAfterFvgRetest(const string sym, const ENUM_TIMEFRAMES if(bias == ICT_BIAS_BEAR) { - for(int sh = touchSh; sh >= 1; sh--) - { - const datetime tBar = iTime(sym, tf, sh); - if(tBar < tTouch) - continue; + IctSwingPoint h0; + if(!IctMss_ReactionHighAfterTouch(sym, tf, h1, tTouch, h0)) + return false; - const IctSwingPoint keyLo = IctMss_NewestSwingLowBefore(lows, nL, sh, tTouch); - if(!keyLo.Valid()) + IctSwingPoint keyLo = IctMss_ProtectedLowBeforeHigh(lows, nL, h0, tTouch); + if(!keyLo.Valid()) + 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; - const double reactHi = IctMss_MaxHighSince(sym, tf, touchSh, sh, tTouch); - if(reactHi <= 0.0) - continue; - - keyLevelOut = keyLo.price; - keyTimeOut = keyLo.time; - chochBarTimeOut = tBar; - slSwingOut = reactHi; + keyLevelOut = keyLo.price; + keyTimeOut = keyLo.time; + mssBarTimeOut = iTime(sym, tf, sh); + slSwingOut = h0.price; return true; } } if(bias == ICT_BIAS_BULL) { - for(int sh = touchSh; sh >= 1; sh--) - { - const datetime tBar = iTime(sym, tf, sh); - if(tBar < tTouch) - continue; + IctSwingPoint l0; + if(!IctMss_ReactionLowAfterTouch(sym, tf, h1, tTouch, l0)) + return false; - const IctSwingPoint keyHi = IctMss_NewestSwingHighBefore(highs, nH, sh, tTouch); - if(!keyHi.Valid()) + IctSwingPoint keyHi = IctMss_ProtectedHighAfterLow(highs, nH, l0, tTouch); + if(!keyHi.Valid()) + 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; - const double reactLo = IctMss_MinLowSince(sym, tf, touchSh, sh, tTouch); - if(reactLo <= 0.0) - continue; - - keyLevelOut = keyHi.price; - keyTimeOut = keyHi.time; - chochBarTimeOut = tBar; - slSwingOut = reactLo; + keyLevelOut = keyHi.price; + keyTimeOut = keyHi.time; + mssBarTimeOut = iTime(sym, tf, sh); + slSwingOut = l0.price; return true; } } @@ -316,8 +385,8 @@ bool IctMss_FindFirstChochAfterFvgRetest(const string sym, const ENUM_TIMEFRAMES return false; } -bool IctMss_TryLockChoch(const string sym, const ENUM_TIMEFRAMES tf, - const IctFvgZone &h1, const ENUM_ICT_BIAS bias) +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; @@ -327,15 +396,15 @@ bool IctMss_TryLockChoch(const string sym, const ENUM_TIMEFRAMES tf, return false; double keyLv = 0.0, slSwing = 0.0; - datetime keyT = 0, chochBarT = 0; - if(!IctMss_FindFirstChochAfterFvgRetest(sym, tf, tTouch, bias, - keyLv, keyT, chochBarT, slSwing)) + datetime keyT = 0, mssBarT = 0; + if(!IctMss_FindMssAfterFvgRetest(sym, tf, h1, tTouch, bias, + keyLv, keyT, mssBarT, slSwing)) return false; g_ictLowTf.mss.chochKeyLevel = keyLv; g_ictLowTf.mss.chochKeyTime = keyT; g_ictLowTf.mss.slSwingPrice = slSwing; - g_ictLowTf.mss.chochTime = chochBarT; + g_ictLowTf.mss.chochTime = mssBarT; g_ictLowTf.mss.chochLocked = true; return true; } @@ -544,18 +613,23 @@ void IctMss_Update(const string sym) if(!IctMss_HasH1FvgRetest(sym, g_ictFvgZones[hIdx])) { - g_ictLowTf.mss.displayReason = StringFormat( - "Chờ retest FVG H1 %s [%.0f–%.0f] (%.0f%% lấp trên H1)", - IctPdZoneText(IctFvg_GetRepPd(g_ictFvgZones[hIdx])), - g_ictFvgZones[hIdx].lower, g_ictFvgZones[hIdx].upper, - InpMssH1MinFillPct); + 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); return; } g_ictLowTf.mss.phase = ICT_MSS_H1_TOUCH; g_ictLowTf.mss.h1TouchTime = g_ictFvgZones[hIdx].firstTouchTime; - g_ictLowTf.mss.displayReason = StringFormat("Retest FVG H1 OK | lấp %.0f%% (H1)", - g_ictFvgZones[hIdx].maxFillRatio * 100.0); + 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); } const int h1Idx = IctMss_FindH1FvgById(g_ictLowTf.mss.h1FvgId); @@ -579,29 +653,31 @@ void IctMss_Update(const string sym) if(g_ictLowTf.mss.phase == ICT_MSS_H1_TOUCH) { - if(!IctMss_TryLockChoch(sym, cTf, g_ictFvgZones[h1Idx], g_ictDailyBias.bias)) + if(!IctMss_TryLockMss(sym, cTf, g_ictFvgZones[h1Idx], g_ictDailyBias.bias)) { g_ictLowTf.mss.displayReason = (g_ictDailyBias.bias == ICT_BIAS_BEAR) ? - "Retest FVG H1 OK — chờ MSS↓ phá swing M5" : - "Retest FVG H1 OK — chờ MSS↑ phá swing M5"; + "Retest FVG H1 OK — chờ MSS↓ phá L0 M5" : + "Retest FVG H1 OK — chờ MSS↑ phá H0 M5"; return; } - const double keyLv = g_ictLowTf.mss.chochKeyLevel; - const double slSwing = g_ictLowTf.mss.slSwingPrice; - const datetime chochT = g_ictLowTf.mss.chochTime; + 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, chochT)) + keyLv, slSwing, mssT)) { g_ictLowTf.mss.displayReason = StringFormat( - "CHoCH khóa @ %.2f — xa H1 FVG, chờ gần hơn", keyLv); + "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 = StringFormat("CHoCH khóa @ %.2f — quét M5 FVG", keyLv); + 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); } if(g_ictLowTf.mss.phase == ICT_MSS_CHOCH) @@ -611,7 +687,7 @@ void IctMss_Update(const string sym) const int mIdx = IctConfirmFvg_FindLatestAfter(g_ictLowTf.mss.chochTime, wantSide); if(mIdx < 0) { - g_ictLowTf.mss.displayReason = "CHoCH OK — chờ M5 FVG"; + g_ictLowTf.mss.displayReason = "MSS OK — chờ M5 FVG"; return; } diff --git a/Include/ICT2026/README.md b/Include/ICT2026/README.md index d381ef3..1b5a59a 100644 --- a/Include/ICT2026/README.md +++ b/Include/ICT2026/README.md @@ -212,15 +212,27 @@ FVG Used **không** kéo dài P/D thêm; P/D độc lập với Used (theo swing ### Retest FVG H1 (POI) — không nhầm với retest swing H1 -**Retest FVG H1** = giá **hồi vào gap Fair Value Gap trên H1** (vùng POI đã chọn), đo trên **`InpFvgTf` (H1)**: +**Retest FVG H1** = giá **hồi vào gap Fair Value Gap trên H1** (vùng POI), đo trên **`InpFvgTf` (H1)**: | | | |--|--| -| **Chạm** | `firstTouchTime` — nến H1 đầu tiên chạm vùng `[lower … upper]` | -| **Lấp %** | Từ cạnh FVG (`lower`→`upper` bear) — ≥ `InpMssH1MinFillPct` (mặc định 38.2%) | -| **Không phải** | Retest swing/pivot H1; retest trên M5; retest đường Premium/Discount riêng | +| **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) | -Sau retest FVG H1 OK → mới arm MSS trên **M5** (phá swing confirm). +**Định nghĩa MSS vs CHoCH (cùng rule Key H0/L0):** + +| HTF bias | M5 cục bộ trước MSS | MSS = | SL swing | +|----------|---------------------|-------|----------| +| Bear (H1↓) | Pullback tăng (bull M5) | Body phá **L0** (đáy tạo H0) | **H0** | +| Bull (H1↑) | Pullback giảm (bear M5) | Body phá **H0** (đỉnh tạo L0) | **L0** | + +CHoCH trên D/H1 = phá key level **ngược** xu hướng HTF (bull→bear phá L0; bear→bull phá H0). MSS trên M5 = cùng rule nhưng trên **pullback cục bộ** sau retest FVG H1. +| **Không phải** | Retest swing H1; bắt buộc body H1 lấp sâu vào gap (khi wick-only bật) | + +**FVG size filter:** `InpFvgMinGap*` chỉ áp dụng **`InpFvgTf` (H1)**. **M5** (`InpConfirmTf`) — không lọc ATR → phát hiện FVG M5 nhỏ. + +Sau retest FVG H1 OK → arm MSS trên M5. ### MSS entry (Confirm TF, v1.115) @@ -229,7 +241,7 @@ Khi `IsAllowTrade`, state machine `g_ictLowTf.mss`: | Phase | Điều kiện | |-------|-----------| | `H1_TOUCH` | **Retest FVG H1** OK: bias + `repPd` + lấp ≥ `InpMssH1MinFillPct` trên H1 | -| `CHOCH` | Sau retest FVG H1: **khóa** lần phá swing M5 đầu tiên (`chochLocked`) — không đổi khi H0/L0 update | +| `CHOCH` (MSS) | Sau retest FVG H1: M5 pullback → **phá L0** (bear HTF) hoặc **phá H0** (bull HTF); khóa `chochLocked` | | `M5_FVG` | FVG `InpConfirmTf` cùng hướng bias, sau thời điểm CHoCH | | `ENTRY_FILL` / `READY` | Giá hồi lấp ≥ `InpMssEntryFillPct` vào M5 FVG đó | @@ -527,6 +539,22 @@ ENUM_ICT_BIAS ICT2026_GetDailyBias(); ## Changelog +### 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) +- Bull HTF: hồi Bullish H1 FVG → M5 pullback (bear cục bộ) → **MSS↑ = body phá H0** +- SL: H0 (sell) / L0 (buy); đường MSS = mức L0/H0 bị phá + +### v1.129 — CHoCH POI: H0/L0 cục bộ trong FVG (giống ví dụ ICT) + +- Bear: đỉnh phản ứng **trong H1 FVG** → L0 cục bộ → CHoCH↓ phá L0 (không dùng L1 xa POI) +- Vẽ: đường CHoCH = mức **bị phá**; `H0 POI` = đỉnh phản ứng tại gap + +### v1.128 — FVG M5 nhỏ; retest H1 = râu chạm POI + +- Lọc gap ATR/points/bar%: **chỉ H1**; M5 confirm FVG không lọc kích thước +- `InpMssH1RetestWickOnly` (mặc định true): arm MSS khi râu H1 chạm FVG, không cần thân lấp % + ### v1.127 — CHoCH khóa thời điểm (không nhảy theo swing M5) - `IctMss_FindFirstChochAfterFvgRetest`: nến M5 **đầu tiên** sau retest FVG H1 body phá swing @@ -536,7 +564,8 @@ 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_TryLockChoch`, `chochLocked` +- `IctMss_HasH1FvgRetest`, `IctMss_TryLockMss`, `chochLocked` + | ### v1.125 — MSS = phá swing M5 (confirm), build structure như chart