Trend confirmation

This commit is contained in:
Bell
2025-10-23 03:16:11 +07:00
parent 17f36609e8
commit ca8b16cd73
8 changed files with 70 additions and 221 deletions
Binary file not shown.
+47 -57
View File
@@ -14,11 +14,11 @@
#include <Trade/Trade.mqh>
CTrade trade;
int handleEMA50 = INVALID_HANDLE;
int handleEMA200 = INVALID_HANDLE;
int handleEMAFast = INVALID_HANDLE;
int handleEMASlow = INVALID_HANDLE;
// ================== INPUTS =========================================
input ENUM_TIMEFRAMES TrendTF = PERIOD_M15; // khung thời gian dùng để lọc xu hướng
input ENUM_TIMEFRAMES TrendTF = PERIOD_H1; // 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 int EMA_Fast = 50; // EMA nhanh
input int EMA_Slow = 200; // EMA chậm
@@ -27,7 +27,7 @@ input double TP_Multiplier = 2.0; // tỉ lệ TP = Risk * multiplier
input int MaxOpenPositions = 2; // tối đa 2 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 = 35; // SL mặc định (points)
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 int TrendShift = 1; // shift dùng để đọc nến đóng (tránh nến đang hình thành)
@@ -36,19 +36,9 @@ input int StructurePrevOffset = 2; // offset cho nến trước đó k
// ================== FUNCTIONS =====================================
// ----- Enums for structured states (avoid hard-coded strings) -----
enum TREND_STRUCTURE { STRUCTURE_NEUTRAL = 0, STRUCTURE_HH_HL, STRUCTURE_LH_LL, STRUCTURE_SIDEWAY };
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 };
string StructureToString(const int s) {
switch(s) {
case STRUCTURE_HH_HL: return "HH-HL (Uptrend)";
case STRUCTURE_LH_LL: return "LH-LL (Downtrend)";
case STRUCTURE_SIDEWAY: return "Sideway";
default: return "Neutral";
}
}
// ----- Enums for EMA and trend result (avoid hard-coded strings) -----
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 };
string EmaConditionToString(const int e) {
switch(e) {
@@ -76,57 +66,42 @@ string GetTrendDirection() {
double buf[];
// read EMA50 value by copying buffer from handle
if(handleEMA50 != INVALID_HANDLE) {
if(CopyBuffer(handleEMA50, 0, shift, 1, buf) > 0) emaFast = buf[0];
if(handleEMAFast != INVALID_HANDLE) {
if(CopyBuffer(handleEMAFast, 0, shift, 1, buf) > 0) emaFast = buf[0];
}
// read EMA200 value by copying buffer from handle
if(handleEMA200 != INVALID_HANDLE) {
if(CopyBuffer(handleEMA200, 0, shift, 1, buf) > 0) emaSlow = buf[0];
if(handleEMASlow != INVALID_HANDLE) {
if(CopyBuffer(handleEMASlow, 0, shift, 1, buf) > 0) emaSlow = buf[0];
}
double priceClose = iClose(_Symbol, TrendTF, shift);
// Lấy giá cao thấp theo cấu hình offsets (recent vs prev)
double high1 = iHigh(_Symbol, TrendTF, StructureRecentOffset);
double high2 = iHigh(_Symbol, TrendTF, StructurePrevOffset);
double low1 = iLow(_Symbol, TrendTF, StructureRecentOffset);
double low2 = iLow(_Symbol, TrendTF, StructurePrevOffset);
int structureEnum = STRUCTURE_NEUTRAL;
int emaEnum = EMA_INSUFFICIENT;
int trendEnum = TREND_NEUTRAL;
// --- B1: Kiểm tra cấu trúc xu hướng
if(high1 > high2 && low1 > low2)
structureEnum = STRUCTURE_HH_HL;
else if(high1 < high2 && low1 < low2)
structureEnum = STRUCTURE_LH_LL;
else
structureEnum = STRUCTURE_SIDEWAY;
// --- 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)
if(priceClose <= 0.0 || emaFast <= 0.0 || emaSlow <= 0.0) {
emaEnum = EMA_INSUFFICIENT;
else if(emaFast > emaSlow && priceClose > emaFast)
trendEnum = TREND_NEUTRAL;
}
else if(emaFast > emaSlow ) { // && priceClose > emaFast
emaEnum = EMA_UPTREND;
else if(emaFast < emaSlow && priceClose < emaFast)
emaEnum = EMA_DOWNTREND;
else
emaEnum = EMA_NEUTRAL;
// --- B3: Tổng hợp kết luận
if(structureEnum == STRUCTURE_HH_HL && emaEnum == EMA_UPTREND)
trendEnum = TREND_UPTREND;
else if(structureEnum == STRUCTURE_LH_LL && emaEnum == EMA_DOWNTREND)
}
else if(emaFast < emaSlow) { // && priceClose < emaFast
emaEnum = EMA_DOWNTREND;
trendEnum = TREND_DOWNTREND;
else
}
else {
emaEnum = EMA_NEUTRAL;
trendEnum = TREND_SIDEWAY_RESULT;
}
// --- B4: Log chi tiết (debug)
// --- Log chi tiết (debug)
PrintFormat("[TREND DEBUG] === %s ===", TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS));
PrintFormat("EMA50=%.2f | EMA200=%.2f | Close=%.2f", emaFast, emaSlow, priceClose);
PrintFormat("Structure: %s | EMA: %s | => TREND: %s",
StructureToString(structureEnum), EmaConditionToString(emaEnum), TrendResultToString(trendEnum));
// print the EMA periods and their current values instead of hard-coded labels
PrintFormat("EMA%d=%.5f | EMA%d=%.5f | PriceClose=%.5f", EMA_Fast, emaFast, EMA_Slow, emaSlow, priceClose);
PrintFormat("EMA: %s | => TREND: %s", EmaConditionToString(emaEnum), TrendResultToString(trendEnum));
return TrendResultToString(trendEnum);
}
@@ -148,17 +123,32 @@ void OnTick()
// ================== KHỞI TẠO & KẾT THÚC ===========================
int OnInit() {
// create EMA indicator handles
handleEMA50 = iMA(_Symbol, TrendTF, EMA_Fast, 0, MODE_EMA, PRICE_CLOSE);
handleEMA200 = iMA(_Symbol, TrendTF, EMA_Slow, 0, MODE_EMA, PRICE_CLOSE);
if(handleEMA50 == INVALID_HANDLE || handleEMA200 == INVALID_HANDLE) {
Sleep(500); // đợi chart visual load hoàn tất
handleEMAFast = iMA(_Symbol, _Period, EMA_Fast, 0, MODE_EMA, PRICE_CLOSE);
handleEMASlow = iMA(_Symbol, _Period, EMA_Slow, 0, MODE_EMA, PRICE_CLOSE);
if(handleEMAFast == INVALID_HANDLE || handleEMASlow == INVALID_HANDLE) {
Print("Failed to create EMA handles. Err=", GetLastError());
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 handles=(%d,%d)", __FILE__, EMA_Fast, EMA_Slow, handleEMAFast, handleEMASlow);
if(VisualizeEMAs) {
long chart_id = ChartID();
bool ok1 = ChartIndicatorAdd(chart_id, 0, handleEMAFast);
bool ok2 = ChartIndicatorAdd(chart_id, 0, handleEMASlow);
if(!ok1 || !ok2)
Print("Warning: ChartIndicatorAdd failed. Err=", GetLastError());
}
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason) {
if(handleEMA50 != INVALID_HANDLE) IndicatorRelease(handleEMA50);
if(handleEMA200 != INVALID_HANDLE) IndicatorRelease(handleEMA200);
if(handleEMAFast != INVALID_HANDLE) IndicatorRelease(handleEMAFast);
if(handleEMASlow != INVALID_HANDLE) IndicatorRelease(handleEMASlow);
}
-164
View File
@@ -1,164 +0,0 @@
//+------------------------------------------------------------------+
//| EA_Trend_EMA50_EMA200.mq5 |
//| Phiên bản: 1.0 |
//| Mục đích: |
//| - Xác định xu hướng bằng EMA50 & EMA200 (m15) |
//| - Vào lệnh trên M5 khi có tín hiệu: 2 đáy / 2 đỉnh / nến nhấn chìm |
//| - Rủi ro cố định: 1% Equity mỗi lệnh |
//| - 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 version "1.00"
#property strict
#include <Trade/Trade.mqh>
CTrade trade;
int handleEMA50 = INVALID_HANDLE;
int handleEMA200 = INVALID_HANDLE;
// ================== INPUTS =========================================
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 int EMA_Fast = 50; // EMA nhanh
input int EMA_Slow = 200; // EMA chậm
input double RiskPercent = 1.0; // rủi ro % equity cho mỗi lệnh
input double TP_Multiplier = 2.0; // tỉ lệ TP = Risk * multiplier
input int MaxOpenPositions = 2; // tối đa 2 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 = 35; // 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 int TrendShift = 1; // shift dùng để đọc nến đóng (tránh nến đang hình thành)
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 for structured states (avoid hard-coded strings) -----
enum TREND_STRUCTURE { STRUCTURE_NEUTRAL = 0, STRUCTURE_HH_HL, STRUCTURE_LH_LL, STRUCTURE_SIDEWAY };
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 };
string StructureToString(const int s) {
switch(s) {
case STRUCTURE_HH_HL: return "HH-HL (Uptrend)";
case STRUCTURE_LH_LL: return "LH-LL (Downtrend)";
case STRUCTURE_SIDEWAY: return "Sideway";
default: return "Neutral";
}
}
string EmaConditionToString(const int e) {
switch(e) {
case EMA_UPTREND: return "EMA Uptrend";
case EMA_DOWNTREND: return "EMA Downtrend";
case EMA_NEUTRAL: return "EMA Neutral";
default: return "EMA InsufficientData";
}
}
string TrendResultToString(const int r) {
switch(r) {
case TREND_UPTREND: return "UPTREND";
case TREND_DOWNTREND: return "DOWNTREND";
case TREND_SIDEWAY_RESULT: return "SIDEWAY";
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[];
// read EMA50 value by copying buffer from handle
if(handleEMA50 != INVALID_HANDLE) {
if(CopyBuffer(handleEMA50, 0, shift, 1, buf) > 0) emaFast = buf[0];
}
// read EMA200 value by copying buffer from handle
if(handleEMA200 != INVALID_HANDLE) {
if(CopyBuffer(handleEMA200, 0, shift, 1, buf) > 0) emaSlow = buf[0];
}
double priceClose = iClose(_Symbol, TrendTF, shift);
// Lấy giá cao thấp theo cấu hình offsets (recent vs prev)
double high1 = iHigh(_Symbol, TrendTF, StructureRecentOffset);
double high2 = iHigh(_Symbol, TrendTF, StructurePrevOffset);
double low1 = iLow(_Symbol, TrendTF, StructureRecentOffset);
double low2 = iLow(_Symbol, TrendTF, StructurePrevOffset);
int structureEnum = STRUCTURE_NEUTRAL;
int emaEnum = EMA_INSUFFICIENT;
int trendEnum = TREND_NEUTRAL;
// --- B1: Kiểm tra cấu trúc xu hướng
if(high1 > high2 && low1 > low2)
structureEnum = STRUCTURE_HH_HL;
else if(high1 < high2 && low1 < low2)
structureEnum = STRUCTURE_LH_LL;
else
structureEnum = STRUCTURE_SIDEWAY;
// --- 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;
else if(emaFast > emaSlow && priceClose > emaFast)
emaEnum = EMA_UPTREND;
else if(emaFast < emaSlow && priceClose < emaFast)
emaEnum = EMA_DOWNTREND;
else
emaEnum = EMA_NEUTRAL;
// --- B3: Tổng hợp kết luận
if(structureEnum == STRUCTURE_HH_HL && emaEnum == EMA_UPTREND)
trendEnum = TREND_UPTREND;
else if(structureEnum == STRUCTURE_LH_LL && emaEnum == EMA_DOWNTREND)
trendEnum = TREND_DOWNTREND;
else
trendEnum = TREND_SIDEWAY_RESULT;
// --- B4: Log chi tiết (debug)
PrintFormat("[TREND DEBUG] === %s ===", TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS));
PrintFormat("EMA50=%.2f | EMA200=%.2f | Close=%.2f", emaFast, emaSlow, priceClose);
PrintFormat("Structure: %s | EMA: %s | => TREND: %s",
StructureToString(structureEnum), EmaConditionToString(emaEnum), TrendResultToString(trendEnum));
return TrendResultToString(trendEnum);
}
// ================== VÒNG LẶP CHÍNH ================================
void OnTick()
{
static datetime lastCheck = 0;
// chỉ check 1 lần mỗi phút
if(TimeCurrent() - lastCheck >= 60) {
string trend = GetTrendDirection();
Comment("Current Trend (", EnumToString(TrendTF), "): ", trend);
lastCheck = TimeCurrent();
}
}
// ================== KHỞI TẠO & KẾT THÚC ===========================
int OnInit() {
// create EMA indicator handles
handleEMA50 = iMA(_Symbol, TrendTF, EMA_Fast, 0, MODE_EMA, PRICE_CLOSE);
handleEMA200 = iMA(_Symbol, TrendTF, EMA_Slow, 0, MODE_EMA, PRICE_CLOSE);
if(handleEMA50 == INVALID_HANDLE || handleEMA200 == INVALID_HANDLE) {
Print("Failed to create EMA handles. Err=", GetLastError());
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason) {
if(handleEMA50 != INVALID_HANDLE) IndicatorRelease(handleEMA50);
if(handleEMA200 != INVALID_HANDLE) IndicatorRelease(handleEMA200);
}
+23
View File
@@ -0,0 +1,23 @@
Sử dụng riêng chiến lược giao dịch dựa trên đường cắt nhau của EMA50 và EMA200 là chưa tối ưu, vì có thể tạo ra các tín hiệu sai lệch và bỏ qua những biến động quan trọng của thị trường. Để nâng cao hiệu quả cho bot, bạn nên thêm các logic xác nhận xu hướng bằng những chỉ báo kỹ thuật khác và quản lý rủi ro tốt hơn.
### Các logic cần bổ sung
#### Xác nhận xu hướng bằng các chỉ báo khác
* **Chỉ báo ADX:** Thêm chỉ báo Sức mạnh Xu hướng Trung bình (ADX) để xác nhận sức mạnh của xu hướng. Hãy lập trình để bot chỉ vào lệnh khi chỉ số ADX vượt trên một ngưỡng nhất định (ví dụ 20 hoặc 25), giúp lọc bỏ các tín hiệu giao cắt sai trong thị trường đi ngang.
* **Chỉ báo RSI:** Sử dụng chỉ báo Sức mạnh Tương đối (RSI) để tránh các vùng quá mua hoặc quá bán. Bot nên tránh vào lệnh mua khi RSI trên 70 và tránh lệnh bán khi RSI dưới 30, giúp giảm thiểu rủi ro giao dịch ngược đỉnh/đáy.
* **Phân tích khối lượng:** Tăng độ tin cậy của tín hiệu bằng cách kiểm tra khối lượng giao dịch. Tín hiệu đảo chiều kèm theo khối lượng lớn sẽ mạnh mẽ hơn tín hiệu với khối lượng nhỏ.
#### Sử dụng nhiều khung thời gian
* **Phân tích đa khung thời gian:** Kết hợp chiến lược EMA50/200 trên khung thời gian dài hơn (ví dụ: ngày hoặc 4 giờ) để xác định xu hướng chính. Sau đó, sử dụng khung thời gian ngắn hơn (ví dụ: 1 giờ hoặc 5 phút) với các EMA nhanh hơn (ví dụ: EMA9 và EMA21) để tìm điểm vào/ra chính xác hơn theo đúng hướng xu hướng lớn.
#### Cải thiện quản lý rủi ro
* **Dừng lỗ động (Trailing Stop-Loss):** Thay vì dừng lỗ cố định, hãy dùng mức dừng lỗ di chuyển theo giá để bảo vệ lợi nhuận. Bot có thể tự động điều chỉnh điểm dừng lỗ khi giá di chuyển theo hướng có lợi.
* **Chốt lời linh hoạt:** Áp dụng các mức chốt lời động dựa trên chỉ báo Biên độ Dao động Thực tế (ATR) để phù hợp với các điều kiện thị trường khác nhau. Ví dụ: đặt chốt lời ở mức 2x hoặc 4x ATR.
* **Tỷ lệ Rủi ro/Lợi nhuận (Risk/Reward):** Cân nhắc chỉ vào lệnh khi tỷ lệ R/R tiềm năng có lợi, chẳng hạn như ít nhất 1:2 hoặc 1:3, để đảm bảo mỗi giao dịch thành công mang lại lợi nhuận đủ lớn để bù đắp các giao dịch thua lỗ.
#### Lọc giao dịch
* **Bộ lọc trạng thái thị trường:** Lập trình bot để tránh giao dịch trong các giai đoạn thị trường đi ngang hoặc sideway, nơi tín hiệu EMA giao cắt dễ bị nhiễu. Có thể sử dụng chỉ báo ADX hoặc độ dốc của các đường EMA để xác định trạng thái này.
* **Bộ lọc tin tức:** Thêm logic tạm dừng giao dịch trong thời điểm có các sự kiện kinh tế quan trọng để tránh rủi ro do biến động giá mạnh bất ngờ.
#### Tối ưu hóa và kiểm thử
* **Kiểm thử lại (Backtesting) toàn diện:** Thực hiện kiểm thử bot trên dữ liệu lịch sử với nhiều cặp tài sản và khung thời gian khác nhau để xác định và tối ưu các tham số EMA cũng như các bộ lọc bổ sung. Ví dụ, việc tối ưu bằng AI có thể mang lại kết quả tốt hơn nhiều so với các thông số mặc định.