FVBO code Version 1 for Tradingview

fvbo strategy Feb 15, 2021

I've been quiet for about a week now in your inbox and on Twitter, mostly because we nailed that selloff dead on! And there's nothing I love more than forgetting to do a big ol' victory lap!

Most importantly I hope we got people out of too much long exposure and maybe some of you more fast money types nailed the short. 

One of our amazing Pollinate Lab community members Abhay coded up the FVBO for Tradingview. It's just the first version and yeah, we have some improving to do on it, just like any good project does. Continuous Improvement is a cornerstone of my belief system, especially in product development! 


I'm back in action this week so hopefully we'll have some good trading as we get positioned for Q42020 setups.

Here's the code:

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © monikabhay

//@version=4

//*************************************************************************************************************************************
strategy(title="FVBO 6.0", shorttitle="FVBO", overlay=true)
//*************************************************************************************************************************************

// input variables
bbLength = input(title="BB Length", type=input.integer, minval=1, defval=20)
bbStdDev = input(title="BB StdDev", type=input.integer, minval=1, defval=2)
kcLength = input(title="KC Length", type=input.integer, minval=1, defval=20)
kcMult = input(title="KC Mult", type=input.float, defval=1.5)
atrLength = input(title="ATR Length", type=input.integer, minval=1, defval=20)

fund = input(title="Fund to Trade", type=input.float, minval=1, defval=25000, step=100)
risk_limit = input(title="Risk Limit (%)", type=input.float, minval=0.5, defval=1.0, step=0.1)
reward_limit = input(title="Risk : Reward", type=input.float, minval=0.5, defval=1.5, step=0.1)
original_sl_type = input(title="Original SL Based on", defval="Close Price", options=["Close Price","Last Traded Price"])

dist_from_compression = input(title="Entry distance from volatility compression", type=input.integer, minval=1, maxval=20, defval=10, step=1)
dist_from_expansion = input(title="Entry distance from volatility expansion", type=input.integer, minval=1, maxval=10, defval=5, step=1)

exit_1_pft_pct = input(title="1st exit when reward is", type=input.float, minval=0.5, maxval=100, defval=1.0, step=0.1)
exit_1_qty_pct = input(title="1st exit quantity %", type=input.float, minval=1, maxval=100, defval=100, step=5)
exit_2_pft_pct = input(title="2nd exit when reward is", type=input.float, minval=0, maxval=100, defval=0, step=0.1)
exit_2_qty_pct = input(title="2nd exit quantity %", type=input.float, minval=0, maxval=100, defval=0, step=5)
sl_trail_pct = input(title="Trailing SL compared to original SL", type=input.float, minval=0.1, maxval=100, defval=0, step=0.1)

plotBB = input(title="Show BB", type=input.bool, defval=true)
plotKC = input(title="Show KC", type=input.bool, defval=true)
plotSignals = input(title="Show Signals", type=input.bool, defval=true)
fillKC = input(title="Fill KC", type=input.bool, defval=true)
showLevels = input(title="Show Levels", type=input.bool, defval=false)

// variables to be used for current candle
long_entry = false
short_entry = false
risk_reward_ok = false
sl_hit_flag = false

// variables to carry value acrros candles
var bb_within_kc = false
var bb_kc_count = 0
var closed_above_bb = false
var closed_below_bb = false
var outside_bb_count = 0
var entry_price = 0.0
var sl_price = 0.0
var qty = 0
var exit_1_qty = 0
var exit_2_qty = 0
var exit_3_qty = 0
var exit_1_price = 0.0
var exit_2_price = 0.0
var hold_high = 0.0
var hold_low = 0.0
var tsl_size = 0.0
var sl_size = 0.0

TickValue = syminfo.mintick == 0.01 ? 10 : syminfo.mintick == 0.001 ? 100 : syminfo.mintick == 0.0001 ? 1000 : syminfo.mintick == 0.00001 ? 10000 : 1

//*************************************************************************************************************************************
// strategy conditions
//*************************************************************************************************************************************
// get current candle BB and KC values

[mBB0,uBB0,lBB0] = bb(close,bbLength,bbStdDev)

mKC0 = ema(close,kcLength)
range0 = kcMult * atr(atrLength)
uKC0 = mKC0 + range0
lKC0 = mKC0 - range0

// check if BB is within KC
if uBB0 < uKC0 or lBB0 > lKC0
bb_within_kc := true
bb_kc_count := 0
outside_bb_count := 0

// keep a candle count after last bb within kc
if bb_within_kc and uBB0 > uKC0 and lBB0 < lKC0
bb_kc_count := bb_kc_count + 1

// if candle count after last bb within kc is greater than N then mark the set up as invalid
if bb_kc_count > dist_from_compression
bb_within_kc := false

// check if a candle closes above BB and KC 
if bb_within_kc and close > uKC0 and close > uBB0
closed_above_bb := true
closed_below_bb := false // avoid overlapping signals

// check if a candle closes below BB and KC
if bb_within_kc and close < lKC0 and close < lBB0
closed_below_bb := true
closed_above_bb := false // avoid overlapping signals


// if candle keeps closing outside BB and KC for continuous N candles then mark the set up as invalid
if closed_above_bb or closed_below_bb
outside_bb_count := outside_bb_count + 1

if outside_bb_count > dist_from_expansion
bb_within_kc := false
closed_above_bb := false
closed_below_bb := false

//*************************************************************************************************************************************
// decide entry price SL and target price
//*************************************************************************************************************************************
if strategy.position_size == 0 and closed_above_bb
short_entry := true
entry_price := low - syminfo.mintick
sl_price := high + syminfo.mintick
sl_size := abs(entry_price - sl_price)
tsl_size := abs(entry_price - sl_price)*sl_trail_pct

if strategy.position_size == 0 and closed_below_bb
long_entry := true
entry_price := high + syminfo.mintick
sl_price := low - syminfo.mintick
sl_size := abs(entry_price - sl_price)
tsl_size := abs(entry_price - sl_price)*sl_trail_pct

// risk evaluation to check Risk:Reward based on values mentioned in settings
// entry level to middle BB distance should be N times of sl size where N is controllable from settings
risk_reward_ok := long_entry ? (mBB0 - entry_price) >= ((entry_price - sl_price) * reward_limit) :
(short_entry ? ((entry_price - mBB0) >= ((sl_price - entry_price) * reward_limit)) : false)

// if Risk:Reward is not as per defined value then do not place order
if not risk_reward_ok
long_entry := false
short_entry := false

//*************************************************************************************************************************************
// place order for entry, SL and target
//*************************************************************************************************************************************

// decide quantity and price for phased exit
// quantity to be decided based on 'Risk Limit' and 'Fund To Trade' defined in settings
if (long_entry or short_entry) and strategy.position_size == 0
qty := floor((fund*(risk_limit/100))/((entry_price - sl_price)*TickValue*syminfo.pointvalue))
exit_1_qty := round(qty * (exit_1_qty_pct/100))
exit_2_qty := round(qty * (exit_2_qty_pct/100))
exit_3_qty := qty - (exit_1_qty + exit_2_qty)
if long_entry
exit_1_price := entry_price + (sl_size * exit_1_pft_pct)
exit_2_price := entry_price + (sl_size * exit_2_pft_pct)
if short_entry
exit_1_price := entry_price - (sl_size * exit_1_pft_pct)
exit_2_price := entry_price - (sl_size * exit_2_pft_pct)

//plot(sl_size, color=color.orange)

// if quantity is less than 1 then no trade
if qty < 1
long_entry := false
short_entry := false

// trail SL after 1st target is hit
if abs(strategy.position_size) == 0
hold_high := 0
hold_low := 0

if strategy.position_size > 0 and high > exit_1_price and abs(strategy.position_size) < qty
if high > hold_high or hold_high == 0
hold_high := high
sl_price := hold_high - tsl_size

if strategy.position_size < 0 and low < exit_1_price and abs(strategy.position_size) < qty

if low < hold_low or hold_low == 0
hold_low := low
sl_price := hold_low + tsl_size

// entry
if long_entry and strategy.position_size == 0
strategy.cancel("BUY", true)
strategy.order("BUY", strategy.long, qty, stop=entry_price, comment="BUY @ "+ tostring(entry_price))

if short_entry and strategy.position_size == 0
strategy.cancel("SELL", true)
strategy.order("SELL", strategy.short, qty, stop=entry_price, comment="SELL @ "+ tostring(entry_price))

// exit at SL
sl_hit_flag := false

if strategy.position_size > 0 and original_sl_type == "Last Traded Price"
strategy.cancel("EXIT at SL", true)
strategy.order("EXIT at SL", strategy.short, abs(strategy.position_size), stop=sl_price, comment="EXIT SL @ "+ tostring(sl_price))
closed_above_bb := false
closed_below_bb := false

if strategy.position_size < 0 and original_sl_type == "Last Traded Price"
strategy.cancel("EXIT at SL", true)
strategy.order("EXIT at SL", strategy.long, abs(strategy.position_size), stop=sl_price, comment="EXIT SL @ "+ tostring(sl_price))
closed_above_bb := false
closed_below_bb := false

if strategy.position_size > 0 and original_sl_type == "Close Price" and close < sl_price
strategy.order("EXIT at SL", strategy.short, abs(strategy.position_size), comment="EXIT SL @ "+ tostring(sl_price))
closed_above_bb := false
closed_below_bb := false
sl_hit_flag := true
strategy.cancel("EXIT 1", true)
strategy.cancel("EXIT 2", true)

if strategy.position_size < 0 and original_sl_type == "Close Price" and close > sl_price
strategy.order("EXIT at SL", strategy.long, abs(strategy.position_size), comment="EXIT SL @ "+ tostring(sl_price))
closed_above_bb := false
closed_below_bb := false 
sl_hit_flag := true
strategy.cancel("EXIT 1", true)
strategy.cancel("EXIT 2", true)

// exit at target
if strategy.position_size > 0 and abs(strategy.position_size) == qty and not sl_hit_flag
strategy.cancel("EXIT 1", true)
strategy.order("EXIT 1", strategy.short, exit_1_qty, limit=exit_1_price, comment="EXIT TG1 @ "+ tostring(exit_1_price))
closed_above_bb := false
closed_below_bb := false

if strategy.position_size > 0 and abs(strategy.position_size) < qty and abs(strategy.position_size) > exit_3_qty and not sl_hit_flag
strategy.cancel("EXIT 2", true)
strategy.order("EXIT 2", strategy.short, exit_2_qty, limit=exit_2_price, comment="EXIT TG2 @ "+ tostring(exit_2_price))
closed_above_bb := false
closed_below_bb := false

if strategy.position_size < 0 and abs(strategy.position_size) == qty and not sl_hit_flag
strategy.cancel("EXIT 1", true)
strategy.order("EXIT 1", strategy.long, exit_1_qty, limit=exit_1_price, comment="EXIT TG1 @ "+ tostring(exit_1_price))
closed_above_bb := false
closed_below_bb := false

if strategy.position_size < 0 and abs(strategy.position_size) < qty and abs(strategy.position_size) > exit_3_qty and not sl_hit_flag
strategy.cancel("EXIT 2", true)
strategy.order("EXIT 2", strategy.long, exit_2_qty, limit=exit_2_price, comment="EXIT TG2 @ "+ tostring(exit_2_price))
closed_above_bb := false
closed_below_bb := false

// cancel all pending orders if the trade is booked
strategy.cancel_all(strategy.position_size == 0 and not (long_entry or short_entry))

//*************************************************************************************************************************************
// plots indicators
//*************************************************************************************************************************************
// plot BB
p_mBB = plot(plotBB ? mBB0 : na, color=color.teal, transp=0)
p_uBB = plot(plotBB ? uBB0 : na, color=color.teal, transp=0, style=plot.style_stepline)
p_lBB = plot(plotBB ? lBB0 : na, color=color.teal, transp=0, style=plot.style_stepline)

// plot KC
p_uKC = plot(plotKC ? uKC0 : na, color=color.red, transp=0)
p_lKC = plot(plotKC ? lKC0 : na, color=color.red, transp=0)

fillKC_color = color.red
if not fillKC
fillKC_color := na

fill(p_uKC, p_lKC, color=fillKC_color, transp=97)

// plot signals
plotshape(plotSignals and closed_above_bb, style=shape.triangledown, location=location.abovebar, color=color.red)
plotshape(plotSignals and closed_below_bb, style=shape.triangleup, location=location.belowbar, color=color.green)

// plot SL, entry and targets
plotchar(strategy.position_size != 0 and showLevels ? entry_price : na, char= '-', location=location.absolute, color=color.blue, size=size.small)
plotchar(strategy.position_size != 0 and showLevels ? sl_price : na, char= '-', location=location.absolute, color=color.red, size=size.small)
plotchar(strategy.position_size != 0 and showLevels ? exit_1_price : na, char= '-', location=location.absolute, color=color.green, size=size.small)
plotchar(strategy.position_size != 0 and showLevels ? exit_2_price : na, char= '-', location=location.absolute, color=color.green, size=size.small)

if strategy.position_size != 0 and strategy.position_size[1] == 0 and showLevels

label.new(bar_index, entry_price, style=label.style_label_right, size=size.small, color=color.new(color.blue, 40), text=tostring(entry_price,'0.00'), textcolor=color.black)
label.new(bar_index, sl_price, style=label.style_label_right, size=size.small, color=color.new(color.red, 40), text=tostring(sl_price, '0.00'), textcolor=color.black)
label.new(bar_index, exit_1_price, style=label.style_label_right, size=size.small, color=color.new(color.green, 40), text=tostring(exit_1_price, '0.00'), textcolor=color.black)
label.new(bar_index, exit_2_price, style=label.style_label_right, size=size.small, color=color.new(color.green, 40), text=tostring(exit_2_price, '0.00'), textcolor=color.black)

//*************************************************************************************************************************************
// end of program
//*************************************************************************************************************************************

Stay connected with news and updates!

Join our mailing list to receive the latest news and updates from our team.
Don't worry, your information will not be shared.

We hate SPAM. We will never sell your information, for any reason.