From 3591694c968f8610a4bc6a96157a9eff2930e8e8 Mon Sep 17 00:00:00 2001 From: Bell Date: Tue, 10 Mar 2026 04:22:02 +0700 Subject: [PATCH] =?UTF-8?q?Update.=20C=E1=BA=A7n=20=C4=91=E1=BB=8Dc=20hi?= =?UTF-8?q?=E1=BB=83u=20c=E1=BA=B7n=20k=E1=BA=BD=20logic=20t=C3=ACm=20FVG?= =?UTF-8?q?=20v=C3=A0=20logic=20mss?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Experts/EA_ICT_CL.mq5 | 254 ++++++++++++++++++++++-------------------- 1 file changed, 136 insertions(+), 118 deletions(-) diff --git a/Experts/EA_ICT_CL.mq5 b/Experts/EA_ICT_CL.mq5 index 6080f42..85b997e 100644 --- a/Experts/EA_ICT_CL.mq5 +++ b/Experts/EA_ICT_CL.mq5 @@ -1,5 +1,5 @@ //+------------------------------------------------------------------+ -//| ICT EA – FVG Edition (MQL5) v4.0 | +//| ICT EA – FVG Edition (MQL5) v4.3 | //| Architecture : BiasTF(D1) + MiddleTF(H1) + TriggerTF(M5) | //| State Machine: IDLE → WAIT_TOUCH → WAIT_TRIGGER → IN_TRADE | //| | @@ -7,17 +7,18 @@ //| 1. D1 bias (UP/DOWN) đồng thuận H1 trend | //| 2. H1 FVG thuận xu hướng → chờ price retrace vào FVG | //| 3. Giá touch H1 FVG → chờ M5 MSS xác nhận đảo chiều | -//| 4. M5 MSS = keyLevel sóng hồi bị phá: | -//| - H1 UP: M5 đang downtrend (hồi), tH0 bị phá (close>tH0) | -//| - H1 DOWN: M5 đang uptrend (hồi), tL0 bị phá (close tH0 (phá swing high) = bull MSS | +//| - H1 DOWN → close < tL0 (phá swing low) = bear MSS | +//| v4.3: MSS chỉ detect khi WAIT_TRIGGER, không vẽ/detect khác | +//| 5. Entry = limit tại swing level vừa bị phá (tH0 hoặc tL0) | +//| 6. SL = swing đối diện (tL0 cho buy, tH0 cho sell) | //| 7. TP = Entry ± 2R | //| | //| Drawing: objects KHÔNG BAO GIỜ bị xóa, chỉ update | //+------------------------------------------------------------------+ #property copyright "Bell's ICT EA" -#property version "4.00" +#property version "4.30" #define MAX_FVG_POOL 30 @@ -41,10 +42,10 @@ input int InpSwingRange = 3; // Bars each side for swi input int InpSwingLookback = 50; // MiddleTF swing scan bars input int InpTriggerSwingLookback = 30; // TriggerTF swing scan bars -input int InpFVGMaxAliveMin = 4320; // Max PENDING lifetime (min) = 72h +input int InpFVGMaxAliveMin = 4320; // Max FVG lifetime (min) = 72h (cả PENDING + TOUCHED) input int InpFVGScanBars = 50; // MiddleTF bars to scan for FVGs input double InpFVGMinBodyPct = 60.0; // Mid-candle min body % -input int InpTriggerMaxBars = 30; // Trigger timeout (TriggerTF bars) +input int InpMSSMinDepthPts = 30; // MSS min swing depth (points): |tH0-tL0| phải >= giá trị này input long InpMagicNumber = 20250308; // EA magic number input int InpSlippage = 5; // Max slippage (points) @@ -90,14 +91,11 @@ struct BiasContext //---------------------------------------------------------------------- // TFTrendContext – Swing structure + MSS // -// v4 MSS (đơn giản): -// MSS = keyLevel sóng hồi trên TriggerTF bị phá vỡ -// - H1 UP → M5 đang DOWN (hồi) → tH0 bị phá (close > tH0) = bull MSS -// - H1 DOWN → M5 đang UP (hồi) → tL0 bị phá (close < tL0) = bear MSS -// -// Entry = giá keyLevel vừa bị phá (đặt limit chờ giá hồi) -// SL = swing extreme sóng hồi (tL0 cho buy, tH0 cho sell) -// Cả 2 được capture TRƯỚC khi re-scan swing. +// v4.3: MSS CHỈ detect cho TriggerTF, CHỈ khi WAIT_TRIGGER state. +// Không detect MSS cho MiddleTF (không dùng cho entry). +// MSS check chạy TRƯỚC re-scan → dùng OLD swing values: +// - H1 UP → close > OLD tH0 = bull MSS → entry=tH0, SL=tL0 +// - H1 DOWN → close < OLD tL0 = bear MSS → entry=tL0, SL=tH0 //---------------------------------------------------------------------- struct TFTrendContext { @@ -127,6 +125,11 @@ struct FVGRecord datetime touchTime; // Thời gian bid đầu tiên vào vùng gap datetime usedTime; // Thời gian FVG bị consumed (broken/expired/triggered) MarketDir triggerTrendAtTouch; // M5 trend tại thời điểm touch (dùng cho case2 check) + + // v4.3: MSS info lưu khi triggered (case2) → dùng cho vẽ + order + datetime mssTime; // Thời gian cây nến MSS + double mssEntry; // Entry = swing bị phá (tH0 hoặc tL0) + double mssSL; // SL = swing đối diện (tL0 hoặc tH0) }; struct OrderPlan @@ -151,8 +154,8 @@ EAState g_State = EA_IDLE; // State machine hiện tại BlockReason g_BlockReason = BLOCK_NONE; // Lý do bị block (nếu có) BiasContext g_Bias; // D1 bias context -TFTrendContext g_MiddleTrend; // H1 trend + swing + MSS -TFTrendContext g_TriggerTrend; // M5 trend + swing + MSS (entry trigger) +TFTrendContext g_MiddleTrend; // H1 trend + swing (không MSS) +TFTrendContext g_TriggerTrend; // M5 swing + MSS (chỉ khi WAIT_TRIGGER) DailyRiskContext g_DailyRisk; // Daily drawdown tracking FVGRecord g_FVGPool[MAX_FVG_POOL]; // Pool chứa tối đa 30 FVG records @@ -285,18 +288,10 @@ void UpdateBiasContext() //---------------------------------------------------------------------- // UpdateTFTrendContext // -// Gọi mỗi bar mới. Thực hiện TRƯỚC khi re-scan swing: -// -// v4 MSS check (TriggerTF only): -// - M5 đang downtrend (hồi khi H1 UP): keyLevel = tH0 -// → close > tH0 = bull MSS → entry BUY LIMIT tại tH0 -// - M5 đang uptrend (hồi khi H1 DOWN): keyLevel = tL0 -// → close < tL0 = bear MSS → entry SELL LIMIT tại tL0 -// -// Chỉ nhận MSS thuận chiều MiddleTF (filter duy nhất). -// Entry price = keyLevel bị phá (tH0 hoặc tL0). -// SL = swing extreme sóng hồi (tL0 cho buy, tH0 cho sell). -// Cả entry + SL capture TRƯỚC re-scan vì sau đó swing thay đổi. +// v4.3: MSS check CHỈ cho TriggerTF + CHỈ khi EA_WAIT_TRIGGER. +// MiddleTF: chỉ scan swing + resolve trend, KHÔNG check MSS. +// TriggerTF: check MSS TRƯỚC re-scan (dùng OLD swing). +// Gate: g_State == EA_WAIT_TRIGGER (có TOUCHED FVG đang chờ). //---------------------------------------------------------------------- void UpdateTFTrendContext(ENUM_TIMEFRAMES tf, int lookback, TFTrendContext &ctx) { @@ -305,67 +300,66 @@ void UpdateTFTrendContext(ENUM_TIMEFRAMES tf, int lookback, TFTrendContext &ctx) ctx.lastBarTime = t0; double bar1C = iClose(_Symbol, tf, 1); // Bar vừa đóng: close - double bar1H = iHigh (_Symbol, tf, 1); // high - double bar1L = iLow (_Symbol, tf, 1); // low datetime bar1T = iTime (_Symbol, tf, 1); // time // ══════════════════════════════════════════════════════════════════ - // MSS check (TRƯỚC re-scan, dùng OLD keyLevel + swing) + // MSS check – CHỈ TriggerTF + CHỈ khi WAIT_TRIGGER // - // Logic: - // trend hiện tại có keyLevel → nếu close phá keyLevel: - // breakDir = hướng phá (UP nếu phá lên, DOWN nếu phá xuống) - // Chỉ nhận nếu breakDir == MiddleTF trend (TriggerTF only) + // Chạy TRƯỚC re-scan → ctx.h0/l0 là OLD values (swing chưa cập nhật) + // → Entry = OLD tH0 (buy) hoặc OLD tL0 (sell) = swing vừa bị phá + // → SL = OLD tL0 (buy) hoặc OLD tH0 (sell) = swing đối diện // - // Capture tại thời điểm MSS: - // lastMssLevel = keyLevel bị phá = ENTRY PRICE cho limit order - // mssSLSwing = swing extreme phía đối diện = SL level - // Bull MSS: SL = L0 (đáy sóng hồi) - // Bear MSS: SL = H0 (đỉnh sóng hồi) + // Khi không ở WAIT_TRIGGER → skip hoàn toàn (không detect, không vẽ) // ══════════════════════════════════════════════════════════════════ - if (ctx.trend != DIR_NONE && ctx.keyLevel > 0) + if (tf == InpTriggerTF // Chỉ TriggerTF (M5) + && g_State == EA_WAIT_TRIGGER // Chỉ khi đang chờ MSS + && ctx.h0 > 0 && ctx.l0 > 0 // Có swing points + && g_MiddleTrend.trend != DIR_NONE) // H1 có hướng { - bool mssHit = - (ctx.trend == DIR_UP && bar1C < ctx.keyLevel) || // Uptrend KL=L0 → break below - (ctx.trend == DIR_DOWN && bar1C > ctx.keyLevel); // Downtrend KL=H0 → break above + bool mssHit = false; + MarketDir breakDir = DIR_NONE; + double entryLevel = 0, slLevel = 0; - if (mssHit && bar1T != ctx.lastMssTime) + if (g_MiddleTrend.trend == DIR_UP // H1 UP → tìm bull MSS + && bar1C > ctx.h0) // M5 close > OLD tH0 → phá swing high { - MarketDir breakDir = (ctx.trend == DIR_UP) ? DIR_DOWN : DIR_UP; + mssHit = true; + breakDir = DIR_UP; + entryLevel = ctx.h0; // Entry = tH0 vừa bị phá + slLevel = ctx.l0; // SL = tL0 (đáy gần nhất) + } + else if (g_MiddleTrend.trend == DIR_DOWN // H1 DOWN → tìm bear MSS + && bar1C < ctx.l0) // M5 close < OLD tL0 → phá swing low + { + mssHit = true; + breakDir = DIR_DOWN; + entryLevel = ctx.l0; // Entry = tL0 vừa bị phá + slLevel = ctx.h0; // SL = tH0 (đỉnh gần nhất) + } - // TriggerTF: chỉ nhận MSS thuận chiều MiddleTF - bool accept = true; - if (tf == InpTriggerTF && g_MiddleTrend.trend != DIR_NONE) + if (mssHit && bar1T != ctx.lastMssTime) // Break detected + chưa ghi nhận bar này + { + // v4.3: Check minimum swing depth — |tH0 - tL0| phải đủ lớn + // Ngăn MSS fire trên swing quá nông (dao động bình thường) + double swingDepth = MathAbs(ctx.h0 - ctx.l0) / _Point; // Depth tính bằng points + if (swingDepth < InpMSSMinDepthPts) { - if (breakDir != (MarketDir)g_MiddleTrend.trend) - accept = false; // Ngược chiều → bỏ qua + if (InpDebugLog) + PrintFormat("[M5 MSS SKIP] depth=%.0f pts < %d | H0=%.5f L0=%.5f | %s", + swingDepth, InpMSSMinDepthPts, ctx.h0, ctx.l0, TimeToString(bar1T)); } - - if (accept) + else { - ctx.lastMssTime = bar1T; // Thời gian cây nến MSS - ctx.lastMssLevel = ctx.keyLevel; // KeyLevel bị phá = ENTRY - ctx.lastMssBreak = breakDir; // Hướng break - - // v4: Capture SL swing TRƯỚC re-scan - if (breakDir == DIR_UP) - ctx.mssSLSwing = ctx.l0; // Bull MSS → SL dưới L0 (đáy hồi) - else - ctx.mssSLSwing = ctx.h0; // Bear MSS → SL trên H0 (đỉnh hồi) + ctx.lastMssTime = bar1T; // Lưu vào context (dùng cho case2 check) + ctx.lastMssLevel = entryLevel; + ctx.lastMssBreak = breakDir; + ctx.mssSLSwing = slLevel; if (InpDebugLog) - PrintFormat("[%s MSS] %s | entry=%.5f SL_swing=%.5f | close=%.5f | %s", - EnumToString(tf), + PrintFormat("[M5 MSS] %s | entry=%.5f SL=%.5f depth=%.0fpts | close=%.5f | H0=%.5f L0=%.5f | %s", (breakDir == DIR_UP) ? "▲ Bull" : "▼ Bear", - ctx.lastMssLevel, ctx.mssSLSwing, - bar1C, TimeToString(bar1T)); - } - else if (InpDebugLog) - { - PrintFormat("[%s MSS skip] %s ngược H1=%s | KL=%.5f", - EnumToString(tf), - (breakDir == DIR_UP) ? "▲" : "▼", - EnumToString(g_MiddleTrend.trend), ctx.keyLevel); + entryLevel, slLevel, swingDepth, bar1C, + ctx.h0, ctx.l0, TimeToString(bar1T)); } } } @@ -418,8 +412,8 @@ void UpdateAllContexts() { UpdateDailyRiskContext(); // 1. Check daily drawdown trước tiên UpdateBiasContext(); // 2. D1 bias (UP/DOWN/SIDEWAY) - UpdateTFTrendContext(InpMiddleTF, InpSwingLookback, g_MiddleTrend); // 3. H1 swing+trend+MSS - UpdateTFTrendContext(InpTriggerTF, InpTriggerSwingLookback, g_TriggerTrend); // 4. M5 swing+trend+MSS (entry signal) + UpdateTFTrendContext(InpMiddleTF, InpSwingLookback, g_MiddleTrend); // 3. H1 swing+trend (no MSS) + UpdateTFTrendContext(InpTriggerTF, InpTriggerSwingLookback, g_TriggerTrend); // 4. M5 swing + MSS (if WAIT_TRIGGER) } //+------------------------------------------------------------------+ @@ -648,8 +642,8 @@ void UpdateFVGStatuses() { // ── 4. Case2: M5 MSS đã xảy ra SAU touch → triggered ─────────── // - // v4: Kiểm tra g_TriggerTrend.lastMssTime > touchTime - // VÀ hướng MSS phù hợp FVG direction + // Check: g_TriggerTrend.lastMssTime > touchTime + cùng hướng + // v4.3: Lưu MSS info vào FVG record (cho vẽ + order) // bool hasMSS = g_TriggerTrend.lastMssTime > g_FVGPool[i].touchTime && // MSS sau touch @@ -660,23 +654,40 @@ void UpdateFVGStatuses() g_FVGPool[i].status = FVG_USED; g_FVGPool[i].usedCase = 2; // Case2 = triggered g_FVGPool[i].usedTime = TimeCurrent(); + + // v4.3: Copy MSS info vào FVG (dùng cho vẽ MSS marker + order plan) + g_FVGPool[i].mssTime = g_TriggerTrend.lastMssTime; + g_FVGPool[i].mssEntry = g_TriggerTrend.lastMssLevel; + g_FVGPool[i].mssSL = g_TriggerTrend.mssSLSwing; + if (InpDebugLog) - PrintFormat("[FVG #%d] TRIGGERED | MSS %s @ %s", + PrintFormat("[FVG #%d] TRIGGERED | MSS %s entry=%.5f SL=%.5f @ %s", g_FVGPool[i].id, (g_TriggerTrend.lastMssBreak == DIR_UP) ? "▲" : "▼", - TimeToString(g_TriggerTrend.lastMssTime, TIME_MINUTES)); + g_FVGPool[i].mssEntry, g_FVGPool[i].mssSL, + TimeToString(g_FVGPool[i].mssTime, TIME_MINUTES)); continue; } - // ── 5. Trigger timeout ──────────────────────────────────────────── - int bars = (int)((TimeCurrent() - g_FVGPool[i].touchTime) / PeriodSeconds(InpTriggerTF)); - if (bars > InpTriggerMaxBars - && g_ActiveFVGIdx >= 0 - && g_FVGPool[g_ActiveFVGIdx].id == g_FVGPool[i].id) + // ── 5. TOUCHED lifetime expire ────────────────────────────────── + // v4.3: Dùng chung InpFVGMaxAliveMin cho cả PENDING và TOUCHED. + // Tính từ createdTime (không phải touchTime) → FVG sống tối đa 72h. + // Không dùng InpTriggerMaxBars nữa (quá ngắn, miss entry). + // + int ageMin = (int)((TimeCurrent() - g_FVGPool[i].createdTime) / 60); + if (ageMin > InpFVGMaxAliveMin) // Quá lifetime { + g_FVGPool[i].status = FVG_USED; + g_FVGPool[i].usedCase = 0; // Case0 = expired + g_FVGPool[i].usedTime = TimeCurrent(); + + if (g_ActiveFVGIdx >= 0 + && g_FVGPool[g_ActiveFVGIdx].id == g_FVGPool[i].id) + g_ActiveFVGIdx = -1; + if (InpDebugLog) - PrintFormat("[FVG #%d] Timeout (%d bars)", g_FVGPool[i].id, bars); - g_ActiveFVGIdx = -1; + PrintFormat("[FVG #%d] TOUCHED EXPIRED (age=%dmin > %d) → USED", + g_FVGPool[i].id, ageMin, InpFVGMaxAliveMin); } } } @@ -714,15 +725,13 @@ double CalcLotFromRisk(double entry, double sl) return NormalizeDouble(rawLot, 2); // Trả về lot 2 chữ số thập phân } -bool BuildOrderPlan(int fvgId, MarketDir dir) +bool BuildOrderPlan(int fvgId, MarketDir dir, double mssEntry, double mssSL) { ZeroMemory(g_OrderPlan); // Reset plan cũ - // v4: Entry = keyLevel vừa bị phá (đã capture trong MSS context) - double entry = NormalizeDouble(g_TriggerTrend.lastMssLevel, _Digits); // tH0 (buy) hoặc tL0 (sell) - - // v4: SL = swing extreme sóng hồi (đã capture trong MSS context) - double sl = g_TriggerTrend.mssSLSwing; // tL0 (buy) hoặc tH0 (sell), captured TRƯỚC re-scan + // v4.3: Entry + SL đã capture trong FVG record khi triggered + double entry = NormalizeDouble(mssEntry, _Digits); // tH0 (buy) hoặc tL0 (sell) + double sl = mssSL; // tL0 (buy) hoặc tH0 (sell) if (entry <= 0 || sl <= 0) return false; // Data invalid → không đặt lệnh @@ -894,13 +903,14 @@ void OnStateWaitTrigger() if (g_FVGPool[ai].usedCase == 2) // Case2 = MSS triggered { if (InpDebugLog) - PrintFormat("[ENTRY SIGNAL] FVG #%d %s [%.5f–%.5f] | MSS entry=%.5f", + PrintFormat("[ENTRY SIGNAL] FVG #%d %s [%.5f–%.5f] | MSS entry=%.5f SL=%.5f", g_FVGPool[ai].id, EnumToString(g_FVGPool[ai].direction), g_FVGPool[ai].low, g_FVGPool[ai].high, - g_TriggerTrend.lastMssLevel); + g_FVGPool[ai].mssEntry, g_FVGPool[ai].mssSL); - // v4: Build order plan dùng MSS data (entry=keyLevel, SL=swing hồi) - if (BuildOrderPlan(g_FVGPool[ai].id, g_FVGPool[ai].direction)) + // v4.3: Build order plan dùng FVG's MSS data (đã capture lúc triggered) + if (BuildOrderPlan(g_FVGPool[ai].id, g_FVGPool[ai].direction, + g_FVGPool[ai].mssEntry, g_FVGPool[ai].mssSL)) { ulong ticket = ExecuteLimitOrder(); if (ticket > 0) @@ -1148,15 +1158,19 @@ void DrawMSSMarker( void DrawMSSMarkers() { if (!InpDebugDraw) return; - if (g_MiddleTrend.lastMssTime > 0) + + // v4.3: CHỈ vẽ MSS cho FVG đã triggered (case2) + // Không vẽ MSS riêng lẻ từ global context nữa + for (int i = 0; i < g_FVGCount; i++) { - string mid = "M_" + IntegerToString((long)g_MiddleTrend.lastMssTime); - DrawMSSMarker(mid, InpMiddleTF, g_MiddleTrend.lastMssTime, g_MiddleTrend.lastMssLevel, g_MiddleTrend.lastMssBreak); - } - if (g_TriggerTrend.lastMssTime > 0) - { - string tid = "T_" + IntegerToString((long)g_TriggerTrend.lastMssTime); - DrawMSSMarker(tid, InpTriggerTF, g_TriggerTrend.lastMssTime, g_TriggerTrend.lastMssLevel, g_TriggerTrend.lastMssBreak); + if (g_FVGPool[i].status != FVG_USED || g_FVGPool[i].usedCase != 2) continue; // Chỉ case2 + if (g_FVGPool[i].mssTime == 0) continue; // Không có MSS data + + string tid = "T_" + IntegerToString(g_FVGPool[i].id); // Dùng FVG ID làm MSS object ID + DrawMSSMarker(tid, InpTriggerTF, + g_FVGPool[i].mssTime, // Thời gian cây nến MSS + g_FVGPool[i].mssEntry, // Swing bị phá (entry level) + g_FVGPool[i].direction == DIR_UP ? DIR_UP : DIR_DOWN); // Hướng MSS = hướng FVG } } @@ -1350,7 +1364,7 @@ void DrawContextDebug() ObjectSetInteger(0,name,OBJPROP_COLOR, clr); \ ObjectSetString (0,name,OBJPROP_TEXT, txt); - LBL("DBG_HDR", "── ICT EA v4 ──", 10, clrSilver) + LBL("DBG_HDR", "── ICT EA v4.3 ──", 10, clrSilver) color cB = (g_Bias.bias==BIAS_UP)?clrLime:(g_Bias.bias==BIAS_DOWN)?clrTomato:(g_Bias.bias==BIAS_SIDEWAY)?clrOrange:clrGray; LBL("DBG_BIAS", StringFormat("Bias : %s", EnumToString(g_Bias.bias)), 34, cB) @@ -1361,13 +1375,17 @@ void DrawContextDebug() color cTT = (g_TriggerTrend.trend==DIR_UP)?clrLime:(g_TriggerTrend.trend==DIR_DOWN)?clrTomato:clrGray; LBL("DBG_TT", StringFormat("M5 : %s KL=%.5f", EnumToString(g_TriggerTrend.trend), g_TriggerTrend.keyLevel), 82, cTT) - if (g_TriggerTrend.lastMssTime > 0) + if (g_ActiveFVGIdx >= 0 && g_ActiveFVGIdx < g_FVGCount // Có active FVG + && g_FVGPool[g_ActiveFVGIdx].usedCase == 2 // Đã triggered + && g_FVGPool[g_ActiveFVGIdx].mssTime > 0) // Có MSS data { - color cM = (g_TriggerTrend.lastMssBreak==DIR_UP)?clrLime:clrTomato; - LBL("DBG_MSS", StringFormat("M5MSS: %s entry=%.5f SL=%.5f @ %s", - (g_TriggerTrend.lastMssBreak==DIR_UP)?"▲":"▼", - g_TriggerTrend.lastMssLevel, g_TriggerTrend.mssSLSwing, - TimeToString(g_TriggerTrend.lastMssTime, TIME_MINUTES)), 106, cM) + int ai = g_ActiveFVGIdx; + color cM = (g_FVGPool[ai].direction==DIR_UP)?clrLime:clrTomato; + LBL("DBG_MSS", StringFormat("MSS : %s entry=%.5f SL=%.5f @ %s (FVG#%d)", + (g_FVGPool[ai].direction==DIR_UP)?"▲":"▼", + g_FVGPool[ai].mssEntry, g_FVGPool[ai].mssSL, + TimeToString(g_FVGPool[ai].mssTime, TIME_MINUTES), + g_FVGPool[ai].id), 106, cM) } else ObjectDelete(0,"DBG_MSS"); @@ -1416,7 +1434,7 @@ void DrawVisuals() { DrawMiddleSwingPoints(); // H1 swing H0/H1/L0/L1 + keyLevel dashed line DrawTriggerSwingPoints(); // M5 swing tH0/tH1/tL0/tL1 + keyLevel dashed line - DrawMSSMarkers(); // MSS arrow + label + broken keyLevel line (cả H1 và M5) + DrawMSSMarkers(); // MSS markers (chỉ cho triggered FVGs) DrawFVGPool(); // MiddleTF FVG rectangles (PENDING=dark, TOUCHED=bright, USED=status color) DrawOrderVisualization(); // TradingView-style: TP zone (green) + SL zone (red) + entry/SL/TP lines DrawContextDebug(); // Top-left info panel: bias, trend, MSS, risk, state, pool, order @@ -1439,7 +1457,7 @@ int OnInit() ScanAndRegisterFVGs(); DrawVisuals(); - PrintFormat("✅ ICT EA v4 | Bias=%s | H1=%s | M5=%s | Pool=%d", + PrintFormat("✅ ICT EA v4.3 | Bias=%s | H1=%s | M5=%s | Pool=%d", EnumToString(g_Bias.bias), EnumToString(g_MiddleTrend.trend), EnumToString(g_TriggerTrend.trend), g_FVGCount); return INIT_SUCCEEDED; @@ -1447,7 +1465,7 @@ int OnInit() void OnTick() { - UpdateAllContexts(); // 1. Cập nhật D1 bias, H1/M5 swing+MSS + UpdateAllContexts(); // 1. Cập nhật D1 bias, H1/M5 swing (MSS nếu WAIT_TRIGGER) if (EvaluateGuards()) // 2. Check guards (session, risk, alignment) RunStateMachine(); // Pass → chạy state machine else if (g_State != EA_IDLE) // Fail + đang active → reset @@ -1461,5 +1479,5 @@ void OnDeinit(const int reason) ObjectsDeleteAll(0, TS_PREFIX); // Xóa M5 swing objects (tạm thời) ObjectsDeleteAll(0, DBG_PREFIX); // Xóa debug panel (giữ lại: FVGP_, MSS_, ORD_) ChartRedraw(0); // Force redraw chart - PrintFormat("ICT EA v4 deinit | reason=%d | pool=%d", reason, g_FVGCount); + PrintFormat("ICT EA v4.3 deinit | reason=%d | pool=%d", reason, g_FVGCount); } \ No newline at end of file