(works) renko_trend_ride_strategy.pine
Copy
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Gotrade
//@version=6
// ── How it works ──────────────────────────────────────────────────────────────
// Pure Renko Reversal strategy — no volume, no RSI, no complex filters.
//
// LONG ENTRY : First GREEN brick after RED bricks (direction flips up)
// LONG EXIT : First RED brick after GREEN bricks (direction flips down)
// OR trailing stop
//
// SHORT ENTRY : First RED brick after GREEN bricks (direction flips down)
// SHORT EXIT : First GREEN brick after RED bricks (direction flips up)
// OR trailing stop
//
// Logic: Renko bricks only form when price moves a meaningful amount.
// A direction flip = the trend has reversed. Ride the new direction
// until the next flip or stop.
// ─────────────────────────────────────────────────────────────────────────────
strategy("Renko Reversal", overlay=true,
default_qty_type=strategy.fixed, default_qty_value=1,
initial_capital=1000000, margin_long=0.1, margin_short=0.1,
commission_type=strategy.commission.percent, commission_value=0.04,
fill_orders_on_standard_ohlc=true)
// ═══════════════════════════════════════════════════════════════════════════════
// INPUTS
// ═══════════════════════════════════════════════════════════════════════════════
grp0 = "Renko Brick Size"
useAtrBrick = input.bool(true, "Auto brick size (ATR-based)", group=grp0,
tooltip="ON: brick = ATR × multiplier. OFF: fixed absolute size.")
atrRenkoPeriod = input.int(14, "ATR period", group=grp0, minval=1)
atrBrickMult = input.float(2.0, "ATR multiplier (brick = ATR × mult)", group=grp0, minval=0.1, step=0.1,
tooltip="2.0 = 2 ATRs per brick. Higher = fewer, larger bricks = smoother but fewer trades.\n1H: try 2-3 | 4H: try 2 | 1D: try 1.5-2")
fixedBrickSize = input.float(10.0,"Fixed brick size (when ATR OFF)", group=grp0, minval=0.001)
grp1 = "Trade Direction"
allowLong = input.bool(true, "Allow Long (buy on confirmed up bricks)", group=grp1)
allowShort = input.bool(false, "Allow Short (sell on confirmed down bricks)", group=grp1,
tooltip="UK100/indices are long-biased. Shorts tend to underperform — disable unless specifically needed.")
grp2 = "Entry & Exit"
entryBricks = input.int(2, "Bricks to confirm entry & exit", group=grp2, minval=1, maxval=10,
tooltip="Enter after N consecutive UP bricks. Exit (close long) after N consecutive DOWN bricks.\nThis is the primary exit — ride the trend until it reverses.\n2 = filters single-brick whipsaws while staying responsive to reversals.")
emergencyStopPct = input.float(15.0, "Crash stop: % drop from entry", group=grp2, minval=1.0, maxval=50.0, step=0.5,
tooltip="Emergency exit: closes immediately if price drops more than X% from entry.\nThis is a safety net for crashes only (COVID crash, Black Monday etc).\nNormal exit is the renko reversal signal — N consecutive down bricks.")
grp3 = "Optional Filters"
useEmaFilter = input.bool(true, "EMA trend filter", group=grp3,
tooltip="Long only when price > EMA. Short only when price < EMA.\nThis aligns entries with the prevailing trend and is the most effective way to improve win rate.")
emaPeriod = input.int(200, "EMA period", group=grp3, minval=5,
tooltip="200 = slow trend direction. Use 50 for a faster filter with more trades.")
useBearFilter = input.bool(false, "Bear regime filter (SMA 200 + consecutive bars)", group=grp3,
tooltip="Stricter than EMA filter: requires N consecutive bars below SMA before blocking longs.")
bearConsecBars = input.int(10, "Bars below SMA to confirm bear", group=grp3, minval=1)
bearExitBars = input.int(5, "Bars above SMA to clear bear", group=grp3, minval=1)
useSessionFilter = input.bool(false, "Only trade during active session", group=grp3)
sessionStr = input.session("0800-1700", "Active session", group=grp3)
grp4 = "Risk Management"
useEquityPct = input.bool(true, "Size as % of equity", group=grp4)
marginEquityPct = input.float(0.2, "Margin % of equity per trade", group=grp4, minval=0.01, step=0.01)
marginAmt = input.float(2000, "Fixed margin (when % OFF)", group=grp4, minval=1)
leverage = input.int(1000, "Leverage (x)", group=grp4, minval=1, maxval=1000)
portfolioStopPct = input.float(50.0, "Emergency stop: X% loss of peak equity", group=grp4, minval=1.0, maxval=100.0)
grp5 = "Martingale (⚠ High Risk)"
useMartingale = input.bool(false, "Enable Martingale (double size on loss)", group=grp5,
tooltip="After a losing trade, the next entry uses 2× the base size. Resets to 1× after a win.\n\nWARNING: Requires win rate > 50% to be sustainable. Can accelerate account loss if win rate is below 50%.")
maxMartLevel = input.int(3, "Max doubling levels (cap)", group=grp5, minval=1, maxval=8,
tooltip="3 = max 8× base. Caps the doubling to prevent catastrophic loss. Stays at max level until a win resets it.")
// ═══════════════════════════════════════════════════════════════════════════════
// RENKO SIMULATION
// ═══════════════════════════════════════════════════════════════════════════════
brickSize = useAtrBrick ? ta.atr(atrRenkoPeriod) * atrBrickMult : fixedBrickSize
var float renkoHigh = na
var float renkoLow = na
var int renkoDir = 1 // 1=up, -1=down
var float renkoClose = na
var bool newBrick = false
// Capture direction BEFORE this bar's brick update — used to detect reversals
renkoWasUp = renkoDir == 1
renkoWasDown = renkoDir == -1
if na(renkoHigh)
renkoHigh := close
renkoLow := close - brickSize
renkoDir := 1
renkoClose := close
newBrick := false
// New UP brick
if close >= renkoHigh + brickSize
n = int(math.floor((close - renkoHigh) / brickSize))
renkoHigh := renkoHigh + brickSize * n
renkoLow := renkoHigh - brickSize
renkoDir := 1
renkoClose := renkoHigh
newBrick := true
// New DOWN brick
if close <= renkoLow - brickSize
n = int(math.floor((renkoLow - close) / brickSize))
renkoLow := renkoLow - brickSize * n
renkoHigh := renkoLow + brickSize
renkoDir := -1
renkoClose := renkoLow
newBrick := true
newUpBrick = newBrick and renkoDir == 1
newDownBrick = newBrick and renkoDir == -1
// Reversal = direction changed this bar (used for plot markers only)
renkoFlipUp = newUpBrick and renkoWasDown
renkoFlipDown = newDownBrick and renkoWasUp
// Consecutive brick counter — resets when direction changes
var int consecUpBricks = 0
var int consecDownBricks = 0
if newUpBrick
consecUpBricks := consecUpBricks + 1
consecDownBricks := 0
else if newDownBrick
consecDownBricks := consecDownBricks + 1
consecUpBricks := 0
// Confirmed signals: fire at exactly the Nth brick (single-shot per run)
longEntry = consecUpBricks == entryBricks // N consecutive up → enter long
shortEntry = consecDownBricks == entryBricks // N consecutive down → enter short
longExit = consecDownBricks == entryBricks // N consecutive down → optional brick exit
shortExit = consecUpBricks == entryBricks // N consecutive up → optional brick exit
// ═══════════════════════════════════════════════════════════════════════════════
// OPTIONAL FILTERS
// ═══════════════════════════════════════════════════════════════════════════════
bearMA = ta.sma(close, 200)
var int barsBelow200 = 0
var int barsAbove200 = 0
if close < bearMA
barsBelow200 := barsBelow200 + 1
barsAbove200 := 0
else
barsAbove200 := barsAbove200 + 1
barsBelow200 := 0
var bool inBearRegime = false
if barsBelow200 >= bearConsecBars
inBearRegime := true
if barsAbove200 >= bearExitBars
inBearRegime := false
bearBlock = useBearFilter and inBearRegime
// EMA trend filter — long only above EMA, short only below EMA
emaLine = ta.ema(close, emaPeriod)
emaAbove = close > emaLine // price above EMA → bullish bias
emaBelow = close < emaLine // price below EMA → bearish bias
emaOkLong = not useEmaFilter or emaAbove
emaOkShort = not useEmaFilter or emaBelow
inSession = not useSessionFilter or not na(time(timeframe.period, sessionStr))
// ═══════════════════════════════════════════════════════════════════════════════
// POSITION SIZING & EQUITY PROTECTION
// ═══════════════════════════════════════════════════════════════════════════════
safeEquity = math.max(strategy.equity, strategy.initial_capital * 0.001)
effectiveMargin = useEquityPct ? safeEquity * marginEquityPct / 100 : marginAmt
qtyContracts = (effectiveMargin * leverage) / math.max(close, 0.000001)
var float equityPeak = strategy.initial_capital
equityPeak := math.max(equityPeak, strategy.equity)
portfolioStopAmt = equityPeak * portfolioStopPct / 100
entryGate = inSession
// ═══════════════════════════════════════════════════════════════════════════════
// MARTINGALE — track last closed trade, double size on loss
// ═══════════════════════════════════════════════════════════════════════════════
var int lastClosedCount = 0
var int martLevel = 0 // how many times we've doubled
var float martMultiplier = 1.0 // current size multiplier (1, 2, 4, 8, …)
if strategy.closedtrades != lastClosedCount
// A trade just closed — check if it was a loss
lastPnl = strategy.closedtrades.profit(strategy.closedtrades - 1)
if useMartingale
if lastPnl < 0
martLevel := math.min(martLevel + 1, maxMartLevel)
else
martLevel := 0
martMultiplier := math.pow(2.0, float(martLevel))
else
martLevel := 0
martMultiplier := 1.0
lastClosedCount := strategy.closedtrades
effectiveQty = qtyContracts * martMultiplier
// ═══════════════════════════════════════════════════════════════════════════════
// POSITION STATE
// ═══════════════════════════════════════════════════════════════════════════════
inLong = strategy.position_size > 0
inShort = strategy.position_size < 0
avgEntry = strategy.position_avg_price
// ═══════════════════════════════════════════════════════════════════════════════
// ORDERS — Buy and Hold the Trend
// Strategy: enter on N up bricks, hold until N down bricks (reversal)
// Emergency: crash stop if price drops >X% from entry
// ═══════════════════════════════════════════════════════════════════════════════
// Crash stop levels — only fires on catastrophic moves (>15% by default)
longCrashStop = avgEntry > 0 ? avgEntry * (1 - emergencyStopPct / 100) : na
shortCrashStop = avgEntry > 0 ? avgEntry * (1 + emergencyStopPct / 100) : na
// ── LONG ──────────────────────────────────────────────────────────────────────
// Entry: N consecutive up bricks + EMA filter + no bear block
if longEntry and emaOkLong and not bearBlock and entryGate and allowLong and not inLong
strategy.entry("Long", strategy.long, qty=effectiveQty,
comment="▲ BUY ×" + str.tostring(entryBricks) + (martLevel > 0 ? " M×" + str.tostring(martMultiplier, "#") : ""))
// Crash stop (intrabar, emergency only — won't fire during normal pullbacks)
if inLong and not na(longCrashStop)
strategy.exit("LongCrash", "Long", stop=longCrashStop,
comment="CRASH >" + str.tostring(emergencyStopPct) + "%")
// Primary exit: N consecutive DOWN bricks = renko trend reversal
// This is the main exit — we ride the up-trend until it definitively reverses
if inLong and longExit
strategy.close("Long", comment="▼ REVERSAL ×" + str.tostring(entryBricks))
// Portfolio-level emergency
if inLong and strategy.openprofit <= -portfolioStopAmt
strategy.close("Long", comment="PORTFOLIO STOP")
// ── SHORT ─────────────────────────────────────────────────────────────────────
// Entry: N consecutive down bricks + EMA below + gate
if shortEntry and emaOkShort and entryGate and allowShort and not inShort
strategy.entry("Short", strategy.short, qty=effectiveQty,
comment="▼ SELL ×" + str.tostring(entryBricks) + (martLevel > 0 ? " M×" + str.tostring(martMultiplier, "#") : ""))
// Crash stop
if inShort and not na(shortCrashStop)
strategy.exit("ShortCrash", "Short", stop=shortCrashStop,
comment="CRASH >" + str.tostring(emergencyStopPct) + "%")
// Primary exit: N consecutive UP bricks = renko trend reversal
if inShort and shortExit
strategy.close("Short", comment="▲ REVERSAL ×" + str.tostring(entryBricks))
// Portfolio-level emergency
if inShort and strategy.openprofit <= -portfolioStopAmt
strategy.close("Short", comment="PORTFOLIO STOP")
// ═══════════════════════════════════════════════════════════════════════════════
// PLOTS
// ═══════════════════════════════════════════════════════════════════════════════
renkoColor = renkoDir == 1 ? color.new(color.lime, 30) : color.new(color.red, 30)
plot(renkoHigh, "Renko Top", color=renkoColor, linewidth=1, style=plot.style_stepline)
plot(renkoLow, "Renko Bottom", color=renkoColor, linewidth=1, style=plot.style_stepline)
plot(useEmaFilter ? emaLine : na, "Trend EMA", color=color.new(color.orange, 0), linewidth=2)
plot(useBearFilter ? bearMA : na, "Bear SMA 200", color=color.new(color.red, 40), linewidth=1)
// Crash stop level — dashed red line only visible when position is open
plot(inLong ? longCrashStop : na, "Long Crash Stop", color=color.new(color.red, 10), linewidth=1, style=plot.style_linebr)
plot(inShort ? shortCrashStop : na, "Short Crash Stop", color=color.new(color.red, 10), linewidth=1, style=plot.style_linebr)
plotshape(renkoFlipUp, "Flip Up (Buy)", shape.triangleup, location.belowbar, color.lime, size=size.large)
plotshape(renkoFlipDown, "Flip Down (Sell)", shape.triangledown, location.abovebar, color.red, size=size.large)
bgcolor(inBearRegime ? color.new(color.red, 88) : na, title="Bear Regime")
bgcolor(inLong ? color.new(color.green, 92) : na, title="Long")
bgcolor(inShort ? color.new(color.red, 92) : na, title="Short")
// ═══════════════════════════════════════════════════════════════════════════════
// DASHBOARD
// ═══════════════════════════════════════════════════════════════════════════════
var table dash = table.new(position.top_right, 2, 12,
bgcolor=color.new(color.black, 55), border_width=1, border_color=color.new(color.gray, 60))
if barstate.islast
netCol = strategy.netprofit >= 0 ? color.lime : color.red
pnlCol = strategy.openprofit >= 0 ? color.lime : color.red
dirCol = renkoDir == 1 ? color.lime : color.red
table.cell(dash, 0, 0, "Renko Reversal", text_color=color.white, text_size=size.small, bgcolor=color.new(color.navy, 30))
table.cell(dash, 1, 0, "L+S", text_color=color.white, text_size=size.small, bgcolor=color.new(color.navy, 30))
table.cell(dash, 0, 1, "Brick Size", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 1, str.tostring(math.round(brickSize, 2)) + (useAtrBrick ? " (ATR×" + str.tostring(atrBrickMult) + ")" : " (fixed)"),
text_color=color.yellow, text_size=size.small)
table.cell(dash, 0, 2, "Renko Dir", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 2, (renkoDir == 1 ? "▲ GREEN" : "▼ RED") + " H=" + str.tostring(math.round(renkoHigh, 1)) + " L=" + str.tostring(math.round(renkoLow, 1)),
text_color=dirCol, text_size=size.small)
table.cell(dash, 0, 3, "Bricks", text_color=color.silver, text_size=size.small)
brickStr = consecUpBricks > 0 ? "▲ UP ×" + str.tostring(consecUpBricks) + "/" + str.tostring(entryBricks) + (longEntry ? " ✓ ENTRY" : longExit ? " ✓ EXIT" : "") : consecDownBricks > 0 ? "▼ DN ×" + str.tostring(consecDownBricks) + "/" + str.tostring(entryBricks) + (shortEntry ? " ✓ ENTRY" : shortExit ? " ✓ EXIT" : "") : "– no brick"
brickCol = longEntry or shortExit ? color.lime : shortEntry or longExit ? color.red : color.silver
table.cell(dash, 1, 3, brickStr, text_color=brickCol, text_size=size.small)
table.cell(dash, 0, 4, "EMA " + str.tostring(emaPeriod), text_color=color.silver, text_size=size.small)
emaStr = not useEmaFilter ? "OFF" : emaAbove ? "▲ ABOVE " + str.tostring(math.round(emaLine, 1)) + " (L only)" : "▼ BELOW " + str.tostring(math.round(emaLine, 1)) + " (S only)"
emaCol = not useEmaFilter ? color.gray : emaAbove ? color.lime : color.red
table.cell(dash, 1, 4, emaStr, text_color=emaCol, text_size=size.small)
table.cell(dash, 0, 5, "Bear Filter", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 5, useBearFilter ? (inBearRegime ? "🐻 BEAR (longs blocked)" : "✓ BULL") : "OFF",
text_color=inBearRegime ? color.red : color.lime, text_size=size.small)
table.cell(dash, 0, 6, "Session", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 6, useSessionFilter ? (inSession ? "✓ Active" : "✗ Closed") : "OFF",
text_color=inSession ? color.lime : color.gray, text_size=size.small)
posStr = inLong ? "LONG @ " + str.tostring(math.round(avgEntry, 2)) : inShort ? "SHORT @ " + str.tostring(math.round(avgEntry, 2)) : "FLAT"
posCol = inLong ? color.lime : inShort ? color.red : color.gray
table.cell(dash, 0, 7, "Position", text_color=color.silver, text_size=size.small)
openPctStr = (inLong or inShort) and avgEntry > 0 ? " (" + str.tostring(math.round(strategy.openprofit / strategy.equity * 100, 2)) + "%)" : ""
table.cell(dash, 1, 7, posStr + openPctStr, text_color=posCol, text_size=size.small)
table.cell(dash, 0, 8, "Crash Stop", text_color=color.silver, text_size=size.small)
crashLvl = inLong and not na(longCrashStop) ? str.tostring(math.round(longCrashStop, 1)) + " (−" + str.tostring(emergencyStopPct) + "%)" : inShort and not na(shortCrashStop) ? str.tostring(math.round(shortCrashStop, 1)) + " (+" + str.tostring(emergencyStopPct) + "%)" : "–"
table.cell(dash, 1, 8, crashLvl, text_color=color.new(color.red, 20), text_size=size.small)
table.cell(dash, 0, 9, "Open P&L", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 9, "$" + str.tostring(math.round(strategy.openprofit, 2)),
text_color=pnlCol, text_size=size.small)
table.cell(dash, 0, 10, "Martingale", text_color=color.silver, text_size=size.small)
martStr = not useMartingale ? "OFF" : martLevel == 0 ? "×1 (base)" : "×" + str.tostring(martMultiplier, "#") + " (L" + str.tostring(martLevel) + "/" + str.tostring(maxMartLevel) + ")"
martCol = not useMartingale ? color.gray : martLevel == 0 ? color.lime : martLevel >= maxMartLevel ? color.red : color.orange
table.cell(dash, 1, 10, martStr, text_color=martCol, text_size=size.small)
table.cell(dash, 0, 11, "Net Profit", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 11, "$" + str.tostring(math.round(strategy.netprofit, 2)) + " (" + str.tostring(strategy.closedtrades) + " trades)",
text_color=netCol, text_size=size.small)
Show all 338 lines