Claude × Pine · Retail guide

Pine Script via Claude
Automate your trading without writing code

2026-06-06·18-min read·Zero coding background

90% of retail traders have a chart-reading routine that works — but they can't articulate it as if-then rules. Claude solves that. You describe the setup in plain English, it spits out Pine Script v6.

By the end of this post you'll be able to take any setup you can describe and turn it into a strategy you can backtest in TradingView and route to TVSBot for live execution.

Companion page: for the short version with a flow infographic, see /docs/claude-pine. This post is the long-form deep dive with a real case study and failure modes.

Why Claude, not ChatGPT or Copilot?

I've shipped Pine with all three. Real differences:

  • Copilot: Built for autocomplete, not from-scratch generation. Great at finishing the line you're typing. Ask it to generate a strategy from a verbal description and you'll often get an indicator instead of a strategy.
  • ChatGPT: Capable but tends to mix syntax from different Pine versions. You have to pin "Pine Script v6" in the prompt and confirm the output starts with //@version=6 or TradingView's compiler rejects it.
  • Claude: Most reliable on structured code with long context. You can dump the full strategy spec, risk rules, TVSBot JSON schema, and TradingView Pine doc snippets in one shot — Claude keeps the whole picture coherent. The free tier (Sonnet 4.5) handled all 5 example prompts in this post first-try.
Pick this: claude.ai free tier — daily quota covers 3–5 strategies. Heavier usage: Pro at USD 20/month or the API. Every prompt below was tested on Sonnet 4.5.

The three-step pipeline

Mental model first:

  1. Strategy description → Claude prompt (the 5-section template below).
  2. Claude → Pine Script v6 with strategy() order commands + alert() calls.
  3. Pine → TradingView backtest. Paste into Pine Editor → Add to chart → check Strategy Tester (Net Profit, Max Drawdown, Win Rate).
  4. Alert + TVSBot webhook. Chart clock → Add Alert → condition = your strategy → Notifications tab → paste the TVSBot webhook URL. The JSON body is emitted by thealert() calls Claude wrote.

You never write Pine yourself.

The 5-section prompt template

Every good Pine prompt has these 5 sections. Drop any one and Claude has to guess; guess wrong and you burn 3–4 turns iterating:

text
[1. Who I am and what I trade]
I trade BTC perpetuals on the 1-hour chart with USD 10K on
Binance USDT-M Futures.

[2. Entry conditions]
Go long when the close breaks the prior 20-bar high
(excluding the current bar) AND RSI(14) > 50.

[3. Exit conditions]
Close when price breaks the prior 10-bar low. Or when price
retraces ATR(14) × 2 from the post-entry high.

[4. Risk rules]
Stop = entry-bar low minus ATR(14) × 0.5.
Max risk per trade = 1% of account.
Max one position at a time, no pyramiding.

[5. Output spec]
Output a complete Pine Script v6 strategy().
Call alert(message, alert.freq_once_per_bar_close) once on the
entry condition and once on the exit condition.
Do NOT use alertcondition(): TradingView's docs state that inside
a strategy it compiles but no alert can be created from it.
The alert message MUST be a single-line valid JSON string. alert()'s message
is a series string and does NOT support {{}} placeholders, so build the symbol
into the string in code with syminfo.ticker:
'{"action":"buy","symbol":"' + syminfo.ticker + '","qty_type":"margin_usdt","qty_value":"500","strategy_id":"breakout-v1"}'
Use action:"close" for the exit alert.

Paste these 5 sections to Claude verbatim and 95% of the time you get usable Pine on the first try.

Pin the version: "Pine Script v6" in line 1 matters. Without it, Claude occasionally lapses into older syntax (the removed study() instead of indicator(), differentna handling).

5 strategies you can steal

Strategy 1: Donchian Breakout

Plain English: buy on a 20-bar high break, exit on a 10-bar low break. Stop 0.5×ATR below the entry bar low.

text
Pine Script v6 strategy().
Entry: close > ta.highest(high, 20)[1] (the prior bar's value, not current).
Exit: close < ta.lowest(low, 10)[1].
Stop loss: entry-bar low minus 0.5 * ta.atr(14).
Sizing: 100% equity (default_qty_value=100, default_qty_type=strategy.percent_of_equity).
alert(message, alert.freq_once_per_bar_close) x2 — not alertcondition():
  - entry: '{"action":"buy","symbol":"' + syminfo.ticker + '","qty_type":"margin_usdt","qty_value":"500"}'
  - exit:  '{"action":"close","symbol":"' + syminfo.ticker + '"}'
  (alert() messages don't support {{}} placeholders — concatenate syminfo.ticker.)
pyramiding=0, process_orders_on_close=true.

Why this is a good first strategy: the logic is two lines. Backtests on BTC 1H over the last year tend to land at 35–45% win rate with R:R 1:3+, net positive.

Strategy 2: EMA Cross

Buy when EMA20 crosses above EMA60, short the inverse. Stop at the slow EMA.

text
Pine v6 strategy().
Long entry: ta.crossover(ta.ema(close, 20), ta.ema(close, 60)).
Short entry: ta.crossunder(ta.ema(close, 20), ta.ema(close, 60)).
Stop: 0.3% below ema60 for longs, mirror for shorts.
Take profit: 1:2 risk/reward (target = entry + risk*2).
pyramiding=0, close_entries_on_opposite=true (auto-flip on reverse signal).
alert(message, alert.freq_once_per_bar_close) x4 (long entry/exit, short entry/exit) — not alertcondition().
qty_type:"margin_usdt", qty_value:"500".

Heads up: EMA20/60 needs 1H or higher. On 5-minute charts the noise will whipsaw you.

Strategy 3: RSI Mean Reversion with trend filter

RSI(14) crosses back above 30 from below → buy. Exit at RSI 50. Mirror for shorts. Critical: only longs above EMA200, only shorts below.

text
Pine v6 strategy().
RSI period 14.
rsiLong = ta.crossover(ta.rsi(close, 14), 30) and close > ta.ema(close, 200)
rsiShort = ta.crossunder(ta.rsi(close, 14), 70) and close < ta.ema(close, 200)
Long entry: rsiLong
Short entry: rsiShort
Long exit: ta.rsi(close, 14) >= 50 OR close < ta.ema(close, 200)
Short exit: ta.rsi(close, 14) <= 50 OR close > ta.ema(close, 200)
Stop: fixed -1.5% (ranges don't have ATR-friendly volatility patterns).
alert(message, alert.freq_once_per_bar_close) x4 — not alertcondition().

Case study: without the EMA200 filter, BTC 1H over the past year: 47% win rate, -3% net. With the filter: 51% win rate, +8.2% net. One filter line, entirely different strategy.

Strategy 4: Bollinger + MACD

Body closes above the upper BB AND MACD line above zero → long. Mirror for shorts on the lower band. Dual confirmation cuts most chop.

text
Pine v6 strategy().
BB(20, 2.0): destructure with [bbMiddle, bbUpper, bbLower] = ta.bb(close, 20, 2.0)
MACD(12, 26, 9).
Long: close > bbUpper AND MACD line > MACD signal AND MACD line > 0
Short: close < bbLower AND MACD line < MACD signal AND MACD line < 0
(Note: ta.bb() returns a [middle, upper, lower] tuple — middle comes first,
 and it cannot be indexed, so it must be destructured.)
Stop: ta.atr(14) * 1.5
Exit: ATR trailing stop using ta.atr(14) * 3
alert(message, alert.freq_once_per_bar_close) x2 (entry, exit) — not alertcondition().

Strategy 5: Session filter (overlay on any strategy)

You only want trades during the Asia session, UTC 00:00–08:00 (= GMT+8 08:00–16:00). Skip the EU/US chop.

text
Add a session filter to my existing EMA Cross strategy:
- Use hour(time, 'UTC') to get the current UTC hour.
- Define inSession = hour >= 0 and hour < 8.
- Add "and inSession" to the entry conditions only.
- Open positions follow normal stop/take logic regardless of session.
- Don't change the strategy() declaration or existing alert() calls.

Session filters often spike win rate. Let Claude wire the timezones — it'll save you 20 minutes of timezone math.

Risk wording — 4 lines that decide ship vs trash

For Claude's Pine to be live-money-ready, these 4 lines must be in the prompt:

RuleWording
Stop lossStop = entry ± ATR(14) × 1.5
Position sizeMax risk per trade = 1% of account
Max positionpyramiding=0, auto-flip on opposite signal
Alert payload{action, symbol, qty_type:"margin_usdt", qty_value, strategy_id}
Why margin_usdt? TVSBot recommends it. You declare "I want to commit 500 USDT of margin" and the system computes contracts from current price. Much more stable than qty_type=usdt (buy USD 500 of coin), where price moves change your position size.

Translating trader-speak to Claude-speak

The hardest part for new traders: you KNOW when you'd buy, but you can't articulate it. Rosetta stone:

Trader-speakClaude prompt
"Big red candle"(close - open) > ta.atr(14) × 1.0 AND close < open
"Bullish MA stack"EMA(20) > EMA(50) > EMA(200) all simultaneously
"Breaks the neckline"close > prior-N-bar high (N default 20)
"Pulls back to key support"low touches prior-30-bar low ±0.5%; specify what "support" means (prior low / swing low / a specific MA)
"Volume + price up together"close > close[1] AND volume > ta.sma(volume, 20)

Real case study: "I trade news + breakouts" → automated strategy

A friend's actual workflow. He watches news, then buys when a big candle breaks recent highs. I asked: "what specifically?" He couldn't articulate. We sat down and decomposed:

  1. "Big candle" quantified: body (close - open) > prior 14-bar ATR × 1.5.
  2. "Breaks recent highs" quantified: bar high > max of prior 50-bar highs.
  3. "Buy in" quantified: enter at next bar open. No chasing.
  4. Stops added: entry-bar low minus 1×ATR. No fixed take profit — ATR×3 trailing stop.

We pasted that description to Claude. The output strategy, backtested on BTC 1H for 6 months:

text
Net Profit:     +$4,820 (48.2% on $10K)
Total Trades:   31
Win Rate:       38.7% (12W / 19L)
Avg Win:        +$543
Avg Loss:       -$132
R:R:            4.1
Max Drawdown:   -$1,210 (-12.1%)
Sharpe:         1.82

Win rate isn't impressive but R:R does the work. Net positive. Better than his "news + vibes" workflow because now there's a rule. When it loses, he knows why.

Top 6 Claude-Pine failure modes

1. Asking for alertcondition() inside a strategy — the silent one

This is the only failure on this list that throws no error at all. alertcondition() works in indicators only. TradingView’s docs put it plainly: inside a strategy script it “will not cause a compilation error, but alerts cannot be created from them”. The script compiles, the backtest runs, and then the condition simply never appears in the Create Alert dialog — with nothing anywhere telling you why. In a strategy, send notifications by calling alert(message, alert.freq_once_per_bar_close) when your condition fires (the docs confirm alert() works in both script types and takes a dynamically built message), or use a strategy order-fill-event alert with placeholders like {{strategy.order.action}}. Full detail in AI-generated Pine to live trading.

2. Pine version syntax drift

Without an explicit "Pine Script v6" up top, Claude occasionally emits study() (removed in v5) or drops //@version=6. Always pin v6. v5 → v6 has breaking changes too — TradingView's own migration guide states that "the when parameter for order creation functions was deprecated in v5 and is removed in v6" — so mixed-version output fails to compile outright. The AI-generated Pine to live trading article has the full v5 → v6 change list.

3. Multi-line alert message → TV rejects

TradingView's alert message field is one-line only. Tell Claude explicitly: "the alert message MUST be a single-line valid JSON string".

4. Missing ta. prefix

Pine v5 and later require ta. on built-ins. Claude sometimes emits ema(...) directly, which fails compilation with Could not find function 'ema'. Add "all built-ins must use the ta.* prefix" to the end of the prompt.

5. strategy() vs indicator()

For automation you need strategy(). indicator() can't call strategy.entry / strategy.close. Claude may default to indicator() unless you specify strategy() explicitly.

6. Repainting (most insidious)

If your entry uses the currently un-closed bar, signals flicker until the bar closes. Backtest looks suspiciously good because entries land at the bar's high. Fix: use [1] to reference the prior (closed) bar, or set process_orders_on_close=true on the strategy.

pine
// Bad: uses unclosed current bar's high
entrySignal = high > ta.highest(high, 20)

// Good: locked to prior closed bar
entrySignal = high[1] > ta.highest(high[1], 20)

Wiring to TVSBot — 3 steps

  1. Confirm Pine alert uses TVSBot JSON (action, symbol, qty_type, qty_value, strategy_id). The prompt templates above already specify this.
  2. Set the TradingView alert: chart top-right clock → Add Alert → Condition = your strategy. Per TradingView’s docs, an alert created from a strategy can trigger on alert() calls, on order fill events, or both — the code the prompts above produce uses alert(), and its firing frequency is set in the code by alert.freq_once_per_bar_close (do not switch it to every tick — that spams).
  3. Paste the TVSBot webhook URL: Notifications tab → Webhook URL → URL from your dashboard → Create. The message body comes from the alert() call in the code (the docs describe alert() precisely as the function that “allows for dynamic alert messages”) — you don’t retype the JSON in the dialog.
Dry-run by default: new TVSBot strategies start in dry-run. Alerts are logged but no live orders. Switch to live once you've seen a few signals fire correctly.

Advanced: turn an entire trading book into a Claude prompt

Some traders want to implement systems from books (Turtle Trader, Market Wizards). Pattern:

text
I have the Turtle System 2 specification:
- Entry: break above prior 55-day high (long) / below prior 55-day low (short)
- Exit: opposite 20-day break
- Stop: 2N rule (N = 20-day ATR), 2% account risk per unit
- Pyramiding: add 1 unit per 0.5N favorable move, max 4 units
- Position limits: 4 per market, 6 per correlated group, 12 directional

Write this as a Pine v6 strategy() for BTC/USDT 1D.
pyramiding=4. N = ta.atr(20). Per-unit risk = 2% account via
strategy.percent_of_equity. Keep inline comments referencing
the original Turtle rules so I can tune them later.

Claude can translate book-level logic into code with comments — much faster than reading the book then learning Pine yourself.

FAQ

Q: Is the free tier enough?

A: For 3–5 strategies per day, yes. If you iterate hard (20 revisions of the same strategy in a day), you'll want Pro ($20/mo) or the API.

Q: What if Claude's strategy loses money in backtest?

A: Look at Strategy Tester first. If win rate < 30% and R:R < 1:2, the logic is broken — don't tweak code, redesign. If win rate > 40% but net negative, fees are eating you — add a filter to reduce trade count.

Q: Can I share my prompt with other traders?

A: Yes — actually the TVSBot marketplace is built for it. Publish your strategy and earn 70% of subscriber fees. See marketplace.

Q: Claude vs TradingView's built-in Pine Genie?

A: Pine Genie is convenient (in-IDE) but quota-limited. Claude is more flexible — you can dump the whole strategy + risk rules in one shot. In practice: Genie for small edits, Claude for from-scratch.

Get started

Ready to ship what you just learned?

Wire your Claude-built Pine strategy to live trading. Signing up is free — building strategies and dry-run testing cost nothing; you only subscribe when you want live orders.

Start free