A Pine v6 strategy for crypto charts that evaluates RSI, a trend moving average with higher timeframe filter, Fibonacci Bollinger Bands and Ichimoku in a fixed order.
//@version=6
// Phase 1: weighted per-indicator entry/exit, Visual vs Backtesting toggles, no setup/confirm dropdowns.
// See README.md in this folder. Evaluation order (hardcoded): RSI → Trend → BB → Ichimoku.
strategy(
title = "Crypto TA Pro - Phase1 Weighted Indicators v7",
shorttitle = "CTAPv7p1",
overlay = true,
precision = 8,
max_bars_back = 500,
pyramiding = 1,
initial_capital = 100,
default_qty_type = strategy.percent_of_equity,
default_qty_value = 100,
commission_type = strategy.commission.percent,
commission_value = 0.05,
slippage = 1,
margin_long = 100,
margin_short = 100
)
// === INPUT GROUPS ===
const string G_EXEC = "01. Execution"
const string G_IND = "02. Indicator Activation"
const string G_EVAL = "02b. Evaluation (phase1)"
const string G_REGIME = "03. Trend MA / Regime"
const string G_RSI = "04. RSI"
const string G_BB = "05. Fibonacci Bollinger Bands"
const string G_ICHI = "06. Ichimoku"
const string G_RISK = "07. Risk Management"
const string G_VIS = "08. Global visuals"
const string G_ALERT = "09. Alerts"
// === EXECUTION ===
tradeDirection = input.string("Long only", "Trade direction", options = ["Long only", "Long + Short"], group = G_EXEC)
startTime = input.time(1767225600000, "Backtest start", group = G_EXEC)
endTime = input.time(1798761540000, "Backtest end", group = G_EXEC)
confirmedOnly = input.bool(true, "Only act after confirmed bar close", group = G_EXEC)
setupLookback = input.int(5, "Setup lookback bars", minval = 1, maxval = 50, group = G_EXEC)
entryConsensus = input.float(1.0, "Entry blend threshold (0–1)", minval = 0.0, maxval = 1.0, step = 0.05, tooltip = "When no indicator has 100% entry weight: weighted score = sum(w×pass)/sum(w). Signal passes if score ≥ this threshold. 1.0 = all weighted contributors must pass.", group = G_EXEC)
exitConsensus = input.float(1.0, "Exit blend threshold (0–1)", minval = 0.0, maxval = 1.0, step = 0.05, group = G_EXEC)
evalOrderNote = input.string("RSI → Trend → BB → Ichimoku", "Evaluation order (phase1 fixed)", options = ["RSI → Trend → BB → Ichimoku"], tooltip = "Phase1: order is fixed in code. Future phase: user-configurable order will change merge logic and settings layout.", group = G_EVAL)
// === INDICATOR ACTIVATION + Visual / Backtest ===
enableRSI = input.bool(true, "Enable RSI", group = G_IND)
rsiVisual = input.bool(true, "Visual", group = G_IND, inline = "rsi1")
rsiBacktest = input.bool(true, "Backtest", group = G_IND, inline = "rsi1")
enableFibBB = input.bool(false, "Enable Fibonacci BB", group = G_IND)
fibVisual = input.bool(true, "Visual", group = G_IND, inline = "fib1")
fibBacktest = input.bool(false, "Backtest", group = G_IND, inline = "fib1")
enableTrendMA = input.bool(false, "Enable trend MA / regime", group = G_IND)
trendVisual = input.bool(true, "Visual", group = G_IND, inline = "tr1")
trendBacktest = input.bool(false, "Backtest", group = G_IND, inline = "tr1")
enableIchimoku = input.bool(false, "Enable Ichimoku", group = G_IND)
ichiVisual = input.bool(true, "Visual", group = G_IND, inline = "ic1")
ichiBacktest = input.bool(false, "Backtest", group = G_IND, inline = "ic1")
// === REGIME (see group only when trend enabled — Pine cannot hide inputs) ===
maType = input.string("EMA", "Trend MA type", options = ["EMA", "SMA", "WMA", "HMA", "DEMA", "TEMA", "VWMA", "RMA", "ZLEMA"], group = G_REGIME)
trendLen = input.int(200, "Trend MA length", minval = 20, maxval = 1000, group = G_REGIME)
trendFilter = input.string("Chart + HTF", "Regime filter", options = ["Off", "Chart MA", "Chart + HTF"], group = G_REGIME)
htfTf = input.timeframe("240", "Higher timeframe", group = G_REGIME)
useVolumeFilter = input.bool(true, "Require volume expansion", group = G_REGIME)
volumeLen = input.int(20, "Volume SMA length", minval = 1, group = G_REGIME)
volumeMult = input.float(0.80, "Min volume x SMA", minval = 0.0, step = 0.05, group = G_REGIME)
useAtrFilter = input.bool(true, "Filter abnormal volatility", group = G_REGIME)
minAtrPct = input.float(0.20, "Min ATR %", minval = 0.0, step = 0.05, group = G_REGIME)
maxAtrPct = input.float(12.0, "Max ATR %", minval = 0.1, step = 0.25, group = G_REGIME)
trendEntryRequired = input.bool(false, "Trend · entry required", group = G_REGIME, inline = "twt")
trendEntryWeight = input.float(25.0, "Entry wt %", minval = 0.0, maxval = 100.0, step = 0.5, group = G_REGIME, inline = "twt")
trendExitRequired = input.bool(false, "Trend · exit required", group = G_REGIME, inline = "twx")
trendExitWeight = input.float(25.0, "Exit wt %", minval = 0.0, maxval = 100.0, step = 0.5, group = G_REGIME, inline = "twx")
// === RSI ===
rsiSrc = input.source(close, "RSI source", group = G_RSI)
rsiLen = input.int(9, "RSI length", minval = 2, maxval = 100, group = G_RSI)
rsiOS = input.float(31.0, "Oversold", minval = 1, maxval = 50, step = 0.5, group = G_RSI)
rsiOB = input.float(67.5, "Overbought", minval = 50, maxval = 99, step = 0.5, group = G_RSI)
rsiEntryRequired = input.bool(false, "RSI · entry required", group = G_RSI, inline = "rwt")
rsiEntryWeight = input.float(100.0, "Entry wt %", minval = 0.0, maxval = 100.0, step = 0.5, group = G_RSI, inline = "rwt")
rsiExitRequired = input.bool(false, "RSI · exit required", group = G_RSI, inline = "rwx")
rsiExitWeight = input.float(100.0, "Exit wt %", minval = 0.0, maxval = 100.0, step = 0.5, group = G_RSI, inline = "rwx")
// === FIBONACCI BB ===
bbLen = input.int(200, "BB length", minval = 10, maxval = 1000, group = G_BB)
bbSrc = input.source(hlc3, "BB source", group = G_BB)
bbMult = input.float(3.0, "Deviation multiplier", minval = 0.1, maxval = 50, step = 0.1, group = G_BB)
bbBasisType = input.string("VWMA", "BB basis type", options = ["EMA", "SMA", "WMA", "HMA", "DEMA", "TEMA", "VWMA", "RMA", "ZLEMA"], group = G_BB)
fibEntryRequired = input.bool(false, "Fib BB · entry required", group = G_BB, inline = "bwt")
fibEntryWeight = input.float(25.0, "Entry wt %", minval = 0.0, maxval = 100.0, step = 0.5, group = G_BB, inline = "bwt")
fibExitRequired = input.bool(false, "Fib BB · exit required", group = G_BB, inline = "bwx")
fibExitWeight = input.float(25.0, "Exit wt %", minval = 0.0, maxval = 100.0, step = 0.5, group = G_BB, inline = "bwx")
// === ICHIMOKU ===
conversionPeriods = input.int(9, "Conversion line length", minval = 1, group = G_ICHI)
basePeriods = input.int(26, "Base line length", minval = 1, group = G_ICHI)
spanBPeriods = input.int(52, "Leading Span B length", minval = 1, group = G_ICHI)
displacement = input.int(26, "Displacement", minval = 1, group = G_ICHI)
ichiEntryRequired = input.bool(false, "Ichimoku · entry required", group = G_ICHI, inline = "iwt")
ichiEntryWeight = input.float(25.0, "Entry wt %", minval = 0.0, maxval = 100.0, step = 0.5, group = G_ICHI, inline = "iwt")
ichiExitRequired = input.bool(false, "Ichimoku · exit required", group = G_ICHI, inline = "iwx")
ichiExitWeight = input.float(25.0, "Exit wt %", minval = 0.0, maxval = 100.0, step = 0.5, group = G_ICHI, inline = "iwx")
// === RISK ===
riskModel = input.string("Tighter of % / ATR", "Stop model", options = ["Percent", "ATR", "Tighter of % / ATR", "Wider of % / ATR"], group = G_RISK)
stopPct = input.float(3.0, "Stop loss %", minval = 0.1, step = 0.1, group = G_RISK)
atrLen = input.int(14, "ATR length", minval = 1, group = G_RISK)
atrStopMult = input.float(2.0, "ATR stop multiplier", minval = 0.1, step = 0.1, group = G_RISK)
useTakeProfit = input.bool(true, "Use take profit", group = G_RISK)
rewardRisk = input.float(2.0, "Reward:risk target", minval = 0.1, step = 0.1, group = G_RISK)
useBreakeven = input.bool(true, "Move stop to breakeven", group = G_RISK)
breakevenAtR = input.float(1.0, "Breakeven trigger in R", minval = 0.1, step = 0.1, group = G_RISK)
breakevenOffsetPct = input.float(0.05, "Breakeven offset %", minval = 0.0, step = 0.01, group = G_RISK)
exitOnOpposite = input.bool(true, "Exit on opposite / weighted signal", group = G_RISK)
// === GLOBAL VISUALS (not per-indicator) ===
showFibFill = input.bool(true, "Fill Fibonacci BB envelope when Fib visual on", group = G_VIS)
showSignals = input.bool(true, "Show entry/exit labels", group = G_VIS)
showRiskLines = input.bool(true, "Show active stop/target", group = G_VIS)
showRegimeBg = input.bool(true, "Show regime background when trend visual on", group = G_VIS)
colorBars = input.bool(false, "Color bars by regime", group = G_VIS)
showDashboard = input.bool(true, "Show dashboard", group = G_VIS)
botId = input.string("230050", "Bot ID", group = G_ALERT)
// === FUNCTIONS ===
f_dema(series float src, simple int length) =>
float ema1 = ta.ema(src, length)
float ema2 = ta.ema(ema1, length)
2.0 * ema1 - ema2
f_tema(series float src, simple int length) =>
float ema1 = ta.ema(src, length)
float ema2 = ta.ema(ema1, length)
float ema3 = ta.ema(ema2, length)
3.0 * (ema1 - ema2) + ema3
f_zlema(series float src, simple int length) =>
int lag = math.max(1, int(math.floor((length - 1) / 2)))
ta.ema(src + (src - nz(src[lag], src)), length)
f_ma(series float src, simple int length, simple string kind) =>
switch kind
"EMA" => ta.ema(src, length)
"SMA" => ta.sma(src, length)
"WMA" => ta.wma(src, length)
"HMA" => ta.hma(src, length)
"DEMA" => f_dema(src, length)
"TEMA" => f_tema(src, length)
"VWMA" => ta.vwma(src, length)
"RMA" => ta.rma(src, length)
"ZLEMA" => f_zlema(src, length)
=> ta.ema(src, length)
f_donchian(simple int length) =>
math.avg(ta.lowest(low, length), ta.highest(high, length))
f_recent(bool condition, simple int lookback) =>
int bars = ta.barssince(condition)
not na(bars) and bars <= lookback
f_json(string action) =>
'{"botId":"' + botId + '","action":"' + action + '","symbol":"' + syminfo.ticker + '","price":' + str.tostring(close, format.mintick) + '}'
// Effective visual / backtest (master enable gates both)
effRsiViz = enableRSI and rsiVisual
effRsiBt = enableRSI and rsiBacktest
effFibViz = enableFibBB and fibVisual
effFibBt = enableFibBB and fibBacktest
effTrendViz = enableTrendMA and trendVisual
effTrendBt = enableTrendMA and trendBacktest
effIchiViz = enableIchimoku and ichiVisual
effIchiBt = enableIchimoku and ichiBacktest
// === CORE ===
inDateRange = time >= startTime and time <= endTime
signalGate = not confirmedOnly or barstate.isconfirmed
trendMA = f_ma(close, trendLen, maType)
// HTF access: lookahead_off is intentional — this script is the Phase 1 weighted-signal spec and uses
// the live (in-progress) HTF bar value for parity comparison with the chart timeframe. This script does
// NOT gate live orders; it is a research/spec reference only. For production use in the day-trading
// scripts see the nonRepaintHTF toggle (lookahead_on + [1]) which avoids intra-bar repaint.
htfMA = request.security(syminfo.tickerid, htfTf, f_ma(close, trendLen, maType), barmerge.gaps_off, barmerge.lookahead_off)
trendBull = close > trendMA and trendMA >= trendMA[1]
trendBear = close < trendMA and trendMA <= trendMA[1]
htfBull = close > htfMA and htfMA >= htfMA[1]
htfBear = close < htfMA and htfMA <= htfMA[1]
longRegimeOK = not effTrendBt or trendFilter == "Off" or (trendBull and (trendFilter != "Chart + HTF" or htfBull))
shortRegimeOK = not effTrendBt or trendFilter == "Off" or (trendBear and (trendFilter != "Chart + HTF" or htfBear))
rsi = ta.rsi(rsiSrc, rsiLen)
rsiMid = math.avg(rsiOS, rsiOB)
basis = f_ma(bbSrc, bbLen, bbBasisType)
dev = bbMult * ta.stdev(bbSrc, bbLen)
upper1 = basis + 0.236 * dev
upper2 = basis + 0.382 * dev
upper3 = basis + 0.500 * dev
upper4 = basis + 0.618 * dev
upper5 = basis + 0.764 * dev
upper6 = basis + 1.000 * dev
lower1 = basis - 0.236 * dev
lower2 = basis - 0.382 * dev
lower3 = basis - 0.500 * dev
lower4 = basis - 0.618 * dev
lower5 = basis - 0.764 * dev
lower6 = basis - 1.000 * dev
atr = ta.atr(atrLen)
atrPct = close == 0.0 ? na : atr / close * 100.0
volumeSma = ta.sma(volume, volumeLen)
volumeOK = not useVolumeFilter or volume >= volumeSma * volumeMult
volatilityOK = not useAtrFilter or (atrPct >= minAtrPct and atrPct <= maxAtrPct)
filtersOK = volumeOK and volatilityOK
conversionLine = f_donchian(conversionPeriods)
baseLine = f_donchian(basePeriods)
leadLine1 = math.avg(conversionLine, baseLine)
leadLine2 = f_donchian(spanBPeriods)
ichiBull = close > math.max(leadLine1, leadLine2) and conversionLine > baseLine
ichiBear = close < math.min(leadLine1, leadLine2) and conversionLine < baseLine
ichiLongOK = not effIchiBt or ichiBull
ichiShortOK = not effIchiBt or ichiBear
// Raw per-indicator passes (reclaim + setup pattern from prior script)
recentLongBB = f_recent(low <= lower6, setupLookback)
recentShortBB = f_recent(high >= upper6, setupLookback)
recentLongRSI = f_recent(rsi <= rsiOS, setupLookback)
recentShortRSI = f_recent(rsi >= rsiOB, setupLookback)
longBBReclaim = ta.crossover(close, lower5)
shortBBReclaim = ta.crossunder(close, upper5)
longRSIReclaim = ta.crossover(rsi, rsiOS)
shortRSIReclaim = ta.crossunder(rsi, rsiOB)
closeCrossUnderBasis = ta.crossunder(close, basis)
closeCrossOverBasis = ta.crossover(close, basis)
rsiLongPass = recentLongRSI and longRSIReclaim
rsiShortPass = recentShortRSI and shortRSIReclaim
bbLongPass = recentLongBB and longBBReclaim
bbShortPass = recentShortBB and shortBBReclaim
trendLongPass = longRegimeOK
trendShortPass = shortRegimeOK
ichiLongPass = ichiBull
ichiShortPass = ichiBear
// --- Weighted merge: evaluation order RSI → Trend → BB → Ichimoku ---
// 100% weight: first in order with wt>=99.99 and effBt drives signal alone for that side.
longBlendReq = (not effRsiBt or not rsiEntryRequired or rsiLongPass) and (not effTrendBt or not trendEntryRequired or trendLongPass) and (not effFibBt or not fibEntryRequired or bbLongPass) and (not effIchiBt or not ichiEntryRequired or ichiLongPass)
longBlendWSum = (effRsiBt and rsiEntryWeight > 0 ? rsiEntryWeight : 0.0) + (effTrendBt and trendEntryWeight > 0 ? trendEntryWeight : 0.0) + (effFibBt and fibEntryWeight > 0 ? fibEntryWeight : 0.0) + (effIchiBt and ichiEntryWeight > 0 ? ichiEntryWeight : 0.0)
longBlendWHit = (effRsiBt and rsiEntryWeight > 0 ? rsiEntryWeight * (rsiLongPass ? 1.0 : 0.0) : 0.0) + (effTrendBt and trendEntryWeight > 0 ? trendEntryWeight * (trendLongPass ? 1.0 : 0.0) : 0.0) + (effFibBt and fibEntryWeight > 0 ? fibEntryWeight * (bbLongPass ? 1.0 : 0.0) : 0.0) + (effIchiBt and ichiEntryWeight > 0 ? ichiEntryWeight * (ichiLongPass ? 1.0 : 0.0) : 0.0)
longBlend = longBlendWSum > 0.0 and longBlendReq and (longBlendWHit / longBlendWSum >= entryConsensus)
longSetupCombined = (effRsiBt and rsiEntryWeight >= 99.99) ? rsiLongPass : (effTrendBt and trendEntryWeight >= 99.99) ? trendLongPass : (effFibBt and fibEntryWeight >= 99.99) ? bbLongPass : (effIchiBt and ichiEntryWeight >= 99.99) ? ichiLongPass : longBlend
shortBlendReq = (not effRsiBt or not rsiEntryRequired or rsiShortPass) and (not effTrendBt or not trendEntryRequired or trendShortPass) and (not effFibBt or not fibEntryRequired or bbShortPass) and (not effIchiBt or not ichiEntryRequired or ichiShortPass)
shortBlendWSum = (effRsiBt and rsiEntryWeight > 0 ? rsiEntryWeight : 0.0) + (effTrendBt and trendEntryWeight > 0 ? trendEntryWeight : 0.0) + (effFibBt and fibEntryWeight > 0 ? fibEntryWeight : 0.0) + (effIchiBt and ichiEntryWeight > 0 ? ichiEntryWeight : 0.0)
shortBlendWHit = (effRsiBt and rsiEntryWeight > 0 ? rsiEntryWeight * (rsiShortPass ? 1.0 : 0.0) : 0.0) + (effTrendBt and trendEntryWeight > 0 ? trendEntryWeight * (trendShortPass ? 1.0 : 0.0) : 0.0) + (effFibBt and fibEntryWeight > 0 ? fibEntryWeight * (bbShortPass ? 1.0 : 0.0) : 0.0) + (effIchiBt and ichiEntryWeight > 0 ? ichiEntryWeight * (ichiShortPass ? 1.0 : 0.0) : 0.0)
shortBlend = shortBlendWSum > 0.0 and shortBlendReq and (shortBlendWHit / shortBlendWSum >= entryConsensus)
shortSetupCombined = (effRsiBt and rsiEntryWeight >= 99.99) ? rsiShortPass : (effTrendBt and trendEntryWeight >= 99.99) ? trendShortPass : (effFibBt and fibEntryWeight >= 99.99) ? bbShortPass : (effIchiBt and ichiEntryWeight >= 99.99) ? ichiShortPass : shortBlend
// Ichimoku / regime hard gates: when BT off for that family, old behavior was to still block — now only eff*Bt gates
longIchiGate = ichiLongOK
shortIchiGate = ichiShortOK
flat = strategy.position_size == 0
allowShorts = tradeDirection == "Long + Short"
longSignal = inDateRange and signalGate and flat and filtersOK and longIchiGate and longSetupCombined
shortSignal = inDateRange and signalGate and flat and allowShorts and filtersOK and shortIchiGate and shortSetupCombined
// Opposite setup for exits (same weights, no flat requirement)
longOppCombined = inDateRange and signalGate and filtersOK and longIchiGate and longSetupCombined
shortOppCombined = inDateRange and signalGate and filtersOK and shortIchiGate and shortSetupCombined
// Weighted exit — same evaluation order RSI → Trend → BB → Ichimoku
longExitRsiX = rsi >= rsiOB ? 1.0 : 0.0
longExitFibX = closeCrossUnderBasis ? 1.0 : 0.0
longExitTrX = not longRegimeOK ? 1.0 : 0.0
longExitIcX = ichiBear ? 1.0 : 0.0
longExitBlendReq = (not effRsiBt or not rsiExitRequired or rsi >= rsiOB) and (not effTrendBt or not trendExitRequired or not longRegimeOK) and (not effFibBt or not fibExitRequired or closeCrossUnderBasis) and (not effIchiBt or not ichiExitRequired or ichiBear)
longExitBlendWSum = (effRsiBt and rsiExitWeight > 0 ? rsiExitWeight : 0.0) + (effTrendBt and trendExitWeight > 0 ? trendExitWeight : 0.0) + (effFibBt and fibExitWeight > 0 ? fibExitWeight : 0.0) + (effIchiBt and ichiExitWeight > 0 ? ichiExitWeight : 0.0)
longExitBlendWHit = (effRsiBt and rsiExitWeight > 0 ? rsiExitWeight * longExitRsiX : 0.0) + (effTrendBt and trendExitWeight > 0 ? trendExitWeight * longExitTrX : 0.0) + (effFibBt and fibExitWeight > 0 ? fibExitWeight * longExitFibX : 0.0) + (effIchiBt and ichiExitWeight > 0 ? ichiExitWeight * longExitIcX : 0.0)
longExitBlend = longExitBlendWSum > 0.0 and longExitBlendReq and (longExitBlendWHit / longExitBlendWSum >= exitConsensus)
weightedLongExit = (effRsiBt and rsiExitWeight >= 99.99) ? (rsi >= rsiOB) : (effTrendBt and trendExitWeight >= 99.99) ? (not longRegimeOK) : (effFibBt and fibExitWeight >= 99.99) ? closeCrossUnderBasis : (effIchiBt and ichiExitWeight >= 99.99) ? ichiBear : longExitBlend
shortExitRsiX = rsi <= rsiOS ? 1.0 : 0.0
shortExitFibX = closeCrossOverBasis ? 1.0 : 0.0
shortExitTrX = not shortRegimeOK ? 1.0 : 0.0
shortExitIcX = ichiBull ? 1.0 : 0.0
shortExitBlendReq = (not effRsiBt or not rsiExitRequired or rsi <= rsiOS) and (not effTrendBt or not trendExitRequired or not shortRegimeOK) and (not effFibBt or not fibExitRequired or closeCrossOverBasis) and (not effIchiBt or not ichiExitRequired or ichiBull)
shortExitBlendWSum = (effRsiBt and rsiExitWeight > 0 ? rsiExitWeight : 0.0) + (effTrendBt and trendExitWeight > 0 ? trendExitWeight : 0.0) + (effFibBt and fibExitWeight > 0 ? fibExitWeight : 0.0) + (effIchiBt and ichiExitWeight > 0 ? ichiExitWeight : 0.0)
shortExitBlendWHit = (effRsiBt and rsiExitWeight > 0 ? rsiExitWeight * shortExitRsiX : 0.0) + (effTrendBt and trendExitWeight > 0 ? trendExitWeight * shortExitTrX : 0.0) + (effFibBt and fibExitWeight > 0 ? fibExitWeight * shortExitFibX : 0.0) + (effIchiBt and ichiExitWeight > 0 ? ichiExitWeight * shortExitIcX : 0.0)
shortExitBlend = shortExitBlendWSum > 0.0 and shortExitBlendReq and (shortExitBlendWHit / shortExitBlendWSum >= exitConsensus)
weightedShortExit = (effRsiBt and rsiExitWeight >= 99.99) ? (rsi <= rsiOS) : (effTrendBt and trendExitWeight >= 99.99) ? (not shortRegimeOK) : (effFibBt and fibExitWeight >= 99.99) ? closeCrossOverBasis : (effIchiBt and ichiExitWeight >= 99.99) ? ichiBull : shortExitBlend
buyLongMsg = f_json("BUY")
sellLongMsg = f_json("SELL")
sellShortMsg = f_json("SELL_SHORT")
buyCoverMsg = f_json("BUY_TO_COVER")
// Entry fill semantics: signal fires on bar *close* (gated by barstate.isconfirmed via signalGate).
// TradingView fills strategy.entry at the *open of the next bar* (market order, 1-tick slippage default).
// This script is a Phase 1 spec reference; fills are approximate and not used for live order routing.
if longSignal
strategy.entry("L", strategy.long, alert_message = buyLongMsg, comment = "Long: weighted")
if shortSignal
strategy.entry("S", strategy.short, alert_message = sellShortMsg, comment = "Short: weighted")
avg = strategy.position_avg_price
longPctStop = avg * (1.0 - stopPct / 100.0)
longAtrStop = avg - atr * atrStopMult
longStopBase = switch riskModel
"Percent" => longPctStop
"ATR" => longAtrStop
"Wider of % / ATR" => math.min(longPctStop, longAtrStop)
=> math.max(longPctStop, longAtrStop)
longRisk = avg - longStopBase
longTarget = avg + longRisk * rewardRisk
longBEActive = useBreakeven and strategy.position_size > 0 and longRisk > 0 and high >= avg + longRisk * breakevenAtR
longStop = longBEActive ? math.max(longStopBase, avg * (1.0 + breakevenOffsetPct / 100.0)) : longStopBase
shortPctStop = avg * (1.0 + stopPct / 100.0)
shortAtrStop = avg + atr * atrStopMult
shortStopBase = switch riskModel
"Percent" => shortPctStop
"ATR" => shortAtrStop
"Wider of % / ATR" => math.max(shortPctStop, shortAtrStop)
=> math.min(shortPctStop, shortAtrStop)
shortRisk = shortStopBase - avg
shortTarget = avg - shortRisk * rewardRisk
shortBEActive = useBreakeven and strategy.position_size < 0 and shortRisk > 0 and low <= avg - shortRisk * breakevenAtR
shortStop = shortBEActive ? math.min(shortStopBase, avg * (1.0 - breakevenOffsetPct / 100.0)) : shortStopBase
if strategy.position_size > 0 and longRisk > 0
strategy.exit("XL Risk", from_entry = "L", stop = longStop, limit = useTakeProfit ? longTarget : na, alert_message = sellLongMsg, comment_profit = "Long TP", comment_loss = "Long SL")
if strategy.position_size < 0 and shortRisk > 0
strategy.exit("XS Risk", from_entry = "S", stop = shortStop, limit = useTakeProfit ? shortTarget : na, alert_message = buyCoverMsg, comment_profit = "Short TP", comment_loss = "Short SL")
longSignalExit = exitOnOpposite and strategy.position_size > 0 and (weightedLongExit or shortOppCombined)
shortSignalExit = exitOnOpposite and strategy.position_size < 0 and (weightedShortExit or longOppCombined)
if longSignalExit
strategy.close("L", alert_message = sellLongMsg, comment = "Long signal exit")
if shortSignalExit
strategy.close("S", alert_message = buyCoverMsg, comment = "Short signal exit")
if not inDateRange and strategy.position_size != 0
strategy.close_all(alert_message = strategy.position_size > 0 ? sellLongMsg : buyCoverMsg, comment = "Outside date range")
// === PLOTS ===
regimeColor = trendBull ? color.new(color.lime, 0) : trendBear ? color.new(color.red, 0) : color.new(color.gray, 0)
bgcolor(enableTrendMA and effTrendViz and showRegimeBg ? trendBull ? color.new(color.green, 92) : trendBear ? color.new(color.red, 94) : na : na, title = "Regime background")
barcolor(enableTrendMA and effTrendViz and colorBars ? regimeColor : na)
plot(enableTrendMA and effTrendViz ? trendMA : na, "Trend MA", color = regimeColor, linewidth = 2)
plot(enableTrendMA and effTrendViz ? htfMA : na, "HTF Trend MA", color = color.new(color.orange, 0), linewidth = 2)
plot(enableRSI and effRsiViz ? rsi : na, "RSI (data window)", display = display.data_window)
plot(enableFibBB and effFibViz ? basis : na, "Fib BB Basis", color = color.new(color.fuchsia, 0), linewidth = 2)
u1 = plot(enableFibBB and effFibViz ? upper1 : na, "Fib BB +0.236", color = color.new(color.white, 55))
u2 = plot(enableFibBB and effFibViz ? upper2 : na, "Fib BB +0.382", color = color.new(color.white, 50))
u3 = plot(enableFibBB and effFibViz ? upper3 : na, "Fib BB +0.500", color = color.new(color.white, 45))
u4 = plot(enableFibBB and effFibViz ? upper4 : na, "Fib BB +0.618", color = color.new(color.white, 40))
u5 = plot(enableFibBB and effFibViz ? upper5 : na, "Fib BB +0.764", color = color.new(color.white, 35))
u6 = plot(enableFibBB and effFibViz ? upper6 : na, "Fib BB +1.000", color = color.new(color.red, 0), linewidth = 2)
l1 = plot(enableFibBB and effFibViz ? lower1 : na, "Fib BB -0.236", color = color.new(color.white, 55))
l2 = plot(enableFibBB and effFibViz ? lower2 : na, "Fib BB -0.382", color = color.new(color.white, 50))
l3 = plot(enableFibBB and effFibViz ? lower3 : na, "Fib BB -0.500", color = color.new(color.white, 45))
l4 = plot(enableFibBB and effFibViz ? lower4 : na, "Fib BB -0.618", color = color.new(color.white, 40))
l5 = plot(enableFibBB and effFibViz ? lower5 : na, "Fib BB -0.764", color = color.new(color.white, 35))
l6 = plot(enableFibBB and effFibViz ? lower6 : na, "Fib BB -1.000", color = color.new(color.green, 0), linewidth = 2)
fill(u6, l6, color = enableFibBB and effFibViz and showFibFill ? color.new(color.gray, 96) : na, title = "Fib BB envelope")
plot(showRiskLines and strategy.position_size > 0 ? longStop : na, "Long stop", color = color.new(color.red, 0), linewidth = 2, style = plot.style_linebr)
plot(showRiskLines and strategy.position_size > 0 and useTakeProfit ? longTarget : na, "Long target", color = color.new(color.green, 0), linewidth = 2, style = plot.style_linebr)
plot(showRiskLines and strategy.position_size < 0 ? shortStop : na, "Short stop", color = color.new(color.red, 0), linewidth = 2, style = plot.style_linebr)
plot(showRiskLines and strategy.position_size < 0 and useTakeProfit ? shortTarget : na, "Short target", color = color.new(color.green, 0), linewidth = 2, style = plot.style_linebr)
plot(enableIchimoku and effIchiViz ? conversionLine : na, "Ichimoku Conversion", color = color.new(color.red, 0))
plot(enableIchimoku and effIchiViz ? baseLine : na, "Ichimoku Base", color = color.new(color.blue, 0))
plot(enableIchimoku and effIchiViz ? close : na, "Ichimoku Lagging Span", color = color.new(color.orange, 0), offset = -displacement + 1)
ichiA = plot(enableIchimoku and effIchiViz ? leadLine1 : na, "Ichimoku Leading Span A", color = color.new(color.purple, 0), offset = displacement - 1)
ichiB = plot(enableIchimoku and effIchiViz ? leadLine2 : na, "Ichimoku Leading Span B", color = color.new(color.lime, 0), offset = displacement - 1)
fill(ichiA, ichiB, color = enableIchimoku and effIchiViz ? leadLine1 > leadLine2 ? color.new(color.green, 88) : color.new(color.red, 88) : na, title = "Ichimoku Cloud")
plotshape(showSignals and longSignal, title = "Long entry", location = location.belowbar, style = shape.labelup, text = "LONG", color = color.new(color.green, 0), textcolor = color.white, size = size.tiny)
plotshape(showSignals and shortSignal, title = "Short entry", location = location.abovebar, style = shape.labeldown, text = "SHORT", color = color.new(color.red, 0), textcolor = color.white, size = size.tiny)
plotshape(showSignals and longSignalExit, title = "Long signal exit", location = location.abovebar, style = shape.labeldown, text = "XL", color = color.new(color.orange, 0), textcolor = color.white, size = size.tiny)
plotshape(showSignals and shortSignalExit, title = "Short signal exit", location = location.belowbar, style = shape.labelup, text = "XS", color = color.new(color.orange, 0), textcolor = color.white, size = size.tiny)
alertcondition(longSignal, title = "Long signal", message = "Long signal on {{ticker}} at {{close}}")
alertcondition(shortSignal, title = "Short signal", message = "Short signal on {{ticker}} at {{close}}")
alertcondition(longSignalExit, title = "Long signal exit", message = "Exit long on {{ticker}} at {{close}}")
alertcondition(shortSignalExit, title = "Short signal exit", message = "Exit short on {{ticker}} at {{close}}")
var table dash = table.new(position.top_right, 2, 8, border_width = 1)
if showDashboard and barstate.islast
string regimeTxt = trendBull ? "Bull" : trendBear ? "Bear" : "Neutral"
string htfTxt = htfBull ? "HTF Bull" : htfBear ? "HTF Bear" : "HTF Neutral"
string posTxt = strategy.position_size > 0 ? "Long" : strategy.position_size < 0 ? "Short" : "Flat"
string setupTxt = longSetupCombined ? "Long OK" : shortSetupCombined ? "Short OK" : "None"
string filterTxt = filtersOK ? "OK" : "Blocked"
string evalTxt = evalOrderNote
table.cell(dash, 0, 0, "Regime", text_color = color.white, bgcolor = color.new(color.black, 0))
table.cell(dash, 1, 0, regimeTxt + " / " + htfTxt, text_color = color.white, bgcolor = trendBull ? color.new(color.green, 20) : trendBear ? color.new(color.red, 20) : color.new(color.gray, 20))
table.cell(dash, 0, 1, "Position", text_color = color.white, bgcolor = color.new(color.black, 0))
table.cell(dash, 1, 1, posTxt, text_color = color.white, bgcolor = strategy.position_size > 0 ? color.new(color.green, 20) : strategy.position_size < 0 ? color.new(color.red, 20) : color.new(color.gray, 20))
table.cell(dash, 0, 2, "Weighted", text_color = color.white, bgcolor = color.new(color.black, 0))
table.cell(dash, 1, 2, setupTxt, text_color = color.white, bgcolor = color.new(color.gray, 20))
table.cell(dash, 0, 3, "Eval order", text_color = color.white, bgcolor = color.new(color.black, 0))
table.cell(dash, 1, 3, evalTxt, text_color = color.white, bgcolor = color.new(color.gray, 20))
table.cell(dash, 0, 4, "RSI", text_color = color.white, bgcolor = color.new(color.black, 0))
table.cell(dash, 1, 4, str.tostring(rsi, "#.##") + " / Mid " + str.tostring(rsiMid, "#.##"), text_color = color.white, bgcolor = rsi <= rsiOS ? color.new(color.green, 20) : rsi >= rsiOB ? color.new(color.red, 20) : color.new(color.gray, 20))
table.cell(dash, 0, 5, "ATR %", text_color = color.white, bgcolor = color.new(color.black, 0))
table.cell(dash, 1, 5, str.tostring(atrPct, "#.##") + "%", text_color = color.white, bgcolor = volatilityOK ? color.new(color.green, 35) : color.new(color.red, 25))
table.cell(dash, 0, 6, "Volume", text_color = color.white, bgcolor = color.new(color.black, 0))
table.cell(dash, 1, 6, volumeOK ? "OK" : "Low", text_color = color.white, bgcolor = volumeOK ? color.new(color.green, 35) : color.new(color.red, 25))
table.cell(dash, 0, 7, "Filters", text_color = color.white, bgcolor = color.new(color.black, 0))
table.cell(dash, 1, 7, filterTxt, text_color = color.white, bgcolor = filtersOK ? color.new(color.green, 35) : color.new(color.red, 25))
Overview
Each indicator can be switched on for visuals, for backtesting or both, and entry and exit signals pass when a weighted blend reaches a consensus threshold. Volume and ATR percentage filters are available, along with direction and date range inputs. It acts on confirmed bars and holds one entry at a time.
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
Trade direction
string
Long only
tradeDirection
Backtest start
time
1767225600000
startTime
Backtest end
time
1798761540000
endTime
Only act after confirmed bar close
bool
true
confirmedOnly
Setup lookback bars
int
5
setupLookback
Entry blend threshold (0–1)
float
1.0
entryConsensus
Exit blend threshold (0–1)
float
1.0
exitConsensus
Evaluation order (phase1 fixed)
string
RSI → Trend → BB → Ichimoku
evalOrderNote
Enable RSI
bool
true
enableRSI
Visual
bool
true
rsiVisual
Backtest
bool
true
rsiBacktest
Enable Fibonacci BB
bool
false
enableFibBB
Show all 40 settings
Setting
Type
Default
Variable
Visual
bool
true
fibVisual
Backtest
bool
false
fibBacktest
Enable trend MA / regime
bool
false
enableTrendMA
Visual
bool
true
trendVisual
Backtest
bool
false
trendBacktest
Enable Ichimoku
bool
false
enableIchimoku
Visual
bool
true
ichiVisual
Backtest
bool
false
ichiBacktest
Trend MA type
string
EMA
maType
Trend MA length
int
200
trendLen
Regime filter
string
Chart + HTF
trendFilter
Higher timeframe
timeframe
240
htfTf
Require volume expansion
bool
true
useVolumeFilter
Volume SMA length
int
20
volumeLen
Min volume x SMA
float
0.80
volumeMult
Filter abnormal volatility
bool
true
useAtrFilter
Min ATR %
float
0.20
minAtrPct
Max ATR %
float
12.0
maxAtrPct
Trend · entry required
bool
false
trendEntryRequired
Entry wt %
float
25.0
trendEntryWeight
Trend · exit required
bool
false
trendExitRequired
Exit wt %
float
25.0
trendExitWeight
RSI source
source
close
rsiSrc
RSI length
int
9
rsiLen
Oversold
float
31.0
rsiOS
Overbought
float
67.5
rsiOB
RSI · entry required
bool
false
rsiEntryRequired
Entry wt %
float
100.0
rsiEntryWeight
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.
This strategy overlays a trend moving average and Supertrend bands directly on the price chart while calculating Stochastic RSI values internally. Long positions trigger when price exceeds the moving average, Supertrend signals bullish momentum, and the StochR
This trading strategy combines three Exponential Moving Averages (8, 14, and 50 periods by default) with Stochastic RSI and Average True Range (ATR). It enters a long position when EMA 1 is above EMA 2, EMA 2 is above EMA 3, and the Stochastic RSI %K line cros
This strategy combines exponential moving averages (EMA 9, 21, 50), RSI, MACD, and Supertrend indicators to enter long positions. It triggers trades using six dynamic setups based on momentum breakouts, EMA crossovers, and pullbacks. Position sizing is compute
This strategy identifies trend reversals through market structure changes (CHoCH) filtered by MACD momentum. It initiates long positions on bullish structure breaks when MACD is positive and above its signal line, and short positions on bearish breaks when MAC
CombinedBinHAndClucV6 is a trading strategy based on the popular BinHV45 and ClucMay72018 algorithms. It calculates dual Bollinger Bands, Exponential Moving Averages, Relative Strength Index, Average True Range, and volume metrics across primary and one-hour h
LuxAlgo Hybrid Gold Scalper is a price-chart strategy aimed at gold. It stacks a fast, slow, trend and 200-period bias EMA to mark trend direction, then filters strength with RSI, ADX and an intraday VWAP. Swing highs and lows are marked from pivot length. Set