Every indicator follows a simple recipe: Setup once → Calculate per candle → Display per candle.
- 1
Setup Phase
Runs once when your indicator first loads. Prepare everything your indicator needs before processing any candles.
Task Description Call define(...)Required — tells kScript about your indicator Create settings with input(...)Optional — let users adjust period, colors, etc. Get data with ohlcv(...)Create all timeserieshere - 2
Calculate Phase
Runs for each candle on the chart. Process indicator calculations. This repeats for every candle, computing values based on your defined logic.
Task Description Calculate indicators rsi(...),ema(...),sma(...)Store temporary values in varFor comparisons, colors, or per-candle logic Make decisions Use if/elseto compare values - 3
Display Phase
Runs for each candle, after calculations. Draw your indicator on the chart using the calculated values.
Function Use Case plotLine(...)Lines for RSI, moving averages, etc. plotBar(...)Vertical bars for volume, histograms plotShape(...)Markers, arrows, labels for signals
Understanding the Flow
Phase 1 (Setup runs once)
↓
Phase 2 (Calculate for candle 1) → Phase 3 (Display candle 1)
↓
Phase 2 (Calculate for candle 2) → Phase 3 (Display candle 2)
↓
...and so on for every candleKey Characteristics
Deterministic Results
Given the same input data, a script will always produce identical output. Essential for reliable backtesting and strategy validation.
Immutable Historical Data
timeseries objects provide read-only access to historical values. Past data cannot be modified, ensuring data integrity.Efficient Memory Usage
Only current bar calculations are held in memory. Historical data is managed by the runtime with optimized caching.
Real-time Compatibility
The same script logic handles both historical analysis and live data processing without special handling.
Limitations and Constraints
- No Future Data Access — Scripts cannot access data from future bars (e.g.,
ts[-1]is invalid). This prevents look-ahead bias in analysis. - Global Scope
timeseriesOnly —timeseriesdeclarations must be in global scope. They cannot be declared inside functions, loops, or conditional blocks. - Execution Time Limits — scripts must complete execution within 500ms (excluding data fetch). This ensures responsive chart rendering and prevents infinite loops.
- No Cross-Bar Variable Persistence —
varvariables cannot maintain state between bars. Usetimeseriesfor values that need historical access, orstaticfor persistent values.
Example: Complete Indicator Structure
//@version=2
// ====== PHASE 1: SETUP ======
define(title="RSI Indicator", position="offchart", axis=true);
// User inputs
var period = input(name="period", type="number", defaultValue=14, label="RSI Period");
var overbought = input(name="overbought", type="number", defaultValue=70, label="Overbought Level");
var oversold = input(name="oversold", type="number", defaultValue=30, label="Oversold Level");
// Data source (timeseries created here)
timeseries ohlcvData = ohlcv(symbol=currentSymbol, exchange=currentExchange);
// ====== PHASE 2: CALCULATE ======
// Calculate RSI
var rsiValue = rsi(source=ohlcvData.close, period=period);
// Determine color based on value
var colorIndex = rsiValue > overbought ? 0 : (rsiValue < oversold ? 1 : 2);
// ====== PHASE 3: DISPLAY ======
plotLine(value=rsiValue, width=2, colors=["red", "green", "blue"], colorIndex=colorIndex, label=["RSI"], desc=["Relative Strength Index"]);
// Draw horizontal reference lines
hline(overbought, "red", 1);
hline(oversold, "green", 1);