Strategy · Pine Script v6 · On the chart

Crypto TA Pro Long Term Hold Companion

by Xellos1010

A Pine v6 research strategy for slower accumulation on crypto charts.

View on GitHub

GitHub stars1on the repository
Pine versionv6current
Lines of code255
Settings32inputs
LicenceMIT
Last update11 days ago18 Oct 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new strategy, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart. The trades and results appear in the Strategy Tester tab; adjust the settings with the gear icon.

Source Code

255 lines of Pine Script v6 from pine-scripts/ctapv6_longterm_hold_companion_v1.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

ctapv6_longterm_hold_companion_v1.pine
//@version=6
strategy(
     title = "Crypto TA Pro v6 - Long Term Hold Companion",
     shorttitle = "CTAPv6-Hold",
     overlay = true,
     precision = 8,
     max_bars_back = 2000,
     max_labels_count = 300,
     max_lines_count = 300,
     max_boxes_count = 200,
     pyramiding = 3,
     initial_capital = 100,
     default_qty_type = strategy.percent_of_equity,
     default_qty_value = 33.33,
     commission_type = strategy.commission.percent,
     commission_value = 0.05,
     slippage = 1,
     margin_long = 100,
     margin_short = 100
)

// -----------------------------------------------------------------------------
// CTAPv6 Long Term Hold Companion
// Purpose: accumulation/hold research, not quick-turn day trading.
// Difference from day version: no intraday max-time auto-exit, broader HTF filters,
// slower entries, optional DCA-style pyramiding, trend invalidation exits.
// Research only. Not financial advice.
//
// RESEARCH ASSUMPTIONS — not live-execution defaults:
//   commission = 0.05% per side (Coinbase Advanced Trade maker rate; taker is ~0.08%).
//     Adjust for your actual fee tier. Long-hold strategies should target maker fills;
//     this value reflects a realistic accumulation scenario. Does not model rebates.
//   slippage = 1 tick (TradingView "points"). For crypto tick = smallest price increment.
//     Real market-order slippage on non-trivial size is typically larger; 1-tick understates cost.
//   initial_capital = $100 (research-scale; NOT representative of live notional).
//   default_qty_value = 33.33% of equity per trade (1/3-position sizing for long-hold legs).
//     This represents a three-tranche accumulation model (initial + 2 DCA adds = full position).
//     Use conservative sizing (5-15% per tranche) for live; 33.33% per leg is research-mode only.
//     Live sizing must be set by the operator based on account size, risk tolerance, and exchange rules.
//   Trade frequency: this script generates approximately 10-30 trades per year on daily/weekly charts.
//     Backtest statistical significance is LOW at this frequency. Require at minimum 5+ years of
//     history for any research conclusion and 30+ completed trades before considering promotion to
//     paper or live. Short backtest windows (< 2 years) are insufficient for long-hold strategy research.
//   These values affect absolute P&L and drawdown numbers but not signal timing or direction.
// -----------------------------------------------------------------------------

const string G_EXEC   = "01. Execution"
const string G_ACC    = "02. Accumulation Logic"
const string G_SR     = "03. Support / Resistance"
const string G_REGIME = "03b. Multi-TF Regime Filter"
const string G_RISK   = "04. Long-Hold Risk"
const string G_VIS    = "05. Visuals"

startTime = input.time(1704067200000, "Research start", group = G_EXEC) // 2024-01-01 UTC
endTime   = input.time(1893455940000, "Research end", group = G_EXEC)   // 2029-12-31 UTC
confirmedOnly = input.bool(true, "Only act after confirmed bar close", group = G_EXEC)
allowShortResearch = input.bool(false, "Allow short research", group = G_EXEC)

fastLen = input.int(50, "Fast trend EMA", minval = 5, maxval = 500, group = G_ACC)
slowLen = input.int(200, "Slow trend EMA", minval = 20, maxval = 1000, group = G_ACC)
htfTf = input.timeframe("W", "Higher timeframe", group = G_ACC)
rsiLen = input.int(14, "RSI length", minval = 2, maxval = 100, group = G_ACC)
rsiAccumulationMax = input.float(45.0, "Accumulation RSI max", minval = 1, maxval = 70, group = G_ACC)
rsiDistributionMin = input.float(75.0, "Distribution RSI min", minval = 50, maxval = 99, group = G_ACC)
useDCA = input.bool(true, "Allow additional accumulation entries", group = G_ACC)
minBarsBetweenAdds = input.int(20, "Minimum bars between adds", minval = 1, maxval = 500, group = G_ACC)
// HTF repaint guard: true (default) uses prior confirmed HTF bar (lookahead_on + [1]); false uses live
// in-progress HTF bar (lookahead_off). Leave true for any live-order or replay fidelity use.
nonRepaintHTF = input.bool(true, "Use confirmed HTF values (repaint-safe)", group = G_ACC)

showSR = input.bool(true, "Show long-hold S/R zones", group = G_SR)
srLeft = input.int(10, "Pivot left", minval = 2, maxval = 100, group = G_SR)
srRight = input.int(10, "Pivot right", minval = 2, maxval = 100, group = G_SR)
srAtrMult = input.float(0.50, "Zone ATR thickness", minval = 0.01, maxval = 10, group = G_SR)
srExtend = input.int(500, "Zone extension bars", minval = 50, maxval = 1000, group = G_SR)

enableMtfRegime   = input.bool(true, "Enable multi-TF regime cascade", group = G_REGIME)
ema4hLen          = input.int(50, "4H EMA length", minval = 10, maxval = 200, group = G_REGIME)
emaDailyFastLen   = input.int(50, "Daily fast EMA length", minval = 10, maxval = 200, group = G_REGIME)
emaDailySlowLen   = input.int(200, "Daily slow EMA length", minval = 50, maxval = 500, group = G_REGIME)
mtfTransitionSize = input.float(0.5, "Position size multiplier during regime transition", minval = 0.1, maxval = 1.0, step = 0.1, group = G_REGIME)

reduceForWeekend  = input.bool(true, "Reduce position 50% on Friday UTC close", group = G_RISK)

atrLen = input.int(14, "ATR length", minval = 1, group = G_RISK)
catastrophicStopAtr = input.float(6.0, "Catastrophic stop ATR", minval = 1.0, step = 0.25, group = G_RISK)
// Freeze semantics: true (default) captures ATR and catastrophic stop level on the entry bar so the
// stop zone does not drift as ATR evolves mid-hold. The zone reference stays anchored to entry-bar
// risk. Reset to na on position close so each accumulation leg starts from a clean baseline.
freezeRiskAtEntry = input.bool(true, "Freeze catastrophic stop ATR at entry", group = G_RISK)
exitOnSlowTrendBreak = input.bool(true, "Exit on slow trend break", group = G_RISK)
exitOnHTFBear = input.bool(true, "Exit on HTF bear regime", group = G_RISK)
usePartialDistribution = input.bool(false, "Use RSI distribution exit", group = G_RISK)

showDashboard = input.bool(true, "Show dashboard", group = G_VIS)
showZones = input.bool(true, "Show accumulation/distribution zones", group = G_VIS)

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_add_box(array<box> arr, box b, int maxCount) =>
    array.push(arr, b)
    if array.size(arr) > maxCount
        box.delete(array.shift(arr))

inRange = time >= startTime and time <= endTime
signalGate = not confirmedOnly or barstate.isconfirmed
fast = ta.ema(close, fastLen)
slow = ta.ema(close, slowLen)
// HTF confirmation semantics:
//   htfSlowNonRepaint — lookahead_on + [1]: prior confirmed HTF close; no intra-bar repaint (default).
//   htfSlowRepainting — lookahead_off: live current HTF bar value; updates intra-bar (repaints on replay).
//   nonRepaintHTF toggle selects which is used. Prefer confirmed variant for all live and replay analysis.
htfSlowNonRepaint = request.security(syminfo.tickerid, htfTf, ta.ema(close, slowLen)[1], barmerge.gaps_off, barmerge.lookahead_on)
htfSlowRepainting = request.security(syminfo.tickerid, htfTf, ta.ema(close, slowLen), barmerge.gaps_off, barmerge.lookahead_off)
htfSlow = nonRepaintHTF ? htfSlowNonRepaint : htfSlowRepainting
rsi = ta.rsi(close, rsiLen)
atr = ta.atr(atrLen)

// Multi-TF regime cascade (Bug 14 fix): 4H + Daily EMA alignment prevents slow single-EMA lag.
// lookahead_off on all HTF requests to avoid future-bar leakage in backtests.
ema4h     = request.security(syminfo.tickerid, "240", ta.ema(close, ema4hLen),     lookahead = barmerge.lookahead_off)
ema1dFast = request.security(syminfo.tickerid, "1D",  ta.ema(close, emaDailyFastLen), lookahead = barmerge.lookahead_off)
ema1dSlow = request.security(syminfo.tickerid, "1D",  ta.ema(close, emaDailySlowLen), lookahead = barmerge.lookahead_off)

mtfBull          = enableMtfRegime ? (ema4h > ema1dFast and ema1dFast > ema1dSlow) : true
mtfBear          = enableMtfRegime ? (ema4h < ema1dFast and ema1dFast < ema1dSlow) : false
mtfTransition    = enableMtfRegime ? (not mtfBull and not mtfBear) : false
mtfSizeMultiplier = mtfTransition ? mtfTransitionSize : 1.0

trendBull = close > slow and fast > slow and slow >= slow[1]
trendBear = close < slow and fast < slow and slow <= slow[1]
htfBull = close > htfSlow and htfSlow >= htfSlow[1]
htfBear = close < htfSlow and htfSlow <= htfSlow[1]

pLow = ta.pivotlow(low, srLeft, srRight)
pHigh = ta.pivothigh(high, srLeft, srRight)
var float supportTop = na
var float supportBottom = na
var float resistanceTop = na
var float resistanceBottom = na
var array<box> sBoxes = array.new<box>()
var array<box> rBoxes = array.new<box>()
buf = atr * srAtrMult
if showSR and not na(pLow)
    supportTop := pLow + buf
    supportBottom := pLow - buf
    box b = box.new(bar_index - srRight, supportTop, bar_index + srExtend, supportBottom, border_color = color.new(color.green, 25), bgcolor = color.new(color.green, 90), text = "HOLD SUPPORT", text_color = color.new(color.green, 0), text_size = size.tiny, text_halign = text.align_center, text_valign = text.align_center)
    f_add_box(sBoxes, b, 20)
if showSR and not na(pHigh)
    resistanceTop := pHigh + buf
    resistanceBottom := pHigh - buf
    box b = box.new(bar_index - srRight, resistanceTop, bar_index + srExtend, resistanceBottom, border_color = color.new(color.red, 25), bgcolor = color.new(color.red, 90), text = "HOLD RESIST", text_color = color.new(color.red, 0), text_size = size.tiny, text_halign = text.align_center, text_valign = text.align_center)
    f_add_box(rBoxes, b, 20)
if showSR
    if array.size(sBoxes) > 0
        for i = 0 to array.size(sBoxes) - 1
            box.set_right(array.get(sBoxes, i), bar_index + srExtend)
    if array.size(rBoxes) > 0
        for i = 0 to array.size(rBoxes) - 1
            box.set_right(array.get(rBoxes, i), bar_index + srExtend)

nearSupport = not na(supportTop) and low <= supportTop and high >= supportBottom
nearResistance = not na(resistanceBottom) and high >= resistanceBottom and low <= resistanceTop
var int lastAddBar = na
canAdd = na(lastAddBar) or bar_index - lastAddBar >= minBarsBetweenAdds
baseLong = inRange and signalGate and trendBull and htfBull and rsi <= rsiAccumulationMax and nearSupport
addLong = useDCA and strategy.position_size > 0 and baseLong and canAdd
firstLong = strategy.position_size == 0 and baseLong

// 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).
// nearSupport zone check uses close vs. zone bounds; the actual fill is next-bar open, which may be
// slightly outside the zone. Pyramiding adds at most once per minBarsBetweenAdds bars.
// mtfSizeMultiplier scales the 33.33% base tranche down to mtfTransitionSize when the regime is in
// transition (neither full bull nor full bear across the 4H and Daily EMA cascade).
entryQty = strategy.equity * 0.3333 * mtfSizeMultiplier / close
if firstLong or addLong
    strategy.entry("L-HOLD", strategy.long, qty = entryQty, comment = firstLong ? "Initial accumulation" : "DCA accumulation")
    lastAddBar := bar_index

shortResearch = allowShortResearch and inRange and signalGate and trendBear and htfBear and rsi >= rsiDistributionMin and nearResistance and strategy.position_size == 0
if shortResearch
    strategy.entry("S-HOLD", strategy.short, qty = entryQty, comment = "Long-hold short research")

// === RISK ENGINE (freeze-at-entry) ===
var float entryAtr = na
var float frozenStop = na
newLongPosition = strategy.position_size > 0 and strategy.position_size[1] <= 0
closedPosition   = strategy.position_size == 0 and strategy.position_size[1] != 0
if newLongPosition
    entryAtr := atr
if closedPosition
    entryAtr := na
    frozenStop := na

riskAtr = freezeRiskAtEntry ? nz(entryAtr, atr) : atr
avg = strategy.position_avg_price
longCatStop = avg - riskAtr * catastrophicStopAtr
shortCatStop = avg + riskAtr * catastrophicStopAtr

// Capture stop level on entry bar so zone reference does not drift with ATR during a long hold.
if newLongPosition
    frozenStop := longCatStop

if strategy.position_size > 0
    strategy.exit("XL Catastrophic", "L-HOLD", stop = longCatStop, comment_loss = "Catastrophic stop")
if strategy.position_size < 0
    strategy.exit("XS Catastrophic", "S-HOLD", stop = shortCatStop, comment_loss = "Catastrophic stop")

longTrendExit = strategy.position_size > 0 and ((exitOnSlowTrendBreak and close < slow) or (exitOnHTFBear and htfBear) or (usePartialDistribution and rsi >= rsiDistributionMin))
shortTrendExit = strategy.position_size < 0 and ((exitOnSlowTrendBreak and close > slow) or (exitOnHTFBear and htfBull) or (usePartialDistribution and rsi <= rsiAccumulationMax))
if longTrendExit
    strategy.close("L-HOLD", comment = "Hold invalidated")
if shortTrendExit
    strategy.close("S-HOLD", comment = "Short hold invalidated")
if not inRange and strategy.position_size != 0
    strategy.close_all(comment = "Outside research range")

// Weekend de-risking (Bug 15 fix): reduce to 50% on Friday UTC 22:00 close to avoid
// weekend funding-rate spikes on leveraged derivatives. No-op for spot unless explicitly enabled.
isFridayUtc22 = dayofweek(time, "UTC") == dayofweek.friday and hour(time, "UTC") >= 22
if strategy.position_size > 0 and reduceForWeekend and isFridayUtc22
    strategy.close("L-HOLD", qty_percent = 50, comment = "WEEKEND_DERISK")

plot(fast, "Fast EMA", color = color.new(color.aqua, 0), linewidth = 2)
plot(slow, "Slow EMA", color = color.new(color.orange, 0), linewidth = 2)
plot(htfSlow, "HTF Slow EMA", color = color.new(color.purple, 0), linewidth = 2)
// Catastrophic stop displayed as frozen entry-bar level when freezeRiskAtEntry is on; live ATR-derived level otherwise.
float plotLongStop = strategy.position_size > 0 ? (freezeRiskAtEntry and not na(frozenStop) ? frozenStop : longCatStop) : na
plot(plotLongStop, "Long catastrophic stop", color = color.new(color.red, 0), style = plot.style_linebr)
plot(strategy.position_size < 0 ? shortCatStop : na, "Short catastrophic stop", color = color.new(color.red, 0), style = plot.style_linebr)
plotshape(firstLong, title = "Initial accumulation", location = location.belowbar, style = shape.labelup, text = "ACC", color = color.new(color.green, 0), textcolor = color.white, size = size.tiny)
plotshape(addLong, title = "Add accumulation", location = location.belowbar, style = shape.labelup, text = "ADD", color = color.new(color.teal, 0), textcolor = color.white, size = size.tiny)
plotshape(longTrendExit, title = "Hold exit", location = location.abovebar, style = shape.labeldown, text = "EXIT", color = color.new(color.orange, 0), textcolor = color.white, size = size.tiny)
bgcolor(showZones and trendBull and htfBull ? color.new(color.green, 94) : showZones and trendBear and htfBear ? color.new(color.red, 95) : na)

var table dash = table.new(position.top_right, 2, 7, border_width = 1)
if showDashboard and barstate.islast
    table.cell(dash, 0, 0, "CTAPv6 Hold", text_color = color.white, bgcolor = color.new(color.black, 0))
    table.cell(dash, 1, 0, strategy.position_size > 0 ? "Long" : strategy.position_size < 0 ? "Short" : "Flat", text_color = color.white, bgcolor = strategy.position_size > 0 ? color.new(color.green, 25) : strategy.position_size < 0 ? color.new(color.red, 25) : color.new(color.gray, 25))
    table.cell(dash, 0, 1, "Trend", text_color = color.white, bgcolor = color.new(color.black, 0))
    table.cell(dash, 1, 1, trendBull ? "Bull" : trendBear ? "Bear" : "Neutral", text_color = color.white, bgcolor = trendBull ? color.new(color.green, 25) : trendBear ? color.new(color.red, 25) : color.new(color.gray, 25))
    table.cell(dash, 0, 2, "HTF", text_color = color.white, bgcolor = color.new(color.black, 0))
    table.cell(dash, 1, 2, htfBull ? "HTF Bull" : htfBear ? "HTF Bear" : "HTF Neutral", text_color = color.white, bgcolor = htfBull ? color.new(color.green, 25) : htfBear ? color.new(color.red, 25) : color.new(color.gray, 25))
    table.cell(dash, 0, 3, "RSI", text_color = color.white, bgcolor = color.new(color.black, 0))
    table.cell(dash, 1, 3, str.tostring(rsi, "#.##"), text_color = color.white, bgcolor = rsi <= rsiAccumulationMax ? color.new(color.green, 25) : rsi >= rsiDistributionMin ? color.new(color.red, 25) : color.new(color.gray, 25))
    table.cell(dash, 0, 4, "S/R", text_color = color.white, bgcolor = color.new(color.black, 0))
    table.cell(dash, 1, 4, nearSupport ? "Near support" : nearResistance ? "Near resistance" : "Neutral", text_color = color.white, bgcolor = nearSupport ? color.new(color.green, 25) : nearResistance ? color.new(color.red, 25) : color.new(color.gray, 25))
    table.cell(dash, 0, 5, "Adds", text_color = color.white, bgcolor = color.new(color.black, 0))
    table.cell(dash, 1, 5, useDCA ? "DCA On" : "One entry", text_color = color.white, bgcolor = color.new(color.gray, 25))
    table.cell(dash, 0, 6, "Range", text_color = color.white, bgcolor = color.new(color.black, 0))
    table.cell(dash, 1, 6, inRange ? "ON" : "OFF", text_color = color.white, bgcolor = inRange ? color.new(color.green, 25) : color.new(color.red, 25))

Overview

Crypto TA Pro Long Term Hold Companion uses fast and slow trend EMAs, a weekly higher timeframe filter, an RSI accumulation threshold and a multi-timeframe regime cascade. Up to three entries can be added with a minimum bar gap, and positions can be cut around weekends. Exits include a wide ATR-based stop, a slow trend break and a bearish higher timeframe regime. It also draws support and resistance zones.

Details

Published by

Xellos1010 on GitHub

Type

Strategy, Pine Script v6

Draws

On the price chart

Category

Trend, Support & resistance

Markets

Crypto

Timeframes

H4 and above

Risk Notes

  • The strategy can add several entries in the same direction

Topics

algorithmic-tradingcoinbasepolymarketrisk-managementrusttokiotrading

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Research starttime1704067200000startTime
Research endtime1893455940000endTime
Only act after confirmed bar closebooltrueconfirmedOnly
Allow short researchboolfalseallowShortResearch
Fast trend EMAint50fastLen
Slow trend EMAint200slowLen
Higher timeframetimeframeWhtfTf
RSI lengthint14rsiLen
Accumulation RSI maxfloat45.0rsiAccumulationMax
Distribution RSI minfloat75.0rsiDistributionMin
Allow additional accumulation entriesbooltrueuseDCA
Minimum bars between addsint20minBarsBetweenAdds
Show all 32 settings
SettingTypeDefaultVariable
Use confirmed HTF values (repaint-safe)booltruenonRepaintHTF
Show long-hold S/R zonesbooltrueshowSR
Pivot leftint10srLeft
Pivot rightint10srRight
Zone ATR thicknessfloat0.50srAtrMult
Zone extension barsint500srExtend
Enable multi-TF regime cascadebooltrueenableMtfRegime
4H EMA lengthint50ema4hLen
Daily fast EMA lengthint50emaDailyFastLen
Daily slow EMA lengthint200emaDailySlowLen
Position size multiplier during regime transitionfloat0.5mtfTransitionSize
Reduce position 50% on Friday UTC closebooltruereduceForWeekend
ATR lengthint14atrLen
Catastrophic stop ATRfloat6.0catastrophicStopAtr
Freeze catastrophic stop ATR at entrybooltruefreezeRiskAtEntry
Exit on slow trend breakbooltrueexitOnSlowTrendBreak
Exit on HTF bear regimebooltrueexitOnHTFBear
Use RSI distribution exitboolfalseusePartialDistribution
Show dashboardbooltrueshowDashboard
Show accumulation/distribution zonesbooltrueshowZones
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.

Similar Pine Scripts

This trend-following strategy executes a classic Donchian channel breakout system designed to cross-validate backtest results against external framework benchmarks. It triggers a long entry when the closing price breaks above the highest high of the prior entr

Strategy v6 BreakoutTrend
Updated yesterday · AGPL-3.0 GitHub repository of Forven S01509 - Simple Donchian 20/10 Breakout

Omar Edited WF

by Alorse
330 stars

Omar Edited WF is a trading strategy overlay built around Williams Fractals and multiple Exponential Moving Averages. It detects high and low fractal pivot points over configurable lookback periods alongside three adjustable EMA trendlines. Long entries are ma

Strategy v5 TrendMoving averages
Updated 2 months ago · None stated GitHub repository of Omar Edited WF
257 stars

This strategy calculates dynamic support and resistance levels using pivot highs and lows alongside a custom smoothed trend filter and a 3-period EMA. It identifies entry opportunities when price breaks out relative to the trend filter and short-term EMA cross

Strategy v5 TrendSupport & resistance Repaints
Updated 6 weeks ago · None stated GitHub repository of 30s - ES 1m Strategy Candle Bar
106 stars

This overlay strategy plots a two-timeframe Ichimoku setup on the price chart, with Tenkan, Kijun, Chikou, and Kumo from a base higher timeframe and an optional highest-timeframe cloud. It allows two entries in the same direction and uses ATR-based trailing st

Strategy v4 TrendVolatility & bands
Updated 2 years ago · GPL-3.0 GitHub repository of 2Tier Ichimoku Pyramiding [Takazudo]
104 stars

This strategy combines three Exponential Moving Averages with Williams Fractals to execute trend-following or mean-reverting trades. It analyzes price structure using short, medium, and long-term EMAs along with fractal highs and lows. Entries trigger when fra

Strategy v5 TrendMoving averages
Updated 3 years ago · MIT GitHub repository of 3MA and Fractals Strategy

More strategys

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers