1Copy the scriptPress Copy script above, or the copy button on the code below.
2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
3Paste over the templateCreate a new strategy, select all of the template text and paste. Press Save and give it a name.
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
130 lines of Pine Script v5 from Breakout Trend Follower Strategy.pine, published under GPL-3.0. Keep the author's credit and licence lines when you reuse it.
Breakout Trend Follower Strategy.pine
//@version=5
// Revision: 3
// Author: @millerrh
// Strategy: Enter long when recent swing high breaks out, using recent swing low as stop level. Move stops up as higher lows print to act
// as trailing stops. Ride trend as long as it is there and the higher lows aren't breached.
// Conditions/Variables
// 1. Manually configure which dates to back test
// 2. Can add a filter to only take setups that are above (or below for shorts) user-defined moving average(s) (helps avoid trading counter trend)
// 3. Can ignore signals that are too extended and not consolidating enough based on ADR and/or RSI.
// 4. Color background of trades - helps to easily see at a glance if the strategy should be long or not.
// === CALL STRATEGY/STUDY, PROGRAMATICALLY ENTER STRATEGY PARAMETERS HERE SO YOU DON'T HAVE TO CHANGE THEM EVERY TIME YOU RUN A TEST ===
// (STRATEGY ONLY) - Comment out srategy() when in a study()
strategy('Breakout Trend Follower', overlay=true, initial_capital=10000, currency='USD', calc_on_every_tick = true,
default_qty_type=strategy.percent_of_equity, default_qty_value=100, commission_type=strategy.commission.percent, commission_value=0.1)
// === BACKTEST RANGE ===
Start = input.time(defval=timestamp('01 Jan 2019 06:00 +0000'), title='Backtest Start Date', group = "backtest window")
Finish = input.time(defval=timestamp('01 Jan 2100 00:00 +0000'), title='Backtest End Date', group = "backtest window")
// === USER INPUTS ===
pvtLb = input.int(defval=3, title='Pivot Lookback', minval=1, group = "support & resistance levels",
tooltip = "Number of bars to left and right to deterine local pivot.")
showPivotPoints = input.bool(title = "Show Historical Pivot Points?", defval = false, group = "support & resistance levels",
tooltip = "Toggle this on to see the historical pivot points that were used.")
currentColorS = input.color(color.new(color.orange,50), title = "Current Range S/R Colors: Support",group = "support & resistance levels", inline = "lineColor")
currentColorR = input.color(color.new(color.blue,50), title = " Resistance", group = "support & resistance levels", inline = "lineColor")
useMaFilter = input.bool(title='Use Current Timeframe Moving Average for Filtering?', defval=true, group = "moving average filters",
tooltip='Signals will be ignored when price is under this moving average. The intent is to keep you out of bear periods and only buying when price is showing strength.')
maType = input.string(defval='SMA', options=['EMA', 'SMA'], group = "moving average filters",title='MA Type For Filtering')
maLength = input.int(defval=50, title='MA Period for Filtering', minval=1, group = "moving average filters", inline = "1ma")
ma1Color = input.color(color.new(color.purple, 60), title = " Color", group = "moving average filters", inline = "1ma")
useMaFilter2 = input.bool(title='Use Multi-Timeframe Moving Average for Filtering?', defval=false, group = "moving average filters",
tooltip='Signals will be ignored when price is under this moving average. The intent is to keep you out of bear periods and only buying when price is showing strength. Other timeframe allows you to use Daily moving average for higher level view of market strength.')
tfSet = input.timeframe(defval='D', title='Moving Average Time Frame', group = "moving average filters",
tooltip='Allows you to set a different time frame moving average to filter your signals by.')
ma2Type = input.string(defval='SMA', options=['EMA', 'SMA'], title='MA Type For Filtering', group = "moving average filters")
ma2Length = input.int(defval=50, title='MA Period for Filtering', minval=1, group = "moving average filters", inline = "2ma")
ma2Color = input.color(color.new(color.yellow, 60), title = " Color", group = "moving average filters", inline = "2ma")
// === MOVING AVERAGE CALCULATIONS ===
// Declare function to be able to swap out EMA/SMA
ma(maType, src, length) =>
maType == 'EMA' ? ta.ema(src, length) : ta.sma(src, length) //Ternary Operator (if maType equals EMA, then do ema calc, else do sma calc)
maFilter = ma(maType, close, maLength)
maFilter2 = request.security(syminfo.tickerid, tfSet, ma(ma2Type, close, ma2Length))
plot(useMaFilter ? maFilter : na, title='Trend Filter MA', color=ma1Color, linewidth=2, style=plot.style_line)
plot(useMaFilter2 ? maFilter2 : na, title='Trend Filter MA', color=ma2Color, linewidth=2, style=plot.style_line)
// === USE RSI FOR FILTERING ===
// The idea here is that you want to buy in a consolodating range for best risk/reward. With the RSI filter, you make sure that the previous bars' RSI
// level is not overbought/overextended before deciding to take a position on.
useRsiFilter = input.bool(title='Use RSI for Filtering?', defval=false, group = "rsi filtering",
tooltip='Signals will be ignored if the RSI level is above a user-defined level for overbought. This allows the user to ensure they are not buying something that is too extended and instead focus on names that are consolidating more.')
rsiTf = input.timeframe(defval='', title='RSI Timeframe', group = "rsi filtering",
tooltip='Allows you to set a different time frame for RSI to filter your signals by.')
rsiOB = input.int(defval=70, title='RSI Overbought Level', minval=1, group = "rsi filtering")
rsiVal = request.security(syminfo.tickerid, rsiTf, ta.rsi(close, 14))
// === PLOT SWING HIGH/LOW AND MOST RECENT LOW TO USE AS STOP LOSS EXIT POINT ===
// Get High and Low Pivot Points
ph = ta.pivothigh(high, pvtLb, pvtLb)
pl = ta.pivotlow(low, pvtLb, pvtLb)
highLevel = ta.valuewhen(ph, high[pvtLb], 0)
lowLevel = ta.valuewhen(pl, low[pvtLb], 0)
barsSinceHigh = ta.barssince(ph) + pvtLb
barsSinceLow = ta.barssince(pl) + pvtLb
timeSinceHigh = time[barsSinceHigh]
timeSinceLow = time[barsSinceLow]
//Removes color when there is a change to ensure only the levels are shown (i.e. no diagonal lines connecting the levels)
pvthis = fixnan(ph)
pvtlos = fixnan(pl)
hipc = ta.change(pvthis) != 0 ? na : color.maroon
lopc = ta.change(pvtlos) != 0 ? na : color.green
// Display Pivot lines
plot(showPivotPoints ? pvthis : na, color=hipc, linewidth=1, offset=-pvtLb, title="Top Levels")
plot(showPivotPoints ? pvthis : na, color=hipc, linewidth=1, offset=0, title="Top Levels 2")
plot(showPivotPoints ? pvtlos : na, color=lopc, linewidth=1, offset=-pvtLb, title="Bottom Levels")
plot(showPivotPoints ? pvtlos : na, color=lopc, linewidth=1, offset=0, title="Bottom Levels 2")
// == PLOT SUPPORT/RESISTANCE LINES FOR CURRENT CHART TIMEFRAME ==
// Use a function to define the lines
f_line(x1, y1, y2, _color) =>
var line id = na
line.delete(id)
id := line.new(x1, y1, time, y2, xloc.bar_time, extend.right, _color)
highLine = f_line(timeSinceHigh, highLevel, highLevel, currentColorR)
lowLine = f_line(timeSinceLow, lowLevel, lowLevel, currentColorS)
// === USE ADR FOR FILTERING ===
// The idea here is that you want to buy in a consolodating range for best risk/reward. So here you can compare the current distance between
// support/resistance vs. the ADR and make sure you aren't buying at a point that is too extended.
useAdrFilter = input.bool(title = "Use ADR for Filtering?", defval = false, group = "adr filtering",
tooltip = "Signals will be ignored if the distance between support and resistance is larger than a user-defined percentage of ADR (or monthly volatility
in the stock screener). This allows the user to ensure they are not buying something that is too extended and instead focus on names that are consolidating more.")
adrPerc = input.int(defval = 120, title = "% of ADR Value", minval = 1, group = "adr filtering")
tableLocation = input.string(defval="Bottom", options=["Top", "Bottom"], title = "ADR Table Visibility", group = "adr filtering",
tooltip = "Place ADR table on the top of the pane, the bottom of the pane, or off.")
adrValue = request.security(syminfo.tickerid, "D", ta.sma((high-low)/math.abs(low) * 100, 21), barmerge.gaps_off, barmerge.lookahead_on) // Monthly Volatility in Stock Screener (also ADR)
adrCompare = (adrPerc * adrValue) / 100
// == ADR TABLE ==
tablePos = tableLocation == "Top" ? position.top_right : position.bottom_right
var table adrTable = table.new(tablePos, 2, 1, border_width = 3)
lightTransp = 90
avgTransp = 80
heavyTransp = 70
posColor = color.rgb(38, 166, 154)
negColor = color.rgb(240, 83, 80)
volColor = color.new(#999999, 0)
f_fillCellVol(_table, _column, _row, _value) =>
_transp = math.abs(_value) > 7 ? heavyTransp : math.abs(_value) > 4 ? avgTransp : lightTransp
_cellText = str.tostring(_value, "0.00") + "%\n" + "ADR"
table.cell(_table, _column, _row, _cellText, bgcolor = color.new(volColor, _transp), text_color = volColor, width = 6)
srDistance = (highLevel - lowLevel)/highLevel * 100
f_fillCellCalc(_table, _column, _row, _value) =>
_c_color = _value >= adrCompare ? negColor : posColor
_transp = _value >= adrCompare*0.8 and _value <= adrCompare*1.2 ? lightTransp :
_value >= adrCompare*0.5 and _value < adrCompare*0.8 ? avgTransp :
_value < adrCompare*0.5 ? heavyTransp :
_value > adrCompare*1.2 and _value <= adrCompare*1.5 ? avgTransp :
_value > adrCompare*1.5 ? heavyTransp : na
_cellText = str.tostring(_value, "0.00") + "%\n" + "Range"
table.cell(_table, _column, _row, _cellText, bgcolor = color.new(_c_color, _transp), text_color = _c_color, width = 6)
if barstate.islast
f_fillCellVol(adrTable, 0, 0, adrValue)
f_fillCellCalc(adrTable, 1, 0, srDistance)
// Conditions for entry and exit
buyConditions = (useMaFilter ? highLevel > maFilter : true) and
(useMaFilter2 ? highLevel > maFilter2 : true) and
(useAdrFilter ? highLevel - lowLevel < adrValue : true) and
(useRsiFilter ? rsiVal[1] < rsiOB : true) and
time > Start and time < Finish
// (STRATEGY ONLY) Comment out for Study
strategy.entry('Long', strategy.long, stop=highLevel, when=buyConditions)
// strategy.entry("Long", strategy.long, stop = buyLevel2, when = time > Start and time < Finish and high > maFilterCheck)
strategy.exit('Exit Long', from_entry='Long', stop=lowLevel)
strategy.cancel('Long', when=not(buyConditions)) // Cancels resting orders when new swing high is printed below filters.
Expand (149 lines)
Overview
Breakout Trend Follower places the stop at the recent swing low and trails that stop upward as higher lows form, exiting when a higher low is breached. A pivot lookback sets how swings are found. Optional filters skip setups below a current-timeframe or higher-timeframe moving average, or when RSI or average daily range shows the move is too extended. Users set the backtest window and can show historical pivots. It recalculates on every tick, so signals can change on the live bar.
Swing-high breakout long entries
Trailing stops at higher swing lows
Current and higher-timeframe moving-average filters
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
Backtest Start Date
time
timestamp('01 Jan 2019 06:00 +0000')
Start
Backtest End Date
time
timestamp('01 Jan 2100 00:00 +0000')
Finish
Pivot Lookback
int
3
pvtLb
Show Historical Pivot Points?
bool
false
showPivotPoints
Current Range S/R Colors: Support
color
color.new(color.orange,50)
currentColorS
Resistance
color
color.new(color.blue,50)
currentColorR
Use Current Timeframe Moving Average for Filtering?
bool
true
useMaFilter
MA Type For Filtering
string
SMA
maType
MA Period for Filtering
int
50
maLength
Color
color
color.new(color.purple, 60)
ma1Color
Use Multi-Timeframe Moving Average for Filtering?
bool
false
useMaFilter2
Moving Average Time Frame
timeframe
D
tfSet
Show all 21 settings
Setting
Type
Default
Variable
MA Type For Filtering
string
SMA
ma2Type
MA Period for Filtering
int
50
ma2Length
Color
color
color.new(color.yellow, 60)
ma2Color
Use RSI for Filtering?
bool
false
useRsiFilter
RSI Timeframe
timeframe
rsiTf
RSI Overbought Level
int
70
rsiOB
Use ADR for Filtering?
bool
false
useAdrFilter
% of ADR Value
int
120
adrPerc
ADR Table Visibility
string
Bottom
tableLocation
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 plots running pivot highs as red R circles and pivot lows as blue S circles directly on the price chart. It computes an EMA 3 and a Cto trend line from close prices, then generates long signals on upward EMA-Cto crossovers combined with price pos
This strategy executes trades on short-term cryptocurrency charts using a combination of pivot support and resistance levels and a multi-pole smoothed trend filter. Entries trigger when price crosses the smoothed trend line and confirms above or below a short-
This strategy identifies trend retracements and breakout entries using an adjustable moving average ribbon alongside higher-timeframe anchored moving averages, fractal pivots, and support and resistance level extensions. Bar colors can be customized using a 3-
The Pivot Trendlines strategy identifies swing pivots on the price chart using a configurable swing lookback period and draws trendlines connecting these pivots. It generates buy and sell signals based on three-move patterns with user-defined move sizes, filte
RR Dangov is a price-chart strategy that combines optional confluence modules for entries. The trader selects a primary and a secondary source from Guppy moving averages, VWAP, an opening-range breakout, Supertrend, or CPR, and can add WaveTrend, stochastic, a
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