Skip to main content
Core Concept5 min read
Understanding how kScript v2 processes your code through its three-phase lifecycle for optimal performance and predictable behavior. Every indicator follows a simple recipe: Setup once → Calculate per candle → Display per candle

Setup Phase

Runs once when your indicator first loadsPrepare everything your indicator needs before processing any candles.
TaskDescription
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 timeseries here

Calculate Phase

Runs for each candle on the chartProcess indicator calculations. This repeats for every candle, computing values based on your defined logic.
TaskDescription
Calculate indicatorsrsi(...), ema(...), sma(...)
Store temporary values in varFor comparisons, colors, or per-candle logic
Make decisionsUse if/else to compare values
Don’t create timeseries in the Calculate phase - use the ones from Setup

Display Phase

Runs for each candle, after calculationsDraw your indicator on the chart using the calculated values.
FunctionUse Case
plotLine(...)Lines for RSI, moving averages, etc.
plotBar(...)Vertical bars for volume, histograms
plotShape(...)Markers, arrows, labels for signals
You can use multiple plot functions in one indicator

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 candle

Key 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

Keep these constraints in mind when writing your indicators.
Scripts cannot access data from future bars (e.g., ts[-1] is invalid). This prevents look-ahead bias in analysis.
timeseries declarations must be in global scope. They cannot be declared inside functions, loops, or conditional blocks.
Scripts must complete execution within 500ms (excluding data fetch). This ensures responsive chart rendering and prevents infinite loops.
var variables cannot maintain state between bars. Use timeseries for values that need historical access, or static for 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(value=overbought, color="red", width=1, style="dashed", label="Overbought");
hline(value=oversold, color="green", width=1, style="dashed", label="Oversold");