name: pine-script description: Convert Python backtest strategies to TradingView Pine Script v6, or generate Pine Script from natural language descriptions. category: tool
Overview
This skill enables two workflows:
- Export: convert an existing
signal_engine.py(from a completed backtest run) into a TradingView Pine Script v6 strategy - Generate: write Pine Script v6 directly from a natural-language strategy description
Output file: artifacts/strategy.pine (inside the run directory, or a new run directory).
Workflow: Export from Backtest
load_skill("pine-script")— read this conversion guideread_file("config.json")— understand instruments, dates, parametersread_file("code/signal_engine.py")— understand the Python strategy logic- Translate the strategy to Pine Script v6 using the mapping table below
write_file("artifacts/strategy.pine")— save the output- Return the Pine Script in a code block with usage instructions
Workflow: Generate from Description
load_skill("pine-script")— read this guide- Write Pine Script v6 directly based on the user's description
write_file("artifacts/strategy.pine")— save the output- Return the code with usage instructions
Pine Script v6 Strategy Template
// This strategy was generated by Vibe-Trading
// Paste into TradingView Pine Editor → Add to Chart
//@version=6
strategy("Strategy Name", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=100, commission_type=strategy.commission.percent, commission_value=0.1, initial_capital=1000000)
// ============================================================================
// INPUTS
// ============================================================================
// [Group inputs logically with input.int(), input.float(), input.string()]
// ============================================================================
// CALCULATIONS
// ============================================================================
// [Core indicator calculations]
// ============================================================================
// CONDITIONS
// ============================================================================
longCondition = false
shortCondition = false
exitLongCondition = false
exitShortCondition = false
// ============================================================================
// STRATEGY EXECUTION
// ============================================================================
if longCondition
strategy.entry("Long", strategy.long)
if shortCondition
strategy.entry("Short", strategy.short)
if exitLongCondition
strategy.close("Long")
if exitShortCondition
strategy.close("Short")
// ============================================================================
// PLOTS
// ============================================================================
// [Visual overlays: moving averages, bands, signals]
// ============================================================================
// ALERTS
// ============================================================================
alertcondition(longCondition, title="Long Signal", message="Long entry signal triggered")
alertcondition(shortCondition, title="Short Signal", message="Short entry signal triggered")
Python → Pine Script Mapping Table
Technical Indicators
| Python (pandas/numpy) | Pine Script v6 |
|---|---|
df['close'].rolling(n).mean() | ta.sma(close, n) |
df['close'].ewm(span=n).mean() | ta.ema(close, n) |
ta.RSI(df['close'], n) or manual RSI | ta.rsi(close, n) |
ta.MACD(df['close']) | [macdLine, signalLine, hist] = ta.macd(close, 12, 26, 9) |
df['close'].rolling(n).std() | ta.stdev(close, n) |
df['high'].rolling(n).max() | ta.highest(high, n) |
df['low'].rolling(n).min() | ta.lowest(low, n) |
df['close'].pct_change() | (close - close[1]) / close[1] |
df['volume'].rolling(n).mean() | ta.sma(volume, n) |
df['close'] > df['close'].shift(1) | close > close[1] |
| Bollinger Bands (manual) | [mid, upper, lower] = ta.bb(close, length, mult) |
| ATR (manual or ta-lib) | ta.atr(length) |
| ADX | ta.adx(high, low, close, length) (returns adx value) |
| Stochastic | ta.stoch(close, high, low, length, smoothK, smoothD) |
| CCI | ta.cci(close, length) (Pine v6: ta.cci(close, length)) |
| Williams %R | ta.wpr(length) |
| MFI | ta.mfi(hlc3, volume, length) — Pine v6: ta.mfi(close, length) |
| OBV | ta.obv |
| VWAP | ta.vwap |
Data References
| Python | Pine Script v6 |
|---|---|
df['open'] | open |
df['high'] | high |
df['low'] | low |
df['close'] | close |
df['volume'] | volume |
df.index (datetime) | time |
df['close'].shift(n) | close[n] |
Signal Logic
| Python Pattern | Pine Script v6 |
|---|---|
(fast > slow) & (fast.shift(1) <= slow.shift(1)) | ta.crossover(fast, slow) |
(fast < slow) & (fast.shift(1) >= slow.shift(1)) | ta.crossunder(fast, slow) |
signal.where(condition, 0) | condition ? value : 0 |
np.where(cond, val_true, val_false) | cond ? val_true : val_false |
signal.clip(-1, 1) | math.max(-1, math.min(1, signal)) |
signal.fillna(0) | nz(signal, 0) |
pd.isna(value) | na(value) |
Position Sizing
| Python Pattern | Pine Script v6 |
|---|---|
| Equal weight 1/N | strategy.percent_of_equity with default_qty_value = 100/N |
| Full position on signal=1.0 | default_qty_type=strategy.percent_of_equity, default_qty_value=100 |
| Half position on signal=0.5 | Use strategy.entry(..., qty=strategy.equity * 0.5 / close) |
| Stop-loss | strategy.exit("Exit", stop=entryPrice * (1 - stopPct)) |
| Take-profit | strategy.exit("Exit", limit=entryPrice * (1 + tpPct)) |
Pine Script v6 Syntax Rules
Critical Rules (common errors)
- Version declaration must be first line:
//@version=6 - Ternary operators MUST stay on one line or use intermediate variables:
// WRONG — causes "end of line without line continuation" text = condition ? "value1" : "value2" // CORRECT text = condition ? "value1" : "value2" - Line continuation: continuation lines must be indented MORE than the starting line
- No plot() in local scope (if/for/function):
// WRONG if condition plot(value) // CORRECT plot(condition ? value : na) - var vs regular variables: use
varfor persistent state across bars, regular assignment recalculates each bar - varip: persistent even on real-time bar updates (intrabar persistence)
Script Types
| Type | Declaration | Use Case |
|---|---|---|
strategy | strategy("Name", ...) | Backtestable with entry/exit orders |
indicator | indicator("Name", ...) | Visual indicators, no backtesting |
library | library("Name") | Reusable functions |
Default output: strategy (matches Vibe-Trading's backtest-first philosophy).
Avoid Repainting
- Use
barstate.isconfirmedfor signals on confirmed bars only - Use
request.security()withlookahead=barmerge.lookahead_off(default in v6) - Do NOT use
security()on lower timeframes without understanding implications
Platform Limits
- Max 500 bars lookback for
[]operator - Max 500 plot calls
- Max 64
strategy.entry/exitcalls per bar - Max 40
request.security()calls
TradingView Symbol Format
When generating Pine Script, map Vibe-Trading codes to TradingView symbols:
| Vibe-Trading Format | TradingView Format | Exchange |
|---|---|---|
000001.SZ | SZSE:000001 | Shenzhen |
600519.SH | SSE:600519 | Shanghai |
AAPL.US | NASDAQ:AAPL | US (auto-detect) |
700.HK | HKEX:0700 | Hong Kong |
BTC-USDT | OKX:BTCUSDT.P or BINANCE:BTCUSDT | Crypto |
Note: Pine Script strategies are chart-independent — the user applies them to whichever symbol they want on TradingView. Include a comment noting the original instrument.
Usage Instructions (include in response)
After generating the Pine Script, always include:
How to use in TradingView:
1. Open TradingView → Pine Editor (bottom panel)
2. Click "Open" → "New blank indicator"
3. Delete all existing code
4. Paste the Pine Script above
5. Click "Add to Chart"
6. The strategy will appear on your chart with entry/exit markers
7. Open "Strategy Tester" tab to see backtest results
Quality Checklist
Before outputting the Pine Script:
-
//@version=6is the first line -
strategy()declaration includes commission and initial_capital matching config.json - All indicator calculations use Pine built-in
ta.*functions (not manual reimplementation) - Entry/exit conditions match the Python signal logic semantically
- No
plot()inside local scopes (if/for/function) - Ternary operators are on single lines
- Inputs use
input.int()/input.float()so users can tune parameters in TradingView UI - Alert conditions are included for key signals
- Comment header notes the original Vibe-Trading run_id and instrument