Remove bias

This commit is contained in:
Bell
2026-03-10 22:21:59 +07:00
parent e7f32ac322
commit 0f13ae8c41
8 changed files with 51 additions and 167 deletions
+10 -15
View File
@@ -1,21 +1,17 @@
//+------------------------------------------------------------------+
//| ICT EA FVG Edition (MQL5) v4.3 |
//| Architecture : BiasTF(D1) + MiddleTF(H1) + TriggerTF(M5) |
//| Architecture : MiddleTF(H1) + TriggerTF(M5) |
//| State Machine: IDLE → WAIT_TOUCH → WAIT_TRIGGER → IN_TRADE |
//| |
//| Flow tổng thể: |
//| 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 = swing break thuận chiều H1: |
//| 1. H1 trend xác định hướng, tìm FVG thuận xu hướng |
//| 2. Giá touch H1 FVG → chờ M5 MSS xác nhận |
//| 3. 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 |
//| 4. Entry = limit tại swing level vừa bị phá (tH0 hoặc tL0) |
//| 5. SL = swing đối diện (tL0 cho buy, tH0 cho sell) |
//| 6. TP = Entry ± 2R |
//+------------------------------------------------------------------+
#property copyright "Bell's ICT EA"
#property version "4.30"
@@ -39,7 +35,6 @@
EAState g_State = EA_IDLE;
BlockReason g_BlockReason = BLOCK_NONE;
BiasContext g_Bias;
TFTrendContext g_MiddleTrend;
TFTrendContext g_TriggerTrend;
DailyRiskContext g_DailyRisk;
@@ -71,7 +66,7 @@ const string PREFIX_SESSION = "Session_";
/** Initializes globals, contexts, FVG pool and first draw. */
int OnInit()
{
ZeroMemory(g_Bias); ZeroMemory(g_MiddleTrend); ZeroMemory(g_TriggerTrend);
ZeroMemory(g_MiddleTrend); ZeroMemory(g_TriggerTrend);
ZeroMemory(g_DailyRisk); ZeroMemory(g_OrderPlan);
for (int i = 0; i < MAX_FVG_POOL; i++) ZeroMemory(g_FVGPool[i]);
g_FVGCount = 0; g_NextFVGId = 0;
@@ -82,8 +77,8 @@ int OnInit()
ScanAndRegisterFVGs();
DrawVisuals();
PrintFormat("✅ ICT EA v4.3 | Bias=%s | H1=%s | M5=%s | Pool=%d",
EnumToString(g_Bias.bias), EnumToString(g_MiddleTrend.trend),
PrintFormat("✅ ICT EA v4.3 | H1=%s | M5=%s | Pool=%d",
EnumToString(g_MiddleTrend.trend),
EnumToString(g_TriggerTrend.trend), g_FVGCount);
return INIT_SUCCEEDED;
}
+3 -4
View File
@@ -1,7 +1,6 @@
#ifndef EA_ICT_CL__CONFIG_MQH
#define EA_ICT_CL__CONFIG_MQH
input ENUM_TIMEFRAMES InpBiasTF = PERIOD_D1;
input ENUM_TIMEFRAMES InpMiddleTF = PERIOD_H1;
input ENUM_TIMEFRAMES InpTriggerTF = PERIOD_M5;
@@ -9,13 +8,13 @@ input double InpRiskPercent = 1.0;
input double InpRiskReward = 2.0;
input double InpMaxDailyLossPct = 3.0;
input int InpLondonStartHour = 8;
input int InpLondonStartHour = 7;
input int InpLondonEndHour = 17;
input int InpNYStartHour = 13;
input int InpNYEndHour = 22;
input int InpMiddleTfSwingRange = 3;
input int InpTriggerTfSwingRange = 3;
input int InpMiddleTfSwingRange = 2;
input int InpTriggerTfSwingRange = 2;
input int InpSwingLookback = 50;
input int InpTriggerSwingLookback = 30;
+4 -66
View File
@@ -1,66 +1,6 @@
#ifndef EA_ICT_CL__CONTEXTS_MQH
#define EA_ICT_CL__CONTEXTS_MQH
/** Resolves D1 bias from two consecutive daily bars (bar1 = last closed, bar2 = prior). */
inline HTFBias ResolveBias(double bar1High, double bar1Low, double bar1Close,
double bar2High, double bar2Low)
{
if (bar1Close > bar2High) return BIAS_UP;
if (bar1Close < bar2Low) return BIAS_DOWN;
bool sweptHigh = (bar1High > bar2High);
bool sweptLow = (bar1Low < bar2Low);
// Trường hợp quét cả hai đầu: so sánh độ dài râu vượt khỏi range bar2.
// Râu nào dài hơn → ưu tiên chiều NGƯỢC LẠI (stop run > đi ngược sweep mạnh hơn).
if (sweptHigh && sweptLow)
{
double upperSweep = bar1High - bar2High; // khoảng quét lên trên đỉnh cũ
double lowerSweep = bar2Low - bar1Low; // khoảng quét xuống dưới đáy cũ
if (upperSweep > lowerSweep) return BIAS_DOWN; // quét đỉnh mạnh hơn → bearish
if (lowerSweep > upperSweep) return BIAS_UP; // quét đáy mạnh hơn → bullish
// Nếu hai râu gần như bằng nhau → dùng close tương đối với mid-range để phân định
double mid = (bar2High + bar2Low) * 0.5;
if (bar1Close > mid) return BIAS_UP;
if (bar1Close < mid) return BIAS_DOWN;
return BIAS_SIDEWAY;
}
// Chỉ quét 1 đầu: giữ logic cũ với điều kiện close quay lại trong range.
if (sweptLow && bar1Close > bar2Low) return BIAS_UP;
if (sweptHigh && bar1Close < bar2High) return BIAS_DOWN;
return BIAS_SIDEWAY;
}
/** Updates global D1 bias context once per new bias-TF bar. */
inline void UpdateBiasContext()
{
datetime currentBiasBarTime = iTime(_Symbol, InpBiasTF, 0);
if (currentBiasBarTime == g_Bias.lastBarTime) return;
g_Bias.lastBarTime = currentBiasBarTime;
if (Bars(_Symbol, InpBiasTF) < 4) { g_Bias.bias = BIAS_NONE; return; }
double bar1High = iHigh (_Symbol, InpBiasTF, 1);
double bar1Low = iLow (_Symbol, InpBiasTF, 1);
double bar1Close = iClose(_Symbol, InpBiasTF, 1);
double bar2High = iHigh (_Symbol, InpBiasTF, 2);
double bar2Low = iLow (_Symbol, InpBiasTF, 2);
HTFBias prev = g_Bias.bias;
g_Bias.bias = ResolveBias(bar1High, bar1Low, bar1Close, bar2High, bar2Low);
g_Bias.rangeHigh = (g_Bias.bias == BIAS_SIDEWAY) ? bar2High : 0;
g_Bias.rangeLow = (g_Bias.bias == BIAS_SIDEWAY) ? bar2Low : 0;
if (InpDebugLog && g_Bias.bias != prev)
PrintFormat("[BIAS] %s → %s | b1[H=%.5f L=%.5f C=%.5f] b2[H=%.5f L=%.5f]",
EnumToString(prev), EnumToString(g_Bias.bias),
bar1High, bar1Low, bar1Close, bar2High, bar2Low);
}
/** Updates TF trend context (swing + trend + MSS detection when on trigger TF). */
inline void UpdateTFTrendContext(ENUM_TIMEFRAMES tf, int lookback, TFTrendContext &ctx)
{
@@ -85,8 +25,8 @@ inline void UpdateTFTrendContext(ENUM_TIMEFRAMES tf, int lookback, TFTrendContex
{
isMssTriggered = true;
mssBreakDirection = DIR_UP;
entryLevel = ctx.h0; // Entry = tH0
slLevel = ctx.l0; // SL = tL0
entryLevel = ctx.h0;
slLevel = ctx.l0;
}
else if (g_MiddleTrend.trend == DIR_DOWN && lastBarClose < ctx.l0)
{
@@ -164,14 +104,12 @@ inline void UpdateDailyRiskContext()
}
}
/** Updates all contexts: daily risk, bias, middle TF trend, trigger TF trend. */
/** Updates all contexts: daily risk, middle TF trend, trigger TF trend. */
inline void UpdateAllContexts()
{
UpdateDailyRiskContext();
UpdateBiasContext();
UpdateTFTrendContext(InpMiddleTF, InpSwingLookback, g_MiddleTrend);
UpdateTFTrendContext(InpTriggerTF, InpTriggerSwingLookback, g_TriggerTrend);
}
#endif // EA_ICT_CL__CONTEXTS_MQH
#endif
+17 -30
View File
@@ -489,18 +489,6 @@ inline void DrawContextDebug()
LBL(PREFIX_DEBUG_PANEL + "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(
PREFIX_DEBUG_PANEL + "BIAS",
StringFormat("Bias : %s", EnumToString(g_Bias.bias)),
34,
cB
)
color cMT = (g_MiddleTrend.trend == DIR_UP)
? clrLime
: (g_MiddleTrend.trend == DIR_DOWN) ? clrTomato : clrGray;
@@ -511,7 +499,7 @@ inline void DrawContextDebug()
EnumToString(g_MiddleTrend.trend),
g_MiddleTrend.keyLevel
),
58,
34,
cMT
)
@@ -525,7 +513,7 @@ inline void DrawContextDebug()
EnumToString(g_TriggerTrend.trend),
g_TriggerTrend.keyLevel
),
82,
58,
cTT
)
@@ -545,7 +533,7 @@ inline void DrawContextDebug()
TimeToString(g_FVGPool[ai].mssTime, TIME_MINUTES),
g_FVGPool[ai].id
),
106,
82,
cM
)
}
@@ -561,7 +549,7 @@ inline void DrawContextDebug()
LBL(
PREFIX_DEBUG_PANEL + "RISK",
StringFormat("Risk : %.2f%% / %.2f%%", lostPct, InpMaxDailyLossPct),
130,
106,
cR
)
@@ -573,7 +561,7 @@ inline void DrawContextDebug()
LBL(
PREFIX_DEBUG_PANEL + "ST",
StringFormat("State: %s", EnumToString(g_State)),
154,
130,
cS
)
@@ -582,7 +570,7 @@ inline void DrawContextDebug()
LBL(
PREFIX_DEBUG_PANEL + "BLK",
StringFormat("Block: %s", EnumToString(g_BlockReason)),
178,
154,
clrTomato
)
}
@@ -610,7 +598,7 @@ inline void DrawContextDebug()
g_FVGCount,
MAX_FVG_POOL
),
202,
178,
clrDodgerBlue
)
@@ -627,7 +615,7 @@ inline void DrawContextDebug()
g_FVGPool[ai].high,
EnumToString(g_FVGPool[ai].status)
),
226,
202,
clrDeepSkyBlue
)
}
@@ -645,7 +633,7 @@ inline void DrawContextDebug()
g_OrderPlan.stopLoss,
g_OrderPlan.takeProfit
),
250,
226,
clrGold
)
}
@@ -703,8 +691,8 @@ inline void DrawSessionMarkers()
if (InpLondonStartHour < InpLondonEndHour)
{
datetime t1 = dayStart + startL;
datetime t2 = dayStart + endL;
datetime t1 = (datetime)(dayStart + startL);
datetime t2 = (datetime)(dayStart + endL);
if (t2 > firstTime && t1 < lastTime)
{
string name = PREFIX_SESSION + "L_" + IntegerToString(d);
@@ -719,8 +707,8 @@ inline void DrawSessionMarkers()
}
else
{
datetime t1 = dayStart + startL;
datetime t2 = dayStart + 86400 + endL;
datetime t1 = (datetime)(dayStart + startL);
datetime t2 = (datetime)(dayStart + 86400 + endL);
if (t2 > firstTime && t1 < lastTime)
{
string name = PREFIX_SESSION + "L_" + IntegerToString(d);
@@ -736,8 +724,8 @@ inline void DrawSessionMarkers()
if (InpNYStartHour < InpNYEndHour)
{
datetime t1 = dayStart + startN;
datetime t2 = dayStart + endN;
datetime t1 = (datetime)(dayStart + startN);
datetime t2 = (datetime)(dayStart + endN);
if (t2 > firstTime && t1 < lastTime)
{
string name = PREFIX_SESSION + "N_" + IntegerToString(d);
@@ -752,8 +740,8 @@ inline void DrawSessionMarkers()
}
else
{
datetime t1 = dayStart + startN;
datetime t2 = dayStart + 86400 + endN;
datetime t1 = (datetime)(dayStart + startN);
datetime t2 = (datetime)(dayStart + 86400 + endN);
if (t2 > firstTime && t1 < lastTime)
{
string name = PREFIX_SESSION + "N_" + IntegerToString(d);
@@ -776,7 +764,6 @@ inline void DrawVisuals()
DrawContextDebug();
DrawMiddleSwingPoints();
DrawFVGPool();
return; // TESTING ONLY
DrawTriggerSwingPoints();
DrawMSSMarkers();
DrawOrderVisualization();
+6 -15
View File
@@ -9,26 +9,17 @@ inline bool IsSessionAllowed()
|| IsHourInRange(hourUtc, InpNYStartHour, InpNYEndHour);
}
/** True if daily loss limit has not been hit. */
inline bool IsDailyLossOK() { return !g_DailyRisk.limitHit; }
/** True if bias is UP or DOWN (not NONE or SIDEWAY). */
inline bool IsBiasValid() { return g_Bias.bias == BIAS_UP || g_Bias.bias == BIAS_DOWN; }
/** True if H1 trend aligns with D1 bias (same direction). */
inline bool IsMiddleTrendAligned()
{
if (g_MiddleTrend.trend == DIR_NONE) return false;
return (g_Bias.bias == BIAS_UP && g_MiddleTrend.trend == DIR_UP) ||
(g_Bias.bias == BIAS_DOWN && g_MiddleTrend.trend == DIR_DOWN);
}
inline bool IsDailyLossOK() { return !g_DailyRisk.limitHit; }
/** True if middle TF has a clear trend (UP or DOWN). */
inline bool IsMiddleTrendValid() { return g_MiddleTrend.trend != DIR_NONE; }
/** Evaluates all guards; sets g_BlockReason and returns false if any guard fails. */
inline bool EvaluateGuards()
{
g_BlockReason = BLOCK_NONE;
if (!IsSessionAllowed()) { g_BlockReason = BLOCK_SESSION; return false; }
if (!IsDailyLossOK()) { g_BlockReason = BLOCK_DAILY_LOSS; return false; }
if (!IsBiasValid()) { g_BlockReason = BLOCK_NO_BIAS; return false; }
if (!IsMiddleTrendAligned()) { g_BlockReason = BLOCK_BIAS_MISMATCH; return false; }
if (!IsSessionAllowed()) { g_BlockReason = BLOCK_SESSION; return false; }
if (!IsDailyLossOK()) { g_BlockReason = BLOCK_DAILY_LOSS; return false; }
if (!IsMiddleTrendValid()) { g_BlockReason = BLOCK_NO_TREND; return false; }
return true;
}
+7 -8
View File
@@ -18,7 +18,7 @@
| File | Chức năng |
|------|-----------|
| **`Config.mqh`** | Toàn bộ **input** của EA: timeframe (Bias/Middle/Trigger), risk %, session giờ (London/NY), swing/FVG/MSS params, magic, slippage, debug flags. |
| **`State.mqh`** | **Enums****struct**: `EAState`, `HTFBias`, `MarketDir`, `BlockReason`, `FVGStatus`; struct `BiasContext`, `TFTrendContext`, `FVGRecord`, `OrderPlan`, `DailyRiskContext`. Không chứa biến global. |
| **`State.mqh`** | **Enums****struct**: `EAState`, `MarketDir`, `BlockReason`, `FVGStatus`; struct `TFTrendContext`, `FVGRecord`, `OrderPlan`, `DailyRiskContext`. Không chứa biến global. |
### Layer 2 Tiện ích (sau Config + State)
@@ -39,8 +39,8 @@
| File | Chức năng |
|------|-----------|
| **`Contexts.mqh`** | Cập nhật context: `ResolveBias`, `UpdateBiasContext`, `UpdateTFTrendContext`, `UpdateDailyRiskContext`, `UpdateAllContexts`. Dùng globals `g_Bias`, `g_MiddleTrend`, `g_TriggerTrend`, `g_DailyRisk`. |
| **`Guards.mqh`** | Điều kiện trước khi trade: `IsSessionAllowed`, `IsDailyLossOK`, `IsBiasValid`, `IsMiddleTrendAligned`, `EvaluateGuards`. Set `g_BlockReason` khi block. |
| **`Contexts.mqh`** | Cập nhật context: `UpdateTFTrendContext`, `UpdateDailyRiskContext`, `UpdateAllContexts`. Dùng globals `g_MiddleTrend`, `g_TriggerTrend`, `g_DailyRisk`. |
| **`Guards.mqh`** | Điều kiện trước khi trade: `IsSessionAllowed`, `IsDailyLossOK`, `IsMiddleTrendValid`, `EvaluateGuards`. Set `g_BlockReason` khi block. |
| **`Signals_BOS_FVG_OB.mqh`** | **FVG**: `IsCandleStrong`, `IsFVGInPool`, `ScanAndRegisterFVGs`, `UpdateFVGStatuses`, `GetBestActiveFVGIdx`. Quản lý pool FVG và trạng thái PENDING/TOUCHED/USED. |
| **`Trade.mqh`** | **Order plan & execution**: `CalcLotFromRisk`, `BuildOrderPlan`, `ExecuteLimitOrder`. Gửi lệnh pending limit, dùng `g_OrderPlan`. |
| **`StateMachine.mqh`** | **State machine**: `TransitionTo`, `ResetToIdle`, `OnStateIdle`, `OnStateWaitTouch`, `OnStateWaitTrigger`, `OnStateInTrade`, `RunStateMachine`. Điều phối theo `g_State`. |
@@ -53,7 +53,7 @@
```
Layer 1: Config.mqh → State.mqh
Layer 2: Utils, Logging, Market, Indicators, Sessions, Filters, Risk, Orders, Swing, Trailing
Globals: g_State, g_Bias, g_MiddleTrend, g_TriggerTrend, g_DailyRisk, g_FVGPool, g_OrderPlan, PREFIX_*
Globals: g_State, g_MiddleTrend, g_TriggerTrend, g_DailyRisk, g_FVGPool, g_OrderPlan, PREFIX_*
Layer 3: Contexts.mqh → Guards.mqh → Signals_BOS_FVG_OB.mqh → Trade.mqh → StateMachine.mqh → Drawing.mqh
```
@@ -65,7 +65,6 @@ Layer 3 phải include **sau** khi globals và prefix đã được khai báo tr
### Timeframe
- **BiasTF (D1):** xác định bias (UP/DOWN/SIDEWAY/NONE).
- **MiddleTF (H1):** trend + quét FVG thuận xu hướng.
- **TriggerTF (M5):** xác nhận entry bằng MSS (market structure shift).
@@ -80,8 +79,8 @@ Layer 3 phải include **sau** khi globals và prefix đã được khai báo tr
### Luồng quyết định (mỗi tick)
1. **UpdateAllContexts()** Cập nhật D1 bias, H1/M5 swing (và MSS nếu đang WAIT_TRIGGER).
2. **EvaluateGuards()** Kiểm tra session, daily loss, bias, alignment H1/D1.
1. **UpdateAllContexts()** Cập nhật H1/M5 swing (và MSS nếu đang WAIT_TRIGGER).
2. **EvaluateGuards()** Kiểm tra session, daily loss, H1 trend.
3. Nếu pass → **RunStateMachine()**: `UpdateFVGStatuses()` + `ScanAndRegisterFVGs()` + xử lý theo state (Idle → chọn FVG; WaitTouch → chờ touch/switch FVG; WaitTrigger → khi FVG triggered thì BuildOrderPlan + ExecuteLimitOrder; InTrade → theo dõi order/position).
4. Nếu **InpDebugDraw** bật → **DrawVisuals()** (swing, MSS, FVG pool, order, debug panel).
@@ -102,7 +101,7 @@ Các hằng trong `EA_ICT_CL.mq5` dùng cho Drawing:
- `PREFIX_MSS_MARKER` Điểm đánh dấu MSS.
- `PREFIX_FVG_POOL` Các hình chữ nhật FVG.
- `PREFIX_ORDER_VISUAL` Vùng/label Entry/SL/TP.
- `PREFIX_DEBUG_PANEL` Bảng thông tin góc trái (Bias, H1/M5, Risk, State, Pool, Order).
- `PREFIX_DEBUG_PANEL` Bảng thông tin góc trái (H1/M5, Risk, State, Pool, Order).
---
+2 -18
View File
@@ -127,7 +127,7 @@ inline void ScanAndRegisterFVGs()
}
}
/** Updates status of each FVG in pool (broken, touched, expired, MSS-triggered). */
/** Updates status of each FVG in pool (broken, touched, MSS-triggered). TOUCHED chỉ chuyển USED khi broke hoặc MSS, không expire. */
inline void UpdateFVGStatuses()
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
@@ -194,24 +194,8 @@ inline void UpdateFVGStatuses()
(g_TriggerTrend.lastMssBreak == DIR_UP) ? "▲" : "▼",
g_FVGPool[i].mssEntry, g_FVGPool[i].mssSL,
TimeToString(g_FVGPool[i].mssTime, TIME_MINUTES));
continue;
}
int ageMinutes = (int)((TimeCurrent() - g_FVGPool[i].createdTime) / 60);
if (ageMinutes > InpFVGMaxAliveMin)
{
g_FVGPool[i].status = FVG_USED;
g_FVGPool[i].usedCase = 0;
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] TOUCHED EXPIRED (age=%dmin > %d) → USED",
g_FVGPool[i].id, ageMinutes, InpFVGMaxAliveMin);
}
// TOUCHED chỉ kết thúc khi BROKE (usedCase 1) hoặc MSS (usedCase 2); không expire theo thời gian.
}
}
}
+2 -11
View File
@@ -9,12 +9,10 @@ enum EAState
EA_IN_TRADE
};
enum HTFBias { BIAS_NONE=0, BIAS_UP=1, BIAS_DOWN=-1, BIAS_SIDEWAY=2 };
enum MarketDir { DIR_NONE=0, DIR_UP=1, DIR_DOWN=-1 };
enum MarketDir { DIR_NONE=0, DIR_UP=1, DIR_DOWN=-1 };
enum BlockReason
{
BLOCK_NONE, BLOCK_SESSION, BLOCK_DAILY_LOSS,
BLOCK_BIAS_MISMATCH, BLOCK_NO_BIAS
BLOCK_NONE, BLOCK_SESSION, BLOCK_DAILY_LOSS, BLOCK_NO_TREND
};
enum FVGStatus
{
@@ -23,13 +21,6 @@ enum FVGStatus
FVG_USED
};
struct BiasContext
{
HTFBias bias;
double rangeHigh, rangeLow;
datetime lastBarTime;
};
struct TFTrendContext
{
MarketDir trend;