Chỉnh lại SL sau barA Htf

This commit is contained in:
Bell
2026-03-11 21:22:25 +07:00
parent de238fd0b3
commit 69d1839529
4 changed files with 172 additions and 9 deletions
+12
View File
@@ -102,4 +102,16 @@ bool IsNewBar()
return true;
}
//+------------------------------------------------------------------+
//| Low TF dùng để xác nhận khi giá chạm FVG: H1->M5, H4->M15, M15->M2 |
//| Trả về low TF hoặc chính highTF nếu không có mapping (không dùng confirm) |
//+------------------------------------------------------------------+
ENUM_TIMEFRAMES GetConfirmationTimeframe(ENUM_TIMEFRAMES highTF)
{
if(highTF == PERIOD_H1) return PERIOD_M5;
if(highTF == PERIOD_H4) return PERIOD_M15;
if(highTF == PERIOD_M15) return PERIOD_M2;
return highTF;
}
#endif
+3 -2
View File
@@ -80,6 +80,7 @@ void DrawTradeStatsPanel()
{
int totalTrades, tpTrades, slTrades;
GetTradeStats(totalTrades, tpTrades, slTrades);
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
string name = EA_PREFIX + "PNL_STATS";
if(ObjectFind(0, name) < 0)
@@ -92,8 +93,8 @@ void DrawTradeStatsPanel()
ObjectSetInteger(0, name, OBJPROP_COLOR, clrWhite);
ObjectSetString (0, name, OBJPROP_FONT, "Consolas");
ObjectSetString (0, name, OBJPROP_TEXT,
StringFormat("Trades: %d | TP: %d | SL: %d",
totalTrades, tpTrades, slTrades));
StringFormat("Balance: %.2f | Trades: %d | TP: %d | SL: %d",
balance, totalTrades, tpTrades, slTrades));
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
}
+80
View File
@@ -222,6 +222,86 @@ void ScanForNewFVGs()
}
}
//+------------------------------------------------------------------+
//| Quét TF bất kỳ, tìm FVG cùng hướng gần nhất (shift 1..maxLookback) |
//| Trả về cạnh trên/dưới vùng và bar A low/high (để đặt SL). |
//+------------------------------------------------------------------+
bool GetLatestLowTFFVG(string symbol,
ENUM_TIMEFRAMES tf,
ENUM_FVG_TYPE type,
int maxLookbackBars,
double &outUpper,
double &outLower,
double &outBarALow,
double &outBarAHigh)
{
int totalBars = Bars(symbol, tf);
int maxShift = MathMin(maxLookbackBars, totalBars - 3);
if(maxShift < 1)
return false;
double maxOuterRatio = InpFVGMaxOuterBarRatio;
double minGapVsBody = InpFVGMinGapVsImpulsePct / 100.0;
for(int shift = 1; shift <= maxShift; shift++)
{
int shiftA = shift + 2;
int shiftB = shift + 1;
int shiftC = shift;
double candleA_High = iHigh(symbol, tf, shiftA);
double candleA_Low = iLow (symbol, tf, shiftA);
double candleB_High = iHigh(symbol, tf, shiftB);
double candleB_Low = iLow (symbol, tf, shiftB);
double candleB_Open = iOpen (symbol, tf, shiftB);
double candleB_Close = iClose(symbol, tf, shiftB);
double candleC_High = iHigh(symbol, tf, shiftC);
double candleC_Low = iLow (symbol, tf, shiftC);
double rangeA = candleA_High - candleA_Low;
double rangeB = candleB_High - candleB_Low;
double rangeC = candleC_High - candleC_Low;
double bodyB = MathAbs(candleB_Close - candleB_Open);
if(rangeB <= 0 || bodyB <= 0)
continue;
if(rangeA > maxOuterRatio * rangeB || rangeC > maxOuterRatio * rangeB)
continue;
if(!IsImpulseCandleStrong(symbol, tf, shiftB))
continue;
if(type == FVG_BULLISH)
{
if(candleA_High >= candleC_Low || candleB_Close <= candleB_Open)
continue;
double gap = candleC_Low - candleA_High;
double gapRatio = gap / bodyB;
if(gapRatio < minGapVsBody)
continue;
outUpper = candleC_Low;
outLower = candleA_High;
outBarALow = candleA_Low;
outBarAHigh = candleA_High;
return true;
}
else // FVG_BEARISH
{
if(candleA_Low <= candleC_High || candleB_Close >= candleB_Open)
continue;
double gap = candleA_Low - candleC_High;
double gapRatio = gap / bodyB;
if(gapRatio < minGapVsBody)
continue;
outUpper = candleA_Low;
outLower = candleC_High;
outBarALow = candleA_Low;
outBarAHigh = candleA_High;
return true;
}
}
return false;
}
//+------------------------------------------------------------------+
//| Check if price has mitigated (filled through) any active FVG |
//+------------------------------------------------------------------+
+77 -7
View File
@@ -241,6 +241,55 @@ double CalculateRiskLotSize(double entryPrice, double slPrice)
return rounded2;
}
// Đặt lệnh limit theo entry/SL từ low TF FVG (sau khi có tín hiệu xác nhận)
bool PlaceLimitFromLowTF(string symbol, ENUM_FVG_TYPE type, double entryPrice, double slPrice)
{
double tpPrice;
ENUM_ORDER_TYPE orderType;
if(type == FVG_BULLISH)
{
double risk = entryPrice - slPrice;
if(risk <= 0.0) return false;
tpPrice = entryPrice + risk * InpRRRatio;
orderType = ORDER_TYPE_BUY_LIMIT;
}
else
{
double risk = slPrice - entryPrice;
if(risk <= 0.0) return false;
tpPrice = entryPrice - risk * InpRRRatio;
orderType = ORDER_TYPE_SELL_LIMIT;
}
if(HasLimitOrderAtPrice(orderType, entryPrice))
return false;
double volume = CalculateRiskLotSize(entryPrice, slPrice);
if(volume <= 0.0)
return false;
MqlTradeRequest req;
MqlTradeResult res;
ZeroMemory(req);
ZeroMemory(res);
req.action = TRADE_ACTION_PENDING;
req.symbol = symbol;
req.magic = InpEAMagic;
req.type = orderType;
req.volume = volume;
req.price = entryPrice;
req.sl = slPrice;
req.tp = tpPrice;
req.type_filling = ORDER_FILLING_RETURN;
req.deviation = 10;
req.comment = "SimpleFVG_LTF";
if(!OrderSend(req, res))
return false;
return (res.retcode == TRADE_RETCODE_DONE || res.retcode == TRADE_RETCODE_PLACED);
}
bool PlaceLimitForZone(const FVGZone &zone)
{
string symbol = GetTradeSymbol();
@@ -333,12 +382,15 @@ void ManageFVGTrades()
if(currentLimits >= InpMaxLimitOrders)
return;
// Đặt lệnh limit khi giá vừa chạm cạnh ngoài FVG (trước khi fill đủ 35%)
// Khi giá chạm cạnh FVG (high TF) -> tìm tín hiệu xác nhận trên low TF (FVG cùng hướng)
ENUM_TREND_DIRECTION trend = g_CurrentTrend;
string symbol = GetTradeSymbol();
double lastHigh = iHigh(symbol, InpTimeframe, 1);
double lastLow = iLow (symbol, InpTimeframe, 1);
ENUM_TIMEFRAMES lowTF = GetConfirmationTimeframe(InpTimeframe);
const int LOW_TF_FVG_LOOKBACK = 15;
for(int i = g_FVGCount - 1; i >= 0 && currentLimits < InpMaxLimitOrders; i--)
{
FVGZone zone = g_FVGZones[i];
@@ -351,24 +403,42 @@ void ManageFVGTrades()
continue;
bool touchedEdge = false;
if(zone.type == FVG_BULLISH)
{
// giá chạm cạnh trên (upperEdge) của bullish FVG
if(lastLow <= zone.upperEdge && lastHigh >= zone.upperEdge)
touchedEdge = true;
}
else // FVG_BEARISH
else
{
// giá chạm cạnh dưới (lowerEdge) của bearish FVG
if(lastHigh >= zone.lowerEdge && lastLow <= zone.lowerEdge)
touchedEdge = true;
}
if(!touchedEdge)
continue;
if(PlaceLimitForZone(zone))
// Chỉ đặt lệnh khi có low TF để xác nhận (H1->M5, H4->M15, M15->M2)
if(lowTF == InpTimeframe)
continue;
double ltfUpper, ltfLower, ltfBarALow, ltfBarAHigh;
if(!GetLatestLowTFFVG(symbol, lowTF, zone.type, LOW_TF_FVG_LOOKBACK,
ltfUpper, ltfLower, ltfBarALow, ltfBarAHigh))
continue;
// Entry theo low TF FVG; SL vẫn dùng bar A của high TF (đủ xa)
double entryPrice, slPrice;
if(zone.type == FVG_BULLISH)
{
entryPrice = ltfUpper; // Buy limit tại cạnh trên low TF FVG
slPrice = zone.slReferencePrice; // SL dưới bar A của high TF FVG
}
else
{
entryPrice = ltfLower; // Sell limit tại cạnh dưới low TF FVG
slPrice = zone.slReferencePrice; // SL trên bar A của high TF FVG
}
if(PlaceLimitFromLowTF(symbol, zone.type, entryPrice, slPrice))
currentLimits++;
}
}