Filter trend h1
This commit is contained in:
+10
-10
@@ -86,9 +86,9 @@ input bool PrintToExperts = false; // không dùng — logs đã được c
|
||||
// slot 0 = HTF, 1 = MTF, 2 = LTF
|
||||
int TrendTF[3]; // 1 = up, -1 = down, 0 = sideway / unknown
|
||||
|
||||
input ENUM_TIMEFRAMES HighTF = PERIOD_D1; // Khung thời gian cao
|
||||
input ENUM_TIMEFRAMES MiddleTF = PERIOD_H1; // Khung thời gian trung bình (dùng để tìm FVG)
|
||||
input ENUM_TIMEFRAMES LowTF = PERIOD_M5; // Khung thời gian thấp (Tìm điểm vào lệnh)
|
||||
input ENUM_TIMEFRAMES HighTF = PERIOD_H4; // Khung thời gian cao
|
||||
input ENUM_TIMEFRAMES MiddleTF = PERIOD_M15; // Khung thời gian trung bình (dùng để tìm FVG)
|
||||
input ENUM_TIMEFRAMES LowTF = PERIOD_M1; // Khung thời gian thấp (Tìm điểm vào lệnh)
|
||||
|
||||
// --- multi-TF swing storage (slots) ---
|
||||
// slot 0 = HighTF, slot 1 = MiddleTF, slot 2 = LowTF
|
||||
@@ -1928,13 +1928,13 @@ bool CheckValidEntry(
|
||||
if(mssDirection == 0)
|
||||
return false;
|
||||
|
||||
// HTF phải có trend rõ ràng
|
||||
if(htfTrend == 0)
|
||||
{
|
||||
if(PrintEntryLog)
|
||||
Print("CheckValidEntry FAIL: HTF is SIDEWAY");
|
||||
return false;
|
||||
}
|
||||
// HTF phải có trend rõ ràng // TEST
|
||||
// if(htfTrend == 0)
|
||||
// {
|
||||
// if(PrintEntryLog)
|
||||
// Print("CheckValidEntry FAIL: HTF is SIDEWAY");
|
||||
// return false;
|
||||
// }
|
||||
|
||||
if(fvgIndex < 0 || fvgIndex >= MTF_FVG_count)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| ICT Early Trend Detection EA |
|
||||
//| Structure + Early Key-Level Break (MSS-style) |
|
||||
//| Clean Architecture – Meaningful Naming |
|
||||
//| Author: Bell CW |
|
||||
//+------------------------------------------------------------------+
|
||||
#property strict
|
||||
|
||||
//====================================================
|
||||
// INPUT PARAMETERS
|
||||
//====================================================
|
||||
|
||||
input ENUM_TIMEFRAMES TrendTimeframe = PERIOD_H1; // Timeframe xác định trend
|
||||
input ENUM_TIMEFRAMES TriggerTimeframe = PERIOD_M5; // Timeframe kích hoạt logic
|
||||
|
||||
input int SwingDetectionRange = 2; // Số nến trái/phải xác định swing
|
||||
input int StructureScanLookbackBars = 150; // Số nến quét structure
|
||||
|
||||
//====================================================
|
||||
// DATA STRUCTURE
|
||||
//====================================================
|
||||
|
||||
struct TrendState
|
||||
{
|
||||
int trendDirection; // 1 = uptrend, -1 = downtrend, 0 = neutral
|
||||
|
||||
double latestSwingHigh; // Swing High mới nhất
|
||||
double previousSwingHigh; // Swing High trước đó
|
||||
|
||||
double latestSwingLow; // Swing Low mới nhất
|
||||
double previousSwingLow; // Swing Low trước đó
|
||||
|
||||
int latestSwingHighIndex;
|
||||
int previousSwingHighIndex;
|
||||
|
||||
int latestSwingLowIndex;
|
||||
int previousSwingLowIndex;
|
||||
|
||||
double currentKeyLevel; // Key level theo ICT structure
|
||||
|
||||
bool earlyFlipUsedThisBar; // Đã dùng early flip trong HTF bar này chưa
|
||||
datetime lastStructureUpdateTime; // Thời gian HTF bar cuối cùng đã xử lý
|
||||
};
|
||||
|
||||
//====================================================
|
||||
// GLOBAL STATE
|
||||
//====================================================
|
||||
|
||||
TrendState g_TrendState;
|
||||
datetime g_LastTriggerBarTime = 0;
|
||||
|
||||
//====================================================
|
||||
// INITIALIZATION
|
||||
//====================================================
|
||||
|
||||
int OnInit()
|
||||
{
|
||||
ZeroMemory(g_TrendState);
|
||||
g_TrendState.trendDirection = 0;
|
||||
g_TrendState.lastStructureUpdateTime = 0;
|
||||
|
||||
Print("ICT Early Trend Detection EA initialized successfully");
|
||||
return INIT_SUCCEEDED;
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// BAR UTILITY
|
||||
//====================================================
|
||||
|
||||
bool IsNewBarFormed(ENUM_TIMEFRAMES timeframe, datetime &lastBarTime)
|
||||
{
|
||||
datetime currentBarTime = iTime(_Symbol, timeframe, 0);
|
||||
if(currentBarTime != lastBarTime)
|
||||
{
|
||||
lastBarTime = currentBarTime;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// SWING DETECTION (GENERIC)
|
||||
//====================================================
|
||||
|
||||
bool IsSwingHighAtBar(
|
||||
ENUM_TIMEFRAMES timeframe,
|
||||
int barIndex
|
||||
)
|
||||
{
|
||||
double highPrice = iHigh(_Symbol, timeframe, barIndex);
|
||||
|
||||
for(int offset = 1; offset <= SwingDetectionRange; offset++)
|
||||
{
|
||||
if(iHigh(_Symbol, timeframe, barIndex - offset) >= highPrice) return false;
|
||||
if(iHigh(_Symbol, timeframe, barIndex + offset) >= highPrice) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsSwingLowAtBar(
|
||||
ENUM_TIMEFRAMES timeframe,
|
||||
int barIndex
|
||||
)
|
||||
{
|
||||
double lowPrice = iLow(_Symbol, timeframe, barIndex);
|
||||
|
||||
for(int offset = 1; offset <= SwingDetectionRange; offset++)
|
||||
{
|
||||
if(iLow(_Symbol, timeframe, barIndex - offset) <= lowPrice) return false;
|
||||
if(iLow(_Symbol, timeframe, barIndex + offset) <= lowPrice) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// STRUCTURE VALIDATION
|
||||
//====================================================
|
||||
|
||||
bool HasConfirmedMarketStructure(const TrendState &state)
|
||||
{
|
||||
return (
|
||||
state.latestSwingHigh > 0 &&
|
||||
state.previousSwingHigh > 0 &&
|
||||
state.latestSwingLow > 0 &&
|
||||
state.previousSwingLow > 0
|
||||
);
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// STRUCTURE UPDATE (TIMEFRAME AGNOSTIC)
|
||||
//====================================================
|
||||
|
||||
void UpdateMarketStructure(
|
||||
ENUM_TIMEFRAMES timeframe,
|
||||
TrendState &state
|
||||
)
|
||||
{
|
||||
datetime currentStructureBarTime = iTime(_Symbol, timeframe, 0);
|
||||
if(currentStructureBarTime == state.lastStructureUpdateTime)
|
||||
return;
|
||||
|
||||
state.lastStructureUpdateTime = currentStructureBarTime;
|
||||
state.earlyFlipUsedThisBar = false;
|
||||
|
||||
double detectedSwingHighs[2];
|
||||
double detectedSwingLows[2];
|
||||
int detectedSwingHighIndices[2];
|
||||
int detectedSwingLowIndices[2];
|
||||
|
||||
int highCount = 0;
|
||||
int lowCount = 0;
|
||||
|
||||
for(int barIndex = SwingDetectionRange + 1;
|
||||
barIndex < StructureScanLookbackBars;
|
||||
barIndex++)
|
||||
{
|
||||
if(highCount < 2 && IsSwingHighAtBar(timeframe, barIndex))
|
||||
{
|
||||
detectedSwingHighs[highCount] = iHigh(_Symbol, timeframe, barIndex);
|
||||
detectedSwingHighIndices[highCount] = barIndex;
|
||||
highCount++;
|
||||
}
|
||||
|
||||
if(lowCount < 2 && IsSwingLowAtBar(timeframe, barIndex))
|
||||
{
|
||||
detectedSwingLows[lowCount] = iLow(_Symbol, timeframe, barIndex);
|
||||
detectedSwingLowIndices[lowCount] = barIndex;
|
||||
lowCount++;
|
||||
}
|
||||
|
||||
if(highCount == 2 && lowCount == 2)
|
||||
break;
|
||||
}
|
||||
|
||||
if(highCount < 2 || lowCount < 2)
|
||||
return;
|
||||
|
||||
state.latestSwingHigh = detectedSwingHighs[0];
|
||||
state.previousSwingHigh = detectedSwingHighs[1];
|
||||
state.latestSwingLow = detectedSwingLows[0];
|
||||
state.previousSwingLow = detectedSwingLows[1];
|
||||
|
||||
state.latestSwingHighIndex = detectedSwingHighIndices[0];
|
||||
state.previousSwingHighIndex = detectedSwingHighIndices[1];
|
||||
state.latestSwingLowIndex = detectedSwingLowIndices[0];
|
||||
state.previousSwingLowIndex = detectedSwingLowIndices[1];
|
||||
|
||||
// ===== STRUCTURE INTERPRETATION =====
|
||||
if(state.previousSwingHigh < state.latestSwingHigh &&
|
||||
state.previousSwingLow < state.latestSwingLow)
|
||||
{
|
||||
state.trendDirection = 1;
|
||||
state.currentKeyLevel = state.latestSwingLow;
|
||||
}
|
||||
else if(state.previousSwingHigh > state.latestSwingHigh &&
|
||||
state.previousSwingLow > state.latestSwingLow)
|
||||
{
|
||||
state.trendDirection = -1;
|
||||
state.currentKeyLevel = state.latestSwingHigh;
|
||||
}
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// EARLY TREND FLIP (MSS-STYLE)
|
||||
//====================================================
|
||||
|
||||
void CheckForEarlyTrendFlip(
|
||||
TrendState &state,
|
||||
double currentPrice
|
||||
)
|
||||
{
|
||||
if(!HasConfirmedMarketStructure(state)) return;
|
||||
if(state.earlyFlipUsedThisBar) return;
|
||||
|
||||
if(state.trendDirection == 1 &&
|
||||
currentPrice < state.currentKeyLevel)
|
||||
{
|
||||
state.trendDirection = -1;
|
||||
state.currentKeyLevel = state.latestSwingHigh;
|
||||
state.earlyFlipUsedThisBar = true;
|
||||
}
|
||||
else if(state.trendDirection == -1 &&
|
||||
currentPrice > state.currentKeyLevel)
|
||||
{
|
||||
state.trendDirection = 1;
|
||||
state.currentKeyLevel = state.latestSwingLow;
|
||||
state.earlyFlipUsedThisBar = true;
|
||||
}
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// DRAWING UTILITIES
|
||||
//====================================================
|
||||
|
||||
void DrawSwingLabel(
|
||||
string objectName,
|
||||
string labelText,
|
||||
ENUM_TIMEFRAMES timeframe,
|
||||
int barIndex,
|
||||
double price,
|
||||
color labelColor
|
||||
)
|
||||
{
|
||||
if(barIndex < 0) return;
|
||||
|
||||
datetime barTime = iTime(_Symbol, timeframe, barIndex);
|
||||
|
||||
ObjectDelete(0, objectName);
|
||||
ObjectCreate(0, objectName, OBJ_TEXT, 0, barTime, price);
|
||||
ObjectSetInteger(0, objectName, OBJPROP_COLOR, labelColor);
|
||||
ObjectSetInteger(0, objectName, OBJPROP_FONTSIZE, 8);
|
||||
ObjectSetString (0, objectName, OBJPROP_TEXT, labelText);
|
||||
}
|
||||
|
||||
void DrawMarketStructure(
|
||||
ENUM_TIMEFRAMES timeframe,
|
||||
const TrendState &state
|
||||
)
|
||||
{
|
||||
DrawSwingLabel("SWING_HIGH_LATEST", "H0", timeframe,
|
||||
state.latestSwingHighIndex,
|
||||
state.latestSwingHigh, clrLime);
|
||||
|
||||
DrawSwingLabel("SWING_HIGH_PREVIOUS", "H1", timeframe,
|
||||
state.previousSwingHighIndex,
|
||||
state.previousSwingHigh, clrGreen);
|
||||
|
||||
DrawSwingLabel("SWING_LOW_LATEST", "L0", timeframe,
|
||||
state.latestSwingLowIndex,
|
||||
state.latestSwingLow, clrRed);
|
||||
|
||||
DrawSwingLabel("SWING_LOW_PREVIOUS", "L1", timeframe,
|
||||
state.previousSwingLowIndex,
|
||||
state.previousSwingLow, clrMaroon);
|
||||
}
|
||||
|
||||
void DrawTrendSummaryLabel(const TrendState &state)
|
||||
{
|
||||
string labelName = "TREND_SUMMARY";
|
||||
ObjectDelete(0, labelName);
|
||||
|
||||
string labelText = "TREND: NEUTRAL";
|
||||
color labelColor = clrGray;
|
||||
|
||||
if(state.trendDirection == 1)
|
||||
{
|
||||
labelText = StringFormat(
|
||||
"UPTREND - Key Level: %.2f%s",
|
||||
state.currentKeyLevel,
|
||||
state.earlyFlipUsedThisBar ? " -> EARLY FLIP" : ""
|
||||
);
|
||||
labelColor = state.earlyFlipUsedThisBar ? clrOrange : clrLime;
|
||||
}
|
||||
else if(state.trendDirection == -1)
|
||||
{
|
||||
labelText = StringFormat(
|
||||
"DOWNTREND - Key Level: %.2f%s",
|
||||
state.currentKeyLevel,
|
||||
state.earlyFlipUsedThisBar ? " -> EARLY FLIP" : ""
|
||||
);
|
||||
labelColor = state.earlyFlipUsedThisBar ? clrOrange : clrRed;
|
||||
}
|
||||
|
||||
ObjectCreate(0, labelName, OBJ_LABEL, 0, 0, 0);
|
||||
ObjectSetInteger(0, labelName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
|
||||
ObjectSetInteger(0, labelName, OBJPROP_XDISTANCE, 10);
|
||||
ObjectSetInteger(0, labelName, OBJPROP_YDISTANCE, 20);
|
||||
ObjectSetInteger(0, labelName, OBJPROP_COLOR, labelColor);
|
||||
ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 9);
|
||||
ObjectSetString (0, labelName, OBJPROP_TEXT, labelText);
|
||||
}
|
||||
|
||||
//====================================================
|
||||
// MAIN LOOP
|
||||
//====================================================
|
||||
|
||||
void OnTick()
|
||||
{
|
||||
if(!IsNewBarFormed(TriggerTimeframe, g_LastTriggerBarTime))
|
||||
return;
|
||||
|
||||
UpdateMarketStructure(TrendTimeframe, g_TrendState);
|
||||
|
||||
double currentBidPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
||||
CheckForEarlyTrendFlip(g_TrendState, currentBidPrice);
|
||||
|
||||
DrawMarketStructure(TrendTimeframe, g_TrendState);
|
||||
DrawTrendSummaryLabel(g_TrendState);
|
||||
|
||||
// === Entry logic sẽ gắn tại đây ===
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Reference in New Issue
Block a user