Optimize logic mss lock đang có vấn đề: Sau khi used/xuyên fvg mss có vẻ chưa reset đợi FVG mới
This commit is contained in:
@@ -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 <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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
+175
-99
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user