From b9c03196f6fda43c2cdd67504b1ae5cfd0023aea Mon Sep 17 00:00:00 2001 From: Bell Date: Mon, 25 May 2026 02:00:48 +0700 Subject: [PATCH] EA STATE ICT --- Include/ICT2026/EaState.mqh | 213 ++++++++++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 Include/ICT2026/EaState.mqh diff --git a/Include/ICT2026/EaState.mqh b/Include/ICT2026/EaState.mqh new file mode 100644 index 0000000..9bedc42 --- /dev/null +++ b/Include/ICT2026/EaState.mqh @@ -0,0 +1,213 @@ +//+------------------------------------------------------------------+ +//| EaState.mqh — State machine tổng: STOP vs SETUP pipeline MSS | +//+------------------------------------------------------------------+ +#ifndef ICT2026_EASTATE_MQH +#define ICT2026_EASTATE_MQH + +#include +#include +#include + +enum ENUM_ICT_EA_CATEGORY +{ + ICT_EA_CAT_STOP = 0, + ICT_EA_CAT_SETUP = 1, + ICT_EA_CAT_TRADE = 2 +}; + +enum ENUM_ICT_EA_STATE +{ + ICT_EA_STOP_NO_BIAS = 0, + ICT_EA_STOP_BIAS_RANGE, + ICT_EA_STOP_INTRADAY_NONE, + ICT_EA_STOP_BIAS_INTRADAY_MISMATCH, + + ICT_EA_WAIT_FVG_TOUCH = 100, + ICT_EA_FVG_TOUCHED_WAIT_MSS, + ICT_EA_MSS_OK_WAIT_M5_FVG, + ICT_EA_M5_FVG_WAIT_RETRACE, + ICT_EA_READY_FOR_LIMIT, + ICT_EA_LIMIT_ORDER_PENDING, + ICT_EA_ON_TRADE +}; + +struct IctEaState +{ + ENUM_ICT_EA_CATEGORY category; + ENUM_ICT_EA_STATE state; + ENUM_ICT_MSS_PHASE mssPhase; + string detail; + + void Clear() + { + category = ICT_EA_CAT_STOP; + state = ICT_EA_STOP_NO_BIAS; + mssPhase = ICT_MSS_IDLE; + detail = ""; + } +}; + +IctEaState g_ictEaState; + +string IctEaState_Code(const ENUM_ICT_EA_STATE st) +{ + switch(st) + { + case ICT_EA_STOP_NO_BIAS: return "STOP_NO_BIAS"; + case ICT_EA_STOP_BIAS_RANGE: return "STOP_BIAS_RANGE"; + case ICT_EA_STOP_INTRADAY_NONE: return "STOP_INTRADAY_NONE"; + case ICT_EA_STOP_BIAS_INTRADAY_MISMATCH: return "STOP_BIAS_INTRADAY_MISMATCH"; + case ICT_EA_WAIT_FVG_TOUCH: return "WAIT_FVG_TOUCH"; + case ICT_EA_FVG_TOUCHED_WAIT_MSS: return "FVG_TOUCHED_WAIT_MSS"; + case ICT_EA_MSS_OK_WAIT_M5_FVG: return "MSS_OK_WAIT_M5_FVG"; + case ICT_EA_M5_FVG_WAIT_RETRACE: return "M5_FVG_WAIT_RETRACE"; + case ICT_EA_READY_FOR_LIMIT: return "READY_FOR_LIMIT"; + case ICT_EA_LIMIT_ORDER_PENDING: return "LIMIT_ORDER_PENDING"; + case ICT_EA_ON_TRADE: return "ON_TRADE"; + default: return "UNKNOWN"; + } +} + +string IctEaState_TitleVi(const ENUM_ICT_EA_STATE st) +{ + switch(st) + { + case ICT_EA_STOP_NO_BIAS: return "STOP: chua co Bias"; + case ICT_EA_STOP_BIAS_RANGE: return "STOP: Bias Range"; + case ICT_EA_STOP_INTRADAY_NONE: return "STOP: H1 chua ro huong"; + case ICT_EA_STOP_BIAS_INTRADAY_MISMATCH: return "STOP: Bias vs H1 lech"; + case ICT_EA_WAIT_FVG_TOUCH: return "Cho retest FVG H1"; + case ICT_EA_FVG_TOUCHED_WAIT_MSS: return "FVG H1 OK — cho MSS M5"; + case ICT_EA_MSS_OK_WAIT_M5_FVG: return "MSS OK — cho M5 FVG"; + case ICT_EA_M5_FVG_WAIT_RETRACE: return "M5 FVG — cho hoi entry"; + case ICT_EA_READY_FOR_LIMIT: return "San sang dat limit"; + case ICT_EA_LIMIT_ORDER_PENDING: return "Limit pending"; + case ICT_EA_ON_TRADE: return "Dang giu lenh"; + default: return "Khong xac dinh"; + } +} + +string IctEaState_CategoryText(const ENUM_ICT_EA_CATEGORY cat) +{ + switch(cat) + { + case ICT_EA_CAT_SETUP: return "SETUP"; + case ICT_EA_CAT_TRADE: return "TRADE"; + default: return "STOP"; + } +} + +bool IctEaState_HasOpenPosition(const string sym) +{ + for(int i = PositionsTotal() - 1; i >= 0; i--) + { + const ulong ticket = PositionGetTicket(i); + if(ticket == 0 || !PositionSelectByTicket(ticket)) + continue; + if(PositionGetString(POSITION_SYMBOL) != sym) + continue; + if((ulong)PositionGetInteger(POSITION_MAGIC) == InpMssMagic) + return true; + } + return false; +} + +bool IctEaState_HasPendingLimit(const string sym, const ulong ticketHint = 0) +{ + if(ticketHint > 0 && OrderSelect(ticketHint)) + { + const ENUM_ORDER_TYPE t = (ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE); + if(t == ORDER_TYPE_BUY_LIMIT || t == ORDER_TYPE_SELL_LIMIT) + return true; + } + + for(int i = OrdersTotal() - 1; i >= 0; i--) + { + const ulong ticket = OrderGetTicket(i); + if(ticket == 0 || !OrderSelect(ticket)) + continue; + if(OrderGetString(ORDER_SYMBOL) != sym) + continue; + if((ulong)OrderGetInteger(ORDER_MAGIC) != InpMssMagic) + continue; + const ENUM_ORDER_TYPE t = (ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE); + if(t == ORDER_TYPE_BUY_LIMIT || t == ORDER_TYPE_SELL_LIMIT) + return true; + } + return false; +} + +ENUM_ICT_EA_STATE IctEaState_FromMssPhase(const ENUM_ICT_MSS_PHASE ph) +{ + switch(ph) + { + case ICT_MSS_H1_TOUCH: return ICT_EA_FVG_TOUCHED_WAIT_MSS; + case ICT_MSS_CHOCH: return ICT_EA_MSS_OK_WAIT_M5_FVG; + case ICT_MSS_M5_FVG: + case ICT_MSS_ENTRY_FILL: return ICT_EA_M5_FVG_WAIT_RETRACE; + case ICT_MSS_READY: return ICT_EA_READY_FOR_LIMIT; + default: return ICT_EA_WAIT_FVG_TOUCH; + } +} + +void IctEaState_Refresh(const string sym) +{ + g_ictEaState.mssPhase = g_ictLowTf.mss.phase; + g_ictEaState.detail = g_ictLowTf.mss.displayReason; + + if(IctEaState_HasOpenPosition(sym)) + { + g_ictEaState.category = ICT_EA_CAT_TRADE; + g_ictEaState.state = ICT_EA_ON_TRADE; + if(StringLen(g_ictEaState.detail) == 0) + g_ictEaState.detail = "Position active"; + return; + } + + if(IctEaState_HasPendingLimit(sym, g_ictLowTf.mss.pendingTicket)) + { + g_ictEaState.category = ICT_EA_CAT_TRADE; + g_ictEaState.state = ICT_EA_LIMIT_ORDER_PENDING; + if(StringLen(g_ictEaState.detail) == 0 && g_ictLowTf.mss.pendingEntry > 0.0) + g_ictEaState.detail = StringFormat("Limit @ %.2f", g_ictLowTf.mss.pendingEntry); + return; + } + + if(!g_ictIntraday.isAllowTrade) + { + g_ictEaState.category = ICT_EA_CAT_STOP; + + if(g_ictDailyBias.bias == ICT_BIAS_NONE) + g_ictEaState.state = ICT_EA_STOP_NO_BIAS; + else if(g_ictDailyBias.bias == ICT_BIAS_RANGE) + g_ictEaState.state = ICT_EA_STOP_BIAS_RANGE; + else if(g_ictIntraday.trend == ICT_TREND_NONE) + g_ictEaState.state = ICT_EA_STOP_INTRADAY_NONE; + else + g_ictEaState.state = ICT_EA_STOP_BIAS_INTRADAY_MISMATCH; + + if(StringLen(g_ictEaState.detail) == 0) + { + g_ictEaState.detail = StringFormat("Bias %s | H1 %s", + IctBiasDisplayShort(g_ictDailyBias.bias), + IctTrendDisplayShort(g_ictIntraday.trend)); + } + return; + } + + g_ictEaState.category = ICT_EA_CAT_SETUP; + g_ictEaState.state = IctEaState_FromMssPhase(g_ictLowTf.mss.phase); + + if(g_ictEaState.state == ICT_EA_READY_FOR_LIMIT && !InpMssTradeEnabled) + g_ictEaState.detail = StringFormat("%s | trade OFF", g_ictEaState.detail); +} + +void IctEaState_Get(IctEaState &out) { out = g_ictEaState; } + +ENUM_ICT_EA_STATE IctEaState_Current() { return g_ictEaState.state; } + +bool IctEaState_IsSetupActive() { return g_ictEaState.category == ICT_EA_CAT_SETUP; } + +bool IctEaState_IsStop() { return g_ictEaState.category == ICT_EA_CAT_STOP; } + +#endif