Python Indicator Studio
Developer Reference
Build custom indicators, quantitative models, and mathematical overlays in pure Python. Scripts execute locally inside an in-browser sandbox with zero server latency and full formula privacy.
1. Execution Architecture
Client-Side Runtime
Code executes locally within a dedicated Web Worker sandbox. Active computation runs entirely on your local CPU for instant responsiveness.
Zero Server Transmission
Proprietary logic, custom indicators, and parameter configurations remain strictly within your browser session and are never transmitted to external servers.
Real-Time Canvas Sync
Computed series instantly synchronize with the charting canvas across all timeframes, updating seamlessly as live market candles progress.
2. The calculate(df, params) Function Protocol
Every custom indicator script must define a top-level function named calculate(df, params). The engine supplies candle history (df) and user inputs (params).
DataFrame (df) Properties
List of closing prices
List of opening prices
List of highest prices
List of lowest prices
List of candle volume
Total number of bars
3. Modules, Built-ins & Security Rules
Pre-Injected Libraries
ti.sma(series, length)
ti.ema(series, length)
ti.rsi(series, length)
ti.bbands(series, length, stddev=2.0)
ti.macd(series, fast=12, slow=26, signal=9)
math.sqrt, math.sin, math.cos, math.log, math.exp, math.pi
abs, min, max, sum, len, range, enumerate, zip, map, filter, sorted, round, print, int, float, bool, str, list, dict, set, tuple
Sandbox Constraints
-
No External Imports: For client safety and sandboxing, raw import statements (
import os,import requests) are blocked. -
No Dynamic Execution: Functions like
eval(),exec(),open(), and__import__are disabled. -
No Dunder Access: Accessing private Python dunder attributes (
__class__,__subclasses__) is restricted.
4. Naming Indicators & Configuring Metadata
Your calculate() function returns a dictionary. Provide a "__meta__" sub-dictionary to define the display title, specify whether it overlays on the main price chart (is_overlay=True) or a lower panel (is_overlay=False), and configure line styles and widths.
return {
"__meta__": {
"name": "Triple EMA Ribbon", # Legend title
"is_overlay": True, # True = Main chart; False = Lower sub-panel
"colors": {
"fast": "#00D6FF", # Series line color
"mid": "#FFFFFF",
"slow": "rgba(255, 255, 255, 0.4)"
},
"widths": {
"fast": 2.0,
"mid": 1.5,
"slow": 1.0
},
"styles": {
"fast": "solid", # "solid", "dashed", or "dotted"
"mid": "dashed",
"slow": "solid"
}
},
"fast": fast_series, # Output lists matching len(df)
"mid": mid_series,
"slow": slow_series
}
5. Production Code Examples
Copy and paste these pre-tested indicators directly into the SlateTick Python IDE.
Triple Exponential Moving Average (EMA) Ribbon
Overlay: TrueCalculates 9, 21, and 55-period EMAs across closing prices to identify trend momentum and support/resistance zones.
def calculate(df, params):
fast_len = int(params.get('fast_length', 9))
mid_len = int(params.get('mid_length', 21))
slow_len = int(params.get('slow_length', 55))
ema_fast = ti.ema(df.close, fast_len)
ema_mid = ti.ema(df.close, mid_len)
ema_slow = ti.ema(df.close, slow_len)
return {
"__meta__": {
"name": f"EMA Ribbon ({fast_len}/{mid_len}/{slow_len})",
"is_overlay": True,
"colors": {
"fast": "#00D6FF",
"mid": "#FFFFFF",
"slow": "rgba(255, 255, 255, 0.4)"
},
"widths": {
"fast": 2.0,
"mid": 1.5,
"slow": 1.0
}
},
"fast": ema_fast,
"mid": ema_mid,
"slow": ema_slow
}
Relative Strength Index (RSI) with Threshold Levels
Overlay: FalseComputes standard 14-period RSI in a separate sub-panel with 70 (Overbought) and 30 (Oversold) threshold lines.
def calculate(df, params):
length = int(params.get('length', 14))
overbought = float(params.get('overbought', 70.0))
oversold = float(params.get('oversold', 30.0))
rsi_line = ti.rsi(df.close, length)
n = len(df)
return {
"__meta__": {
"name": f"RSI ({length})",
"is_overlay": False,
"colors": {
"rsi": "#00D6FF",
"ob": "#FFFFFF",
"os": "#FFFFFF",
"mid": "rgba(255, 255, 255, 0.2)"
},
"styles": {
"rsi": "solid",
"ob": "dashed",
"os": "dashed",
"mid": "dotted"
},
"widths": {
"rsi": 2.0,
"ob": 1.0,
"os": 1.0
}
},
"rsi": rsi_line,
"ob": [overbought] * n,
"os": [oversold] * n,
"mid": [50.0] * n
}
Bollinger Bands with StdDev Multiplier
Overlay: TrueCalculates 20-period moving average with upper and lower statistical volatility bands.
def calculate(df, params):
length = int(params.get('length', 20))
stddev = float(params.get('stddev', 2.0))
bands = ti.bbands(df.close, length, stddev=stddev)
return {
"__meta__": {
"name": f"Bollinger Bands ({length}, {stddev})",
"is_overlay": True,
"colors": {
"upper": "#00D6FF",
"middle": "#FFFFFF",
"lower": "#00D6FF"
},
"widths": {
"upper": 1.2,
"middle": 1.0,
"lower": 1.2
},
"styles": {
"upper": "solid",
"middle": "dashed",
"lower": "solid"
}
},
"upper": bands["upper"],
"middle": bands["middle"],
"lower": bands["lower"]
}
MACD (Moving Average Convergence Divergence)
Overlay: FalseCalculates 12/26 MACD line, 9-period signal line, and difference histogram in a lower sub-panel.
def calculate(df, params):
fast_period = int(params.get('fast', 12))
slow_period = int(params.get('slow', 26))
signal_period = int(params.get('signal', 9))
res = ti.macd(df.close, fast=fast_period, slow=slow_period, signal=signal_period)
return {
"__meta__": {
"name": f"MACD ({fast_period},{slow_period},{signal_period})",
"is_overlay": False,
"colors": {
"macd": "#00D6FF",
"signal": "#FFFFFF",
"hist": "rgba(0, 214, 255, 0.4)"
},
"widths": {
"macd": 1.8,
"signal": 1.2,
"hist": 1.0
}
},
"macd": res["macd"],
"signal": res["signal"],
"hist": res["hist"]
}
Ready to Build Your Custom Indicators?
Open the SlateTick terminal, launch the Python IDE, and instantly overlay your quantitative logic on live global charts.