01. Your first Python indicator
A guided 6-step walkthrough that ends with a working dual_sma.py indicator: two moving averages plus a fill that turns green when fast is above slow and red when it crosses below.
You will use @indicator, declare two input.int parameters and two input.color parameters, compute averages with ta.sma, and call plot() and fill(). By the end you will know how to: declare a Python indicator, expose user-tunable parameters, read the OHLC dataframe, plot named series, and fill between them. Read each step in order; the final step has the complete file you can paste into indicators/.
Step 1. Imports
Pull only what you need from quant_charts. Each imported name is documented in the Python tab.
Example
import numpy as np
from quant_charts import indicator, input, ta, plot, fill
Notes
tais the vectorized technical-analysis namespace (ta.sma,ta.ema,ta.rsi,ta.atr, ...).- Importing
plotandfillhere lets you call them as plain functions insidecalculate().
Step 2. The decorator
Mark the class as an indicator. The decorator registers it with the engine and exposes its parameters in the chart settings panel.
Example
@indicator(
name="Dual SMA",
description="Fast/slow SMA with cross-direction fill.",
overlay=True,
data_mode="ohlc",
required_columns=["close"],
)
class DualSMA:
pass
Notes
overlay=Truedraws on the price pane. Set toFalsefor a separate subpane (e.g. RSI, MACD).data_mode="ohlc"runs the indicator on aggregated bars. Use"both"if it should also work in tick-by-tick TBBO view.required_columnsmakes the loader ship only the columns you read across the worker boundary. Keeps sweep memory tight.
Step 3. Parameters
Declare class-level input.* fields. They become editable inputs in the indicator panel and the analyzer parameter form.
Example
class DualSMA:
fast_period = input.int(20, "Fast Period", min=2, max=500)
slow_period = input.int(50, "Slow Period", min=2, max=500)
fast_color = input.color("#7aa2f7", "Fast Color")
slow_color = input.color("#e0af68", "Slow Color")
bull_fill = input.color("#22c55e40", "Bull Fill")
bear_fill = input.color("#ef444440", "Bear Fill")
Notes
input.int(default, label, min=, max=, step=)exposes an integer field.input.floatis the same shape for floats.input.color(default_hex, label)accepts 6-char#rrggbbor 8-char#rrggbbaa. The trailing40here is hex alpha (40/255 ~= 25%).- Read parameters as
self.fast_period,self.fast_color, etc., insidecalculate().
Step 4. The calculate body
Compute both averages and decide the fill color per bar.
Example
def calculate(self, df):
close = np.asarray(df["close"], dtype=np.float64)
fast = ta.sma(close, self.fast_period)
slow = ta.sma(close, self.slow_period)
# element-wise: pick bull color where fast > slow, bear color otherwise
return fast, slow
Notes
- Convert pandas columns to numpy with
np.asarray(..., dtype=np.float64). The TA namespace expects numpy arrays. ta.sma(close, period)returns an array the same length asclose, with NaN for the warmup bars beforeperiodsamples are available.- The return value of
calculate()is ignored when you useplot()/fill()directly. Returning is optional for indicators (signal dicts are for strategies, not indicators).
Step 5. Plot the lines and fill between
Two plot() calls register named series on the chart. fill() references those names and shades the area between them.
Example
def calculate(self, df):
close = np.asarray(df["close"], dtype=np.float64)
fast = ta.sma(close, self.fast_period)
slow = ta.sma(close, self.slow_period)
plot(fast, "Fast SMA", color=self.fast_color, linewidth=2)
plot(slow, "Slow SMA", color=self.slow_color, linewidth=2)
# fill takes the two plot names; color is hex with optional alpha
fill("Fast SMA", "Slow SMA", color=self.bull_fill)
Notes
- The
nameyou pass toplot()is whatfill()references. Names must be unique within an indicator. - Single-color fill is the simplest path. To get a regime-switching fill (green when bull, red when bear), call
fill()twice with two pairs of bookkeeping plots, or usebgcolor()on a per-bar basis. The single-color path is enough for this tutorial.
Step 6. The full file
Save this as dual_sma.py under your workspace/indicators/ and Quant Charts auto-loads it.
Example
import numpy as np
from quant_charts import indicator, input, ta, plot, fill
@indicator(
name="Dual SMA",
description="Fast/slow SMA with cross-direction fill.",
overlay=True,
data_mode="ohlc",
required_columns=["close"],
)
class DualSMA:
fast_period = input.int(20, "Fast Period", min=2, max=500)
slow_period = input.int(50, "Slow Period", min=2, max=500)
fast_color = input.color("#7aa2f7", "Fast Color")
slow_color = input.color("#e0af68", "Slow Color")
fill_color = input.color("#7aa2f733", "Fill")
def calculate(self, df):
close = np.asarray(df["close"], dtype=np.float64)
fast = ta.sma(close, self.fast_period)
slow = ta.sma(close, self.slow_period)
plot(fast, "Fast SMA", color=self.fast_color, linewidth=2)
plot(slow, "Slow SMA", color=self.slow_color, linewidth=2)
fill("Fast SMA", "Slow SMA", color=self.fill_color)
Step 7. Run it
Open the indicator in Quant Charts and attach it to a chart.
- Open the Indicator panel from the chart top bar, click "Add", select "Dual SMA".
- Tune
Fast Period/Slow Periodfrom the panel; the chart re-runs on every change.
Notes
- Validation runs on save. If it fails, errors print to the in-app terminal panel.
- Adjusting an
input.colorfrom the panel respects the 8-char hex with alpha format.