Update SL + Spread, TP - 2 spread
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = "";
|
||||
|
||||
Reference in New Issue
Block a user