Decorators
Top-level annotations that turn a Python file into an indicator, strategy, script, or day-start hoist.
@indicator
@indicator(name, overlay?, description?, data_mode?, timeframe?)
Mark a Python class as a chart indicator.
The @indicator decorator transforms a Python class into a chart indicator that receives price data and draws visual output. The class must implement a calculate(self, df) method that receives the chart DataFrame.
Call plot(), hline(), or fill() inside calculate() to draw on the chart. Access price data via the global series: close, open, high, low, volume.
Python indicators run on OHLC bars. For TBBO tick-level indicators, use a Rust .rs file with the #[indicator] macro instead.
Parameters
name(str, defaultrequired): Display name shown in the indicator paneloverlay(bool, defaultFalse): IfTrue, draws on price chart. IfFalse, separate panedescription(str, defaultNone): Optional tooltip descriptiondata_mode(str, default'ohlc'): Always'ohlc'for Python indicators. Use Rust for tick.timeframe(Timeframe, defaultNone): Target timeframe for the indicator
Returns
None. Use plot() inside calculate() to draw output.
Example
from quant_charts import indicator, input, plot, close
@indicator("SMA", overlay=True)
class SMA:
period = input.int(20, "Period", min=1, max=500)
color = input.color("#2962FF", "Color")
def calculate(self, df):
result = close.rolling(self.period).mean()
plot(result, f"SMA({self.period})", color=self.color)
Notes
calculate()is called every time the chart data updates.- Use
input.*class variables to create user-configurable parameters. - Multiple
plot()calls create multiple series on the same indicator.
@strategy
@strategy(name, overlay?, timeframe?, description?, data_mode?, uses_sltp?, emit_sltp?, required_columns?)
Mark a Python class as a backtestable trading strategy.
The @strategy decorator creates a trading strategy that returns entry/exit signals for backtesting. The class must implement calculate(self, df) which returns a dict of boolean signal Series.
The backtester uses these signals to simulate trades and compute equity curves, win rates, drawdowns, and other performance metrics.
Python strategies run on OHLC bars only. For tick-level TBBO strategies use a Rust .rs file.
Parameters
name(str, defaultrequired): Display name shown in the strategy paneloverlay(bool, defaultTrue): IfTrue, draws on the price charttimeframe(Timeframe, defaultNone): Default execution timeframedescription(str, defaultNone): Optional tooltip descriptiondata_mode(str, default'ohlc'): Always'ohlc'for Python strategiesuses_sltp(bool, defaultFalse): IfTrue, the strategy returnssl_long/tp_long/sl_short/tp_shortarraysemit_sltp(str, default'entry_only'):'entry_only'(set once at entry) or'per_tick'(re-evaluated each bar)required_columns(list[str], defaultauto): Columns the strategy reads. SHM only ships these to workers.
Returns
A dict with keys: "entry_long", "exit_long", "entry_short", "exit_short". With uses_sltp=True, also "sl_long", "tp_long", "sl_short", "tp_short".
Example
from quant_charts import strategy, input, indicators, cross_above, cross_below, Timeframe
@strategy("MA Cross", overlay=True, timeframe=Timeframe.M1)
class MACross:
fast = input.int(10, "Fast", min=1, max=100)
slow = input.int(20, "Slow", min=2, max=200)
def calculate(self, df):
fast_ma = indicators.sma(period=self.fast, color="#26A69A")
slow_ma = indicators.sma(period=self.slow, color="#EF5350")
return {
'entry_long': cross_above(fast_ma, slow_ma),
'exit_long': cross_below(fast_ma, slow_ma),
'entry_short': cross_below(fast_ma, slow_ma),
'exit_short': cross_above(fast_ma, slow_ma),
}
Notes
- Use
indicators.sma()/indicators.ema()to add visual overlays alongside your strategy. - Signal Series must be boolean. Use
cross_above()/cross_below()for crossovers. - Conflicting signals on the same bar: exit is resolved before entry.
- Hoist param-independent work into a
@day_startmethod for fast optimization sweeps.
@day_start
@day_start(method)
Mark a method to run once per day per worker, before the parameter sweep.
Hoists parameter-independent computation out of the per-combo calculate() body. The decorated method runs once per trading day per worker process; results stored on self are visible inside calculate() for every parameter combination.
Use this for any heavy work that does not depend on swept params: full-series ta calls with literal periods, day-level summary stats, regime detection, cached indicator outputs.
Parameters
method(callable, defaultrequired): Method on the strategy/indicator class with signature(self, df) -> None
Returns
None. Store hoisted arrays as self.<name> for use inside calculate().
Example
from quant_charts import strategy, day_start, input, ta, close, cross_above, cross_below
@strategy("Hoisted EMA Cross")
class HoistedCross:
fast = input.int(10, "Fast", min=2, max=50)
slow = input.int(30, "Slow", min=5, max=200)
@day_start
def prep(self, df):
# hoisted: param-independent, runs once per day not once per combo
self.atr = ta.atr(df['high'], df['low'], df['close'], 14)
def calculate(self, df):
fast_ma = close.rolling(self.fast).mean()
slow_ma = close.rolling(self.slow).mean()
return {
'entry_long': cross_above(fast_ma, slow_ma),
'exit_long': cross_below(fast_ma, slow_ma),
'entry_short': cross_below(fast_ma, slow_ma),
'exit_short': cross_above(fast_ma, slow_ma),
}
Notes
- Critical for fast optimization sweeps: a 100-combo sweep with hoisted ATR runs the ATR once instead of 100 times.
- Anything assigned to
self.*inside@day_startis visible incalculate(). - Calls inside
@day_startshould use literal periods, not swept parameters.
@script
@script(name, description?, version?)
Mark a Python class as a utility script for data analysis. Used in .py files only (not notebooks).
The @script decorator creates a standalone script that runs once when executed. Unlike indicators and strategies, scripts do not draw on the chart. Instead they process data, export files, or produce analysis output.
Note: Scripts are standalone .py files executed from the file explorer. For notebook-based analysis, use regular Python cells instead.
Scripts have access to script_helpers for exporting data, reading chart state, and accessing indicator values.
Parameters
name(str, defaultrequired): Display name for the scriptdescription(str, defaultNone): Optional descriptionversion(str, defaultNone): Optional version string
Returns
Optional dict, displayed in the output panel.
Example
from quant_charts import script, input
from quant_charts.script_helpers import get_chart_data, export_csv
@script("Data Export")
class DataExporter:
filename = input.string("export.csv", "Filename")
def execute(self, df):
df.to_csv(self.filename)
return {"status": "success", "rows": len(df)}
Output
>>> Output
{'status': 'success', 'rows': 14523}
Notes
- Scripts implement
execute(self, df)instead ofcalculate(self, df). - Import from
quant_charts.script_helpersfor data access and export.