The latest version of the Daily Range
script on TradingView looks like this:
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/// © AndreSolbach
//@version=5
indicator(title="Daily Range", precision=2, overlay=true)
days_used_for_calculation = input.int(defval=50, title="Days used for calculation", minval=1, tooltip="How many past days should be used to calculate the Daily Range", group="Settings")
text_color = input.color(defval=color.rgb(233, 30, 99, 0), title="Text color", tooltip="Color of the Daily Range value", group="Settings")
block_mult = 0.0
var1 = false
if barstate.islast
var1 := true
if (syminfo.mintick == 0.00001) or ((syminfo.mintick == 0.001) and str.contains(syminfo.ticker, "JPY"))
block_mult := syminfo.mintick * 10
else if (syminfo.mintick == 0.01)
block_mult := syminfo.mintick * 100
else if (syminfo.mintick == 0.0000001)
block_mult := syminfo.mintick * 10000000
else if (syminfo.mintick == 1.0)
block_mult := syminfo.mintick * 1
else
block_mult := syminfo.mintick / syminfo.mintick
calcResult_ = ((1 / block_mult) * (math.sum(high-low, days_used_for_calculation)) / (days_used_for_calculation))
calcResult = request.security(syminfo.tickerid, "D", calcResult_[0] , barmerge.gaps_off, barmerge.lookahead_on)
plot(var1 ? calcResult : na, color=text_color, display=display.status_line, editable=false)
The first step in rewriting it in Indie is to create a class Main
(decorated with @indicator
) for the main instrument and a function HighLowSma
(decorated with @sec_context
) for the 1-day time frame. Accordingly, the code that calculates calcResult_
should be placed in HighLowSma
:
@sec_context
def HighLowSma(self):
# calculating calcResult_
@indicator('Daily Range')
class Main(MainContext):
def __init__(self):
self._high_low_sma = self.calc_on(time_frame=TimeFrame.from_str('1D'), sec_context=HighLowSma, lookahead=True)
def calc(self):
return self._high_low_sma[0]
Using Indie syntax, the body of HighLowSma
becomes this:
def HighLowSma(self, days_used_for_calculation):
block_mult = nan
if self.is_last_bar:
if self.info.tick_size == 0.00001 or (self.info.tick_size == 0.001 and 'JPY' in self.info.ticker):
block_mult = self.info.tick_size * 10
elif self.info.tick_size == 0.01:
block_mult = self.info.tick_size * 100
elif self.info.tick_size == 0.0000001:
block_mult = self.info.tick_size * 10000000
elif self.info.tick_size == 1.0:
block_mult = self.info.tick_size * 1
else:
block_mult = self.info.tick_size / self.info.tick_size
return 1 / block_mult * Sum.new(MutSeriesF.new(self.high[0] - self.low[0]), days_used_for_calculation)[0] / days_used_for_calculation
After adding all the necessary decorators and imports, the code becomes this:
# indie:lang_version = 5
from math import nan
from indie import indicator, sec_context, param, format, MutSeriesF, param_ref, MainContext, TimeFrame, plot, color
from indie.algorithms import Sum
@sec_context
@param_ref('days_used_for_calculation')
def HighLowSma(self, days_used_for_calculation):
block_mult = nan
if self.is_last_bar:
if self.info.tick_size == 0.00001 or self.info.tick_size == 0.001 and 'JPY' in self.info.ticker:
block_mult = self.info.tick_size * 10
elif self.info.tick_size == 0.01:
block_mult = self.info.tick_size * 100
elif self.info.tick_size == 0.0000001:
block_mult = self.info.tick_size * 10000000
elif self.info.tick_size == 1.0:
block_mult = self.info.tick_size * 1
else:
block_mult = self.info.tick_size / self.info.tick_size
return 1 / block_mult * Sum.new(MutSeriesF.new(self.high[0] - self.low[0]), days_used_for_calculation)[0] / days_used_for_calculation
@indicator('Daily Range', format=format.PRICE, precision=2, overlay_main_pane=True)
@param.int('days_used_for_calculation', default=50, min=1, title='Days used for calculation')
@plot.line(color=color.rgba(233, 30, 99), display_options=plot.LineDisplayOptions(status_line=True))
class Main(MainContext):
def __init__(self):
self._high_low_sma = self.calc_on(time_frame=TimeFrame.from_str('1D'), sec_context=HighLowSma, lookahead=True)
def calc(self):
return self._high_low_sma[0] if self.is_last_bar else nan
Note: This indicator requests daily data for 50 days, so on lower timeframes (e.g., 1 minute), there may not be enough historical bars, resulting in nan
values in the indicator’s output data. On a 1-hour chart, however, the history depth should be sufficient to cover the requested period without issues.
In addition, the HighLowSma
code can be simplified: all the if
statements except the first one set block_mult
to 1.0
, and Sum.new(..., len)[0] / len
can be rewritten as Sma.new(..., len)[0]
. With a little refactoring, the code can become:
# indie:lang_version = 5
from math import nan
from indie import indicator, sec_context, param, format, MutSeriesF, param_ref, MainContext, TimeFrame, plot, color
from indie.algorithms import Sma
@sec_context
@param_ref('days_used_for_calculation')
def HighLowSma(self, days_used_for_calculation):
block_mult = nan
if self.is_last_bar:
block_mult = 1.0
if self.info.tick_size == 0.00001 or self.info.tick_size == 0.001 and 'JPY' in self.info.ticker:
block_mult = self.info.tick_size * 10
return 1 / block_mult * Sma.new(MutSeriesF.new(self.high[0] - self.low[0]), days_used_for_calculation)[0]
@indicator('Daily Range', format=format.PRICE, precision=2, overlay_main_pane=True)
@param.int('days_used_for_calculation', default=50, min=1, title='Days used for calculation')
@plot.line(color=color.rgba(233, 30, 99), display_options=plot.LineDisplayOptions(status_line=True))
class Main(MainContext):
def __init__(self):
self._high_low_sma = self.calc_on(time_frame=TimeFrame.from_str('1D'), sec_context=HighLowSma, lookahead=True)
def calc(self):
return self._high_low_sma[0] if self.is_last_bar else nan
With that, the Daily Range indicator is fully ported to Indie. The final version is cleaner, easier to maintain, and uses Indie’s composable architecture for clarity and efficiency. Now it’s ready for production use or further customization.
Be the first to comment
Publish your first comment to unleash the wisdom of crowd.