Comments chi tiết

This commit is contained in:
Bell
2026-03-10 19:28:06 +07:00
parent 1ddb802480
commit 3170da62ba
17 changed files with 380 additions and 422 deletions
+60 -60
View File
@@ -17,67 +17,67 @@
//| |
//| Drawing: objects KHÔNG BAO GIỜ bị xóa, chỉ update |
//+------------------------------------------------------------------+
#property copyright "Bell's ICT EA"
#property version "4.30"
#property copyright "Bell's ICT EA" // Bản quyền EA
#property version "4.30" // Phiên bản
#define MAX_FVG_POOL 30
#define MAX_FVG_POOL 30 // Số FVG tối đa trong pool
//====================================================
// LAYER 1 Config + Types (no dependencies)
//====================================================
#include "EA_ICT_CL/Config.mqh"
#include "EA_ICT_CL/State.mqh"
#include "EA_ICT_CL/Config.mqh" // Inputs và cấu hình
#include "EA_ICT_CL/State.mqh" // Enums, structs (EAState, BiasContext, FVGRecord...)
//====================================================
// LAYER 2 Utility modules (depend on types + inputs)
//====================================================
#include "EA_ICT_CL/Utils.mqh"
#include "EA_ICT_CL/Logging.mqh"
#include "EA_ICT_CL/Market.mqh"
#include "EA_ICT_CL/Indicators.mqh"
#include "EA_ICT_CL/Sessions.mqh"
#include "EA_ICT_CL/Filters.mqh"
#include "EA_ICT_CL/Risk.mqh"
#include "EA_ICT_CL/Orders.mqh"
#include "EA_ICT_CL/Swing.mqh"
#include "EA_ICT_CL/Trailing.mqh"
#include "EA_ICT_CL/Utils.mqh" // Clamp, RoundToStep, IsNewBar
#include "EA_ICT_CL/Logging.mqh" // LogPrint, LogPrintF
#include "EA_ICT_CL/Market.mqh" // GetBid, GetAsk, GetPoint, IsTradeAllowedNow
#include "EA_ICT_CL/Indicators.mqh" // CopyBufferSafe, CopyTimeSafe
#include "EA_ICT_CL/Sessions.mqh" // IsHourInRange, GetUTCHour
#include "EA_ICT_CL/Filters.mqh" // Filter_MaxSpreadPoints
#include "EA_ICT_CL/Risk.mqh" // NormalizeVolume, LotsFromRiskMoneyAndSLPoints
#include "EA_ICT_CL/Orders.mqh" // NormalizePrice, BuildOrderComment
#include "EA_ICT_CL/Swing.mqh" // MyBarShift, IsSwingHighAt, ScanSwingStructure, ResolveTrendFromSwings
#include "EA_ICT_CL/Trailing.mqh" // Placeholder trailing/BE
//====================================================
// GLOBALS
//====================================================
EAState g_State = EA_IDLE;
BlockReason g_BlockReason = BLOCK_NONE;
EAState g_State = EA_IDLE; // Trạng thái EA hiện tại
BlockReason g_BlockReason = BLOCK_NONE; // Lý do chặn trade (session/daily loss/bias...)
BiasContext g_Bias;
TFTrendContext g_MiddleTrend;
TFTrendContext g_TriggerTrend;
DailyRiskContext g_DailyRisk;
BiasContext g_Bias; // D1 bias (UP/DOWN/SIDEWAY/NONE)
TFTrendContext g_MiddleTrend; // H1 swing + trend + MSS
TFTrendContext g_TriggerTrend; // M5 swing + trend
DailyRiskContext g_DailyRisk; // Balance đầu ngày, limit hit
FVGRecord g_FVGPool[MAX_FVG_POOL];
int g_FVGCount = 0;
int g_NextFVGId = 0;
int g_ActiveFVGIdx = -1;
int g_TradeBarIndex = -1;
FVGRecord g_FVGPool[MAX_FVG_POOL]; // Pool các FVG đã quét
int g_FVGCount = 0; // Số FVG trong pool
int g_NextFVGId = 0; // ID gán cho FVG mới
int g_ActiveFVGIdx = -1; // Chỉ số FVG đang theo dõi (-1 = không có)
int g_TradeBarIndex = -1; // Bar index khi vào lệnh (dùng cho timeout...)
OrderPlan g_OrderPlan;
ulong g_PendingTicket = 0;
OrderPlan g_OrderPlan; // Kế hoạch lệnh (entry, SL, TP, lot)
ulong g_PendingTicket = 0; // Ticket lệnh pending đã gửi
const string PREFIX_SWING_MIDDLE = "SwingMiddle_"; // H1 swing arrows/labels
const string PREFIX_SWING_TRIGGER = "SwingTrigger_"; // M5 swing arrows/labels
const string PREFIX_MSS_MARKER = "MSSMarker_"; // MSS break markers
const string PREFIX_FVG_POOL = "FVGPool_"; // FVG rectangles
const string PREFIX_ORDER_VISUAL = "OrderVisual_"; // Entry/SL/TP visualization
const string PREFIX_DEBUG_PANEL = "DebugPanel_"; // Top-left info labels
const string PREFIX_SWING_MIDDLE = "SwingMiddle_"; // Tiền tố object H1 swing
const string PREFIX_SWING_TRIGGER = "SwingTrigger_"; // Tiền tố object M5 swing
const string PREFIX_MSS_MARKER = "MSSMarker_"; // Tiền tố marker MSS
const string PREFIX_FVG_POOL = "FVGPool_"; // Tiền tố hình FVG
const string PREFIX_ORDER_VISUAL = "OrderVisual_"; // Tiền tố vùng Entry/SL/TP
const string PREFIX_DEBUG_PANEL = "DebugPanel_"; // Tiền tố panel debug góc trái
//====================================================
// LAYER 3 Logic modules (depend on globals)
//====================================================
#include "EA_ICT_CL/Contexts.mqh"
#include "EA_ICT_CL/Guards.mqh"
#include "EA_ICT_CL/Signals_BOS_FVG_OB.mqh"
#include "EA_ICT_CL/Trade.mqh"
#include "EA_ICT_CL/StateMachine.mqh"
#include "EA_ICT_CL/Drawing.mqh"
#include "EA_ICT_CL/Contexts.mqh" // UpdateBiasContext, UpdateTFTrendContext, UpdateAllContexts
#include "EA_ICT_CL/Guards.mqh" // IsSessionAllowed, EvaluateGuards
#include "EA_ICT_CL/Signals_BOS_FVG_OB.mqh" // ScanAndRegisterFVGs, UpdateFVGStatuses, GetBestActiveFVGIdx
#include "EA_ICT_CL/Trade.mqh" // BuildOrderPlan, ExecuteLimitOrder
#include "EA_ICT_CL/StateMachine.mqh" // TransitionTo, RunStateMachine, OnStateIdle...
#include "EA_ICT_CL/Drawing.mqh" // DrawVisuals, DrawFVGPool, DrawContextDebug...
//+------------------------------------------------------------------+
//| EA LIFECYCLE |
@@ -85,38 +85,38 @@ const string PREFIX_DEBUG_PANEL = "DebugPanel_"; // Top-left info labels
int OnInit()
{
ZeroMemory(g_Bias); 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;
g_ActiveFVGIdx = -1; g_TradeBarIndex = -1; g_PendingTicket = 0;
g_State = EA_IDLE; g_BlockReason = BLOCK_NONE;
ZeroMemory(g_Bias); ZeroMemory(g_MiddleTrend); ZeroMemory(g_TriggerTrend); // Xóa context
ZeroMemory(g_DailyRisk); ZeroMemory(g_OrderPlan); // Xóa risk + order plan
for (int i = 0; i < MAX_FVG_POOL; i++) ZeroMemory(g_FVGPool[i]); // Xóa toàn bộ pool FVG
g_FVGCount = 0; g_NextFVGId = 0; // Reset đếm FVG
g_ActiveFVGIdx = -1; g_TradeBarIndex = -1; g_PendingTicket = 0; // Không FVG active, không pending
g_State = EA_IDLE; g_BlockReason = BLOCK_NONE; // State = IDLE, không block
UpdateAllContexts();
ScanAndRegisterFVGs();
DrawVisuals();
UpdateAllContexts(); // Cập nhật D1 bias, H1/M5 trend, daily risk
ScanAndRegisterFVGs(); // Quét H1 và đăng ký FVG vào pool
DrawVisuals(); // Vẽ swing, FVG, debug panel (nếu bật)
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;
return INIT_SUCCEEDED; // Khởi tạo thành công
}
void OnTick()
{
UpdateAllContexts();
if (EvaluateGuards())
RunStateMachine();
UpdateAllContexts(); // Mỗi tick: cập nhật bias, H1/M5 swing, daily risk, MSS (nếu WAIT_TRIGGER)
if (EvaluateGuards()) // Kiểm tra session, daily loss, bias, alignment
RunStateMachine(); // Chạy state machine (Idle/WaitTouch/WaitTrigger/InTrade)
else if (g_State != EA_IDLE)
ResetToIdle(EnumToString(g_BlockReason));
if (InpDebugDraw) DrawVisuals();
ResetToIdle(EnumToString(g_BlockReason)); // Đang không IDLE mà fail guard → reset về IDLE
if (InpDebugDraw) DrawVisuals(); // Vẽ lại nếu bật debug draw
}
void OnDeinit(const int reason)
{
ObjectsDeleteAll(0, PREFIX_SWING_MIDDLE);
ObjectsDeleteAll(0, PREFIX_SWING_TRIGGER);
ObjectsDeleteAll(0, PREFIX_DEBUG_PANEL);
ChartRedraw(0);
PrintFormat("ICT EA v4.3 deinit | reason=%d | pool=%d", reason, g_FVGCount);
ObjectsDeleteAll(0, PREFIX_SWING_MIDDLE); // Xóa toàn bộ object H1 swing
ObjectsDeleteAll(0, PREFIX_SWING_TRIGGER); // Xóa toàn bộ object M5 swing
ObjectsDeleteAll(0, PREFIX_DEBUG_PANEL); // Xóa panel debug (FVG/order objects giữ lại theo thiết kế)
ChartRedraw(0); // Vẽ lại chart
PrintFormat("ICT EA v4.3 deinit | reason=%d | pool=%d", reason, g_FVGCount); // Log thoát
}
+23 -25
View File
@@ -1,40 +1,38 @@
#ifndef EA_ICT_CL__CONFIG_MQH
#define EA_ICT_CL__CONFIG_MQH
#define EA_ICT_CL__CONFIG_MQH // Tránh include trùng
// Module: Config
// This file now hosts EA inputs. Keep other types (enums/structs/globals) in the .mq5
// until you intentionally migrate them to State/Config to avoid redefinition.
// Module: Config toàn bộ input của EA
//====================================================
// INPUTS
//====================================================
input ENUM_TIMEFRAMES InpBiasTF = PERIOD_D1; // Bias TF (HTF)
input ENUM_TIMEFRAMES InpMiddleTF = PERIOD_H1; // FVG + trend TF (MTF)
input ENUM_TIMEFRAMES InpTriggerTF = PERIOD_M5; // Entry confirmation (LTF)
input ENUM_TIMEFRAMES InpBiasTF = PERIOD_D1; // Timeframe xác định bias (D1)
input ENUM_TIMEFRAMES InpMiddleTF = PERIOD_H1; // TF quét FVG + trend (H1)
input ENUM_TIMEFRAMES InpTriggerTF = PERIOD_M5; // TF xác nhận entry bằng MSS (M5)
input double InpRiskPercent = 1.0; // Risk % per trade
input double InpRiskReward = 2.0; // TP/SL ratio
input double InpMaxDailyLossPct = 3.0; // Max daily loss %
input double InpRiskPercent = 1.0; // % balance risk mỗi lệnh
input double InpRiskReward = 2.0; // Tỷ lệ R:R (TP = entry ± R*riskDist)
input double InpMaxDailyLossPct = 3.0; // % lỗ tối đa trong ngày → dừng trade
input int InpLondonStartHour = 8; // London open (UTC)
input int InpLondonEndHour = 17; // London close (UTC)
input int InpNYStartHour = 13; // NY open (UTC)
input int InpNYEndHour = 22; // NY close (UTC)
input int InpLondonStartHour = 8; // Giờ mở London (UTC)
input int InpLondonEndHour = 17; // Giờ đóng London (UTC)
input int InpNYStartHour = 13; // Giờ mở NY (UTC)
input int InpNYEndHour = 22; // Giờ đóng NY (UTC)
input int InpSwingRange = 3; // Bars each side for swing confirm
input int InpSwingLookback = 50; // MiddleTF swing scan bars
input int InpTriggerSwingLookback = 30; // TriggerTF swing scan bars
input int InpSwingRange = 3; // Số nến mỗi bên để xác nhận swing high/low
input int InpSwingLookback = 50; // Số bar quét swing trên MiddleTF (H1)
input int InpTriggerSwingLookback = 30; // Số bar quét swing trên TriggerTF (M5)
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 InpMSSMinDepthPts = 30; // MSS min swing depth (points): |tH0-tL0| phải >= giá trị này
input int InpFVGMaxAliveMin = 4320; // Thời gian sống FVG tối đa (phút), 4320 = 72h
input int InpFVGScanBars = 50; // Số bar H1 quét tìm FVG
input double InpFVGMinBodyPct = 60.0; // Nến giữa FVG: body % tối thiểu (strong candle)
input int InpMSSMinDepthPts = 30; // Độ sâu swing M5 tối thiểu (point) mới chấp nhận MSS
input long InpMagicNumber = 20250308; // EA magic number
input int InpSlippage = 5; // Max slippage (points)
input long InpMagicNumber = 20250308; // Magic number cho lệnh EA
input int InpSlippage = 5; // Slippage tối đa (point) khi gửi lệnh
input bool InpDebugLog = true; // Journal logging
input bool InpDebugDraw = true; // Chart drawing
input bool InpDebugLog = true; // Bật log ra Journal
input bool InpDebugDraw = true; // Bật vẽ swing/FVG/order/debug panel
#endif // EA_ICT_CL__CONFIG_MQH
+43 -45
View File
@@ -1,40 +1,37 @@
#ifndef EA_ICT_CL__CONTEXTS_MQH
#define EA_ICT_CL__CONTEXTS_MQH
#define EA_ICT_CL__CONTEXTS_MQH // Tránh include trùng
// Module: Contexts
// Context updaters extracted from EA_ICT_CL.mq5 (Section 2 Context updaters).
// NOTE: These functions currently use EA globals (g_*) and existing structs.
// Include this file AFTER structs + globals are declared in EA_ICT_CL.mq5.
// Module: Contexts cập nhật D1 bias, H1/M5 trend (swing + MSS), daily risk
inline HTFBias ResolveBias(double b1H, double b1L, double b1C, double b2H, double b2L)
{
if (b1C > b2H) return BIAS_UP;
if (b1C < b2L) return BIAS_DOWN;
if (b1H > b2H && b1C < b2H) return BIAS_DOWN;
if (b1L < b2L && b1C > b2L) return BIAS_UP;
return BIAS_SIDEWAY;
if (b1C > b2H) return BIAS_UP; // Close bar 1 trên range bar 2 → tăng
if (b1C < b2L) return BIAS_DOWN; // Close bar 1 dưới range bar 2 → giảm
if (b1H > b2H && b1C < b2H) return BIAS_DOWN; // Phá cao rồi đóng dưới → bearish
if (b1L < b2L && b1C > b2L) return BIAS_UP; // Phá thấp rồi đóng trên → bullish
return BIAS_SIDEWAY; // Còn lại = sideway
}
inline void UpdateBiasContext()
{
datetime t0 = iTime(_Symbol, InpBiasTF, 0);
if (t0 == g_Bias.lastBarTime) return;
datetime t0 = iTime(_Symbol, InpBiasTF, 0); // Bar D1 hiện tại (đang hình thành)
if (t0 == g_Bias.lastBarTime) return; // Đã xử lý bar này rồi → bỏ qua
g_Bias.lastBarTime = t0;
if (Bars(_Symbol, InpBiasTF) < 4) { g_Bias.bias = BIAS_NONE; return; }
if (Bars(_Symbol, InpBiasTF) < 4) { g_Bias.bias = BIAS_NONE; return; } // Không đủ dữ liệu
double b1H = iHigh (_Symbol, InpBiasTF, 1);
double b1H = iHigh (_Symbol, InpBiasTF, 1); // Bar D1 vừa đóng
double b1L = iLow (_Symbol, InpBiasTF, 1);
double b1C = iClose(_Symbol, InpBiasTF, 1);
double b2H = iHigh (_Symbol, InpBiasTF, 2);
double b2H = iHigh (_Symbol, InpBiasTF, 2); // Bar D1 trước đó
double b2L = iLow (_Symbol, InpBiasTF, 2);
HTFBias prev = g_Bias.bias;
g_Bias.bias = ResolveBias(b1H, b1L, b1C, b2H, b2L);
g_Bias.rangeHigh = (g_Bias.bias == BIAS_SIDEWAY) ? b2H : 0;
g_Bias.bias = ResolveBias(b1H, b1L, b1C, b2H, b2L); // Tính bias
g_Bias.rangeHigh = (g_Bias.bias == BIAS_SIDEWAY) ? b2H : 0; // Vùng sideway
g_Bias.rangeLow = (g_Bias.bias == BIAS_SIDEWAY) ? b2L : 0;
if (InpDebugLog && g_Bias.bias != prev)
if (InpDebugLog && g_Bias.bias != prev) // Chỉ log khi bias đổi
PrintFormat("[BIAS] %s → %s | b1[H=%.5f L=%.5f C=%.5f] b2[H=%.5f L=%.5f]",
EnumToString(prev), EnumToString(g_Bias.bias), b1H, b1L, b1C, b2H, b2L);
}
@@ -42,12 +39,13 @@ inline void UpdateBiasContext()
inline void UpdateTFTrendContext(ENUM_TIMEFRAMES tf, int lookback, TFTrendContext &ctx)
{
datetime t0 = iTime(_Symbol, tf, 0);
if (t0 == ctx.lastBarTime) return;
if (t0 == ctx.lastBarTime) return; // Bar chưa đổi → không cập nhật
ctx.lastBarTime = t0;
double bar1C = iClose(_Symbol, tf, 1);
double bar1C = iClose(_Symbol, tf, 1); // Close bar vừa đóng
datetime bar1T = iTime (_Symbol, tf, 1);
// Chỉ detect MSS khi đang WAIT_TRIGGER, trên M5, đã có h0/l0, H1 trend rõ
if (tf == InpTriggerTF
&& g_State == EA_WAIT_TRIGGER
&& ctx.h0 > 0 && ctx.l0 > 0
@@ -57,14 +55,14 @@ inline void UpdateTFTrendContext(ENUM_TIMEFRAMES tf, int lookback, TFTrendContex
MarketDir breakDir = DIR_NONE;
double entryLevel = 0, slLevel = 0;
if (g_MiddleTrend.trend == DIR_UP && bar1C > ctx.h0)
if (g_MiddleTrend.trend == DIR_UP && bar1C > ctx.h0) // H1 uptrend + M5 close phá tH0 = bull MSS
{
mssHit = true;
breakDir = DIR_UP;
entryLevel = ctx.h0;
slLevel = ctx.l0;
entryLevel = ctx.h0; // Entry = tH0
slLevel = ctx.l0; // SL = tL0
}
else if (g_MiddleTrend.trend == DIR_DOWN && bar1C < ctx.l0)
else if (g_MiddleTrend.trend == DIR_DOWN && bar1C < ctx.l0) // Bear MSS
{
mssHit = true;
breakDir = DIR_DOWN;
@@ -72,10 +70,10 @@ inline void UpdateTFTrendContext(ENUM_TIMEFRAMES tf, int lookback, TFTrendContex
slLevel = ctx.h0;
}
if (mssHit && bar1T != ctx.lastMssTime)
if (mssHit && bar1T != ctx.lastMssTime) // MSS mới (chưa ghi nhận bar này)
{
double swingDepth = MathAbs(ctx.h0 - ctx.l0) / _Point;
if (swingDepth < InpMSSMinDepthPts)
double swingDepth = MathAbs(ctx.h0 - ctx.l0) / _Point; // Độ sâu swing (point)
if (swingDepth < InpMSSMinDepthPts) // Quá nông → bỏ qua
{
if (InpDebugLog)
PrintFormat("[M5 MSS SKIP] depth=%.0f pts < %d | H0=%.5f L0=%.5f | %s",
@@ -83,10 +81,10 @@ inline void UpdateTFTrendContext(ENUM_TIMEFRAMES tf, int lookback, TFTrendContex
}
else
{
ctx.lastMssTime = bar1T;
ctx.lastMssLevel = entryLevel;
ctx.lastMssBreak = breakDir;
ctx.mssSLSwing = slLevel;
ctx.lastMssTime = bar1T; // Ghi nhận thời điểm MSS
ctx.lastMssLevel = entryLevel; // Giá entry
ctx.lastMssBreak = breakDir; // UP/DOWN
ctx.mssSLSwing = slLevel; // Giá SL (tL0 hoặc tH0)
if (InpDebugLog)
PrintFormat("[M5 MSS] %s | entry=%.5f SL=%.5f depth=%.0fpts | close=%.5f | H0=%.5f L0=%.5f | %s",
@@ -100,15 +98,15 @@ inline void UpdateTFTrendContext(ENUM_TIMEFRAMES tf, int lookback, TFTrendContex
double h0, h1, l0, l1;
int idxH0, idxH1, idxL0, idxL1;
if (!ScanSwingStructure(tf, lookback, h0, h1, idxH0, idxH1, l0, l1, idxL0, idxL1))
{ ctx.trend = DIR_NONE; return; }
{ ctx.trend = DIR_NONE; return; } // Không đủ swing
ctx.h0 = h0; ctx.idxH0 = idxH0;
ctx.h0 = h0; ctx.idxH0 = idxH0; // Gán swing vào context
ctx.h1 = h1; ctx.idxH1 = idxH1;
ctx.l0 = l0; ctx.idxL0 = idxL0;
ctx.l1 = l1; ctx.idxL1 = idxL1;
MarketDir prev = ctx.trend;
ResolveTrendFromSwings(tf, h0, h1, l0, l1, ctx.trend, ctx.keyLevel);
ResolveTrendFromSwings(tf, h0, h1, l0, l1, ctx.trend, ctx.keyLevel); // Suy trend + key level
if (InpDebugLog && ctx.trend != prev)
PrintFormat("[%s TREND] %s → %s | H0=%.5f H1=%.5f L0=%.5f L1=%.5f | KL=%.5f",
@@ -118,20 +116,20 @@ inline void UpdateTFTrendContext(ENUM_TIMEFRAMES tf, int lookback, TFTrendContex
inline void UpdateDailyRiskContext()
{
datetime today = iTime(_Symbol, PERIOD_D1, 0);
if (today != g_DailyRisk.dayStartTime)
datetime today = iTime(_Symbol, PERIOD_D1, 0); // Mốc D1 hiện tại
if (today != g_DailyRisk.dayStartTime) // Sang ngày mới
{
g_DailyRisk.dayStartTime = today;
g_DailyRisk.startBalance = AccountInfoDouble(ACCOUNT_BALANCE);
g_DailyRisk.limitHit = false;
g_DailyRisk.startBalance = AccountInfoDouble(ACCOUNT_BALANCE); // Balance đầu ngày
g_DailyRisk.limitHit = false; // Reset cờ chạm limit
if (InpDebugLog) PrintFormat("[DAILY RISK] New day | start=%.2f", g_DailyRisk.startBalance);
}
if (g_DailyRisk.limitHit) return;
if (g_DailyRisk.limitHit) return; // Đã chạm limit → không cập nhật gì thêm
g_DailyRisk.currentBalance = AccountInfoDouble(ACCOUNT_BALANCE);
double lostPct = (g_DailyRisk.startBalance - g_DailyRisk.currentBalance)
/ g_DailyRisk.startBalance * 100.0;
if (lostPct >= InpMaxDailyLossPct)
/ g_DailyRisk.startBalance * 100.0; // % lỗ so với đầu ngày
if (lostPct >= InpMaxDailyLossPct) // Vượt ngưỡng max daily loss
{
g_DailyRisk.limitHit = true;
PrintFormat("[DAILY RISK] ⛔ Limit hit | lost=%.2f%% | bal=%.2f",
@@ -141,10 +139,10 @@ inline void UpdateDailyRiskContext()
inline void UpdateAllContexts()
{
UpdateDailyRiskContext();
UpdateBiasContext();
UpdateTFTrendContext(InpMiddleTF, InpSwingLookback, g_MiddleTrend);
UpdateTFTrendContext(InpTriggerTF, InpTriggerSwingLookback, g_TriggerTrend);
UpdateDailyRiskContext(); // Cập nhật balance, limit hit
UpdateBiasContext(); // D1 bias
UpdateTFTrendContext(InpMiddleTF, InpSwingLookback, g_MiddleTrend); // H1 swing + trend + (MSS không ở đây)
UpdateTFTrendContext(InpTriggerTF, InpTriggerSwingLookback, g_TriggerTrend); // M5 swing + trend + MSS
}
#endif // EA_ICT_CL__CONTEXTS_MQH
+6 -7
View File
@@ -1,16 +1,15 @@
#ifndef EA_ICT_CL__FILTERS_MQH
#define EA_ICT_CL__FILTERS_MQH
#define EA_ICT_CL__FILTERS_MQH // Tránh include trùng
// Module: Filters
// Put spread/news/day-of-week/max-trades filters here.
// Module: Filters lọc spread (có thể mở rộng news, max trades...)
inline bool Filter_MaxSpreadPoints(const string symbol, const double max_spread_points)
{
if (max_spread_points <= 0) return true;
if (max_spread_points <= 0) return true; // Không giới hạn → luôn pass
const double pt = SymbolInfoDouble(symbol, SYMBOL_POINT);
if (pt <= 0.0) return true;
const double spread_pts = (SymbolInfoDouble(symbol, SYMBOL_ASK) - SymbolInfoDouble(symbol, SYMBOL_BID)) / pt;
return (spread_pts <= max_spread_points);
if (pt <= 0.0) return true; // Point lỗi → bỏ qua check
const double spread_pts = (SymbolInfoDouble(symbol, SYMBOL_ASK) - SymbolInfoDouble(symbol, SYMBOL_BID)) / pt; // Spread theo point
return (spread_pts <= max_spread_points); // Pass khi spread <= ngưỡng
}
#endif // EA_ICT_CL__FILTERS_MQH
+12 -14
View File
@@ -1,29 +1,27 @@
#ifndef EA_ICT_CL__GUARDS_MQH
#define EA_ICT_CL__GUARDS_MQH
#define EA_ICT_CL__GUARDS_MQH // Tránh include trùng
// Module: Guards
// Pre-trade guard checks extracted from EA_ICT_CL.mq5 (Section 3 Guards).
// NOTE: Uses EA globals (g_*) and inputs. Include AFTER globals exist.
// Module: Guards điều kiện trước khi cho chạy state machine (session, daily loss, bias, alignment)
inline bool IsSessionAllowed() { return true; /* TODO: implement session filter using InpLondon/NY hours */ }
inline bool IsDailyLossOK() { return !g_DailyRisk.limitHit; }
inline bool IsBiasValid() { return g_Bias.bias == BIAS_UP || g_Bias.bias == BIAS_DOWN; }
inline bool IsSessionAllowed() { return true; /* TODO: lọc giờ London/NY theo InpLondonStartHour/End, InpNY... */ }
inline bool IsDailyLossOK() { return !g_DailyRisk.limitHit; } // Chưa chạm max daily loss
inline bool IsBiasValid() { return g_Bias.bias == BIAS_UP || g_Bias.bias == BIAS_DOWN; } // Bias rõ (không NONE/SIDEWAY)
inline bool IsMiddleTrendAligned()
{
if (g_MiddleTrend.trend == DIR_NONE) return false;
if (g_MiddleTrend.trend == DIR_NONE) return false; // H1 không có trend → không align
return (g_Bias.bias == BIAS_UP && g_MiddleTrend.trend == DIR_UP) ||
(g_Bias.bias == BIAS_DOWN && g_MiddleTrend.trend == DIR_DOWN);
(g_Bias.bias == BIAS_DOWN && g_MiddleTrend.trend == DIR_DOWN); // D1 và H1 cùng chiều
}
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; }
return true;
if (!IsSessionAllowed()) { g_BlockReason = BLOCK_SESSION; return false; } // Ngoài giờ trade
if (!IsDailyLossOK()) { g_BlockReason = BLOCK_DAILY_LOSS; return false; } // Đã chạm limit lỗ
if (!IsBiasValid()) { g_BlockReason = BLOCK_NO_BIAS; return false; } // Không có bias
if (!IsMiddleTrendAligned()) { g_BlockReason = BLOCK_BIAS_MISMATCH; return false; } // D1 ≠ H1
return true; // Tất cả pass
}
#endif // EA_ICT_CL__GUARDS_MQH
+9 -10
View File
@@ -1,22 +1,21 @@
#ifndef EA_ICT_CL__INDICATORS_MQH
#define EA_ICT_CL__INDICATORS_MQH
#define EA_ICT_CL__INDICATORS_MQH // Tránh include trùng
// Module: Indicators
// Keep indicator handle lifecycle helpers here. This file is safe to include now.
// Module: Indicators copy dữ liệu buffer/time an toàn (series index 0 = mới nhất)
inline bool CopyBufferSafe(const int handle, const int buffer, const int start_pos, const int count, double &out[])
{
if (handle == INVALID_HANDLE) return false;
ArraySetAsSeries(out, true);
const int copied = CopyBuffer(handle, buffer, start_pos, count, out);
return (copied == count);
if (handle == INVALID_HANDLE) return false; // Handle không hợp lệ
ArraySetAsSeries(out, true); // Index 0 = bar mới nhất
const int copied = CopyBuffer(handle, buffer, start_pos, count, out); // Copy dữ liệu indicator
return (copied == count); // Thành công khi copy đủ count phần tử
}
inline bool CopyTimeSafe(const string symbol, const ENUM_TIMEFRAMES tf, const int start_pos, const int count, datetime &out[])
{
ArraySetAsSeries(out, true);
const int copied = CopyTime(symbol, tf, start_pos, count, out);
return (copied == count);
ArraySetAsSeries(out, true); // Index 0 = bar mới nhất
const int copied = CopyTime(symbol, tf, start_pos, count, out); // Copy thời gian mở bar
return (copied == count); // Thành công khi copy đủ count
}
#endif // EA_ICT_CL__INDICATORS_MQH
+6 -6
View File
@@ -1,18 +1,18 @@
#ifndef EA_ICT_CL__LOGGING_MQH
#define EA_ICT_CL__LOGGING_MQH
#define EA_ICT_CL__LOGGING_MQH // Tránh include trùng
// Module: Logging
// Module: Logging in log ra Journal khi bật InpDebugLog
inline void LogPrint(const bool enabled, const string msg)
{
if (!enabled) return;
Print(msg);
if (!enabled) return; // Tắt log thì thoát
Print(msg); // In chuỗi ra Experts/Journal
}
inline void LogPrintF(const bool enabled, const string fmt, const string a0 = "", const string a1 = "", const string a2 = "")
{
if (!enabled) return;
Print(StringFormat(fmt, a0, a1, a2));
if (!enabled) return; // Tắt log thì thoát
Print(StringFormat(fmt, a0, a1, a2)); // Format rồi in (tối đa 3 tham số string)
}
#endif // EA_ICT_CL__LOGGING_MQH
+15 -16
View File
@@ -1,29 +1,28 @@
#ifndef EA_ICT_CL__MARKET_MQH
#define EA_ICT_CL__MARKET_MQH
#define EA_ICT_CL__MARKET_MQH // Tránh include trùng
// Module: Market
// Market/tick/contract-spec helpers live here.
// Module: Market giá, point, spread, điều kiện trade
inline double GetBid(const string symbol) { return SymbolInfoDouble(symbol, SYMBOL_BID); }
inline double GetAsk(const string symbol) { return SymbolInfoDouble(symbol, SYMBOL_ASK); }
inline double GetPoint(const string symbol) { return SymbolInfoDouble(symbol, SYMBOL_POINT); }
inline int GetDigits(const string symbol) { return (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); }
inline double GetBid(const string symbol) { return SymbolInfoDouble(symbol, SYMBOL_BID); } // Giá bid
inline double GetAsk(const string symbol) { return SymbolInfoDouble(symbol, SYMBOL_ASK); } // Giá ask
inline double GetPoint(const string symbol) { return SymbolInfoDouble(symbol, SYMBOL_POINT); } // Kích thước 1 point
inline int GetDigits(const string symbol) { return (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); } // Số chữ số thập phân
inline double GetSpreadPoints(const string symbol)
{
const double bid = GetBid(symbol);
const double ask = GetAsk(symbol);
const double pt = GetPoint(symbol);
if (pt <= 0.0) return 0.0;
return (ask - bid) / pt;
const double bid = GetBid(symbol); // Lấy bid
const double ask = GetAsk(symbol); // Lấy ask
const double pt = GetPoint(symbol); // Lấy point
if (pt <= 0.0) return 0.0; // Tránh chia 0
return (ask - bid) / pt; // Spread quy đổi ra số point
}
inline bool IsTradeAllowedNow(const string symbol)
{
if (!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) return false;
if (!MQLInfoInteger(MQL_TRADE_ALLOWED)) return false;
if (!SymbolInfoInteger(symbol, SYMBOL_TRADE_MODE)) return false;
return true;
if (!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) return false; // Terminal có cho trade không
if (!MQLInfoInteger(MQL_TRADE_ALLOWED)) return false; // EA có quyền trade không
if (!SymbolInfoInteger(symbol, SYMBOL_TRADE_MODE)) return false; // Symbol có cho trade không
return true; // Đủ điều kiện
}
#endif // EA_ICT_CL__MARKET_MQH
+5 -6
View File
@@ -1,18 +1,17 @@
#ifndef EA_ICT_CL__ORDERS_MQH
#define EA_ICT_CL__ORDERS_MQH
#define EA_ICT_CL__ORDERS_MQH // Tránh include trùng
// Module: Orders
// Helpers for building request fields, normalize price, magic/comment conventions.
// Module: Orders chuẩn hóa giá, tạo comment lệnh (magic, fvg_id)
inline double NormalizePrice(const string symbol, const double price)
{
const int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
return NormalizeDouble(price, digits);
const int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); // Số chữ số thập phân của symbol
return NormalizeDouble(price, digits); // Làm tròn giá theo digits
}
inline string BuildOrderComment(const long magic, const int fvg_id, const string tag = "ICT")
{
return StringFormat("%s|mg=%I64d|fvg=%d", tag, magic, fvg_id);
return StringFormat("%s|mg=%I64d|fvg=%d", tag, magic, fvg_id); // Comment để trace EA + FVG
}
#endif // EA_ICT_CL__ORDERS_MQH
+97 -114
View File
@@ -1,134 +1,117 @@
# EA_ICT_CL Kiến trúc & luồng chạy
# EA_ICT_CL Kiến trúc & cấu trúc file
File chính: `Experts/EA_ICT_CL.mq5`
Thư mục module: `Experts/EA_ICT_CL/` (các `.mqh`)
**EA chính:** `Experts/EA_ICT_CL.mq5`
**Thư mục module:** `Experts/EA_ICT_CL/` (các file `.mqh`)
## 1) Mục tiêu thiết kế
---
- `EA_ICT_CL.mq5` nên là **file “glue”**: `OnInit/OnDeinit/OnTick/...` + gọi hàm module.
- Mỗi `.mqh` chỉ gánh **một trách nhiệm**: config/state/signals/risk/trade/filters/…
- Migrate **từng phần nhỏ** để tránh trùng định nghĩa (enum/struct/global) và dễ debug.
## 1. Cấu trúc thư mục và chức năng từng file
## 2) Luồng chạy tổng thể (theo mô tả hiện tại trong header v4.3)
### File chính (entry point)
### Bối cảnh timeframe
| File | Vai trò |
|------|--------|
| **`EA_ICT_CL.mq5`** | File “glue”: khai báo globals, include 3 tầng module, và chỉ chứa `OnInit()`, `OnTick()`, `OnDeinit()`. Không chứa logic nghiệp vụ. |
- **BiasTF (D1)**: xác định bias (UP/DOWN/SIDEWAY/NONE)
- **MiddleTF (H1)**: xác định trend + quét FVG thuận xu hướng
- **TriggerTF (M5)**: xác nhận entry bằng **MSS** (market structure shift)
### Layer 1 Cấu hình & kiểu dữ liệu (include đầu tiên)
| 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. |
### Layer 2 Tiện ích (sau Config + State)
| File | Chức năng |
|------|-----------|
| **`Utils.mqh`** | Hàm helper thuần: `ClampDouble`, `ClampInt`, `RoundToStep`, `IsNewBar`. |
| **`Logging.mqh`** | Wrapper log bật/tắt: `LogPrint`, `LogPrintF` (gọi khi `InpDebugLog` bật). |
| **`Market.mqh`** | Helper market: `GetBid`, `GetAsk`, `GetPoint`, `GetDigits`, `GetSpreadPoints`, `IsTradeAllowedNow`. |
| **`Indicators.mqh`** | Wrapper an toàn: `CopyBufferSafe`, `CopyTimeSafe` cho dữ liệu series. |
| **`Sessions.mqh`** | Lọc theo giờ: `IsHourInRange`, `GetUTCHour` (dùng cho session London/NY). |
| **`Filters.mqh`** | Bộ lọc chung: `Filter_MaxSpreadPoints` (có thể mở rộng news, max trades/day). |
| **`Risk.mqh`** | Risk & volume: `NormalizeVolume`, `LotsFromRiskMoneyAndSLPoints`. |
| **`Orders.mqh`** | Chuẩn hoá order: `NormalizePrice`, `BuildOrderComment`. |
| **`Swing.mqh`** | **Swing structure**: `MyBarShift`, `IsSwingHighAt`, `IsSwingLowAt`, `ScanSwingStructure`, `ResolveTrendFromSwings`. |
| **`Trailing.mqh`** | Placeholder cho logic trailing / breakeven / partial close (chưa implement). |
### Layer 3 Logic nghiệp vụ (sau khi đã khai báo globals trong `.mq5`)
| 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. |
| **`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`. |
| **`Drawing.mqh`** | **Vẽ trên chart**: `DrawOneSwingPoint`, `DrawMiddleSwingPoints`, `DrawTriggerSwingPoints`, `DrawMSSMarker`, `DrawMSSMarkers`, `DrawOrderVisualization`, `DrawOneFVGRecord`, `DrawFVGPool`, `DrawContextDebug`, `DrawVisuals`. Dùng prefix `PREFIX_SWING_MIDDLE`, `PREFIX_ORDER_VISUAL`, v.v. |
---
## 2. Thứ tự include trong `EA_ICT_CL.mq5`
```
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_*
Layer 3: Contexts.mqh → Guards.mqh → Signals_BOS_FVG_OB.mqh → Trade.mqh → StateMachine.mqh → Drawing.mqh
```
Layer 3 phải include **sau** khi globals và prefix đã được khai báo trong `.mq5`.
---
## 3. Luồng chạy tổng thể (v4.3)
### 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).
### State machine
EA đang dùng state machine:
| State | Mục đích |
|-------|----------|
| **EA_IDLE** | Chọn FVG “tốt nhất” (ưu tiên TOUCHED, rồi PENDING mới nhất). |
| **EA_WAIT_TOUCH** | Chờ giá retrace vào vùng FVG (H1). |
| **EA_WAIT_TRIGGER** | Đã touch FVG → chờ M5 MSS (chỉ detect MSS trong state này). |
| **EA_IN_TRADE** | Theo dõi pending/position; reset khi fill, cancel hoặc đóng lệnh. |
- **`EA_IDLE`**
- Mục tiêu: tìm/đặt “FVG tốt nhất” (MiddleTF) để theo dõi.
- **`EA_WAIT_TOUCH`**
- Mục tiêu: chờ giá retrace và **touch vào vùng FVG** (H1).
- **`EA_WAIT_TRIGGER`**
- Mục tiêu: khi đã touch FVG, chờ **M5 MSS** xác nhận đảo chiều theo trend.
- v4.3: MSS chỉ detect khi state này.
- **`EA_IN_TRADE`**
- Mục tiêu: quản lý pending/position (trailing/timeout/cleanup tuỳ EA).
### Luồng quyết định (mỗi tick)
### Decision flow “từ trên xuống”
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.
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).
1) **D1 Bias**
- Xác định `HTFBias` (UP/DOWN/SIDEWAY/NONE).
2) **H1 Trend / Swing structure**
- Xác định `MarketDir` (UP/DOWN/NONE) và các swing gần nhất: `h0/h1/l0/l1`.
3) **Quét H1 FVG**
- Tạo/duy trì pool FVG (`g_FVGPool`) tối đa `MAX_FVG_POOL`.
- FVG có lifecycle: `PENDING → TOUCHED → USED`.
4) **Touch FVG**
- Khi bid/ask đi vào vùng gap → `touchTime` được set, chuyển state sang chờ trigger.
5) **M5 MSS (chỉ khi `EA_WAIT_TRIGGER`)**
- Nếu H1 UP: bull MSS khi close phá **OLD** `tH0` → entry = `tH0`, SL = `tL0`.
- Nếu H1 DOWN: bear MSS khi close phá **OLD** `tL0` → entry = `tL0`, SL = `tH0`.
6) **Lập kế hoạch lệnh (OrderPlan)**
- `direction`: +1 BUY LIMIT / -1 SELL LIMIT
- `entry`, `stopLoss`, `takeProfit`, `lot`
7) **Risk sizing**
- Lot theo `%risk` và khoảng SL (points).
- Chặn trade nếu chạm max daily loss (`InpMaxDailyLossPct`).
8) **Gửi pending limit**
- Gắn `magic` và comment có `fvg_id` để trace.
### Entry / SL / TP
## 3) Các folder/file module (vai trò + khi nào dùng)
- **Entry:** giá swing bị phá (tH0 cho buy, tL0 cho sell).
- **SL:** swing đối diện (tL0 cho buy, tH0 cho sell) + buffer 2 point.
- **TP:** Entry ± `InpRiskReward` × |Entry SL|.
Thư mục: `Experts/EA_ICT_CL/`
---
- **`Config.mqh`**
- Nơi đưa `input`, `enum` và hằng số cấu hình.
- Khi migrate: chuyển dần `input ...` và các enum khỏi `.mq5` sang đây (rồi include).
## 4. Đặt tên object trên chart (prefix)
- **`State.mqh`**
- Nơi đưa `struct` contexts (bias/trend/fvg/orderplan/daily risk) + state machine.
- Khi migrate: chuyển dần các `struct`, `g_*` globals sang đây để module nào cũng dùng chung.
Các hằng trong `EA_ICT_CL.mq5` dùng cho Drawing:
- **`Utils.mqh`**
- Helper thuần: clamp/round/newbar/time formatting…
- Ưu tiên migrate các hàm nhỏ, không phụ thuộc EA logic (vd `MyBarShift` cũng có thể đặt vào đây hoặc `Market/Indicators`).
- `PREFIX_SWING_MIDDLE` H1 swing (MiddleH0/L0…).
- `PREFIX_SWING_TRIGGER` M5 swing (TriggerH0/L0…).
- `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).
- **`Logging.mqh`**
- Chuẩn hoá log bật/tắt theo `InpDebugLog`.
- Có thể mở rộng: prefix theo symbol/tf/state, ghi file, debug panel.
---
- **`Market.mqh`**
- Helper về symbol specs (digits/point/spread), trade allowed, quote access…
- **`Sessions.mqh`**
- Helper session/time filter (London/NY theo UTC).
- Khi migrate: đưa logic “được trade trong giờ nào?” sang đây.
- **`Filters.mqh`**
- Các bộ lọc: spread, news (nếu có), day-of-week, max trades/day, cooldown…
- **`Indicators.mqh`**
- Wrapper CopyBuffer/CopyTime, quản lý handles nếu bạn dùng iMA/iATR/…
- **`Signals_BOS_FVG_OB.mqh`**
- Nơi tập trung **logic tín hiệu**: BOS/MSS/FVG/OB… và build `OrderPlan`.
- Mục tiêu: module này “pure” nhất có thể (input/state snapshot → plan).
- **`Risk.mqh`**
- Tính lot, normalize volume, kiểm soát daily drawdown.
- **`Orders.mqh`**
- Chuẩn hoá normalize price, build comment, mapping direction→order type…
- **`Trade.mqh`**
- Các hàm “side-effect”: `OrderSend`, modify, cancel, close.
- **`Trailing.mqh`**
- Trailing/BE/partial close (nếu có).
## 4) Gợi ý thứ tự migrate (an toàn, ít rủi ro nhất)
Để tránh trùng định nghĩa và lỗi include:
1) **Move helpers**: `MyBarShift`, swing helper functions → `Utils.mqh` (hoặc tách `Swing.mqh` nếu bạn muốn).
2) **Move trade wrappers**: các đoạn `MqlTradeRequest/Result``Trade.mqh` + helper normalize → `Orders.mqh`.
3) **Move risk**: tính lot / daily loss → `Risk.mqh`.
4) **Move filters/session**`Sessions.mqh`, `Filters.mqh`.
5) **Cuối cùng mới move types**: enums/struct/global sang `Config.mqh` + `State.mqh`.
> Lưu ý: Chỉ include module nào khi bạn đã chuyển phần tương ứng khỏi `.mq5` (để tránh “redefinition”).
## 5) Quy ước include trong `EA_ICT_CL.mq5` (gợi ý)
Khi bắt đầu migrate, thường include theo thứ tự:
1. `Config.mqh`
2. `State.mqh`
3. `Utils.mqh`
4. `Logging.mqh`
5. `Market.mqh`
6. `Indicators.mqh`
7. `Sessions.mqh` / `Filters.mqh`
8. `Risk.mqh`
9. `Orders.mqh`
10. `Trade.mqh`
11. `Signals_BOS_FVG_OB.mqh`
12. `Trailing.mqh`
## 5. Mở rộng / chỉnh sửa gợi ý
- **Thêm input:** chỉnh trong `Config.mqh`.
- **Thêm enum/struct:** chỉnh trong `State.mqh`.
- **Logic FVG / chọn FVG:** chỉnh trong `Signals_BOS_FVG_OB.mqh`.
- **Tính lot / gửi lệnh:** chỉnh trong `Trade.mqh`.
- **Chuyển state / xử lý từng state:** chỉnh trong `StateMachine.mqh`.
- **Trailing / breakeven:** bổ sung trong `Trailing.mqh` và gọi từ state IN_TRADE (trong `StateMachine.mqh` hoặc từ `OnTick`).
- **Vẽ thêm object:** chỉnh trong `Drawing.mqh`, dùng đúng prefix để `OnDeinit` có thể dọn theo prefix nếu cần.
+15 -16
View File
@@ -1,40 +1,39 @@
#ifndef EA_ICT_CL__RISK_MQH
#define EA_ICT_CL__RISK_MQH
#define EA_ICT_CL__RISK_MQH // Tránh include trùng
// Module: Risk
// Put risk sizing and daily loss logic here.
// Module: Risk chuẩn hóa volume, tính lot từ tiền risk và SL (point)
inline double NormalizeVolume(const string symbol, const double vol)
{
const double vmin = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
const double vmax = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
const double vstep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
const double vmin = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); // Lot tối thiểu
const double vmax = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); // Lot tối đa
const double vstep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP); // Bước lot
double v = vol;
if (vstep > 0.0) v = MathFloor(v / vstep) * vstep;
if (v < vmin) v = vmin;
if (v > vmax) v = vmax;
if (vstep > 0.0) v = MathFloor(v / vstep) * vstep; // Làm tròn xuống theo step
if (v < vmin) v = vmin; // Không nhỏ hơn min
if (v > vmax) v = vmax; // Không lớn hơn max
return v;
}
inline double LotsFromRiskMoneyAndSLPoints(const string symbol, const double risk_money, const double sl_points)
{
if (risk_money <= 0.0) return 0.0;
if (sl_points <= 0.0) return 0.0;
if (risk_money <= 0.0) return 0.0; // Không risk → 0 lot
if (sl_points <= 0.0) return 0.0; // SL = 0 → không tính được
double tick_value = 0.0, tick_size = 0.0;
if (!SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE, tick_value)) return 0.0;
if (!SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE, tick_size)) return 0.0;
if (!SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE, tick_value)) return 0.0; // Giá trị 1 tick/lot
if (!SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE, tick_size)) return 0.0; // Kích thước tick
if (tick_value <= 0.0 || tick_size <= 0.0) return 0.0;
const double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
if (point <= 0.0) return 0.0;
// Money per 1 lot per point move:
// Tiền mất trên 1 point khi di chuyển 1 lot:
const double money_per_point_1lot = tick_value * (point / tick_size);
if (money_per_point_1lot <= 0.0) return 0.0;
const double lots = risk_money / (sl_points * money_per_point_1lot);
return NormalizeVolume(symbol, lots);
const double lots = risk_money / (sl_points * money_per_point_1lot); // Lot = risk_money / (sl_points * $/point)
return NormalizeVolume(symbol, lots); // Chuẩn hóa theo min/max/step
}
#endif // EA_ICT_CL__RISK_MQH
+8 -11
View File
@@ -1,24 +1,21 @@
#ifndef EA_ICT_CL__SESSIONS_MQH
#define EA_ICT_CL__SESSIONS_MQH
#define EA_ICT_CL__SESSIONS_MQH // Tránh include trùng
// Module: Sessions
// Time/session filters live here (UTC-based if your EA uses UTC inputs).
// Module: Sessions kiểm tra giờ trong khoảng (UTC), dùng cho London/NY
inline bool IsHourInRange(const int hour, const int start_hour, const int end_hour)
{
// Handles normal and overnight windows:
// - start < end: [start, end)
// - start > end: [start, 24) U [0, end)
if (start_hour == end_hour) return true;
if (start_hour < end_hour) return (hour >= start_hour && hour < end_hour);
return (hour >= start_hour || hour < end_hour);
// start < end: [start, end); start > end: qua đêm [start,24) U [0,end)
if (start_hour == end_hour) return true; // Cả ngày
if (start_hour < end_hour) return (hour >= start_hour && hour < end_hour); // Cùng ngày
return (hour >= start_hour || hour < end_hour); // Qua nửa đêm
}
inline int GetUTCHour(const datetime t)
{
MqlDateTime dt;
TimeToStruct(t, dt);
return dt.hour;
TimeToStruct(t, dt); // Chuyển datetime sang struct (năm, tháng, giờ...)
return dt.hour; // Trả về giờ (023)
}
#endif // EA_ICT_CL__SESSIONS_MQH
+5 -8
View File
@@ -1,10 +1,7 @@
#ifndef EA_ICT_CL__SIGNALS_BOS_FVG_OB_MQH
#define EA_ICT_CL__SIGNALS_BOS_FVG_OB_MQH
#define EA_ICT_CL__SIGNALS_BOS_FVG_OB_MQH // Tránh include trùng
// Module: Signals (FVG)
// Extracted from EA_ICT_CL.mq5 (Sections 5, 6, 7, 8).
// FVG helpers, scan/register, status update, best selector.
// NOTE: Uses EA globals (g_*) and inputs. Include AFTER globals exist.
// Module: Signals (FVG) helper FVG, quét/đăng ký pool, cập nhật trạng thái, chọn FVG tốt nhất
//+------------------------------------------------------------------+
//| SECTION 5 FVG HELPERS |
@@ -15,14 +12,14 @@ inline bool IsCandleStrong(ENUM_TIMEFRAMES tf, int i)
double h = iHigh(_Symbol, tf, i), l = iLow(_Symbol, tf, i);
double o = iOpen(_Symbol, tf, i), c = iClose(_Symbol, tf, i);
double range = h - l;
if (range < _Point) return false;
return (MathAbs(c - o) / range * 100.0) >= InpFVGMinBodyPct;
if (range < _Point) return false; // Tránh chia 0
return (MathAbs(c - o) / range * 100.0) >= InpFVGMinBodyPct; // Body % >= ngưỡng = nến mạnh
}
inline bool IsFVGInPool(datetime created)
{
for (int j = 0; j < g_FVGCount; j++)
if (g_FVGPool[j].createdTime == created) return true;
if (g_FVGPool[j].createdTime == created) return true; // Đã có FVG cùng thời điểm tạo
return false;
}
+44 -46
View File
@@ -1,33 +1,31 @@
#ifndef EA_ICT_CL__STATE_MQH
#define EA_ICT_CL__STATE_MQH
#define EA_ICT_CL__STATE_MQH // Tránh include trùng
// Module: State
// Core EA types: enums + structs used across all modules.
// Extracted from EA_ICT_CL.mq5 (enums + structs sections).
// Module: State enums và struct dùng chung toàn EA
//====================================================
// ENUMS
//====================================================
enum EAState
{
EA_IDLE,
EA_WAIT_TOUCH,
EA_WAIT_TRIGGER,
EA_IN_TRADE
EA_IDLE, // Chờ chọn FVG tốt nhất
EA_WAIT_TOUCH, // Chờ giá chạm vào vùng FVG
EA_WAIT_TRIGGER, // Đã touch FVG, chờ M5 MSS
EA_IN_TRADE // Đã gửi pending / đang giữ position
};
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 HTFBias { BIAS_NONE=0, BIAS_UP=1, BIAS_DOWN=-1, BIAS_SIDEWAY=2 }; // Bias D1
enum MarketDir { DIR_NONE=0, DIR_UP=1, DIR_DOWN=-1 }; // Hướng trend H1/M5
enum BlockReason
{
BLOCK_NONE, BLOCK_SESSION, BLOCK_DAILY_LOSS,
BLOCK_BIAS_MISMATCH, BLOCK_NO_BIAS
BLOCK_NONE, BLOCK_SESSION, BLOCK_DAILY_LOSS, // Không chặn / chặn session / chặn daily loss
BLOCK_BIAS_MISMATCH, BLOCK_NO_BIAS // Bias không khớp H1 / không có bias
};
enum FVGStatus
{
FVG_PENDING,
FVG_TOUCHED,
FVG_USED
FVG_PENDING, // Chưa bị giá chạm
FVG_TOUCHED, // Đã chạm, chờ MSS
FVG_USED // Đã dùng (broken/expired/triggered)
};
//====================================================
@@ -35,55 +33,55 @@ enum FVGStatus
//====================================================
struct BiasContext
{
HTFBias bias;
double rangeHigh, rangeLow;
datetime lastBarTime;
HTFBias bias; // UP/DOWN/SIDEWAY/NONE
double rangeHigh, rangeLow; // Vùng sideway (nếu có)
datetime lastBarTime; // Thời gian bar D1 đã xử lý (tránh cập nhật trùng)
};
struct TFTrendContext
{
MarketDir trend;
double h0, h1, l0, l1;
int idxH0, idxH1, idxL0, idxL1;
double keyLevel;
datetime lastBarTime;
MarketDir trend; // DIR_UP / DIR_DOWN / DIR_NONE
double h0, h1, l0, l1; // Giá 2 swing high, 2 swing low gần nhất
int idxH0, idxH1, idxL0, idxL1; // Chỉ số bar tương ứng
double keyLevel; // Mức key (l0 hoặc h0 tùy trend)
datetime lastBarTime; // Bar đã cập nhật (tránh cập nhật lại mỗi tick)
datetime lastMssTime;
double lastMssLevel;
MarketDir lastMssBreak;
double mssSLSwing;
datetime lastMssTime; // Thời gian MSS gần nhất (chỉ M5)
double lastMssLevel; // Giá entry MSS (tH0 hoặc tL0)
MarketDir lastMssBreak; // Hướng break (UP/DOWN)
double mssSLSwing; // Giá SL tương ứng (tL0 hoặc tH0)
};
struct FVGRecord
{
int id;
FVGStatus status;
int usedCase;
MarketDir direction;
double high, low, mid;
datetime createdTime;
datetime touchTime;
datetime usedTime;
MarketDir triggerTrendAtTouch;
int id; // ID FVG trong pool
FVGStatus status; // PENDING / TOUCHED / USED
int usedCase; // 0=expired, 1=broken, 2=triggered by MSS
MarketDir direction; // DIR_UP (bull FVG) / DIR_DOWN (bear FVG)
double high, low, mid; // Vùng gap và điểm giữa
datetime createdTime; // Thời điểm tạo FVG
datetime touchTime; // Thời điểm giá chạm (nếu TOUCHED)
datetime usedTime; // Thời điểm chuyển USED
MarketDir triggerTrendAtTouch; // Trend M5 lúc touch (debug)
datetime mssTime;
double mssEntry;
double mssSL;
datetime mssTime; // Thời điểm MSS (nếu usedCase==2)
double mssEntry; // Entry level từ MSS
double mssSL; // SL level từ MSS
};
struct OrderPlan
{
bool valid;
int direction;
double entry, stopLoss, takeProfit, lot;
int parentFVGId;
bool valid; // Plan có hợp lệ không
int direction; // +1 buy, -1 sell
double entry, stopLoss, takeProfit, lot; // Giá và khối lượng
int parentFVGId; // ID FVG gốc (để trace)
};
struct DailyRiskContext
{
double startBalance, currentBalance;
datetime dayStartTime;
bool limitHit;
double startBalance, currentBalance; // Balance đầu ngày và hiện tại
datetime dayStartTime; // Mốc đầu ngày D1
bool limitHit; // Đã chạm max daily loss chưa
};
#endif // EA_ICT_CL__STATE_MQH
+22 -26
View File
@@ -1,35 +1,31 @@
#ifndef EA_ICT_CL__SWING_MQH
#define EA_ICT_CL__SWING_MQH
#define EA_ICT_CL__SWING_MQH // Tránh include trùng
// Module: Swing
// Extracted from EA_ICT_CL.mq5 (Section 1 Swing helpers).
// Depends on:
// - InpSwingRange (input)
// - MarketDir enum values DIR_UP/DIR_DOWN/DIR_NONE
// Module: Swing tìm bar shift theo time, swing high/low, quét cấu trúc swing, suy trend
//+------------------------------------------------------------------+
//| MQL5 HELPER: iBarShift replacement |
//| MyBarShift: tìm chỉ số bar (series) ứng với thời gian time |
//+------------------------------------------------------------------+
inline int MyBarShift(string symbol, ENUM_TIMEFRAMES tf, datetime time, bool exact = false)
{
datetime arr[];
int maxCopy = MathMin(Bars(symbol, tf), 5000);
int maxCopy = MathMin(Bars(symbol, tf), 5000); // Giới hạn copy
int copied = CopyTime(symbol, tf, 0, maxCopy, arr);
if (copied <= 0) return -1;
for (int i = copied - 1; i >= 0; i--)
for (int i = copied - 1; i >= 0; i--) // Duyệt từ bar cũ → mới
{
if (arr[i] <= time)
return copied - 1 - i;
return copied - 1 - i; // Index trong series (0 = mới nhất)
}
return exact ? -1 : copied - 1;
return exact ? -1 : copied - 1; // exact: không tìm thấy = -1; không exact: trả về bar xa nhất
}
inline bool IsSwingHighAt(ENUM_TIMEFRAMES tf, int i)
{
double p = iHigh(_Symbol, tf, i);
for (int k = 1; k <= InpSwingRange; k++)
if (iHigh(_Symbol, tf, i-k) >= p || iHigh(_Symbol, tf, i+k) >= p) return false;
double p = iHigh(_Symbol, tf, i); // High tại bar i
for (int k = 1; k <= InpSwingRange; k++) // So với InpSwingRange bar mỗi bên
if (iHigh(_Symbol, tf, i-k) >= p || iHigh(_Symbol, tf, i+k) >= p) return false; // Có high cao hơn → không phải swing high
return true;
}
@@ -46,20 +42,20 @@ inline bool ScanSwingStructure(
double &h0, double &h1, int &idxH0, int &idxH1,
double &l0, double &l1, int &idxL0, int &idxL1)
{
int maxBar = MathMin(lookback, Bars(_Symbol, tf) - InpSwingRange - 2);
double highs[2]; int hiIdx[2]; int hc = 0;
double lows [2]; int loIdx[2]; int lc = 0;
int maxBar = MathMin(lookback, Bars(_Symbol, tf) - InpSwingRange - 2); // Giới hạn quét
double highs[2]; int hiIdx[2]; int hc = 0; // 2 swing high gần nhất
double lows [2]; int loIdx[2]; int lc = 0; // 2 swing low gần nhất
for (int i = InpSwingRange + 1; i <= maxBar; i++)
for (int i = InpSwingRange + 1; i <= maxBar; i++) // Từ bar gần hiện tại trở lại
{
if (hc < 2 && IsSwingHighAt(tf, i)) { highs[hc] = iHigh(_Symbol, tf, i); hiIdx[hc] = i; hc++; }
if (lc < 2 && IsSwingLowAt (tf, i)) { lows [lc] = iLow (_Symbol, tf, i); loIdx[lc] = i; lc++; }
if (hc == 2 && lc == 2) break;
if (hc == 2 && lc == 2) break; // Đủ 2 high + 2 low thì dừng
}
if (hc < 2 || lc < 2) return false;
if (hc < 2 || lc < 2) return false; // Không đủ swing
h0 = highs[0]; idxH0 = hiIdx[0];
h1 = highs[1]; idxH1 = hiIdx[1];
h0 = highs[0]; idxH0 = hiIdx[0]; // h0 = swing high gần nhất (index nhỏ)
h1 = highs[1]; idxH1 = hiIdx[1]; // h1 = swing high cũ hơn
l0 = lows [0]; idxL0 = loIdx[0];
l1 = lows [1]; idxL1 = loIdx[1];
return true;
@@ -70,10 +66,10 @@ inline void ResolveTrendFromSwings(
double h0, double h1, double l0, double l1,
MarketDir &trend, double &keyLevel)
{
double c1 = iClose(_Symbol, tf, 1);
if (h0 > h1 && l0 > l1 && c1 > l0) { trend = DIR_UP; keyLevel = l0; }
else if (h0 < h1 && l0 < l1 && c1 < h0) { trend = DIR_DOWN; keyLevel = h0; }
else { trend = DIR_NONE; keyLevel = 0; }
double c1 = iClose(_Symbol, tf, 1); // Close bar 1 (gần nhất đã đóng)
if (h0 > h1 && l0 > l1 && c1 > l0) { trend = DIR_UP; keyLevel = l0; } // HH + HL, giá trên L0 → uptrend
else if (h0 < h1 && l0 < l1 && c1 < h0) { trend = DIR_DOWN; keyLevel = h0; } // LH + LL, giá dưới H0 → downtrend
else { trend = DIR_NONE; keyLevel = 0; } // Không rõ
}
#endif // EA_ICT_CL__SWING_MQH
+2 -3
View File
@@ -1,8 +1,7 @@
#ifndef EA_ICT_CL__TRAILING_MQH
#define EA_ICT_CL__TRAILING_MQH
#define EA_ICT_CL__TRAILING_MQH // Tránh include trùng
// Module: Trailing
// Put trailing/BE/partial-close logic here once you migrate it.
// Module: Trailing placeholder cho trailing stop / breakeven / partial close (chưa implement)
#endif // EA_ICT_CL__TRAILING_MQH
+8 -9
View File
@@ -1,14 +1,13 @@
#ifndef EA_ICT_CL__UTILS_MQH
#define EA_ICT_CL__UTILS_MQH
#define EA_ICT_CL__UTILS_MQH // Tránh include trùng
// Module: Utils
// Put small, dependency-free helpers here (time, rounding, clamps, formatting).
// Module: Utils helper không phụ thuộc logic EA (clamp, round, new bar)
inline double ClampDouble(const double v, const double lo, const double hi)
{
if (v < lo) return lo;
if (v > hi) return hi;
return v;
if (v < lo) return lo; // Nhỏ hơn min → trả về min
if (v > hi) return hi; // Lớn hơn max → trả về max
return v; // Nằm trong [lo,hi] → giữ nguyên
}
inline int ClampInt(const int v, const int lo, const int hi)
@@ -20,13 +19,13 @@ inline int ClampInt(const int v, const int lo, const int hi)
inline double RoundToStep(const double value, const double step)
{
if (step <= 0.0) return value;
return MathRound(value / step) * step;
if (step <= 0.0) return value; // Step không hợp lệ → không làm tròn
return MathRound(value / step) * step; // Làm tròn theo bước step
}
inline bool IsNewBar(const datetime last_bar_time, const datetime current_bar_time)
{
return (current_bar_time != 0 && current_bar_time != last_bar_time);
return (current_bar_time != 0 && current_bar_time != last_bar_time); // Bar mới khi thời gian bar đổi
}
#endif // EA_ICT_CL__UTILS_MQH