I'm building an indicator that visualizes candle volume per bin on a higher timeframe (HTF), like the classic "HTF Candle Volume Thermometer".
My PineScript version uses request.security()
to get HTF values and works fine. I'm trying to convert this to Indie, and I'm stuck using @sec_context
and MutSeriesF
properly.
Here are my goals:
- Use
@sec_context('timeframe')
to calculate HTF open/close values. - Access those values in the main indicator function.
- Use
MutSeriesF
to track evolving data like high, low, and volume. - Avoid invalid operations or restricted syntax (like
global
orlist comprehension
).
Errors Encountered
MutSeriesF.new(...) outside context:
Error: `indie.MutSeriesF.new` is a syntactic sugar function in Indie and can only be called from a function decorated with @indie.algorithm, @indie.sec_context or @indie.indicator
Use of global
Error: 11:4 `global` statements are prohibited
self.security(...) not recognized
Error: 13:15 symbol `self.security` not found
Current code.
I tried using @sec_context
to get HTF values and store them in MutSeriesF
variables declared outside the function (but this triggered error #1 and #2). Then I tried using self.security(...)
, but that seems not to exist in Indie.
# indie:lang_version = 5
from indie import indicator, param, color, MutSeriesF, plot, sec_context
from indie.algorithms import Atr
from indie.color import LIME, RED, YELLOW
open_htf = MutSeriesF.new(0)
close_htf = MutSeriesF.new(0)
@sec_context('timeframe')
def Htf(self):
open_htf[0] = self.open[1]
close_htf[0] = self.close[1]
@indicator('HTF Candle Volume Thermometer', overlay_main_pane=True)
@param.str('timeframe', default='D', title='HTF Timeframe')
@param.str('resolution', default='Mid', options=['High', 'Mid', 'Low'], title='Resolution')
@plot.line(id='top', color=color.GRAY)
@plot.line(id='bottom', color=color.GRAY)
@plot.fill('top', 'bottom')
def Main(self, timeframe, resolution):
htf_high = MutSeriesF.new(self.high[0])
htf_low = MutSeriesF.new(self.low[0])
bars_volume = MutSeriesF.new(self.volume[0])
bar_index0 = self.index
is_new_htf_bar = self.index > 0 and self.time[0] != self.time[1]
if is_new_htf_bar:
htf_high[0] = self.high[0]
htf_low[0] = self.low[0]
bars_volume[0] = self.volume[0]
bar_index0 = self.index
else:
htf_high[0] = max(htf_high[1], self.high[0])
htf_low[0] = min(htf_low[1], self.low[0])
bars_volume[0] = bars_volume[1] + self.volume[0]
div = 3
if resolution == 'High':
div = 5
elif resolution == 'Low':
div = 1
step = Atr.new(200)[0] / div
box_size = htf_high[0] - htf_low[0]
levels = int(box_size / step)
bin = box_size / levels if levels > 0 else 1
bins = []
for _ in range(levels):
bins.append(0.0)
for i in range(self.index - bar_index0):
for j in range(levels):
lo = htf_low[0] + bin * j
hi = lo + bin
c = self.close[i]
if lo <= c and c <= hi:
bins[j] += self.volume[i]
min_vol = min(bins)
max_vol = max(bins)
top = MutSeriesF.new(0)
bottom = MutSeriesF.new(0)
max_index = 0
max_value = 0
for i in range(levels):
lo = htf_low[0] + bin * i
hi = lo + bin
vol = bins[i]
if vol > max_value:
max_value = vol
max_index = i
for i in range(levels):
lo = htf_low[0] + bin * i
hi = lo + bin
vol = bins[i]
norm = (vol - min_vol) / (max_vol - min_vol) if max_vol > min_vol else 0
c_up = LIME.alpha(0.8 * (1 - norm))
c_dn = RED.alpha(0.8 * (1 - norm))
fill_color = YELLOW if i == max_index else (c_up if close_htf[0] > open_htf[0] else c_dn)
top[0] = hi
bottom[0] = lo
return top[0], bottom[0]
What is the correct way to:
- Use HTF series (like
open[1]
,close[1]
) from another timeframe. - Pass those values safely into the
@indicator
function. - Declare
MutSeriesF
safely across contexts without using global or invalid scope.