Up until now, drawing on the chart (lines, labels, annotations, etc.) was possible only manually through the UI. That limited how flexible and expressive your indicators could be.
This update introduces support for non-series drawings in Indie™ — allowing you to programmatically render visual elements on the chart in a fully dynamic, condition-based way. Instead of drawing something on every bar (as with traditional plots), you can now render visuals only when and where they matter.
Indie now supports three distinct ways to render visual content:
The traditional way of showing indicator values:
# indie:lang_version = 5from indie import indicator, Var, colorfrom indie.drawings import (LabelRel, LineSegment, AbsolutePosition, RelativePosition,vertical_anchor as va, horizontal_anchor as ha, line_ending_style as les)@indicator('Plotting example')def Main(self):return self.close[0] # example of a price plot
UI-only enhancements like background fills or levels:
# indie:lang_version = 5from indie import indicator, color, band, level@indicator('Plotting Helpers Example', overlay_main_pane=False)@band(0, 30, fill_color=color.RED(0.1)) # Oversold zone@band(70, 100, fill_color=color.GREEN(0.1)) # Overbought zone@band(30, 70, fill_color=color.GRAY(0.05)) # Neutral zone@level(30)@level(70)def Main(self):# Simulated indicator value in 0–100 rangevalue = (self.bar_index % 100) * 1.0return value
Newly added dynamic chart objects that:
Examples include:Label, LineSegment, and more object types under development
self.chart.draw(LabelAbs(text="Close: " + str(self.close[0]),position=AbsolutePosition(self.time[0], self.close[0])))
Here’s a simple indicator that draws a stats panel in the top-right corner and adds a vertical arrow every 50 bars:
# indie:lang_version = 5from indie import indicator, Var, colorfrom indie.drawings import (LabelRel, LineSegment, AbsolutePosition, RelativePosition,vertical_anchor as va, horizontal_anchor as ha, line_ending_style as les)@indicator('Drawings example', overlay_main_pane=True)def Main(self):stats_label = Var[LabelRel].new(LabelRel("text",RelativePosition(vertical_anchor=va.TOP,horizontal_anchor=ha.RIGHT,top_bottom_ratio=0.1,left_right_ratio=0.9,),bg_color=color.NAVY(0.5),text_color=color.YELLOW,))stats_label.get().text = ("Bar count: " + str(self.bar_count) +"\nCurrent price: " + str(self.close[0]))self.chart.draw(stats_label.get())if self.bar_count % 50 == 0:self.chart.draw(LineSegment(AbsolutePosition(self.time[0], 2*self.high[0]-self.low[0]),AbsolutePosition(self.time[0], self.low[0]),b_end=les.ARROW,color=color.OLIVE,))
This example highlights two key principles:
RelativePosition allows you to pin elements to the UI (e.g. corners)AbsolutePosition aligns objects with chart data (e.g. time and price)You can now draw:
LabelAbs / LabelRel — labels placed on the chart or in the UILineSegment — straight lines, arrows, or connectorsMore non-series objects — such as rectangles, icons, and shapes — are actively being developed.
→ You can follow progress in the Indie Changelog.
To see how this works in practice, check out the built-in indicators on the platform like:
These examples showcase real-time use of non-series drawings — directly editable in code.
Non-series drawings introduce a new level of flexibility for Indie indicators. You’re no longer limited to one value per bar — instead, you can build visually rich, context-aware tools that highlight, annotate, and explain market behavior the way you want.
This is just the beginning. As the feature set grows, so will your creative freedom.
If you have any questions or want to discuss how to use non-series drawings in your indicators, feel free to reach out in our Discord community. We’re always happy to help.


Be the first to comment
Publish your first comment to unleash the wisdom of crowd.