diff --git a/Experts/RsiMomentumEA.mq5 b/Experts/RsiMomentumEA.mq5 index 0a0dd73..fbcf35c 100644 --- a/Experts/RsiMomentumEA.mq5 +++ b/Experts/RsiMomentumEA.mq5 @@ -4,7 +4,7 @@ //| RSI×WMA45 + 5phase entry | ATR↑ EMA200 phiên | Limit 50% body | //+------------------------------------------------------------------+ #property copyright "RsiMomentumEA" -#property version "4.22" +#property version "4.23" #include #include @@ -35,7 +35,7 @@ input double InpRSIOversold = 30.0; // RSI ≤ ngưỡng → bỏ SELL input group "Entry 5 phase (mở rộng → cuộn EMA9 → EMA9 hướng → WMA45 phẳng → cắt gần)" input bool InpPhaseFilterEnabled = true; input int InpPhaseExpandLookback = 25; // P1: quét mở rộng 3 đường -input double InpPhaseMinExpandSpread = 8.0; // P1: min (WMA45-RSI) đơn vị RSI (buy) +input double InpPhaseMinExpandSpread = 10.0; // P1: min max(WMA45-RSI) pt RSI [tối ưu ~6–18, step 1] input int InpPhaseCoilLookback = 12; // P2: quét cuộn trước nến tín hiệu input int InpPhaseMinRsiEma9Cross = 2; // P2: RSI cắt EMA9 ≥ N lần (chống xuyên 1 lần) input double InpPhaseCoilBand = 6.0; // P2: |RSI-EMA9| ≤ band = quanh EMA9 @@ -416,8 +416,10 @@ void Panel_UpdateStatus() Panel_SetLine(ln++, "────────────────────────────────────", clrDarkGray); - Panel_SetLine(ln++, StringFormat("5 phase: %s | EMA200: %s (%d bar)", + Panel_SetLine(ln++, StringFormat("5 phase: %s P1>=%.1f LB%d | EMA200: %s (%d bar)", Panel_FmtOnOff(InpPhaseFilterEnabled), + InpPhaseMinExpandSpread, + InpPhaseExpandLookback, Panel_FmtOnOff(InpTrendFilterEnabled), MathMax(1, InpTrendConfirmBars)), InpPhaseFilterEnabled ? clrWhite : clrDimGray); diff --git a/Experts/RsiMomentumEA_README.md b/Experts/RsiMomentumEA_README.md index 4738c9f..2425f5c 100644 --- a/Experts/RsiMomentumEA_README.md +++ b/Experts/RsiMomentumEA_README.md @@ -139,7 +139,7 @@ Quét trên các nến **đã đóng** trong lookback: từ `shift+1` trở về ``` RSI[j] < EMA9[j] < WMA45[j] -spread[j] = WMA45[j] - RSI[j] → max(spread) >= InpPhaseMinExpandSpread (mặc định 8 điểm RSI) +spread[j] = WMA45[j] - RSI[j] → max(spread) >= InpPhaseMinExpandSpread (mặc định 10 điểm RSI) ``` **SELL:** `RSI[j] > EMA9[j] > WMA45[j]`, `spread = RSI[j] - WMA45[j]`. @@ -411,7 +411,7 @@ EA **không** đọc file indicator. Indicator `Indicators/RsiMomentumIndicator` | Input | Mặc định | Phase / vai trò | |-------|----------|-----------------| | `InpPhaseExpandLookback` | 25 | P1 | -| `InpPhaseMinExpandSpread` | 8.0 | P1 | +| `InpPhaseMinExpandSpread` | 10.0 | P1 — tối ưu edge (xem §15) | | `InpPhaseCoilLookback` | 12 | P2 | | `InpPhaseMinRsiEma9Cross` | 2 | P2 | | `InpPhaseEma9SlopeBars` | 2 | P3 | @@ -425,4 +425,21 @@ EA **không** đọc file indicator. Indicator `Indicators/RsiMomentumIndicator` --- -*Tài liệu đồng bộ với mã nguồn v4.14. P1–P2 giữ nguyên; P3–P5 đã nới lỏng mặc định.* +## 15. Tối ưu P1 — độ mở rộng (`InpPhaseMinExpandSpread`) + +**Mục tiêu:** Lọc setup yếu — chỉ vào khi sóng trước đó đã giãn RSI↔WMA45 đủ lớn. + +**Strategy Tester (MT5):** + +1. Tab **Inputs** → chọn `InpPhaseMinExpandSpread` → bật **Optimization**. +2. Gợi ý: **Start** `6`, **Stop** `18`, **Step** `1` (XAU M5/M15; FX có thể thử 5–14). +3. Tiêu chí: **Profit Factor** hoặc **Custom max** (PF × sqrt(trades) nếu cần đủ mẫu). +4. So sánh **số lệnh** vs PF — ngưỡng quá cao → ít lệnh, overfit. + +**Debug trên chart:** dấu SKIP hover hiển thị `P1:FAIL(sp=7.2<10.0)` = max spread tìm được trong lookback chưa đạt ngưỡng; `P1:OK(sp=12.4>=10.0)` = đạt. + +**Panel:** dòng `5 phase` hiển thị `P1>=10.0 LB25`. + +--- + +*Tài liệu đồng bộ với mã nguồn v4.23.* diff --git a/Include/RsiMom/SignalDebug.mqh b/Include/RsiMom/SignalDebug.mqh index 5e3ab94..c3b5b03 100644 --- a/Include/RsiMom/SignalDebug.mqh +++ b/Include/RsiMom/SignalDebug.mqh @@ -101,7 +101,9 @@ SignalEvalResult Signal_EvaluateBuyAt(const int shift, const int rates_total, co const double gap = wma[shift] - ema9[shift]; const bool p5 = Phase_Ema9NearWmaBuy(shift, phaseCfg.maxEma9WmaGap, ema9, wma); - SignalEval_Append(r.detail, p1 ? StringFormat("P1:OK(sp=%.1f)", maxSp) : "P1:FAIL"); + SignalEval_Append(r.detail, p1 + ? StringFormat("P1:OK(sp=%.1f>=%.1f)", maxSp, phaseCfg.minExpandSpread) + : StringFormat("P1:FAIL(sp=%.1f<%.1f)", maxSp, phaseCfg.minExpandSpread)); SignalEval_Append(r.detail, StringFormat("P2:%s(x=%d)", xc >= phaseCfg.minRsiEma9Crosses ? "OK" : "FAIL", xc)); SignalEval_Append(r.detail, p3 ? "P3:OK" : "P3:FAIL"); SignalEval_Append(r.detail, p4 ? "P4:OK" : "P4:FAIL"); @@ -238,7 +240,9 @@ SignalEvalResult Signal_EvaluateSellAt(const int shift, const int rates_total, c const double gap = ema9[shift] - wma[shift]; const bool p5 = Phase_Ema9NearWmaSell(shift, phaseCfg.maxEma9WmaGap, ema9, wma); - SignalEval_Append(r.detail, p1 ? StringFormat("P1:OK(sp=%.1f)", maxSp) : "P1:FAIL"); + SignalEval_Append(r.detail, p1 + ? StringFormat("P1:OK(sp=%.1f>=%.1f)", maxSp, phaseCfg.minExpandSpread) + : StringFormat("P1:FAIL(sp=%.1f<%.1f)", maxSp, phaseCfg.minExpandSpread)); SignalEval_Append(r.detail, StringFormat("P2:%s(x=%d)", xc >= phaseCfg.minRsiEma9Crosses ? "OK" : "FAIL", xc)); SignalEval_Append(r.detail, p3 ? "P3:OK" : "P3:FAIL"); SignalEval_Append(r.detail, p4 ? "P4:OK" : "P4:FAIL"); @@ -441,17 +445,15 @@ bool Signal_DebugFindTipAtMouse(const long chartId, const string prefix, if(s < 0) continue; const datetime bt = iTime(_Symbol, _Period, s); - const string btKey = IntegerToString((int)bt); - const string tryN[4]; - tryN[0] = prefix + btKey + "_B_hit"; - tryN[1] = prefix + btKey + "_S_hit"; - tryN[2] = prefix + btKey + "_B_ar"; - tryN[3] = prefix + btKey + "_S_ar"; - for(int k = 0; k < 4; k++) - { - if(Signal_DebugReadTipFromMark(chartId, tryN[k], tip)) - return true; - } + const string btKey = prefix + IntegerToString((int)bt); + if(Signal_DebugReadTipFromMark(chartId, btKey + "_B_hit", tip)) + return true; + if(Signal_DebugReadTipFromMark(chartId, btKey + "_S_hit", tip)) + return true; + if(Signal_DebugReadTipFromMark(chartId, btKey + "_B_ar", tip)) + return true; + if(Signal_DebugReadTipFromMark(chartId, btKey + "_S_ar", tip)) + return true; } return false; } @@ -517,7 +519,7 @@ void Signal_DebugDrawMark(const long chartId, const string prefix, const double pad = MathMax(_Point * 8.0, (barHigh - barLow) * 0.08); const double rHi = barHigh + pad; const double rLo = barLow - pad; - const color hitFill = ColorToARGB(clr, (uchar)24); + const color hitFill = (color)ColorToARGB(clr, (uchar)24); if(ObjectCreate(chartId, hitName, OBJ_RECTANGLE, 0, barTime, rHi, tEnd, rLo)) {