Update SL + Spread, TP - 2 spread

This commit is contained in:
Bell
2026-05-26 02:34:21 +07:00
parent b3132b500b
commit 19c5ac149a
5 changed files with 118 additions and 29 deletions
+2 -2
View File
@@ -3,8 +3,8 @@
//| BOS = Continue | CHoCH = Reversal |
//+------------------------------------------------------------------+
#property copyright "ICT 2026"
#property version "1.142"
#property description "ICT2026 MSS limit entry + SL swing CHoCH + TP intraday"
#property version "1.151"
#property description "ICT2026 MSS | SL = swing + ATR + spread | TP = iL0/iH0 + ATR 2×spread (dễ khớp)"
#include <ICT2026/Config.mqh>
#include <ICT2026/DailyBias.mqh>
+7 -3
View File
@@ -35,7 +35,7 @@ input int InpChartLabelFontSize = 9;
input group "══ Confirm swing (M5) ══"
input ENUM_TIMEFRAMES InpConfirmTf = PERIOD_M5; // TF confirmation (tương lai)
input int InpConfirmSwingRange = 1;
input int InpConfirmSwingRange = 2; // M5 swing strength: N bar mỗi bên (5-bar fractal khi =2)
input int InpConfirmSwingLookback = 80;
input int InpConfirmRecentBars = 40;
@@ -77,8 +77,12 @@ input group "══ MSS Trade ══"
input bool InpMssTradeEnabled = true; // Đặt lệnh limit MSS
input ulong InpMssMagic = 202604; // Magic number
input double InpMssRiskPct = 1.0; // R % balance mỗi lệnh
input double InpMssSlAtrMult = 0.5; // SL: buffer ngoài H0/L0 M5 (× ATR M5)
input double InpMssMinRR = 2.0; // TP tối thiểu (× risk entry→SL)
input ENUM_TIMEFRAMES InpMssSlAtrTf = PERIOD_M5; // TF tính ATR cho buffer SL
input ENUM_TIMEFRAMES InpMssTpAtrTf = PERIOD_M5; // TF tính ATR cho buffer TP
input int InpMssBufferAtrPeriod = 14; // Period ATR cho buffer SL/TP
input double InpMssSlAtrMult = 2.0; // SL: buffer ngoài max(H0,H1)/min(L0,L1) (× ATR M5) — tránh spike đỉnh
input double InpMssMinRR = 1.5; // TP tối thiểu (× risk entry→SL) — block trade nếu iL0/iH0 không đạt
input double InpMssTpAtrBuffer = 2.0; // TP buffer trước iL0/iH0 (× ATR M5) — chốt trước vùng cản
input int InpMssPendingExpireHours = 24; // Hết hạn pending (giờ, 0=không)
input bool InpMssOnePosition = true; // Một position/pending MSS
input bool InpMssCancelPendingEod = true; // Hủy pending cuối phiên Mỹ (nếu chưa khớp)
+54 -4
View File
@@ -103,17 +103,54 @@ bool IctMssEntry_ComputeLevels(const string sym, const IctFvgZone &m5Zone,
return false;
}
const double atrM5 = IctMssEntry_Atr(sym, InpConfirmTf, InpFvgAtrPeriod);
const double bufSl = (atrM5 > 0.0) ? atrM5 * InpMssSlAtrMult : 10.0 * _Point;
// SL dùng ATR M5 (sát swing M5, không quá rộng để giữ risk thấp + RR đạt minRR)
// TP dùng ATR H1 (trung bình sóng H1 đang đánh, buffer rõ ràng trên chart)
double atrSl = IctMssEntry_Atr(sym, InpMssSlAtrTf, InpMssBufferAtrPeriod);
if(atrSl <= 0.0)
atrSl = IctMssEntry_Atr(sym, InpConfirmTf, InpFvgAtrPeriod);
double atrTp = IctMssEntry_Atr(sym, InpMssTpAtrTf, InpMssBufferAtrPeriod);
if(atrTp <= 0.0)
atrTp = atrSl;
// SL: cộng spread (stop trigger theo ask/bid — bù để khỏi bị quét sớm)
// TP: trừ 2×spread (TP gần entry hơn để dễ khớp — không cần giá hit chính xác iL0/iH0)
const double spreadNow = MathMax(0.0,
SymbolInfoDouble(sym, SYMBOL_ASK) -
SymbolInfoDouble(sym, SYMBOL_BID));
const double bufSl = ((atrSl > 0.0) ? atrSl * InpMssSlAtrMult : 100.0 * _Point) + spreadNow;
const double bufTp = ((atrTp > 0.0) ? atrTp * InpMssTpAtrBuffer : 50.0 * _Point) + 2.0 * spreadNow;
const double minRR = MathMax(1.0, InpMssMinRR);
// ── TP target = iL0 (BEAR) / iH0 (BULL): sóng H1, m5 chỉ để entry
// TP đặt CÁCH target một buffer (gần chạm — không chờ hit chính xác)
const IctSwingSet iSw = g_ictIntraday.swings;
double tpTarget = 0.0;
if(isBuy && iSw.hasH0)
tpTarget = iSw.h0.price;
else if(!isBuy && iSw.hasL0)
tpTarget = iSw.l0.price;
if(isBuy)
{
slOut = swingSl - bufSl;
const double risk = entryOut - slOut;
if(risk <= _Point)
return false;
tpOut = entryOut + risk * minRR;
if(tpTarget > 0.0 && tpTarget > entryOut + bufTp + _Point)
tpOut = tpTarget - bufTp;
else
tpOut = entryOut + risk * minRR; // fallback nếu iH0 không có hoặc quá gần
const double rrAchieved = (tpOut - entryOut) / risk;
if(rrAchieved < minRR - 0.01)
{
g_ictLowTf.mss.displayReason = StringFormat(
"RR=%.2f < min %.2f (entry=%.2f SL=%.2f TP=%.2f) — chốt iH0 không đủ",
rrAchieved, minRR, entryOut, slOut, tpOut);
return false;
}
}
else
{
@@ -121,7 +158,20 @@ bool IctMssEntry_ComputeLevels(const string sym, const IctFvgZone &m5Zone,
const double risk = slOut - entryOut;
if(risk <= _Point)
return false;
tpOut = entryOut - risk * minRR;
if(tpTarget > 0.0 && tpTarget < entryOut - bufTp - _Point)
tpOut = tpTarget + bufTp;
else
tpOut = entryOut - risk * minRR; // fallback nếu iL0 không có hoặc quá gần
const double rrAchieved = (entryOut - tpOut) / risk;
if(rrAchieved < minRR - 0.01)
{
g_ictLowTf.mss.displayReason = StringFormat(
"RR=%.2f < min %.2f (entry=%.2f SL=%.2f TP=%.2f) — chốt iL0 không đủ",
rrAchieved, minRR, entryOut, slOut, tpOut);
return false;
}
}
entryOut = IctMssEntry_NormalizePrice(sym, entryOut);
+47 -20
View File
@@ -272,26 +272,17 @@ bool IctMss_UpdateLiveM5Swings(const string sym, const ENUM_ICT_BIAS bias,
g_ictLowTf.mss.liveH0Price = 0.0;
g_ictLowTf.mss.liveL0Time = 0;
g_ictLowTf.mss.liveH0Time = 0;
g_ictLowTf.mss.liveL1Price = 0.0;
g_ictLowTf.mss.liveH1Price = 0.0;
g_ictLowTf.mss.liveL1Time = 0;
g_ictLowTf.mss.liveH1Time = 0;
IctSwingSet sw;
ENUM_ICT_STRUCT st = ICT_STRUCT_NONE;
if(!IctBuildConfirmSwingSet(sym, sw, st))
return false;
if(bias == ICT_BIAS_BEAR)
{
if(!sw.hasL0 || !sw.hasH0)
return false;
if(sw.l0.time < tTouch && sw.h0.time < tTouch)
return false;
g_ictLowTf.mss.liveL0Price = sw.l0.price;
g_ictLowTf.mss.liveL0Time = sw.l0.time;
g_ictLowTf.mss.liveH0Price = sw.h0.price;
g_ictLowTf.mss.liveH0Time = sw.h0.time;
return true;
}
if(bias == ICT_BIAS_BULL)
if(bias == ICT_BIAS_BEAR || bias == ICT_BIAS_BULL)
{
if(!sw.hasL0 || !sw.hasH0)
return false;
@@ -301,6 +292,16 @@ bool IctMss_UpdateLiveM5Swings(const string sym, const ENUM_ICT_BIAS bias,
g_ictLowTf.mss.liveL0Time = sw.l0.time;
g_ictLowTf.mss.liveH0Price = sw.h0.price;
g_ictLowTf.mss.liveH0Time = sw.h0.time;
if(sw.hasL1)
{
g_ictLowTf.mss.liveL1Price = sw.l1.price;
g_ictLowTf.mss.liveL1Time = sw.l1.time;
}
if(sw.hasH1)
{
g_ictLowTf.mss.liveH1Price = sw.h1.price;
g_ictLowTf.mss.liveH1Time = sw.h1.time;
}
return true;
}
@@ -388,9 +389,14 @@ bool IctMss_TryLockMss(const string sym, const ENUM_TIMEFRAMES tf,
if(breakT < tTouch)
return false;
// SL trên cao nhất giữa H0 và H1 (cap toàn pullback bull) + buffer ATR (cộng ở MssEntry)
double slSwingHi = g_ictLowTf.mss.liveH0Price;
if(g_ictLowTf.mss.liveH1Price > slSwingHi)
slSwingHi = g_ictLowTf.mss.liveH1Price;
g_ictLowTf.mss.chochKeyLevel = g_ictLowTf.mss.liveL0Price;
g_ictLowTf.mss.chochKeyTime = g_ictLowTf.mss.liveL0Time;
g_ictLowTf.mss.slSwingPrice = g_ictLowTf.mss.liveH0Price;
g_ictLowTf.mss.slSwingPrice = slSwingHi;
}
else if(bias == ICT_BIAS_BULL)
{
@@ -400,9 +406,14 @@ bool IctMss_TryLockMss(const string sym, const ENUM_TIMEFRAMES tf,
if(breakT < tTouch)
return false;
// SL dưới thấp nhất giữa L0 và L1 (đáy toàn pullback bear) + buffer ATR (trừ ở MssEntry)
double slSwingLo = g_ictLowTf.mss.liveL0Price;
if(g_ictLowTf.mss.liveL1Price > 0.0 && g_ictLowTf.mss.liveL1Price < slSwingLo)
slSwingLo = g_ictLowTf.mss.liveL1Price;
g_ictLowTf.mss.chochKeyLevel = g_ictLowTf.mss.liveH0Price;
g_ictLowTf.mss.chochKeyTime = g_ictLowTf.mss.liveH0Time;
g_ictLowTf.mss.slSwingPrice = g_ictLowTf.mss.liveL0Price;
g_ictLowTf.mss.slSwingPrice = slSwingLo;
}
else
return false;
@@ -449,12 +460,20 @@ bool IctMss_GetConfirmMssSwing(const string sym, const ENUM_ICT_BIAS bias, doubl
{
if(bias == ICT_BIAS_BEAR && sw.hasH0)
{
swingOut = sw.h0.price;
// BEAR SL: max(H0, H1) — cap toàn pullback bull
double hi = sw.h0.price;
if(sw.hasH1 && sw.h1.price > hi)
hi = sw.h1.price;
swingOut = hi;
return true;
}
if(bias == ICT_BIAS_BULL && sw.hasL0)
{
swingOut = sw.l0.price;
// BULL SL: min(L0, L1) — đáy toàn pullback bear
double lo = sw.l0.price;
if(sw.hasL1 && sw.l1.price < lo)
lo = sw.l1.price;
swingOut = lo;
return true;
}
}
@@ -466,12 +485,20 @@ bool IctMss_GetConfirmMssSwing(const string sym, const ENUM_ICT_BIAS bias, doubl
const int nL = ArraySize(lows);
if(bias == ICT_BIAS_BEAR && nH > 0)
{
swingOut = highs[nH - 1].price;
// max của 2 swing high gần nhất
double hi = highs[nH - 1].price;
if(nH >= 2 && highs[nH - 2].price > hi)
hi = highs[nH - 2].price;
swingOut = hi;
return true;
}
if(bias == ICT_BIAS_BULL && nL > 0)
{
swingOut = lows[nL - 1].price;
// min của 2 swing low gần nhất
double lo = lows[nL - 1].price;
if(nL >= 2 && lows[nL - 2].price < lo)
lo = lows[nL - 2].price;
swingOut = lo;
return true;
}
return false;
+8
View File
@@ -232,6 +232,10 @@ struct IctMssState
double liveH0Price;
datetime liveL0Time;
datetime liveH0Time;
double liveL1Price;
double liveH1Price;
datetime liveL1Time;
datetime liveH1Time;
datetime h1LastInvalidBarTime;
ulong h1WatchFvgId;
string displayReason;
@@ -256,6 +260,10 @@ struct IctMssState
liveH0Price = 0.0;
liveL0Time = 0;
liveH0Time = 0;
liveL1Price = 0.0;
liveH1Price = 0.0;
liveL1Time = 0;
liveH1Time = 0;
h1LastInvalidBarTime = 0;
h1WatchFvgId = 0;
displayReason = "";