From 21e65f95af984b5bd5d4f16cd521e369178440d2 Mon Sep 17 00:00:00 2001 From: Bell Date: Sun, 7 Dec 2025 00:06:14 +0700 Subject: [PATCH] =?UTF-8?q?Ki=E1=BB=83m=20tra=20mss=20thu=E1=BA=ADn=20chi?= =?UTF-8?q?=E1=BB=81u=20t=E1=BA=A1i=20MTF=20FVG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Experts/EA_ICT_v2.mq5 | 204 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 198 insertions(+), 6 deletions(-) diff --git a/Experts/EA_ICT_v2.mq5 b/Experts/EA_ICT_v2.mq5 index 0c233dc..cd291a2 100644 --- a/Experts/EA_ICT_v2.mq5 +++ b/Experts/EA_ICT_v2.mq5 @@ -7,6 +7,16 @@ #property version "2.00" #property strict +// --- Watch MSS mode (user requested) --- +bool watchMSSMode = false; // mặc định false +int watchedFVGIndex = -1; // index trong FVG_* arrays (khi watchMSSMode==true) +int watchedFVGDir = 0; // 1 = bullish FVG, -1 = bearish FVG + +// --- Mảng trạng thái: MTF FVG đã bị chạm bởi LTF hay chưa --- +bool MTF_FVG_Touched[]; // true = MTF FVG k đã bị LTF chạm +datetime MTF_FVG_TouchTime[]; // thời điểm bar LTF đầu tiên chạm zone (datetime) +double MTF_FVG_TouchPrice[]; // giá chạm đại diện (low khi bullish, high khi bearish) + // Bật/tắt MSS detection cho từng TF input bool DetectMSS_HTF = false; input bool DetectMSS_MTF = false; @@ -14,7 +24,7 @@ input bool DetectMSS_LTF = true; // Cấu hình Swing input int htfSwingRange = 2; // X: số nến trước và sau để xác định 1 đỉnh/đáy -input int mtfSwingRange = 2; // X: số nến trước và sau để xác định 1 đỉnh/đáy +input int mtfSwingRange = 3; // X: số nến trước và sau để xác định 1 đỉnh/đáy input int ltfSwingRange = 2; // X: số nến trước và sau để xác định 1 đỉnh/đáy input int MaxSwingKeep = 2; // Số đỉnh/đáy gần nhất cần lưu (bạn yêu cầu 2) @@ -69,7 +79,7 @@ struct MSSInfo { bool found; // true nếu tìm thấy MSS int direction; // 1 = down->up (bull MSS), -1 = up->down (bear MSS) datetime sweep_time; // thời điểm bar "sweep" (bar quét thanh khoản) - double sweep_price; // giá (râu) bị sweep (low cho bull, high cho bear) + double sweep_price; // giá swing gốc bị phá // --- thêm: swing gốc đã bị swept (time/price) --- datetime swept_swing_time; // time của swing bar trước khi bị sweep (ví dụ l0/h0 tại thời điểm detect) double swept_swing_price; // giá swing gốc @@ -80,7 +90,7 @@ struct MSSInfo { // --- thêm: swing gốc bị broken (time/price) --- datetime broken_swing_time; // time của swing bar bị phá (ví dụ sh0/sl0 tại thời điểm detect) - double broken_swing_price; // giá swing gốc bị phá + double low_sweap_price; // giá đóng nến của bos }; // Kết quả BOS @@ -109,6 +119,169 @@ string BOS_Names[3][2]; // tên objects (composite) cho mỗi store entry int BOS_Count[3] = {0,0,0}; // số BOS hiện có cho mỗi slot (0..2) bool BOS_HaveZone[3][2]; // flag có zone hay không +// ----------------------------------------------------------------- +// - Dùng mảng global FVG_top/FVG_bottom/FVG_timeC/FVG_type +// - Quét từng FVG và kiểm tra trên LowTF xem có bar nào *sau* FVG_timeC +// chạm zone không. Nếu có -> đánh dấu touched + lưu thời gian/giá +// - Gọi hàm này sau khi EnsureFVGUpToDate() được gọi +// ----------------------------------------------------------------- +void UpdateMTFFVGTouched(string symbol) +{ + // ensure global FVG arrays exist + if(FVG_count <= 0) + { + // ensure arrays are empty if none + ArrayFree(MTF_FVG_Touched); ArrayFree(MTF_FVG_TouchTime); ArrayFree(MTF_FVG_TouchPrice); + return; + } + + // ensure arrays sized to FVG_count + int oldSize = ArraySize(MTF_FVG_Touched); + if(oldSize != FVG_count) + { + ArrayResize(MTF_FVG_Touched, FVG_count); + ArrayResize(MTF_FVG_TouchTime, FVG_count); + ArrayResize(MTF_FVG_TouchPrice, FVG_count); + // init new slots false/0 + for(int i=0;i= oldSize) + { + MTF_FVG_Touched[i] = false; + MTF_FVG_TouchTime[i] = 0; + MTF_FVG_TouchPrice[i] = 0.0; + } + } + } + + double point = SymbolInfoDouble(symbol, SYMBOL_POINT); + double tol = (point > 0.0) ? point * 0.5 : 0.0; + + // scan each MTF FVG + for(int k = 0; k < FVG_count; k++) + { + // if already touched, skip (keeps first-touch) + if(MTF_FVG_Touched[k]) continue; + + datetime mtfC = FVG_timeC[k]; + if(mtfC == 0) continue; + + double top = FVG_top[k]; + double bottom = FVG_bottom[k]; + int dir = FVG_type[k]; // 1=bull, -1=bear + + // find index of mtfC on LowTF + int idxC_on_LTF = iBarShift(symbol, LowTF, mtfC, false); + if(idxC_on_LTF == -1) idxC_on_LTF = 0; + + bool touched = false; + datetime touch_time = 0; + double touch_price = 0.0; + + // scan forward on LowTF (bars newer than mtfC): idx = idxC_on_LTF-1 ... 0 + int barsAvail = iBars(symbol, LowTF); + for(int idx = idxC_on_LTF - 1; idx >= 0; idx--) + { + double hh = iHigh(symbol, LowTF, idx); + double ll = iLow(symbol, LowTF, idx); + if(hh == 0 || ll == 0) continue; + + // --- NEW: touch only on specific edge depending on FVG direction --- + if(dir == 1) // bullish FVG -> touch only when price reaches the UPPER edge (top) + { + // if the bar's high reaches or exceeds the top (allow small tol) + if(hh >= top - tol) + { + touched = true; + touch_time = iTime(symbol, LowTF, idx); + // representative price: use the exact edge price (top) + touch_price = top; + break; + } + } + else // dir == -1 -> bearish FVG -> touch only when price reaches the LOWER edge (bottom) + { + // if the bar's low reaches or goes below the bottom (allow small tol) + if(ll <= bottom + tol) + { + touched = true; + touch_time = iTime(symbol, LowTF, idx); + // representative price: use the exact edge price (bottom) + touch_price = bottom; + break; + } + } + } + + if(touched) + { + MTF_FVG_Touched[k] = true; + MTF_FVG_TouchTime[k] = touch_time; + MTF_FVG_TouchPrice[k] = touch_price; + if(PrintToExperts) + PrintFormat("UpdateMTFFVGTouched: MTF FVG idx=%d dir=%d touched at %s price=%.5f", k, dir, TimeToString(touch_time, TIME_DATE|TIME_MINUTES), touch_price); + + // --- NEW: enable watchMSSMode when any MTF FVG is first touched --- + if(!watchMSSMode) + { + watchMSSMode = true; + watchedFVGIndex = k; + watchedFVGDir = dir; + if(PrintToExperts) + PrintFormat("watchMSSMode ENABLED for FVG idx=%d dir=%d", watchedFVGIndex, watchedFVGDir); + } + } + } // end for each FVG +} + +// Kiểm tra điều kiện vô hiệu hoá watchMSSMode: +// 1) last closed candle trên LowTF đóng dưới cạnh dưới của bullish FVG +// 2) last closed candle trên LowTF đóng trên cạnh trên của bearish FVG +void CheckWatchMSSInvalidation(string symbol) +{ + if(!watchMSSMode || watchedFVGIndex < 0 || watchedFVGIndex >= FVG_count) return; + + // Lấy last closed close trên LowTF (index 1) + double lastClose = iClose(symbol, LowTF, 1); + if(lastClose == 0.0) return; + + double point = SymbolInfoDouble(symbol, SYMBOL_POINT); + double tol = (point > 0.0) ? point * 0.5 : 0.0; + + int idx = watchedFVGIndex; + int dir = watchedFVGDir; + + // bảo đảm FVG arrays còn hợp lệ + if(idx < 0 || idx >= FVG_count) return; + + double top = FVG_top[idx]; + double bottom = FVG_bottom[idx]; + + // Nếu bullish FVG (dir == 1): invalid khi đóng dưới bottom + if(dir == 1) + { + if(lastClose < bottom - tol) + { + if(PrintToExperts) PrintFormat("CheckWatchMSSInvalidation: bullish FVG idx=%d invalidated by close=%.5f < bottom=%.5f", idx, lastClose, bottom); + // clear + watchMSSMode = false; + watchedFVGIndex = -1; + watchedFVGDir = 0; + } + } + else if(dir == -1) // bearish: invalid khi đóng trên top + { + if(lastClose > top + tol) + { + if(PrintToExperts) PrintFormat("CheckWatchMSSInvalidation: bearish FVG idx=%d invalidated by close=%.5f > top=%.5f", idx, lastClose, top); + // clear + watchMSSMode = false; + watchedFVGIndex = -1; + watchedFVGDir = 0; + } + } +} + void StoreNewBOS(int slot, const BOSInfo &bos) { // Nếu chưa có BOS nào @@ -1082,10 +1255,10 @@ void DrawMss(string symbol, ENUM_TIMEFRAMES tf, const MSSInfo &mss, int slot) if(t_swing == 0 || p_swing == 0.0) { // try broken swing - if(mss.broken_swing_time != 0 && mss.broken_swing_price != 0.0) + if(mss.broken_swing_time != 0 && mss.low_sweap_price != 0.0) { t_swing = mss.broken_swing_time; - p_swing = mss.broken_swing_price; + p_swing = mss.low_sweap_price; } else if(mss.sweep_time != 0 && mss.sweep_price != 0.0) { @@ -1659,6 +1832,7 @@ void DetectMSSOnTimeframe(string sym, ENUM_TIMEFRAMES tf, int slot, bool enabled double tol = pip * 0.1; // tolerance nhỏ double sweep_price = older.broken_sw_price; // **important** double break_price = newer.broken_sw_price; // **important** + double low_sweap_price = sweep_price; if(sweep_price == 0.0 || break_price == 0.0) { @@ -1695,7 +1869,7 @@ void DetectMSSOnTimeframe(string sym, ENUM_TIMEFRAMES tf, int slot, bool enabled mss.swept_swing_time = older.broken_sw_time; mss.swept_swing_price = older.broken_sw_price; mss.broken_swing_time = newer.broken_sw_time; - mss.broken_swing_price = newer.broken_sw_price; + mss.low_sweap_price = low_sweap_price; mss.key_level = newer.broken_sw_price; if(PrintToExperts) @@ -1704,6 +1878,21 @@ void DetectMSSOnTimeframe(string sym, ENUM_TIMEFRAMES tf, int slot, bool enabled TimeToString(older.break_time, TIME_DATE|TIME_MINUTES), TimeToString(newer.break_time, TIME_DATE|TIME_MINUTES)); + // Giá vừa chạm MTF FVG (vùng vào lệnh tiềm năng) + if(watchMSSMode && watchedFVGIndex >= 0) + { + // Nếu MSS direction trùng với FVG direction -> MSS thuận chiều + if(mss.found && mss.direction == watchedFVGDir) + { + if(PrintToExperts) PrintFormat("DetectMSSOnTimeframe: MSS direction %d matches watchedFVGDir %d -> disabling watchMSSMode", mss.direction, watchedFVGDir); + watchMSSMode = false; + watchedFVGIndex = -1; + watchedFVGDir = 0; + + SetUpPendingEntryForMSS(mss, slot); + } + } + DrawMss(sym, tf, mss, slot); } @@ -1743,7 +1932,10 @@ void OnTick() if(IsNewClosedBar(sym, LowTF, 2)) { HandleLogicForTimeframe(sym, LowTF, 2, DetectMSS_LTF, ltfSwingRange, true, 10.0, 2, 50, FVGLookback); + CheckWatchMSSInvalidation(sym); } + + UpdateMTFFVGTouched(sym); } int OnInit()