From a5069481b4e7f129404d77337c80f0ceaada0a07 Mon Sep 17 00:00:00 2001 From: Bell Date: Tue, 10 Mar 2026 20:51:27 +0700 Subject: [PATCH] Forrmat --- Experts/EA_ICT_CL.mq5 | 139 +++++----- Experts/EA_ICT_CL/Config.mqh | 2 +- Experts/EA_ICT_CL/Drawing.mqh | 488 ++++++++++++++++++++++++++-------- Experts/EA_ICT_CL/Guards.mqh | 1 + Experts/EA_ICT_CL/Market.mqh | 35 ++- Experts/EA_ICT_CL/Risk.mqh | 5 +- Experts/EA_ICT_CL/Swing.mqh | 77 +++--- 7 files changed, 504 insertions(+), 243 deletions(-) diff --git a/Experts/EA_ICT_CL.mq5 b/Experts/EA_ICT_CL.mq5 index c4b2c9e..0990f02 100644 --- a/Experts/EA_ICT_CL.mq5 +++ b/Experts/EA_ICT_CL.mq5 @@ -17,106 +17,93 @@ //| | //| Drawing: objects KHÔNG BAO GIỜ bị xóa, chỉ update | //+------------------------------------------------------------------+ -#property copyright "Bell's ICT EA" // Bản quyền EA -#property version "4.30" // Phiên bản +#property copyright "Bell's ICT EA" +#property version "4.30" -#define MAX_FVG_POOL 30 // Số FVG tối đa trong pool +#define MAX_FVG_POOL 30 -//==================================================== -// LAYER 1 – Config + Types (no dependencies) -//==================================================== -#include "EA_ICT_CL/Config.mqh" // Inputs và cấu hình -#include "EA_ICT_CL/State.mqh" // Enums, structs (EAState, BiasContext, FVGRecord...) +#include "EA_ICT_CL/Config.mqh" +#include "EA_ICT_CL/State.mqh" -//==================================================== -// LAYER 2 – Utility modules (depend on types + inputs) -//==================================================== -#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 +#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" -//==================================================== -// GLOBALS -//==================================================== -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...) +EAState g_State = EA_IDLE; +BlockReason g_BlockReason = BLOCK_NONE; -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 +BiasContext g_Bias; +TFTrendContext g_MiddleTrend; +TFTrendContext g_TriggerTrend; +DailyRiskContext g_DailyRisk; -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...) +FVGRecord g_FVGPool[MAX_FVG_POOL]; +int g_FVGCount = 0; +int g_NextFVGId = 0; +int g_ActiveFVGIdx = -1; +int g_TradeBarIndex = -1; -OrderPlan g_OrderPlan; // Kế hoạch lệnh (entry, SL, TP, lot) -ulong g_PendingTicket = 0; // Ticket lệnh pending đã gửi +OrderPlan g_OrderPlan; +ulong g_PendingTicket = 0; -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 +const string PREFIX_SWING_MIDDLE = "SwingMiddle_"; +const string PREFIX_SWING_TRIGGER = "SwingTrigger_"; +const string PREFIX_MSS_MARKER = "MSSMarker_"; +const string PREFIX_FVG_POOL = "FVGPool_"; +const string PREFIX_ORDER_VISUAL = "OrderVisual_"; +const string PREFIX_DEBUG_PANEL = "DebugPanel_"; -//==================================================== -// LAYER 3 – Logic modules (depend on globals) -//==================================================== -#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 | -//+------------------------------------------------------------------+ +#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" +/** Initializes globals, contexts, FVG pool and first draw. */ int OnInit() { - 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 + 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; - 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) + UpdateAllContexts(); + ScanAndRegisterFVGs(); + DrawVisuals(); 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; // Khởi tạo thành công + return INIT_SUCCEEDED; } +/** Each tick: update contexts, run guards and state machine, optionally redraw. */ void OnTick() { - 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) + UpdateAllContexts(); + if (EvaluateGuards()) + RunStateMachine(); else if (g_State != EA_IDLE) - 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 + ResetToIdle(EnumToString(g_BlockReason)); + if (InpDebugDraw) DrawVisuals(); } +/** Removes swing and debug panel objects and redraws chart. */ void OnDeinit(const int reason) { - 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 + 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); } diff --git a/Experts/EA_ICT_CL/Config.mqh b/Experts/EA_ICT_CL/Config.mqh index 4b557a8..95cb69a 100644 --- a/Experts/EA_ICT_CL/Config.mqh +++ b/Experts/EA_ICT_CL/Config.mqh @@ -14,7 +14,7 @@ input int InpLondonEndHour = 17; input int InpNYStartHour = 13; input int InpNYEndHour = 22; -input int InpSwingRange = 3; +input int InpSwingRange = 2; input int InpSwingLookback = 50; input int InpTriggerSwingLookback = 30; diff --git a/Experts/EA_ICT_CL/Drawing.mqh b/Experts/EA_ICT_CL/Drawing.mqh index d1a123a..c82c5ca 100644 --- a/Experts/EA_ICT_CL/Drawing.mqh +++ b/Experts/EA_ICT_CL/Drawing.mqh @@ -12,7 +12,8 @@ inline void DrawOneSwingPoint( string keyLevelObjName = prefix + "KL_" + tag; datetime barTime = iTime(_Symbol, tf, barIdx); - if (ObjectFind(0, arrowObjName) < 0) ObjectCreate(0, arrowObjName, OBJ_ARROW, 0, barTime, price); + if (ObjectFind(0, arrowObjName) < 0) + ObjectCreate(0, arrowObjName, OBJ_ARROW, 0, barTime, price); ObjectSetInteger(0, arrowObjName, OBJPROP_ARROWCODE, isHigh ? 234 : 233); ObjectSetInteger(0, arrowObjName, OBJPROP_COLOR, clr); ObjectSetInteger(0, arrowObjName, OBJPROP_WIDTH, arrowSz); @@ -21,7 +22,8 @@ inline void DrawOneSwingPoint( double barRange = iHigh(_Symbol, tf, barIdx) - iLow(_Symbol, tf, barIdx); double textY = isHigh ? price + barRange * 0.3 : price - barRange * 0.3; - if (ObjectFind(0, textObjName) < 0) ObjectCreate(0, textObjName, OBJ_TEXT, 0, barTime, textY); + if (ObjectFind(0, textObjName) < 0) + ObjectCreate(0, textObjName, OBJ_TEXT, 0, barTime, textY); ObjectMove(0, textObjName, 0, barTime, textY); ObjectSetString (0, textObjName, OBJPROP_TEXT, tag); ObjectSetInteger(0, textObjName, OBJPROP_COLOR, clr); @@ -31,7 +33,8 @@ inline void DrawOneSwingPoint( if (isKL) { datetime endTime = iTime(_Symbol, tf, 0); - if (ObjectFind(0, keyLevelObjName) < 0) ObjectCreate(0, keyLevelObjName, OBJ_TREND, 0, barTime, price, endTime, price); + if (ObjectFind(0, keyLevelObjName) < 0) + ObjectCreate(0, keyLevelObjName, OBJ_TREND, 0, barTime, price, endTime, price); ObjectSetInteger(0, keyLevelObjName, OBJPROP_COLOR, clr); ObjectSetInteger(0, keyLevelObjName, OBJPROP_STYLE, STYLE_DASH); ObjectSetInteger(0, keyLevelObjName, OBJPROP_WIDTH, 1); @@ -52,10 +55,26 @@ inline void DrawMiddleSwingPoints() bool isUp = (g_MiddleTrend.trend == DIR_UP); bool isDown = (g_MiddleTrend.trend == DIR_DOWN); - DrawOneSwingPoint(PREFIX_SWING_MIDDLE, InpMiddleTF, "MiddleH0", true, g_MiddleTrend.idxH0, g_MiddleTrend.h0, clrAqua, isDown, 2, 8); - DrawOneSwingPoint(PREFIX_SWING_MIDDLE, InpMiddleTF, "MiddleH1", true, g_MiddleTrend.idxH1, g_MiddleTrend.h1, C'0,140,160', false, 2, 8); - DrawOneSwingPoint(PREFIX_SWING_MIDDLE, InpMiddleTF, "MiddleL0", false, g_MiddleTrend.idxL0, g_MiddleTrend.l0, clrYellow, isUp, 2, 8); - DrawOneSwingPoint(PREFIX_SWING_MIDDLE, InpMiddleTF, "MiddleL1", false, g_MiddleTrend.idxL1, g_MiddleTrend.l1, C'160,140,0', false, 2, 8); + DrawOneSwingPoint( + PREFIX_SWING_MIDDLE, InpMiddleTF, "MiddleH0", + true, g_MiddleTrend.idxH0, g_MiddleTrend.h0, + clrAqua, isDown, 2, 8 + ); + DrawOneSwingPoint( + PREFIX_SWING_MIDDLE, InpMiddleTF, "MiddleH1", + true, g_MiddleTrend.idxH1, g_MiddleTrend.h1, + C'0,140,160', false, 2, 8 + ); + DrawOneSwingPoint( + PREFIX_SWING_MIDDLE, InpMiddleTF, "MiddleL0", + false, g_MiddleTrend.idxL0, g_MiddleTrend.l0, + clrYellow, isUp, 2, 8 + ); + DrawOneSwingPoint( + PREFIX_SWING_MIDDLE, InpMiddleTF, "MiddleL1", + false, g_MiddleTrend.idxL1, g_MiddleTrend.l1, + C'160,140,0', false, 2, 8 + ); } /** Draws M5 swing points when debug draw enabled. */ @@ -68,10 +87,26 @@ inline void DrawTriggerSwingPoints() bool isUp = (g_TriggerTrend.trend == DIR_UP); bool isDown = (g_TriggerTrend.trend == DIR_DOWN); - DrawOneSwingPoint(PREFIX_SWING_TRIGGER, InpTriggerTF, "TriggerH0", true, g_TriggerTrend.idxH0, g_TriggerTrend.h0, C'180,100,255', isDown, 1, 7); - DrawOneSwingPoint(PREFIX_SWING_TRIGGER, InpTriggerTF, "TriggerH1", true, g_TriggerTrend.idxH1, g_TriggerTrend.h1, C'100,60,160', false, 1, 7); - DrawOneSwingPoint(PREFIX_SWING_TRIGGER, InpTriggerTF, "TriggerL0", false, g_TriggerTrend.idxL0, g_TriggerTrend.l0, C'255,160,40', isUp, 1, 7); - DrawOneSwingPoint(PREFIX_SWING_TRIGGER, InpTriggerTF, "TriggerL1", false, g_TriggerTrend.idxL1, g_TriggerTrend.l1, C'160,100,20', false, 1, 7); + DrawOneSwingPoint( + PREFIX_SWING_TRIGGER, InpTriggerTF, "TriggerH0", + true, g_TriggerTrend.idxH0, g_TriggerTrend.h0, + C'180,100,255', isDown, 1, 7 + ); + DrawOneSwingPoint( + PREFIX_SWING_TRIGGER, InpTriggerTF, "TriggerH1", + true, g_TriggerTrend.idxH1, g_TriggerTrend.h1, + C'100,60,160', false, 1, 7 + ); + DrawOneSwingPoint( + PREFIX_SWING_TRIGGER, InpTriggerTF, "TriggerL0", + false, g_TriggerTrend.idxL0, g_TriggerTrend.l0, + C'255,160,40', isUp, 1, 7 + ); + DrawOneSwingPoint( + PREFIX_SWING_TRIGGER, InpTriggerTF, "TriggerL1", + false, g_TriggerTrend.idxL1, g_TriggerTrend.l1, + C'160,100,20', false, 1, 7 + ); } /** Draws one MSS marker (arrow + label + horizontal level) at given time/level. */ @@ -131,10 +166,13 @@ inline void DrawMSSMarkers() if (g_FVGPool[i].mssTime == 0) continue; string tid = "T_" + IntegerToString(g_FVGPool[i].id); - DrawMSSMarker(tid, InpTriggerTF, + DrawMSSMarker( + tid, + InpTriggerTF, g_FVGPool[i].mssTime, g_FVGPool[i].mssEntry, - g_FVGPool[i].direction == DIR_UP ? DIR_UP : DIR_DOWN); + g_FVGPool[i].direction == DIR_UP ? DIR_UP : DIR_DOWN + ); } } @@ -155,9 +193,14 @@ inline void DrawOrderVisualization() if (!g_OrderPlan.valid || g_State == EA_IDLE) { - ObjectDelete(0, tpZoneN); ObjectDelete(0, slZoneN); - ObjectDelete(0, entLineN); ObjectDelete(0, slLineN); ObjectDelete(0, tpLineN); - ObjectDelete(0, entLblN); ObjectDelete(0, slLblN); ObjectDelete(0, tpLblN); + ObjectDelete(0, tpZoneN); + ObjectDelete(0, slZoneN); + ObjectDelete(0, entLineN); + ObjectDelete(0, slLineN); + ObjectDelete(0, tpLineN); + ObjectDelete(0, entLblN); + ObjectDelete(0, slLblN); + ObjectDelete(0, tpLblN); ObjectDelete(0, infoLblN); return; } @@ -180,58 +223,127 @@ inline void DrawOrderVisualization() color tpClr = C'38,166,91'; color slClr = C'229,57,53'; - double tpTop = isBuy ? tp : entry, tpBot = isBuy ? entry : tp; - if (ObjectFind(0, tpZoneN) < 0) ObjectCreate(0, tpZoneN, OBJ_RECTANGLE, 0, tStart, tpTop, tEnd, tpBot); - ObjectSetInteger(0, tpZoneN, OBJPROP_COLOR, tpFill); ObjectSetInteger(0, tpZoneN, OBJPROP_FILL, true); - ObjectSetInteger(0, tpZoneN, OBJPROP_BACK, true); - ObjectMove(0, tpZoneN, 0, tStart, tpTop); ObjectMove(0, tpZoneN, 1, tEnd, tpBot); + double tpTop = isBuy ? tp : entry; + double tpBot = isBuy ? entry : tp; + if (ObjectFind(0, tpZoneN) < 0) + ObjectCreate(0, tpZoneN, OBJ_RECTANGLE, 0, tStart, tpTop, tEnd, tpBot); + ObjectSetInteger(0, tpZoneN, OBJPROP_COLOR, tpFill); + ObjectSetInteger(0, tpZoneN, OBJPROP_FILL, true); + ObjectSetInteger(0, tpZoneN, OBJPROP_BACK, true); + ObjectMove(0, tpZoneN, 0, tStart, tpTop); + ObjectMove(0, tpZoneN, 1, tEnd, tpBot); - double slTop = isBuy ? entry : sl, slBot = isBuy ? sl : entry; - if (ObjectFind(0, slZoneN) < 0) ObjectCreate(0, slZoneN, OBJ_RECTANGLE, 0, tStart, slTop, tEnd, slBot); - ObjectSetInteger(0, slZoneN, OBJPROP_COLOR, slFill); ObjectSetInteger(0, slZoneN, OBJPROP_FILL, true); - ObjectSetInteger(0, slZoneN, OBJPROP_BACK, true); - ObjectMove(0, slZoneN, 0, tStart, slTop); ObjectMove(0, slZoneN, 1, tEnd, slBot); + double slTop = isBuy ? entry : sl; + double slBot = isBuy ? sl : entry; + if (ObjectFind(0, slZoneN) < 0) + ObjectCreate(0, slZoneN, OBJ_RECTANGLE, 0, tStart, slTop, tEnd, slBot); + ObjectSetInteger(0, slZoneN, OBJPROP_COLOR, slFill); + ObjectSetInteger(0, slZoneN, OBJPROP_FILL, true); + ObjectSetInteger(0, slZoneN, OBJPROP_BACK, true); + ObjectMove(0, slZoneN, 0, tStart, slTop); + ObjectMove(0, slZoneN, 1, tEnd, slBot); - if (ObjectFind(0, entLineN) < 0) ObjectCreate(0, entLineN, OBJ_TREND, 0, tStart, entry, tEnd, entry); - ObjectSetInteger(0, entLineN, OBJPROP_COLOR, entryClr); ObjectSetInteger(0, entLineN, OBJPROP_STYLE, STYLE_SOLID); - ObjectSetInteger(0, entLineN, OBJPROP_WIDTH, 2); ObjectSetInteger(0, entLineN, OBJPROP_RAY_RIGHT, true); - ObjectMove(0, entLineN, 0, tStart, entry); ObjectMove(0, entLineN, 1, tEnd, entry); + if (ObjectFind(0, entLineN) < 0) + ObjectCreate(0, entLineN, OBJ_TREND, 0, tStart, entry, tEnd, entry); + ObjectSetInteger(0, entLineN, OBJPROP_COLOR, entryClr); + ObjectSetInteger(0, entLineN, OBJPROP_STYLE, STYLE_SOLID); + ObjectSetInteger(0, entLineN, OBJPROP_WIDTH, 2); + ObjectSetInteger(0, entLineN, OBJPROP_RAY_RIGHT, true); + ObjectMove(0, entLineN, 0, tStart, entry); + ObjectMove(0, entLineN, 1, tEnd, entry); - if (ObjectFind(0, tpLineN) < 0) ObjectCreate(0, tpLineN, OBJ_TREND, 0, tStart, tp, tEnd, tp); - ObjectSetInteger(0, tpLineN, OBJPROP_COLOR, tpClr); ObjectSetInteger(0, tpLineN, OBJPROP_STYLE, STYLE_DASH); - ObjectSetInteger(0, tpLineN, OBJPROP_WIDTH, 1); ObjectSetInteger(0, tpLineN, OBJPROP_RAY_RIGHT, true); - ObjectMove(0, tpLineN, 0, tStart, tp); ObjectMove(0, tpLineN, 1, tEnd, tp); + if (ObjectFind(0, tpLineN) < 0) + ObjectCreate(0, tpLineN, OBJ_TREND, 0, tStart, tp, tEnd, tp); + ObjectSetInteger(0, tpLineN, OBJPROP_COLOR, tpClr); + ObjectSetInteger(0, tpLineN, OBJPROP_STYLE, STYLE_DASH); + ObjectSetInteger(0, tpLineN, OBJPROP_WIDTH, 1); + ObjectSetInteger(0, tpLineN, OBJPROP_RAY_RIGHT, true); + ObjectMove(0, tpLineN, 0, tStart, tp); + ObjectMove(0, tpLineN, 1, tEnd, tp); - if (ObjectFind(0, slLineN) < 0) ObjectCreate(0, slLineN, OBJ_TREND, 0, tStart, sl, tEnd, sl); - ObjectSetInteger(0, slLineN, OBJPROP_COLOR, slClr); ObjectSetInteger(0, slLineN, OBJPROP_STYLE, STYLE_DASH); - ObjectSetInteger(0, slLineN, OBJPROP_WIDTH, 1); ObjectSetInteger(0, slLineN, OBJPROP_RAY_RIGHT, true); - ObjectMove(0, slLineN, 0, tStart, sl); ObjectMove(0, slLineN, 1, tEnd, sl); + if (ObjectFind(0, slLineN) < 0) + ObjectCreate(0, slLineN, OBJ_TREND, 0, tStart, sl, tEnd, sl); + ObjectSetInteger(0, slLineN, OBJPROP_COLOR, slClr); + ObjectSetInteger(0, slLineN, OBJPROP_STYLE, STYLE_DASH); + ObjectSetInteger(0, slLineN, OBJPROP_WIDTH, 1); + ObjectSetInteger(0, slLineN, OBJPROP_RAY_RIGHT, true); + ObjectMove(0, slLineN, 0, tStart, sl); + ObjectMove(0, slLineN, 1, tEnd, sl); datetime lblT = tEnd; - string eTxt = StringFormat("%s %s | %.2f lot", isBuy?"▶ BUY LIM":"▶ SELL LIM", DoubleToString(entry,_Digits), g_OrderPlan.lot); - if (ObjectFind(0, entLblN) < 0) ObjectCreate(0, entLblN, OBJ_TEXT, 0, lblT, entry); - ObjectMove(0, entLblN, 0, lblT, entry); ObjectSetString(0, entLblN, OBJPROP_TEXT, eTxt); - ObjectSetInteger(0, entLblN, OBJPROP_COLOR, entryClr); ObjectSetInteger(0, entLblN, OBJPROP_FONTSIZE, 8); + string eTxt = StringFormat( + "%s %s | %.2f lot", + isBuy ? "▶ BUY LIM" : "▶ SELL LIM", + DoubleToString(entry, _Digits), + g_OrderPlan.lot + ); + if (ObjectFind(0, entLblN) < 0) + ObjectCreate(0, entLblN, OBJ_TEXT, 0, lblT, entry); + ObjectMove(0, entLblN, 0, lblT, entry); + ObjectSetString(0, entLblN, OBJPROP_TEXT, eTxt); + ObjectSetInteger(0, entLblN, OBJPROP_COLOR, entryClr); + ObjectSetInteger(0, entLblN, OBJPROP_FONTSIZE, 8); ObjectSetInteger(0, entLblN, OBJPROP_ANCHOR, ANCHOR_LEFT); - string tTxt = StringFormat("◎ TP %s +%.0fp (%.1fR)", DoubleToString(tp,_Digits), tpPips, rr); - if (ObjectFind(0, tpLblN) < 0) ObjectCreate(0, tpLblN, OBJ_TEXT, 0, lblT, tp); - ObjectMove(0, tpLblN, 0, lblT, tp); ObjectSetString(0, tpLblN, OBJPROP_TEXT, tTxt); - ObjectSetInteger(0, tpLblN, OBJPROP_COLOR, tpClr); ObjectSetInteger(0, tpLblN, OBJPROP_FONTSIZE, 8); - ObjectSetInteger(0, tpLblN, OBJPROP_ANCHOR, isBuy?ANCHOR_LEFT_LOWER:ANCHOR_LEFT_UPPER); + string tTxt = StringFormat( + "◎ TP %s +%.0fp (%.1fR)", + DoubleToString(tp, _Digits), + tpPips, + rr + ); + if (ObjectFind(0, tpLblN) < 0) + ObjectCreate(0, tpLblN, OBJ_TEXT, 0, lblT, tp); + ObjectMove(0, tpLblN, 0, lblT, tp); + ObjectSetString(0, tpLblN, OBJPROP_TEXT, tTxt); + ObjectSetInteger(0, tpLblN, OBJPROP_COLOR, tpClr); + ObjectSetInteger(0, tpLblN, OBJPROP_FONTSIZE, 8); + ObjectSetInteger( + 0, + tpLblN, + OBJPROP_ANCHOR, + isBuy ? ANCHOR_LEFT_LOWER : ANCHOR_LEFT_UPPER + ); - string sTxt = StringFormat("✕ SL %s -%.0fp", DoubleToString(sl,_Digits), slPips); - if (ObjectFind(0, slLblN) < 0) ObjectCreate(0, slLblN, OBJ_TEXT, 0, lblT, sl); - ObjectMove(0, slLblN, 0, lblT, sl); ObjectSetString(0, slLblN, OBJPROP_TEXT, sTxt); - ObjectSetInteger(0, slLblN, OBJPROP_COLOR, slClr); ObjectSetInteger(0, slLblN, OBJPROP_FONTSIZE, 8); - ObjectSetInteger(0, slLblN, OBJPROP_ANCHOR, isBuy?ANCHOR_LEFT_UPPER:ANCHOR_LEFT_LOWER); + string sTxt = StringFormat( + "✕ SL %s -%.0fp", + DoubleToString(sl, _Digits), + slPips + ); + if (ObjectFind(0, slLblN) < 0) + ObjectCreate(0, slLblN, OBJ_TEXT, 0, lblT, sl); + ObjectMove(0, slLblN, 0, lblT, sl); + ObjectSetString(0, slLblN, OBJPROP_TEXT, sTxt); + ObjectSetInteger(0, slLblN, OBJPROP_COLOR, slClr); + ObjectSetInteger(0, slLblN, OBJPROP_FONTSIZE, 8); + ObjectSetInteger( + 0, + slLblN, + OBJPROP_ANCHOR, + isBuy ? ANCHOR_LEFT_UPPER : ANCHOR_LEFT_LOWER + ); - string iTxt = StringFormat("Risk %.1f%% | %.0f:%.0f pips | %.1fR", InpRiskPercent, slPips, tpPips, rr); - if (ObjectFind(0, infoLblN) < 0) ObjectCreate(0, infoLblN, OBJ_TEXT, 0, lblT, (entry+sl)/2.0); - ObjectMove(0, infoLblN, 0, lblT, (entry+sl)/2.0); ObjectSetString(0, infoLblN, OBJPROP_TEXT, iTxt); - ObjectSetInteger(0, infoLblN, OBJPROP_COLOR, C'160,160,160'); ObjectSetInteger(0, infoLblN, OBJPROP_FONTSIZE, 7); - ObjectSetInteger(0, infoLblN, OBJPROP_ANCHOR, ANCHOR_LEFT); + string iTxt = StringFormat( + "Risk %.1f%% | %.0f:%.0f pips | %.1fR", + InpRiskPercent, + slPips, + tpPips, + rr + ); + if (ObjectFind(0, infoLblN) < 0) + ObjectCreate( + 0, + infoLblN, + OBJ_TEXT, + 0, + lblT, + (entry + sl) / 2.0 + ); + ObjectMove(0, infoLblN, 0, lblT, (entry + sl) / 2.0); + ObjectSetString(0, infoLblN, OBJPROP_TEXT, iTxt); + ObjectSetInteger(0, infoLblN, OBJPROP_COLOR, C'160,160,160'); + ObjectSetInteger(0, infoLblN, OBJPROP_FONTSIZE, 7); + ObjectSetInteger(0, infoLblN, OBJPROP_ANCHOR, ANCHOR_LEFT); } /** Draws one FVG record (rectangle + mid line + label) by pool index. */ @@ -267,18 +379,51 @@ inline void DrawOneFVGRecord(int idx) else fillColor = C'50,50,50'; if (ObjectFind(0, rectN) < 0) - ObjectCreate(0, rectN, OBJ_RECTANGLE, 0, g_FVGPool[idx].createdTime, g_FVGPool[idx].high, rectEnd, g_FVGPool[idx].low); - ObjectSetInteger(0, rectN, OBJPROP_COLOR, fillColor); ObjectSetInteger(0, rectN, OBJPROP_FILL, true); - ObjectSetInteger(0, rectN, OBJPROP_BACK, true); - ObjectMove(0, rectN, 0, g_FVGPool[idx].createdTime, g_FVGPool[idx].high); + ObjectCreate( + 0, + rectN, + OBJ_RECTANGLE, + 0, + g_FVGPool[idx].createdTime, + g_FVGPool[idx].high, + rectEnd, + g_FVGPool[idx].low + ); + ObjectSetInteger(0, rectN, OBJPROP_COLOR, fillColor); + ObjectSetInteger(0, rectN, OBJPROP_FILL, true); + ObjectSetInteger(0, rectN, OBJPROP_BACK, true); + ObjectMove( + 0, + rectN, + 0, + g_FVGPool[idx].createdTime, + g_FVGPool[idx].high + ); ObjectMove(0, rectN, 1, rectEnd, g_FVGPool[idx].low); color midColor = (g_FVGPool[idx].status == FVG_USED) ? C'60,60,60' : clrSilver; if (ObjectFind(0, midN) < 0) - ObjectCreate(0, midN, OBJ_TREND, 0, g_FVGPool[idx].createdTime, g_FVGPool[idx].mid, rectEnd, g_FVGPool[idx].mid); - ObjectSetInteger(0, midN, OBJPROP_COLOR, midColor); ObjectSetInteger(0, midN, OBJPROP_STYLE, STYLE_DOT); - ObjectSetInteger(0, midN, OBJPROP_WIDTH, 1); ObjectSetInteger(0, midN, OBJPROP_RAY_RIGHT, false); - ObjectMove(0, midN, 0, g_FVGPool[idx].createdTime, g_FVGPool[idx].mid); + ObjectCreate( + 0, + midN, + OBJ_TREND, + 0, + g_FVGPool[idx].createdTime, + g_FVGPool[idx].mid, + rectEnd, + g_FVGPool[idx].mid + ); + ObjectSetInteger(0, midN, OBJPROP_COLOR, midColor); + ObjectSetInteger(0, midN, OBJPROP_STYLE, STYLE_DOT); + ObjectSetInteger(0, midN, OBJPROP_WIDTH, 1); + ObjectSetInteger(0, midN, OBJPROP_RAY_RIGHT, false); + ObjectMove( + 0, + midN, + 0, + g_FVGPool[idx].createdTime, + g_FVGPool[idx].mid + ); ObjectMove(0, midN, 1, rectEnd, g_FVGPool[idx].mid); string sym = (g_FVGPool[idx].direction == DIR_UP) ? "▲" : "▼"; @@ -289,10 +434,34 @@ inline void DrawOneFVGRecord(int idx) else if (g_FVGPool[idx].status == FVG_USED) stTxt = " [EXP]"; if (ObjectFind(0, lblN) < 0) - ObjectCreate(0, lblN, OBJ_TEXT, 0, g_FVGPool[idx].createdTime, g_FVGPool[idx].high); - ObjectMove(0, lblN, 0, g_FVGPool[idx].createdTime, g_FVGPool[idx].high); - ObjectSetString(0, lblN, OBJPROP_TEXT, StringFormat("FVG#%d %s%s", g_FVGPool[idx].id, sym, stTxt)); - ObjectSetInteger(0, lblN, OBJPROP_COLOR, fillColor); ObjectSetInteger(0, lblN, OBJPROP_FONTSIZE, 8); + ObjectCreate( + 0, + lblN, + OBJ_TEXT, + 0, + g_FVGPool[idx].createdTime, + g_FVGPool[idx].high + ); + ObjectMove( + 0, + lblN, + 0, + g_FVGPool[idx].createdTime, + g_FVGPool[idx].high + ); + ObjectSetString( + 0, + lblN, + OBJPROP_TEXT, + StringFormat( + "FVG#%d %s%s", + g_FVGPool[idx].id, + sym, + stTxt + ) + ); + ObjectSetInteger(0, lblN, OBJPROP_COLOR, fillColor); + ObjectSetInteger(0, lblN, OBJPROP_FONTSIZE, 8); ObjectSetInteger(0, lblN, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER); } @@ -308,71 +477,177 @@ inline void DrawContextDebug() { if (!InpDebugDraw) return; - #define LBL(name,txt,y,clr) \ - if(ObjectFind(0,name)<0) ObjectCreate(0,name,OBJ_LABEL,0,0,0); \ - ObjectSetInteger(0,name,OBJPROP_CORNER, CORNER_LEFT_UPPER); \ - ObjectSetInteger(0,name,OBJPROP_XDISTANCE, 10); \ - ObjectSetInteger(0,name,OBJPROP_YDISTANCE, y); \ - ObjectSetInteger(0,name,OBJPROP_FONTSIZE, 9); \ - ObjectSetInteger(0,name,OBJPROP_COLOR, clr); \ - ObjectSetString (0,name,OBJPROP_TEXT, txt); + #define LBL(name,txt,y,clr) \ + if (ObjectFind(0, name) < 0) \ + ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0); \ + ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER); \ + ObjectSetInteger(0, name, OBJPROP_XDISTANCE, 10); \ + ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y); \ + ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 9); \ + ObjectSetInteger(0, name, OBJPROP_COLOR, clr); \ + ObjectSetString (0, name, OBJPROP_TEXT, txt); 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 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; - LBL(PREFIX_DEBUG_PANEL + "MT", StringFormat("H1 : %s KL=%.5f", EnumToString(g_MiddleTrend.trend), g_MiddleTrend.keyLevel), 58, cMT) + color cMT = (g_MiddleTrend.trend == DIR_UP) + ? clrLime + : (g_MiddleTrend.trend == DIR_DOWN) ? clrTomato : clrGray; + LBL( + PREFIX_DEBUG_PANEL + "MT", + StringFormat( + "H1 : %s KL=%.5f", + EnumToString(g_MiddleTrend.trend), + g_MiddleTrend.keyLevel + ), + 58, + cMT + ) - color cTT = (g_TriggerTrend.trend==DIR_UP)?clrLime:(g_TriggerTrend.trend==DIR_DOWN)?clrTomato:clrGray; - LBL(PREFIX_DEBUG_PANEL + "TT", StringFormat("M5 : %s KL=%.5f", EnumToString(g_TriggerTrend.trend), g_TriggerTrend.keyLevel), 82, cTT) + color cTT = (g_TriggerTrend.trend == DIR_UP) + ? clrLime + : (g_TriggerTrend.trend == DIR_DOWN) ? clrTomato : clrGray; + LBL( + PREFIX_DEBUG_PANEL + "TT", + StringFormat( + "M5 : %s KL=%.5f", + EnumToString(g_TriggerTrend.trend), + g_TriggerTrend.keyLevel + ), + 82, + cTT + ) if (g_ActiveFVGIdx >= 0 && g_ActiveFVGIdx < g_FVGCount && g_FVGPool[g_ActiveFVGIdx].usedCase == 2 && g_FVGPool[g_ActiveFVGIdx].mssTime > 0) { int ai = g_ActiveFVGIdx; - color cM = (g_FVGPool[ai].direction==DIR_UP)?clrLime:clrTomato; - LBL(PREFIX_DEBUG_PANEL + "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) + color cM = (g_FVGPool[ai].direction == DIR_UP) ? clrLime : clrTomato; + LBL( + PREFIX_DEBUG_PANEL + "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, PREFIX_DEBUG_PANEL + "MSS"); - double lostPct = g_DailyRisk.startBalance > 0 - ? (g_DailyRisk.startBalance - g_DailyRisk.currentBalance) / g_DailyRisk.startBalance * 100.0 : 0.0; - color cR = g_DailyRisk.limitHit?clrRed:(lostPct>InpMaxDailyLossPct*0.7?clrOrange:clrLime); - LBL(PREFIX_DEBUG_PANEL + "RISK", StringFormat("Risk : %.2f%% / %.2f%%", lostPct, InpMaxDailyLossPct), 130, cR) + double lostPct = (g_DailyRisk.startBalance > 0) + ? (g_DailyRisk.startBalance - g_DailyRisk.currentBalance) + / g_DailyRisk.startBalance * 100.0 + : 0.0; + color cR = g_DailyRisk.limitHit + ? clrRed + : (lostPct > InpMaxDailyLossPct * 0.7) ? clrOrange : clrLime; + LBL( + PREFIX_DEBUG_PANEL + "RISK", + StringFormat("Risk : %.2f%% / %.2f%%", lostPct, InpMaxDailyLossPct), + 130, + cR + ) - color cS = (g_State==EA_IDLE)?clrSilver:(g_State==EA_WAIT_TOUCH)?clrOrange:(g_State==EA_WAIT_TRIGGER)?clrYellow:clrLime; - LBL(PREFIX_DEBUG_PANEL + "ST", StringFormat("State: %s", EnumToString(g_State)), 154, cS) + color cS = (g_State == EA_IDLE) + ? clrSilver + : (g_State == EA_WAIT_TOUCH) + ? clrOrange + : (g_State == EA_WAIT_TRIGGER) ? clrYellow : clrLime; + LBL( + PREFIX_DEBUG_PANEL + "ST", + StringFormat("State: %s", EnumToString(g_State)), + 154, + cS + ) if (g_BlockReason != BLOCK_NONE) - { LBL(PREFIX_DEBUG_PANEL + "BLK", StringFormat("Block: %s", EnumToString(g_BlockReason)), 178, clrTomato) } + { + LBL( + PREFIX_DEBUG_PANEL + "BLK", + StringFormat("Block: %s", EnumToString(g_BlockReason)), + 178, + clrTomato + ) + } else ObjectDelete(0, PREFIX_DEBUG_PANEL + "BLK"); - int countPending = 0, countTouched = 0, countUsed = 0; + int countPending = 0; + int countTouched = 0; + int countUsed = 0; for (int i = 0; i < g_FVGCount; i++) - { if (g_FVGPool[i].status == FVG_PENDING) countPending++; else if (g_FVGPool[i].status == FVG_TOUCHED) countTouched++; else countUsed++; } - LBL(PREFIX_DEBUG_PANEL + "POOL", StringFormat("Pool : P=%d T=%d U=%d (%d/%d)", countPending, countTouched, countUsed, g_FVGCount, MAX_FVG_POOL), 202, clrDodgerBlue) + { + if (g_FVGPool[i].status == FVG_PENDING) + countPending++; + else if (g_FVGPool[i].status == FVG_TOUCHED) + countTouched++; + else + countUsed++; + } + LBL( + PREFIX_DEBUG_PANEL + "POOL", + StringFormat( + "Pool : P=%d T=%d U=%d (%d/%d)", + countPending, + countTouched, + countUsed, + g_FVGCount, + MAX_FVG_POOL + ), + 202, + clrDodgerBlue + ) if (g_ActiveFVGIdx >= 0 && g_ActiveFVGIdx < g_FVGCount) { int ai = g_ActiveFVGIdx; - LBL(PREFIX_DEBUG_PANEL + "ACT", StringFormat("Act : #%d %s [%.5f–%.5f] %s", - g_FVGPool[ai].id, EnumToString(g_FVGPool[ai].direction), - g_FVGPool[ai].low, g_FVGPool[ai].high, EnumToString(g_FVGPool[ai].status)), 226, clrDeepSkyBlue) + LBL( + PREFIX_DEBUG_PANEL + "ACT", + StringFormat( + "Act : #%d %s [%.5f–%.5f] %s", + g_FVGPool[ai].id, + EnumToString(g_FVGPool[ai].direction), + g_FVGPool[ai].low, + g_FVGPool[ai].high, + EnumToString(g_FVGPool[ai].status) + ), + 226, + clrDeepSkyBlue + ) } else ObjectDelete(0, PREFIX_DEBUG_PANEL + "ACT"); if (g_PendingTicket > 0 && g_OrderPlan.valid) { - LBL(PREFIX_DEBUG_PANEL + "ORD", StringFormat("Order: %s #%llu @ %.5f SL=%.5f TP=%.5f", - (g_OrderPlan.direction>0)?"BUY":"SELL", g_PendingTicket, - g_OrderPlan.entry, g_OrderPlan.stopLoss, g_OrderPlan.takeProfit), 250, clrGold) + LBL( + PREFIX_DEBUG_PANEL + "ORD", + StringFormat( + "Order: %s #%llu @ %.5f SL=%.5f TP=%.5f", + (g_OrderPlan.direction > 0) ? "BUY" : "SELL", + g_PendingTicket, + g_OrderPlan.entry, + g_OrderPlan.stopLoss, + g_OrderPlan.takeProfit + ), + 250, + clrGold + ) } else ObjectDelete(0, PREFIX_DEBUG_PANEL + "ORD"); @@ -383,12 +658,13 @@ inline void DrawContextDebug() /** Draws all debug visuals: swings, MSS markers, FVG pool, order, debug panel. */ inline void DrawVisuals() { + DrawContextDebug(); + return; // TESTING ONLY DrawMiddleSwingPoints(); DrawTriggerSwingPoints(); DrawMSSMarkers(); DrawFVGPool(); DrawOrderVisualization(); - DrawContextDebug(); } #endif // EA_ICT_CL__DRAWING_MQH diff --git a/Experts/EA_ICT_CL/Guards.mqh b/Experts/EA_ICT_CL/Guards.mqh index 636c470..fffb4f6 100644 --- a/Experts/EA_ICT_CL/Guards.mqh +++ b/Experts/EA_ICT_CL/Guards.mqh @@ -1,6 +1,7 @@ #ifndef EA_ICT_CL__GUARDS_MQH #define EA_ICT_CL__GUARDS_MQH +/** True if within allowed session (currently always true). */ inline bool IsSessionAllowed() { return true; } /** True if daily loss limit has not been hit. */ inline bool IsDailyLossOK() { return !g_DailyRisk.limitHit; } diff --git a/Experts/EA_ICT_CL/Market.mqh b/Experts/EA_ICT_CL/Market.mqh index cd47186..9eef2a7 100644 --- a/Experts/EA_ICT_CL/Market.mqh +++ b/Experts/EA_ICT_CL/Market.mqh @@ -1,29 +1,28 @@ #ifndef EA_ICT_CL__MARKET_MQH -#define EA_ICT_CL__MARKET_MQH // Tránh include trùng +#define EA_ICT_CL__MARKET_MQH -// Module: Market – giá, point, spread, điều kiện trade - -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 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); } +/** Returns spread in points (ask - bid) / point. */ inline double GetSpreadPoints(const string symbol) { - 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 + const double bid = GetBid(symbol); + const double ask = GetAsk(symbol); + const double pointSize = GetPoint(symbol); + if (pointSize <= 0.0) return 0.0; + return (ask - bid) / pointSize; } +/** True if terminal, EA and symbol allow trading. */ inline bool IsTradeAllowedNow(const string symbol) { - 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 + if (!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) return false; + if (!MQLInfoInteger(MQL_TRADE_ALLOWED)) return false; + if (!SymbolInfoInteger(symbol, SYMBOL_TRADE_MODE)) return false; + return true; } -#endif // EA_ICT_CL__MARKET_MQH - +#endif diff --git a/Experts/EA_ICT_CL/Risk.mqh b/Experts/EA_ICT_CL/Risk.mqh index ddbcbd2..b6bd83b 100644 --- a/Experts/EA_ICT_CL/Risk.mqh +++ b/Experts/EA_ICT_CL/Risk.mqh @@ -20,9 +20,8 @@ inline double LotsFromRiskMoneyAndSLPoints(const string symbol, const double ris if (riskMoney <= 0.0) return 0.0; if (slPoints <= 0.0) return 0.0; - double tickValue = 0.0, tickSize = 0.0; - if (!SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE, tickValue)) return 0.0; - if (!SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE, tickSize)) return 0.0; + double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); + double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); if (tickValue <= 0.0 || tickSize <= 0.0) return 0.0; const double point = SymbolInfoDouble(symbol, SYMBOL_POINT); diff --git a/Experts/EA_ICT_CL/Swing.mqh b/Experts/EA_ICT_CL/Swing.mqh index 8762d17..820668a 100644 --- a/Experts/EA_ICT_CL/Swing.mqh +++ b/Experts/EA_ICT_CL/Swing.mqh @@ -1,76 +1,75 @@ #ifndef EA_ICT_CL__SWING_MQH -#define EA_ICT_CL__SWING_MQH // Tránh include trùng +#define EA_ICT_CL__SWING_MQH -// Module: Swing – tìm bar shift theo time, swing high/low, quét cấu trúc swing, suy trend - -//+------------------------------------------------------------------+ -//| MyBarShift: tìm chỉ số bar (series) ứng với thời gian time | -//+------------------------------------------------------------------+ +/** Returns bar index (series) for given time; -1 if not found or exact and no match. */ inline int MyBarShift(string symbol, ENUM_TIMEFRAMES tf, datetime time, bool exact = false) { datetime arr[]; - 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; + int maxBarsToCopy = MathMin(Bars(symbol, tf), 5000); + int copiedCount = CopyTime(symbol, tf, 0, maxBarsToCopy, arr); + if (copiedCount <= 0) return -1; - for (int i = copied - 1; i >= 0; i--) // Duyệt từ bar cũ → mới + for (int i = copiedCount - 1; i >= 0; i--) { if (arr[i] <= time) - return copied - 1 - i; // Index trong series (0 = mới nhất) + return copiedCount - 1 - i; } - return exact ? -1 : copied - 1; // exact: không tìm thấy = -1; không exact: trả về bar xa nhất + return exact ? -1 : copiedCount - 1; } -inline bool IsSwingHighAt(ENUM_TIMEFRAMES tf, int i) +/** True if bar at index i is a swing high (InpSwingRange bars each side lower). */ +inline bool IsSwingHighAt(ENUM_TIMEFRAMES tf, int barIndex) { - 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; -} - -inline bool IsSwingLowAt(ENUM_TIMEFRAMES tf, int i) -{ - double p = iLow(_Symbol, tf, i); + double highAtBar = iHigh(_Symbol, tf, barIndex); for (int k = 1; k <= InpSwingRange; k++) - if (iLow(_Symbol, tf, i-k) <= p || iLow(_Symbol, tf, i+k) <= p) return false; + if (iHigh(_Symbol, tf, barIndex - k) >= highAtBar || iHigh(_Symbol, tf, barIndex + k) >= highAtBar) return false; return true; } +/** True if bar at index i is a swing low (InpSwingRange bars each side higher). */ +inline bool IsSwingLowAt(ENUM_TIMEFRAMES tf, int barIndex) +{ + double lowAtBar = iLow(_Symbol, tf, barIndex); + for (int k = 1; k <= InpSwingRange; k++) + if (iLow(_Symbol, tf, barIndex - k) <= lowAtBar || iLow(_Symbol, tf, barIndex + k) <= lowAtBar) return false; + return true; +} + +/** Scans for two most recent swing highs and two most recent swing lows; fills out params, returns true if all found. */ inline bool ScanSwingStructure( ENUM_TIMEFRAMES tf, int lookback, 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); // 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 + int maxBar = MathMin(lookback, Bars(_Symbol, tf) - InpSwingRange - 2); + double highs[2]; int hiIdx[2]; int highCount = 0; + double lows [2]; int loIdx[2]; int lowCount = 0; - for (int i = InpSwingRange + 1; i <= maxBar; i++) // Từ bar gần hiện tại trở lại + for (int i = InpSwingRange + 1; i <= maxBar; 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; // Đủ 2 high + 2 low thì dừng + if (highCount < 2 && IsSwingHighAt(tf, i)) { highs[highCount] = iHigh(_Symbol, tf, i); hiIdx[highCount] = i; highCount++; } + if (lowCount < 2 && IsSwingLowAt (tf, i)) { lows [lowCount] = iLow (_Symbol, tf, i); loIdx[lowCount] = i; lowCount++; } + if (highCount == 2 && lowCount == 2) break; } - if (hc < 2 || lc < 2) return false; // Không đủ swing + if (highCount < 2 || lowCount < 2) return false; - 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 + h0 = highs[0]; idxH0 = hiIdx[0]; + h1 = highs[1]; idxH1 = hiIdx[1]; l0 = lows [0]; idxL0 = loIdx[0]; l1 = lows [1]; idxL1 = loIdx[1]; return true; } +/** Resolves trend and key level from swing highs/lows and last close. */ inline void ResolveTrendFromSwings( ENUM_TIMEFRAMES tf, double h0, double h1, double l0, double l1, MarketDir &trend, double &keyLevel) { - 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õ + double lastClose = iClose(_Symbol, tf, 1); + if (h0 > h1 && l0 > l1 && lastClose > l0) { trend = DIR_UP; keyLevel = l0; } + else if (h0 < h1 && l0 < l1 && lastClose < h0) { trend = DIR_DOWN; keyLevel = h0; } + else { trend = DIR_NONE; keyLevel = 0; } } -#endif // EA_ICT_CL__SWING_MQH - +#endif