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

//This code must be applied to a candle graph (not a renko one)
//Interactive Broker fees are applied on this strategy and a realistic slippage is set to simulate real market conditions
//@version=5
strategy("RENKO BACKTESTING", overlay=false, initial_capital=1000, commission_type=strategy.commission.percent, commission_value=0.18, slippage=3)


//------------------------------TOOL TIPS--------------------------------//

t1 = "Each gain or losse (relative to the previous reference) in an amount equal to this fixed ratio will change quantity of orders."
t2 = "The amount of money to be added to or subtracted from orders once the fixed ratio has been reached."


//------------------------------FUNCTIONS---------------------------------//

//@function Displays text passed to `txt` when called.
debugLabel(txt, color) =>
    label.new(bar_index, high, text = txt, color=color, style = label.style_label_lower_right, textcolor = color.black, size = size.small)

//@function which looks if the close date of the current bar falls inside the date range
inBacktestPeriod(start, end) => (time >= start) and (time <= end)


//----------------------------USER INPUTS---------------------------------//

//User inputs to choose the source and the box size
source = input.source(defval=close, title='Base price', group="Technical parameters")
box_size = input.float(title='Box size', defval=10.0, minval=0.00001, group="Technical parameters")
//User inputs to manage money : 
//Every gains of fixedRatio we increase orders by increasingOrderAmount and every losses of fixedRatio we decrease the quantity to buy/sell by increasingOrderAmount
fixedRatio = input.int(defval=400, minval=1, title="Fixed Ratio Value ($)", group="Money Management", tooltip=t1)
increasingOrderAmount = input.int(defval=200, minval=1, title="Increasing Order Amount ($)", group="Money Management", tooltip=t2)
//User inputs to choose the backtesting date
startDate = input.time(title="Start Date", defval=timestamp("1 Jan 2013 00:00:00"), group="Backtesting Period")
endDate = input.time(title="End Date", defval=timestamp("1 July 2024 00:00:00"), group="Backtesting Period")


//----------------------------VARIABLES INITIALISATION-------------------------------//

//The var variables are used to store data for the next script execution (next candle)
renko_high = array.new_float(12, na)
renko_low = array.new_float(12, na)
renko_color = array.new_color(12, na)
int array_lenght = na
var float last_ref_high = close
var float last_ref_low = close - box_size
var color last_ref_color = color.lime
bool inRange = na
equity = math.abs(strategy.equity - strategy.openprofit)
var float capital_ref = strategy.initial_capital
var float cashOrder = strategy.initial_capital * 0.95


//----------------------------CHECKING SOME CONDITIONS ON EACH SCRIPT EXECUTION---------------------//

//Checking if the date belong to the range
inRange := inBacktestPeriod(startDate, endDate)

//Checking performances of the strategy to adjust order quantity
if equity > capital_ref + fixedRatio
    spread = (equity - capital_ref)/fixedRatio
    nb_level = int(spread)
    increasingOrder = nb_level * increasingOrderAmount
    cashOrder := cashOrder + increasingOrder
    capital_ref := capital_ref + nb_level*fixedRatio
if equity < capital_ref - fixedRatio
    spread = (capital_ref - equity)/fixedRatio
    nb_level = int(spread)
    decreasingOrder = nb_level * increasingOrderAmount
    cashOrder := cashOrder - decreasingOrder
    capital_ref := capital_ref - nb_level*fixedRatio

// Checking if we close all trades in case where we exit the backtesting period
if strategy.position_size!=0 and not inRange
    debugLabel("END OF BACKTESTING PERIOD : we close the trade", color=color.rgb(116, 116, 116))
    strategy.close_all()


//--------------------------SCRIPT EXECUTION AND CALCULATION---------------------------//

if (source - last_ref_high)/box_size >1
    spread = (source - last_ref_high)/box_size
    nb_box = int(spread)
    for i=1 to nb_box
        if i <= 12
            array.set(renko_high, i-1, last_ref_high + (i * box_size))
            array.set(renko_low, i-1, last_ref_low + (i * box_size))
            array.set(renko_color, i-1, color.lime)
        else
            array.push(renko_high, last_ref_high + (i * box_size))
            array.push(renko_low, last_ref_low + (i * box_size))
            array.push(renko_color, color.lime)
    array_lenght := array.size(renko_high)
    //We check the direction of our position
    if strategy.position_size<=0 and inRange
        //If we were in a short position, we pass to a long position
        debugLabel("Long entry order created at " + str.tostring(array.get(renko_high, 0)), color=color.rgb(78, 188, 135))
        qty = cashOrder/close
        strategy.entry("Long entry", strategy.long, qty)

else if (last_ref_low - source)/box_size >1
    spread = (last_ref_low - source)/box_size
    nb_box = int(spread)
    for i=1 to nb_box
        if i <= 12
            array.set(renko_high, i-1, last_ref_high - (i * box_size))
            array.set(renko_low, i-1, last_ref_low - (i * box_size))
            array.set(renko_color, i-1, color.red)
        else
            array.push(renko_high, last_ref_high - (i * box_size))
            array.push(renko_low, last_ref_low - (i * box_size))
            array.push(renko_color, color.red)
    array_lenght := array.size(renko_high)
    //We check the direction of our position
    if strategy.position_size>=0 and inRange
        debugLabel("Short entry order created at " + str.tostring(array.get(renko_low, 0)), color=color.rgb(252, 81, 81))
        qty = cashOrder/close
        strategy.entry("Short entry", strategy.short, qty)

else
    array.set(renko_high, 0, last_ref_high)
    array.set(renko_low, 0, last_ref_low)
    array.set(renko_color, 0, last_ref_color)
    array_lenght := array.size(renko_high)

for i = (array_lenght-1) to 0
    if not na(array.get(renko_high, i))
        last_ref_high := array.get(renko_high, i)
        break
for i = (array_lenght-1) to 0
    if not na(array.get(renko_low, i))
        last_ref_low := array.get(renko_low, i)
        break
for i = (array_lenght-1) to 0
    if not na(array.get(renko_color, i))
        last_ref_color := array.get(renko_color, i)
        break


//--------------------------PLOTTING BOX ELEMENT----------------------------//

//We plot the first 9 candles and the last 3 candles. Tranding view limit us to plot 64 data by candles. Here we plot 5x12 = 60 data
plotcandle(array.get(renko_high, 0), array.get(renko_high, 0), array.get(renko_low, 0), array.get(renko_low, 0), color=array.get(renko_color, 0))
plotcandle(array.get(renko_high, 1), array.get(renko_high, 1), array.get(renko_low, 1), array.get(renko_low, 1), color=array.get(renko_color, 1))
plotcandle(array.get(renko_high, 2), array.get(renko_high, 2), array.get(renko_low, 2), array.get(renko_low, 2), color=array.get(renko_color, 2))
plotcandle(array.get(renko_high, 3), array.get(renko_high, 3), array.get(renko_low, 3), array.get(renko_low, 3), color=array.get(renko_color, 3))
plotcandle(array.get(renko_high, 4), array.get(renko_high, 4), array.get(renko_low, 4), array.get(renko_low, 4), color=array.get(renko_color, 4))
plotcandle(array.get(renko_high, 5), array.get(renko_high, 5), array.get(renko_low, 5), array.get(renko_low, 5), color=array.get(renko_color, 5))
plotcandle(array.get(renko_high, 6), array.get(renko_high, 6), array.get(renko_low, 6), array.get(renko_low, 6), color=array.get(renko_color, 6))
plotcandle(array.get(renko_high, 7), array.get(renko_high, 7), array.get(renko_low, 7), array.get(renko_low, 7), color=array.get(renko_color, 7))
plotcandle(array.get(renko_high, 8), array.get(renko_high, 8), array.get(renko_low, 8), array.get(renko_low, 8), color=array.get(renko_color, 8))
plotcandle(array.get(renko_high, array_lenght-3), array.get(renko_high, array_lenght-3), array.get(renko_low, array_lenght-3), array.get(renko_low, array_lenght-3), color=array.get(renko_color, array_lenght-3))
plotcandle(array.get(renko_high, array_lenght-2), array.get(renko_high, array_lenght-2), array.get(renko_low, array_lenght-2), array.get(renko_low, array_lenght-2), color=array.get(renko_color, array_lenght-2))
plotcandle(array.get(renko_high, array_lenght-1), array.get(renko_high, array_lenght-1), array.get(renko_low, array_lenght-1), array.get(renko_low, array_lenght-1), color=array.get(renko_color, array_lenght-1))
