📖 Guides

TradingView Pine Script Beginner Guide: Build Your First Trading Indicator in 2026

⚠️ Disclosure: Some links on this page are affiliate links. If you sign up through them, I may earn a commission — at no extra cost to you. I only review tools I actually use.
I've been trading USDJPY for over a year now, and the single tool that transformed my workflow was Pine Script. Not Python. Not MQL4. Pine Script — TradingView's built-in scripting language that lets you build custom indicators, backtest strategies, and set alerts, all without leaving your chart.

In this guide, I'll walk you through everything I wish someone had told me when I started. We'll build two real indicators from scratch, cover the v6 syntax basics, and I'll share the mistakes that cost me hours of debugging.

What Is Pine Script?

Pine Script is TradingView's domain-specific programming language for creating custom technical indicators, strategies, and alerts. It runs directly on TradingView's servers, which means:

If you've ever stared at a chart thinking "I wish I could combine RSI with a moving average crossover and get an alert when they align," Pine Script is exactly what you need.

Pine Script vs. MQL4 vs. Python

Before we dive in, let's be honest about where Pine Script fits:

FeaturePine Script v6MQL4Python (backtrader)
Learning curve30 minutesDaysHours
Setup requiredNoneMT4 installPython + libs
VisualizationBuilt-inMT4 onlymatplotlib
Broker integrationAlerts onlyDirect tradingVia API
External APIs❌ No✅ Yes✅ Yes
BacktestingBuilt-inBuilt-inFlexible
CommunityMassiveLargeLarge
The trade-off is clear: Pine Script is the fastest way to prototype and visualize ideas, but it can't place orders directly or call external services. For me, Pine Script handles the signal generation and alerting, while a separate Python script handles the actual order execution on Interactive Brokers.

Getting Started: The Pine Script Editor

1. Go to TradingView and open any chart

2. Click "Pine Editor" at the bottom of the screen 3. You'll see a default script — delete it, we're starting fresh

Pine Script v6 Basics

As of 2026, v6 is the current version. Always start your scripts with the version declaration:

//@version=6

Key syntax rules:

Here are the essential building blocks:

//@version=6
indicator("My First Indicator", overlay=true)

// Variables
length = 14
src = close

// Built-in functions
smaValue = ta.sma(src, length)
rsiValue = ta.rsi(src, length)

// Plotting
plot(smaValue, "SMA", color.blue, 2)

The indicator() function declares your script as an indicator (as opposed to a strategy() for backtesting). The overlay=true parameter draws it on the price chart instead of a separate pane.

Project 1: SMA Crossover Indicator

Let's build a classic — the Simple Moving Average crossover. When a fast SMA crosses above a slow SMA, it's a bullish signal. When it crosses below, bearish.

//@version=6
indicator("SMA Crossover", overlay=true)

// Input parameters — users can adjust these in the settings panel
fastLength = input.int(9, "Fast SMA Length", minval=1)
slowLength = input.int(21, "Slow SMA Length", minval=1)

// Calculate SMAs
fastSMA = ta.sma(close, fastLength)
slowSMA = ta.sma(close, slowLength)

// Detect crossovers
bullishCross = ta.crossover(fastSMA, slowSMA)
bearishCross = ta.crossunder(fastSMA, slowSMA)

// Plot the moving averages
plot(fastSMA, "Fast SMA", color.green, 2)
plot(slowSMA, "Slow SMA", color.red, 2)

// Plot signals as shapes on the chart
plotshape(bullishCross, "Buy Signal", shape.triangleup, location.belowbar, color.green, size=size.small)
plotshape(bearishCross, "Sell Signal", shape.triangledown, location.abovebar, color.red, size=size.small)

// Background color on crossover bars
bgcolor(bullishCross ? color.new(color.green, 90) : bearishCross ? color.new(color.red, 90) : na)

What's Happening Here

Copy this into the Pine Editor, click "Add to chart," and you'll see it immediately. Try changing the lengths and watch the signals update in real-time.

Project 2: Momentum + Signal Indicator

Now let's build something closer to what I actually use for USDJPY trading. This indicator combines momentum measurement with signal generation:

//@version=6
indicator("Momentum Signal", overlay=false)

// Inputs
momentumLength = input.int(60, "Momentum Length (bars)", minval=10)
signalLength = input.int(9, "Signal Smoothing", minval=1)
overbought = input.float(2.0, "Overbought Threshold")
oversold = input.float(-2.0, "Oversold Threshold")

// Calculate momentum as percentage change
momentum = ((close - close[momentumLength]) / close[momentumLength]) * 100

// Signal line (smoothed momentum)
signal = ta.ema(momentum, signalLength)

// Histogram
hist = momentum - signal

// Conditions
bullishMomentum = momentum > 0 and momentum > signal
bearishMomentum = momentum < 0 and momentum < signal
strongBull = momentum > overbought
strongBear = momentum < oversold

// Colors
histColor = hist >= 0 ? (hist > hist[1] ? color.green : color.new(color.green, 50)) : (hist < hist[1] ? color.red : color.new(color.red, 50))

// Plot
plot(momentum, "Momentum", color.blue, 2)
plot(signal, "Signal", color.orange, 1)
plot(hist, "Histogram", histColor, style=plot.style_columns)

// Reference lines
hline(0, "Zero", color.gray, hline.style_dashed)
hline(overbought, "Overbought", color.red, hline.style_dotted)
hline(oversold, "Oversold", color.green, hline.style_dotted)

// Background highlights for strong conditions
bgcolor(strongBull ? color.new(color.green, 85) : strongBear ? color.new(color.red, 85) : na)

Breaking It Down

This indicator sits in a separate pane below the chart (overlay=false). Here's why each piece matters:

1. Momentum calculation: close - close[momentumLength] — the [momentumLength] syntax accesses the value from N bars ago. We express it as a percentage for cross-asset comparison.

2. Signal line: An EMA of the momentum smooths out noise. When momentum crosses above its signal, the trend is accelerating.

3. Histogram coloring: The histogram uses four colors — bright green (expanding bullish), dim green (contracting bullish), dim red (contracting bearish), bright red (expanding bearish). This is the MACD-style visualization that makes trend changes visible at a glance.

4. hline(): Draws horizontal reference lines. These don't move — they mark your overbought/oversold thresholds.

For my USDJPY setup, I use a 60-bar momentum on the daily chart. When momentum is positive in February, June, or October (historically strong months for USDJPY longs), I look for entries. This is the indicator that generates the signals my automated system acts on.

Backtesting Basics

Pine Script has a built-in backtesting engine. To use it, change indicator() to strategy():

//@version=6
strategy("SMA Crossover Strategy", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=100)

fastLength = input.int(9, "Fast SMA")
slowLength = input.int(21, "Slow SMA")

fastSMA = ta.sma(close, fastLength)
slowSMA = ta.sma(close, slowLength)

// Entry and exit conditions
if ta.crossover(fastSMA, slowSMA)
    strategy.entry("Long", strategy.long)

if ta.crossunder(fastSMA, slowSMA)
    strategy.close("Long")

plot(fastSMA, "Fast", color.green)
plot(slowSMA, "Slow", color.red)

After adding this to your chart, click the "Strategy Tester" tab to see:

Backtesting Caveats

Be honest with yourself about backtesting limitations:

strategy("Realistic Backtest", overlay=true, 
     commission_type=strategy.commission.percent, 
     commission_value=0.1, 
     slippage=2,
     default_qty_type=strategy.percent_of_equity, 
     default_qty_value=95)

Setting Up Alerts

Alerts are where Pine Script becomes truly powerful for active traders. You can trigger notifications based on any condition in your script:

//@version=6
indicator("Alert Example", overlay=true)

fast = ta.sma(close, 9)
slow = ta.sma(close, 21)
bullish = ta.crossover(fast, slow)
bearish = ta.crossunder(fast, slow)

plot(fast, "Fast", color.green)
plot(slow, "Slow", color.red)

// Alert conditions
alertcondition(bullish, "Bullish Crossover", "SMA 9/21 bullish crossover on {{ticker}}")
alertcondition(bearish, "Bearish Crossover", "SMA 9/21 bearish crossover on {{ticker}}")

After adding the indicator to your chart:

1. Click the "Alerts" button (clock icon) 2. Choose your indicator as the condition 3. Select the specific alert condition 4. Set delivery: push notification, email, webhook, or SMS

Webhook Alerts for Automation

The webhook option is the bridge between Pine Script and automated trading. When an alert fires, TradingView sends an HTTP POST to your URL:

Alert message: {"action": "buy", "ticker": "{{ticker}}", "price": {{close}}}
Webhook URL: https://your-server.com/webhook

This is how I connect TradingView signals to my Python execution script. Pine Script generates the signal, the webhook delivers it, and Python places the order on Interactive Brokers.

Common Mistakes (And How to Avoid Them)

After a year of daily Pine Script usage, here are the mistakes I see most often:

1. Repainting Indicators

// BAD — this repaints! The current bar's close changes until the bar closes
signal = close > ta.sma(close, 20)

// BETTER — use the previous bar's close for confirmed signals
signal = close[1] > ta.sma(close, 20)[1]

Repainting means your indicator changes historical signals after the fact. It looks profitable in backtests but fails in live trading.

2. Forgetting na Checks

// This will error if myValue is na
result = myValue > 0

// Safe version
result = not na(myValue) and myValue > 0

// Or use nz() to replace na with zero
result = nz(myValue) > 0

3. Exceeding Execution Limits

Pine Script runs on TradingView's servers, and there are hard limits:

If your script is too complex, you'll get a runtime error. The fix is usually to simplify: fewer indicators, fewer timeframes, or pre-compute values.

4. Misunderstanding request.security()

// Getting daily close on a 1H chart
dailyClose = request.security(syminfo.tickerid, "D", close)

// CAUTION: This looks ahead by default in v6
// Use barmerge.lookahead_off for backtesting accuracy
dailyClose_safe = request.security(syminfo.tickerid, "D", close, lookahead=barmerge.lookahead_off)

Pine Script Limitations — Be Realistic

I love Pine Script, but you need to know its walls:

1. No external API calls — You can't fetch data from REST APIs, databases, or external services. Your data is limited to what TradingView provides.

2. No direct order execution — Pine Script can't place trades. It can send alerts (including webhooks), but you need external infrastructure to act on them.

3. Server-side constraints — Execution time limits, memory limits, and a maximum number of bars in history. Complex machine learning models won't work here.

4. Limited debugging — No breakpoints, no step-through. You debug with plot(), label.new(), and log.info(). It's primitive but workable.

5. Vendor lock-in — Your scripts only run on TradingView. If you leave the platform, your code doesn't come with you (conceptually, at least — you still own the logic).

For my workflow, Pine Script handles about 60% of the job (signal generation, visualization, alerts), and Python handles the rest (order execution, risk management, portfolio tracking). They complement each other.

Tips for Learning Faster

1. Read the official docs — TradingView's Pine Script reference is excellent. The v6 migration guide is essential if you find older v4/v5 code online.

2. Study community scripts — Go to Indicators → Community Scripts and read the source code of popular indicators. You'll learn patterns and idioms quickly.

3. Start by modifying — Don't write from scratch initially. Take a working script, change one thing, see what happens. Build intuition through experimentation.

4. Use log.info() — When something isn't working, print values to the Pine Script console. It's your only debugger.

5. Keep scripts short — If your script is over 200 lines, it's probably doing too much. Split it into multiple indicators.

What's Next?

You've now built two working indicators and understand the core concepts. Here's your progression path:

1. Week 1: Build and customize the SMA crossover. Try different lengths. Add RSI as a filter.

2. Week 2: Build the momentum indicator. Apply it to your favorite asset. Adjust thresholds. 3. Week 3: Convert your best indicator into a strategy. Backtest it. Be brutally honest about the results. 4. Week 4: Set up webhook alerts. Connect them to a simple logging script to see the signals in real-time.

Pine Script won't make you profitable by itself — no tool will. But it gives you the ability to test ideas quickly, visualize your edge, and automate your alert workflow. For a trader, that's worth its weight in gold.

The USDJPY momentum indicator I built took me about 2 hours in Pine Script. The same thing in Python would have taken a full day, plus another day wiring up the visualization. That speed difference compounds when you're iterating on ideas daily.

---

*Ready to start building your own indicators? Try TradingView Free — the Pine Editor is available on all plans, including the free tier. Open a chart, paste in the SMA crossover code above, and see it working in under 60 seconds.*

TradingView

Ready to get started? Use the link below — it helps support ChartedTrader at no cost to you.

Try TradingView Free →
📈

About the author

I'm a systematic trader running live strategies on IB (USDJPY momentum) and Hyperliquid (crypto perps). Every tool reviewed here is something I've used with real capital. Questions? Reach out.

📚 Related Articles

📖 Guides

TradingView Strategy Tester Backtest Settings Explained (2026 Guide)

I backtested 200+ USDJPY trades on TradingView and discovered my results were 40% off until I fixed 3 settings. Here's what actually matters.

March 2, 2026 ⏱ 10 min read
📖 Guides

How to Deposit USDC to Hyperliquid from OKX (Step-by-Step Guide 2026)

I bridged USDC from OKX to Hyperliquid in under 20 minutes. Here's every step, the exact fees I paid, and two mistakes to avoid.

March 2, 2026 ⏱ 6 min read
📖 Guides

How to Set a Stop Loss on Hyperliquid: Step-by-Step Guide (2026)

Hyperliquid's stop loss UI is confusing. Here's exactly how to set market stops, limit stops, and trailing stops — with screenshots from my actual trades.

February 28, 2026 ⏱ 7 min read

📬 Get weekly trading insights

Real trades, honest reviews, no fluff. One email per week.