Pine Script for Custom Indicators
Pine Script is the language behind millions of custom indicators used by traders worldwide. Nydar's indicator engine supports 29 built-in functions with Pine Script-compatible syntax, letting you build custom indicators and run them against live data across 3 asset classes — crypto, stocks, and forex — without installing any software.
What Is Pine Script?
Pine Script is a domain-specific programming language designed exclusively for creating trading indicators and strategies. Concepts that take dozens of lines in Python — like calculating a moving average over the last 20 bars — take a single function call here. If you can write a spreadsheet formula, you can write Pine Script.
Why It Matters
Custom analysis. Combine and invent indicators that match your trading style.
Rapid prototyping. Test an idea in minutes — write, see the chart, tweak, iterate.
Portable skills. Pine Script concepts transfer directly to Nydar's custom indicator builder, which supports 29 functions and 11 ready-made formula examples.
Nydar integration: Build indicators in Pine Script, then adapt them for Nydar's formula builder — variable assignments, function calls like sma() and ema(), and arithmetic operators all transfer. See the Custom Indicators help page.
Pine Script Basics
Every script starts with a version and type declaration:
//@version=5
indicator("My Indicator", overlay=false)
myMA = ta.sma(close, 20)
plot(myMA, title="20 SMA", color=color.blue, linewidth=2)Script Types
indicator() — visual study. strategy() — backtest-capable with entry/exit logic.
Data Types
int — integersfloat — decimalsbool — true/falsestring — textcolor — rgba valuesseries — per-bar dataSeries vs Simple
A simple value (like 14) is known at compile time. A series (like close) changes every bar. Some parameters require simple values. var initialises once and persists across bars; varip also persists across real-time ticks.
Built-in Variables
Price & Volume
Bar & Symbol
bar_index — bar index (0 = first)
time — UNIX timestamp (ms)
syminfo.ticker — symbol name
timeframe.period — chart timeframe
//@version=5
indicator("Bar Stats", overlay=false)
barRange = high - low
barBody = math.abs(close - open)
bodyPct = barBody / barRange * 100
plot(bodyPct, title="Body %", color=color.orange)
hline(50, "50%", color=color.gray, linestyle=hline.style_dashed)
bgcolor(bodyPct < 30 ? color.new(color.purple, 85) : na)Plots body-to-range ratio. Bars below 30% are highlighted as indecision candles.
Essential Functions
ta.sma(source, length)Simple Moving Average
ta.ema(source, length)ta.rsi(source, length)RSI oscillator (0-100)
ta.macd(src, fast, slow, sig)Returns [macd, signal, histogram]
ta.crossover(a, b)True when a crosses above b
ta.crossunder(a, b)True when a crosses below b
ta.highest(source, length)Highest value over N bars
ta.lowest(source, length)Lowest value over N bars
math.abs(value)Absolute value
math.round(value)Round to nearest integer
//@version=5
indicator("RSI + MA Filter", overlay=false)
rsiVal = ta.rsi(close, 14)
rsiSmooth = ta.sma(rsiVal, 5)
plot(rsiVal, "RSI", color=color.orange)
plot(rsiSmooth, "Smoothed", color=color.blue, linewidth=2)
hline(70, "OB", color=color.red)
hline(30, "OS", color=color.green)
bgcolor(ta.crossover(rsiVal, rsiSmooth) ? color.new(color.green, 90) : na)Plotting & Visualization
Core Plot Functions
plot(series, title, color, linewidth, style) — line, histogram, columns, or area
plotshape(condition, style, location, color) — triangles, arrows, circles on signal bars
plotchar(condition, char, location, color) — single character markers
bgcolor(color) — background colour for the entire bar
barcolor(color) — change the price bar colour
hline(price, title, color) — fixed horizontal reference line
// Conditional coloring
maFast = ta.ema(close, 9)
maSlow = ta.ema(close, 21)
trendColor = maFast > maSlow ? color.green : color.red
plot(maFast, "Fast MA", color=trendColor, linewidth=2)
// Transparency: color.new(baseColor, 0=opaque to 100=invisible)
bgcolor(ta.rsi(close, 14) > 70 ? color.new(color.red, 90) :
ta.rsi(close, 14) < 30 ? color.new(color.green, 90) : na)Tip: Use na as a colour to hide a plot on specific bars — nothing renders when the colour is na.
Building Your First Indicator
A dual MA crossover: when the fast MA crosses above the slow, it signals bullish momentum. This is one of the most common technical analysis techniques. This walkthrough builds it step by step.
1. indicator("Dual MA Crossover", overlay=true) — MAs draw on price.
2. input.int() and input.source() — create a settings panel.
3. Two ta.ema() calls and two ta.crossover()/ta.crossunder() calls.
4. Colour-coded MAs, triangle shapes at crosses, and subtle background tint.
Complete Script
//@version=5
indicator("Dual MA Crossover", overlay=true)
fastLen = input.int(9, "Fast Length", minval=1)
slowLen = input.int(21, "Slow Length", minval=1)
src = input.source(close, "Source")
fastMA = ta.ema(src, fastLen)
slowMA = ta.ema(src, slowLen)
bullCross = ta.crossover(fastMA, slowMA)
bearCross = ta.crossunder(fastMA, slowMA)
maColor = fastMA > slowMA ? color.green : color.red
plot(fastMA, "Fast MA", color=maColor, linewidth=2)
plot(slowMA, "Slow MA", color=color.gray, linewidth=1)
plotshape(bullCross, "Buy", shape.triangleup, location.belowbar, color.green, size=size.small)
plotshape(bearCross, "Sell", shape.triangledown, location.abovebar, color.red, size=size.small)
bgcolor(fastMA > slowMA ? color.new(color.green, 95) : color.new(color.red, 95))Seventeen lines. Two MAs, crossover detection, colour-coded trend, and signal markers.
Conditional Logic & Alerts
if/else
var string trend = "Neutral"
if ta.ema(close, 9) > ta.ema(close, 21)
trend := "Bullish"
else
trend := "Bearish"4-space indent. := reassigns; = declares.
Ternary & switch
col = close > open ? color.green : color.red
maLen = switch timeframe.period
"1" => 50
"5" => 40
=> 20 // defaultalertcondition()
Registers conditions users can attach alerts to:
rsiVal = ta.rsi(close, 14)
alertcondition(rsiVal > 70, "RSI Overbought", "RSI above 70 on {{ticker}}")
alertcondition(rsiVal < 30, "RSI Oversold", "RSI below 30 on {{ticker}}")
alertcondition(ta.crossover(rsiVal, 50), "RSI Bull Cross", "Momentum bullish")Placeholders: {{ticker}}, {{close}}, {{time}}.
Importing into Nydar
Nydar's Custom Indicator Builder uses a formula language that shares core concepts with Pine Script — variables, functions, arithmetic, and lookback references all work the same way.
Open Custom Indicators widget from the widget menu.
Translate your logic. No indicator()/plot() needed. Use result as output. Conditionals use iff().
Validate and preview on live data. Fix errors before saving.
Save and add to chart. Name it, save, toggle on from any chart widget.
Pine Script
fast = ta.ema(close, 9)
slow = ta.ema(close, 21)
spread = fast - slow
plot(spread)Nydar Formula
fast = ema(close, 9)
slow = ema(close, 21)
result = fast - slowFull reference: 29 functions, syntax rules, and 11 examples at the Custom Indicators help page.
Common Patterns
Colour-Coded RSI Zones
//@version=5
indicator("Color RSI", overlay=false)
rsiVal = ta.rsi(close, 14)
rsiColor = rsiVal > 70 ? color.red : rsiVal < 30 ? color.green : color.gray
plot(rsiVal, "RSI", color=rsiColor, linewidth=2)Volume Spike Detector
//@version=5
indicator("Volume Spike", overlay=true)
volMA = ta.sma(volume, 20)
spike = input.float(2.0, "Spike Multiplier", minval=1.0)
isSpike = volume > volMA * spike
barcolor(isSpike ? (close > open ? color.lime : color.fuchsia) : na)
alertcondition(isSpike, "Vol Spike", "Volume spike on {{ticker}}")Multi-Timeframe Moving Average
//@version=5
indicator("HTF MA", overlay=true)
htf = input.timeframe("D", "Higher Timeframe")
htfMA = request.security(syminfo.tickerid, htf, ta.sma(close, 50))
plot(htfMA, "HTF MA", color=color.orange, linewidth=2)Dynamic Support & Resistance
//@version=5
indicator("Dynamic S/R", overlay=true)
lookback = input.int(20, "Lookback", minval=5)
resistance = ta.highest(high, lookback)
support = ta.lowest(low, lookback)
r = plot(resistance, "R", color=color.red)
s = plot(support, "S", color=color.green)
fill(r, s, color=color.new(color.blue, 95))Tips & Pitfalls
Repainting
Historical signals that change after the bar closes. Causes: request.security() without lookahead=barmerge.lookahead_off, referencing close before bar close, or barstate.isrealtime in calculations. Perfect backtests, failing live.
Future Leak
lookahead=barmerge.lookahead_on gives you a higher-timeframe close before that bar finishes. Always use lookahead_off and verify with barstate.isconfirmed.
na Handling
na propagates — any operand being na makes the result na. Use nz(value, replacement) to substitute defaults. Common on the first N bars.
= vs :=
= declares a new variable. := reassigns. Using = inside an if block creates a local variable that vanishes — a silent logic bug.
Best Practices
Use input() for all parameters — expose every tunable value.
Test on multiple symbols and timeframes — what works on one asset may break on another.
Keep scripts focused — one indicator, one job. Combine simple indicators on your chart.
Comment your logic — explain why, not just what.
Key Takeaways
- Pine Script is purpose-built for trading — single function calls replace dozens of lines.
- Built-in variables (open, high, low, close, volume) give immediate access to price data.
- The ta namespace provides SMA, EMA, RSI, MACD, and crossover detection out of the box.
- Visualization is first-class — plot(), plotshape(), bgcolor() communicate analysis visually.
- Watch for repainting — verify historical signals do not change after bars close.
- Skills transfer to Nydar — adapt scripts for the Custom Indicator Builder directly.
Related Guides
Build Your Own Indicators
Use Nydar's Custom Indicator Builder to turn your Pine Script ideas into live dashboard indicators. No install needed.
Get Started FreeFurther Reading
- Investopedia: Technical Indicators — Foundation concepts for what indicators measure
- Investopedia: Moving Averages — Deep dive into the most used indicator type
- Investopedia: RSI — Understanding the Relative Strength Index
Written by Ryan Clinton
Founder of Nydar. Software engineer with experience at Cowen Inc (Wall Street) and on large-scale infrastructure projects. Built Nydar to make professional trading tools accessible to everyone.
Last reviewed: March 2026