Chỉnh lại SL sau barA Htf
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user