Pine Script to CodeLab Migration
Side-by-side guide for converting TradingView Pine Script indicators to ChartLabs CodeLab.
Key Differences
| Aspect | Pine Script | CodeLab |
|---|---|---|
| Language | Pine Script | TypeScript |
| Structure | Top-level functions | Class-based (extends Script) |
| Entry point | indicator() / strategy() | class extends Script/Strategy |
| Lifecycle | Implicit | calculate() method |
| State | var keyword | this.setState() / this.getState() |
| Functions | ta.sma() | this.sma() |
| Inputs | input.int() | input.number() |
| Plotting | plot() | plot() (similar syntax) |
| Colors | color.green | color.green (same!) |
Function Mapping
Moving Averages
| Pine Script | CodeLab |
|---|---|
ta.sma(close, 14) | this.sma('close', 14) |
ta.ema(close, 14) | this.ema('close', 14) |
ta.wma(close, 14) | this.wma('close', 14) |
ta.rma(close, 14) | this.rma('close', 14) |
ta.dema(close, 14) | this.dema('close', 14) |
ta.tema(close, 14) | this.tema('close', 14) |
ta.hma(close, 14) | this.hma('close', 14) |
ta.vwma(close, 14) | this.vwma('close', 14) |
ta.linreg(close, 14, 0) | this.linreg('close', 14) |
Indicators
| Pine Script | CodeLab |
|---|---|
ta.rsi(close, 14) | this.rsi('close', 14) |
ta.atr(14) | this.atr(14) |
ta.cci(close, 20) | this.cci('close', 20) |
ta.mfi(close, 14) | this.mfi(14) |
ta.obv | this.obv() |
ta.stdev(close, 14) | this.stdev('close', 14) |
ta.bb(close, 20, 2) | this.bbands('close', 20, 2) |
ta.macd(close, 12, 26, 9) | this.macd('close', 12, 26, 9) |
ta.stoch(close, high, low, 14) | this.stoch(14, 3, 3) |
ta.supertrend(3, 10) | this.supertrend(10, 3) |
ta.dmi(14) | this.adx(14) |
Range & Utility
| Pine Script | CodeLab |
|---|---|
ta.highest(high, 14) | this.highest('high', 14) |
ta.lowest(low, 14) | this.lowest('low', 14) |
math.sum(close, 14) | this.sum('close', 14) |
ta.tr | this.trueRange() |
ta.change(close) | this.change('close') |
ta.roc(close, 14) | this.roc('close', 14) |
ta.percentrank(close, 14) | this.percentRank('close', 14) |
ta.barssince(cond) | this.barsSince(cond) |
ta.valuewhen(cond, close, 0) | this.valuewhen(cond, 'close') |
ta.rising(close, 3) | this.rising('close', 3) |
ta.falling(close, 3) | this.falling('close', 3) |
Crossovers
| Pine Script | CodeLab |
|---|---|
ta.crossover(fast, slow) | this.crossOver(fast, slow, prevFast, prevSlow) |
ta.crossunder(fast, slow) | this.crossUnder(fast, slow, prevFast, prevSlow) |
WARNING
CodeLab crossover functions need 4 arguments (current + previous for both series). Use this.getPlot() to get previous values.
Inputs
| Pine Script | CodeLab |
|---|---|
input.int("Period", 14) | input.number('Period', 14) |
input.float("Mult", 2.0) | input.number('Mult', 2.0, { step: 0.1 }) |
input.source(close) | input.source('Source', 'close') |
input.bool("Show", true) | input.boolean('Show', true) |
input.color(color.blue) | input.color('Color', '#3b82f6') |
input.string("fast", options=...) | input.string('Mode', 'fast', { options: [...] }) |
Plotting
| Pine Script | CodeLab |
|---|---|
plot(val, "Name", color.blue) | plot('Name', val, { color: color.blue }) |
hline(70) | hline('Level', 70, { color: color.red }) |
plotshape(cond, ...) | plotShape('Name', cond, { ... }) |
bgcolor(color.new(...)) | bgcolor('#rrggbbaa') |
barcolor(c) | barcolor(c) |
State (Variables)
| Pine Script | CodeLab |
|---|---|
var float x = na | this.setState('x', 0) on first bar |
x := newValue | this.setState('x', newValue) |
Read: x | this.getState('x') |
Full Conversion Example
Pine Script (Original)
//@version=5
indicator("RSI with MA", overlay=false)
length = input.int(14, "RSI Period", minval=2)
maLength = input.int(9, "MA Period", minval=1)
src = input.source(close, "Source")
rsiVal = ta.rsi(src, length)
rsiMA = ta.sma(rsiVal, maLength)
plot(rsiVal, "RSI", color.purple, 2)
plot(rsiMA, "RSI MA", color.orange, 1)
hline(70, "OB", color.red)
hline(30, "OS", color.green)CodeLab (Converted)
typescript
import { Script, input, plot, hline, color } from '@chartlabs/script-sdk';
export default class RSIWithMA extends Script {
length = input.number('RSI Period', 14, { min: 2, max: 200 });
maLength = input.number('MA Period', 9, { min: 1, max: 100 });
source = input.source('Source', 'close');
calculate() {
const rsiVal = this.rsi(this.source, this.length);
plot('RSI', rsiVal, { color: color.purple, width: 2 });
// SMA of RSI — pass the numeric RSI value as source
const rsiMA = this.sma(rsiVal, this.maLength);
plot('RSI MA', rsiMA, { color: color.orange, width: 1 });
hline('OB', 70, { color: color.red, style: 'dashed' });
hline('OS', 30, { color: color.green, style: 'dashed' });
}
}Key Migration Notes
- Class-based: Wrap everything in a class extending
Script this.prefix: All SDK functions needthis.(this.sma,this.ema, etc.)- String sources: Pass series names as strings (
'close'notclose) - Explicit imports: Import only what you use from
@chartlabs/script-sdk - Plot order: Name comes first in CodeLab:
plot('Name', value, opts)vs Pine'splot(value, "Name", ...) - crossOver needs 4 args: Biggest gotcha — you must provide previous bar values too
- No
navalue: Use0,NaN, or conditional logic for uninitialized state - State management: Replace Pine's
varwithsetState/getState

