v7: make RSI gate practical — add gate mode (In zone now / Cross within lookback / In zone within lookback) and lookback bars (default 3)

This commit is contained in:
root
2025-10-22 10:11:04 +02:00
parent b3e939ee47
commit e8be5de41a

View File

@@ -39,11 +39,13 @@ macdSlowLen = input.int(26, "Slow", minval=1, inline="macdLens")
macdSigLen = input.int(9, "Signal", minval=1, inline="macdLens") macdSigLen = input.int(9, "Signal", minval=1, inline="macdLens")
// RSI gate (designed for 15m by default) // RSI gate (designed for 15m by default)
useRsi = input.bool(true, "Use RSI gate", group="RSI Gate", tooltip="Require RSI to be oversold for longs and overbought for shorts.") useRsi = input.bool(true, "Use RSI gate", group="RSI Gate", tooltip="Gate signals with RSI conditions from a selectable timeframe.")
rsiTf = input.timeframe("15", "RSI timeframe", group="RSI Gate") rsiTf = input.timeframe("15", "RSI timeframe", group="RSI Gate")
rsiLen = input.int(14, "RSI Length", minval=1, group="RSI Gate") rsiLen = input.int(14, "RSI Length", minval=1, group="RSI Gate")
rsiOverbought = input.int(70, "RSI Overbought", minval=1, maxval=100, group="RSI Gate") rsiOverbought = input.int(70, "RSI Overbought", minval=1, maxval=100, group="RSI Gate")
rsiOversold = input.int(30, "RSI Oversold", minval=1, maxval=100, group="RSI Gate") rsiOversold = input.int(30, "RSI Oversold", minval=1, maxval=100, group="RSI Gate")
rsiGateMode = input.string("Cross within lookback", "RSI gate mode", options=["In zone now","Cross within lookback","In zone within lookback"], group="RSI Gate", tooltip="How RSI should validate: require being in OB/OS now, a recent cross out of the zone, or having touched the zone within a lookback window.")
rsiLookback = input.int(3, "RSI lookback bars", minval=0, maxval=20, group="RSI Gate", tooltip="Bars to look back for a cross/touch. 0 = only this bar.")
// Entry filters (optional, same behavior as v5) // Entry filters (optional, same behavior as v5)
groupFilters = "Entry filters" groupFilters = "Entry filters"
@@ -132,8 +134,19 @@ if barstate.islast and showProfileLabel
// RSI from selected timeframe (use regular close for RSI by default) // RSI from selected timeframe (use regular close for RSI by default)
rsiTfVal = request.security(syminfo.tickerid, rsiTf, ta.rsi(close, rsiLen), lookahead=barmerge.lookahead_off) rsiTfVal = request.security(syminfo.tickerid, rsiTf, ta.rsi(close, rsiLen), lookahead=barmerge.lookahead_off)
longRsiOk = not useRsi or (rsiTfVal <= rsiOversold)
shortRsiOk = not useRsi or (rsiTfVal >= rsiOverbought) // Build RSI conditions per selected mode
rsiLongNow = rsiTfVal <= rsiOversold
rsiShortNow = rsiTfVal >= rsiOverbought
rsiCrossUp = ta.crossover(rsiTfVal, rsiOversold) // crossed up from below Oversold
rsiCrossDown = ta.crossunder(rsiTfVal, rsiOverbought) // crossed down from above Overbought
rsiLongRecent = rsiLookback == 0 ? rsiLongNow : (ta.lowest(rsiTfVal, rsiLookback + 1) <= rsiOversold)
rsiShortRecent = rsiLookback == 0 ? rsiShortNow : (ta.highest(rsiTfVal, rsiLookback + 1) >= rsiOverbought)
rsiCrossUpRecent = rsiLookback == 0 ? rsiCrossUp : (ta.barssince(rsiCrossUp) <= rsiLookback)
rsiCrossDownRecent = rsiLookback == 0 ? rsiCrossDown : (ta.barssince(rsiCrossDown) <= rsiLookback)
longRsiOk = not useRsi or (rsiGateMode == "In zone now" ? rsiLongNow : rsiGateMode == "Cross within lookback" ? rsiCrossUpRecent : rsiLongRecent)
shortRsiOk = not useRsi or (rsiGateMode == "In zone now" ? rsiShortNow : rsiGateMode == "Cross within lookback" ? rsiCrossDownRecent : rsiShortRecent)
// MACD confirmation logic // MACD confirmation logic
[macdLine, macdSignal, macdHist] = ta.macd(macdSrc, macdFastLen, macdSlowLen, macdSigLen) [macdLine, macdSignal, macdHist] = ta.macd(macdSrc, macdFastLen, macdSlowLen, macdSigLen)