Thêm text đổi trend

This commit is contained in:
Bell
2025-10-27 23:45:26 +07:00
parent ca8b16cd73
commit 1959a7d305
+98 -88
View File
@@ -1,146 +1,154 @@
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
//| EA_Trend_EMA50_EMA200.mq5 | //| EA_Trend_EMA50_EMA200_v1.1.mq5 |
//| Phiên bản: 1.0 | //| Tác giả: Bell Hyperpush |
//| Mục đích: | //| Mục đích: |
//| - Xác định xu hướng bằng EMA50 & EMA200 (m15) | //| - Xác định xu hướng bằng EMA50 & EMA200 (theo TrendTF) |
//| - Vào lệnh trên M5 khi có tín hiệu: 2 đáy / 2 đỉnh / nến nhấn chìm | //| - In ra khi xu hướng thay đổi, vẽ marker lên chart |
//| - Rủi ro cố định: 1% Equity mỗi lệnh | //| - Tùy chọn hiển thị EMA trên biểu đồ |
//| - Giới hạn tối đa 2 lệnh mở cùng lúc |
//| - Tùy chọn hiển thị EMA lên biểu đồ |
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
#property copyright "Bell Hyperpush" #property copyright "Bell Hyperpush"
#property version "1.00" #property version "1.10"
#property strict #property strict
#include <Trade/Trade.mqh> #include <Trade/Trade.mqh>
CTrade trade; CTrade trade;
#define TrendTF PERIOD_M5 // Test
#define EntryTF PERIOD_M5 // Test
int handleEMAFast = INVALID_HANDLE; int handleEMAFast = INVALID_HANDLE;
int handleEMASlow = INVALID_HANDLE; int handleEMASlow = INVALID_HANDLE;
// ================== INPUTS ========================================= // ================== INPUTS =========================================
input ENUM_TIMEFRAMES TrendTF = PERIOD_H1; // khung thời gian dùng để lọc xu hướng // input ENUM_TIMEFRAMES TrendTF = PERIOD_M15; // khung thời gian dùng để lọc xu hướng
input ENUM_TIMEFRAMES EntryTF = PERIOD_M5; // khung thời gian để tìm điểm vào // input ENUM_TIMEFRAMES EntryTF = PERIOD_M5; // khung thời gian để tìm điểm vào
input int EMA_Fast = 50; // EMA nhanh input int EMA_Fast = 50; // EMA nhanh
input int EMA_Slow = 200; // EMA chậm input int EMA_Slow = 200; // EMA chậm
input double RiskPercent = 1.0; // rủi ro % equity cho mỗi lệnh input double RiskPercent = 1.0; // rủi ro % equity mỗi lệnh
input double TP_Multiplier = 2.0; // tỉ lệ TP = Risk * multiplier input double TP_Multiplier = 2.0; // tỉ lệ TP = Risk * multiplier
input int MaxOpenPositions = 2; // tối đa 2 lệnh mở input int MaxOpenPositions = 2; // tối đa số lệnh mở
input double DoubleTolerancePoints = 30; // dung sai giữa 2 đáy/đỉnh
input int MinBarsBetweenDouble = 4; // khoảng cách tối thiểu giữa 2 đáy/đỉnh
input int SL_Pips_Default = 40; // SL mặc định (points)
input int Slippage = 10; // trượt giá tối đa
input bool VisualizeEMAs = true; // có vẽ EMA lên chart không input bool VisualizeEMAs = true; // có vẽ EMA lên chart không
input int TrendShift = 1; // shift dùng để đọc nến đóng (tránh nến đang hình thành) input int TrendShift = 1; // đọc nến đóng (tránh nến đang chạy)
input int StructureRecentOffset = 1; // offset cho nến recent khi kiểm tra cấu trúc (high1/low1)
input int StructurePrevOffset = 2; // offset cho nến trước đó khi kiểm tra cấu trúc (high2/low2)
// ================== FUNCTIONS ===================================== // ================== ENUMS & UTILITIES ==============================
// ----- Enums for EMA and trend result (avoid hard-coded strings) -----
enum EMA_COND { EMA_INSUFFICIENT = 0, EMA_UPTREND, EMA_DOWNTREND, EMA_NEUTRAL }; enum EMA_COND { EMA_INSUFFICIENT = 0, EMA_UPTREND, EMA_DOWNTREND, EMA_NEUTRAL };
enum TREND_RESULT { TREND_NEUTRAL = 0, TREND_UPTREND, TREND_DOWNTREND, TREND_SIDEWAY_RESULT }; enum TREND_RESULT { TREND_NEUTRAL = 0, TREND_UPTREND, TREND_DOWNTREND, TREND_SIDEWAY_RESULT };
string EmaConditionToString(const int e) { string TrendResultToString(const TREND_RESULT t) {
switch(e) { switch(t) {
case EMA_UPTREND: return "EMA Uptrend"; case TREND_UPTREND: return "UPTREND";
case EMA_DOWNTREND: return "EMA Downtrend"; case TREND_DOWNTREND: return "DOWNTREND";
case EMA_NEUTRAL: return "EMA Neutral"; case TREND_SIDEWAY_RESULT:return "SIDEWAY";
default: return "EMA InsufficientData"; default: return "NEUTRAL";
} }
} }
string TrendResultToString(const int r) { // ================== XÁC ĐỊNH XU HƯỚNG =============================
switch(r) { TREND_RESULT GetTrendDirection()
case TREND_UPTREND: return "UPTREND"; {
case TREND_DOWNTREND: return "DOWNTREND"; int shift = TrendShift;
case TREND_SIDEWAY_RESULT: return "SIDEWAY"; double emaFast = 0.0, emaSlow = 0.0;
default: return "NEUTRAL";
}
}
// Xác định xu hướng hiện tại
string GetTrendDirection() {
int shift = TrendShift; // tránh dùng nến đang chạy (mặc định = 1)
double emaFast = 0.0;
double emaSlow = 0.0;
double buf[]; double buf[];
// read EMA50 value by copying buffer from handle // --- Copy EMA buffers từ khung TrendTF ---
if(handleEMAFast != INVALID_HANDLE) { if(handleEMAFast != INVALID_HANDLE)
if(CopyBuffer(handleEMAFast, 0, shift, 1, buf) > 0) emaFast = buf[0]; if(CopyBuffer(handleEMAFast, 0, shift, 1, buf) > 0) emaFast = buf[0];
} if(handleEMASlow != INVALID_HANDLE)
// read EMA200 value by copying buffer from handle
if(handleEMASlow != INVALID_HANDLE) {
if(CopyBuffer(handleEMASlow, 0, shift, 1, buf) > 0) emaSlow = buf[0]; if(CopyBuffer(handleEMASlow, 0, shift, 1, buf) > 0) emaSlow = buf[0];
}
double priceClose = iClose(_Symbol, TrendTF, shift); double priceClose = iClose(_Symbol, TrendTF, shift);
TREND_RESULT trendEnum = TREND_NEUTRAL;
int emaEnum = EMA_INSUFFICIENT; if(priceClose <= 0.0 || emaFast <= 0.0 || emaSlow <= 0.0)
int trendEnum = TREND_NEUTRAL;
// --- B2: Kiểm tra EMA (an toàn: đảm bảo dữ liệu hợp lệ)
if(priceClose <= 0.0 || emaFast <= 0.0 || emaSlow <= 0.0) {
emaEnum = EMA_INSUFFICIENT;
trendEnum = TREND_NEUTRAL; trendEnum = TREND_NEUTRAL;
} else if(emaFast > emaSlow)
else if(emaFast > emaSlow ) { // && priceClose > emaFast
emaEnum = EMA_UPTREND;
trendEnum = TREND_UPTREND; trendEnum = TREND_UPTREND;
} else if(emaFast < emaSlow)
else if(emaFast < emaSlow) { // && priceClose < emaFast
emaEnum = EMA_DOWNTREND;
trendEnum = TREND_DOWNTREND; trendEnum = TREND_DOWNTREND;
} else
else {
emaEnum = EMA_NEUTRAL;
trendEnum = TREND_SIDEWAY_RESULT; trendEnum = TREND_SIDEWAY_RESULT;
}
// --- Log chi tiết (debug) // --- Debug log ---
PrintFormat("[TREND DEBUG] === %s ===", TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS)); PrintFormat("[TREND DEBUG] %s | EMA%d=%.5f | EMA%d=%.5f | Close=%.5f | => %s",
// print the EMA periods and their current values instead of hard-coded labels TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS),
PrintFormat("EMA%d=%.5f | EMA%d=%.5f | PriceClose=%.5f", EMA_Fast, emaFast, EMA_Slow, emaSlow, priceClose); EMA_Fast, emaFast, EMA_Slow, emaSlow, priceClose,
PrintFormat("EMA: %s | => TREND: %s", EmaConditionToString(emaEnum), TrendResultToString(trendEnum)); TrendResultToString(trendEnum));
return TrendResultToString(trendEnum); return trendEnum;
} }
// ================== VẼ MARKER XU HƯỚNG =============================
void DrawTrendChangeMarker(TREND_RESULT trend)
{
string name = "TrendChange_" + TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS);
double price = iClose(_Symbol, TrendTF, 1);
datetime barTime = iTime(_Symbol, TrendTF, 1);
// ================== VÒNG LẶP CHÍNH ================================ color c = clrWhite;
string label = "";
if(trend == TREND_UPTREND) { c = clrLime; label = "↑ UPTREND"; }
else if(trend == TREND_DOWNTREND){ c = clrRed; label = "↓ DOWNTREND"; }
else if(trend == TREND_SIDEWAY_RESULT) { c = clrYellow; label = "→ SIDEWAY"; }
ObjectCreate(0, name, OBJ_TEXT, 0, barTime, price);
ObjectSetString(0, name, OBJPROP_TEXT, label);
ObjectSetInteger(0, name, OBJPROP_COLOR, c);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 10);
ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_CENTER);
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
// ObjectSetDouble(0, name, OBJPROP_YDISTANCE, 10); // tránh chữ đè lên nến
}
// ================== VÒNG LẶP CHÍNH =================================
void OnTick() void OnTick()
{ {
static datetime lastCheck = 0; static TREND_RESULT lastTrend = TREND_NEUTRAL;
static datetime lastLogTime = 0;
// chỉ check 1 lần mỗi phút TREND_RESULT trend = GetTrendDirection();
if(TimeCurrent() - lastCheck >= 60) {
string trend = GetTrendDirection(); // Nếu trend mới khác trend cũ → in log & đánh dấu
Comment("Current Trend (", EnumToString(TrendTF), "): ", trend); if(trend != lastTrend && lastTrend != TREND_NEUTRAL)
lastCheck = TimeCurrent(); {
string msg = StringFormat("TREND CHANGED: %s → %s",
TrendResultToString(lastTrend),
TrendResultToString(trend));
Print(msg);
Comment("Current Trend: ", TrendResultToString(trend));
DrawTrendChangeMarker(trend);
}
lastTrend = trend;
// Cập nhật comment mỗi phút
if(TimeCurrent() - lastLogTime >= 60) {
Comment("Current Trend: ", TrendResultToString(trend));
lastLogTime = TimeCurrent();
} }
} }
// ================== KHỞI TẠO & KẾT THÚC =========================== // ================== KHỞI TẠO & KẾT THÚC ===========================
int OnInit() { int OnInit()
Sleep(500); // đợi chart visual load hoàn tất {
Sleep(500);
handleEMAFast = iMA(_Symbol, _Period, EMA_Fast, 0, MODE_EMA, PRICE_CLOSE); handleEMAFast = iMA(_Symbol, TrendTF, EMA_Fast, 0, MODE_EMA, PRICE_CLOSE);
handleEMASlow = iMA(_Symbol, _Period, EMA_Slow, 0, MODE_EMA, PRICE_CLOSE); handleEMASlow = iMA(_Symbol, TrendTF, EMA_Slow, 0, MODE_EMA, PRICE_CLOSE);
if(handleEMAFast == INVALID_HANDLE || handleEMASlow == INVALID_HANDLE) { if(handleEMAFast == INVALID_HANDLE || handleEMASlow == INVALID_HANDLE) {
Print("Failed to create EMA handles. Err=", GetLastError()); Print("Failed to create EMA handles. Err=", GetLastError());
return(INIT_FAILED); return(INIT_FAILED);
} }
// Diagnostic: print which EA file is running and the active EMA periods (helps detect .set overrides) PrintFormat("Init: EA=%s | EMA_Fast=%d | EMA_Slow=%d | TF=%s",
PrintFormat("Init: EA=%s EMA_Fast=%d EMA_Slow=%d handles=(%d,%d)", __FILE__, EMA_Fast, EMA_Slow, handleEMAFast, handleEMASlow); __FILE__, EMA_Fast, EMA_Slow, EnumToString(TrendTF));
if(VisualizeEMAs) { if(VisualizeEMAs) {
long chart_id = ChartID(); long chart_id = ChartID();
bool ok1 = ChartIndicatorAdd(chart_id, 0, handleEMAFast); bool ok1 = ChartIndicatorAdd(chart_id, 0, handleEMAFast);
bool ok2 = ChartIndicatorAdd(chart_id, 0, handleEMASlow); bool ok2 = ChartIndicatorAdd(chart_id, 0, handleEMASlow);
if(!ok1 || !ok2) if(!ok1 || !ok2)
Print("Warning: ChartIndicatorAdd failed. Err=", GetLastError()); Print("Warning: ChartIndicatorAdd failed. Err=", GetLastError());
} }
@@ -148,7 +156,9 @@ int OnInit() {
return(INIT_SUCCEEDED); return(INIT_SUCCEEDED);
} }
void OnDeinit(const int reason) { void OnDeinit(const int reason)
if(handleEMAFast != INVALID_HANDLE) IndicatorRelease(handleEMAFast); {
if(handleEMAFast != INVALID_HANDLE) IndicatorRelease(handleEMAFast);
if(handleEMASlow != INVALID_HANDLE) IndicatorRelease(handleEMASlow); if(handleEMASlow != INVALID_HANDLE) IndicatorRelease(handleEMASlow);
Comment(""); // clear chart comment
} }