Update. Cần đọc hiểu cặn kẽ logic tìm FVG và logic mss
This commit is contained in:
+136
-118
@@ -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<tL0) |
|
||||
//| 5. Entry = limit tại keyLevel vừa bị phá (tH0 hoặc tL0) |
|
||||
//| 6. SL = swing extreme sóng hồi (tL0 cho buy, tH0 cho sell) |
|
||||
//| 4. M5 MSS = swing break thuận chiều H1: |
|
||||
//| - H1 UP → 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);
|
||||
}
|
||||
Reference in New Issue
Block a user