EA STATE ICT

This commit is contained in:
Bell
2026-05-25 02:00:48 +07:00
parent 68c1f864e4
commit b9c03196f6
+213
View File
@@ -0,0 +1,213 @@
//+------------------------------------------------------------------+
//| EaState.mqh — State machine tổng: STOP vs SETUP pipeline MSS |
//+------------------------------------------------------------------+
#ifndef ICT2026_EASTATE_MQH
#define ICT2026_EASTATE_MQH
#include <ICT2026/DailyBias.mqh>
#include <ICT2026/IntradayStructure.mqh>
#include <ICT2026/LowTfApi.mqh>
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