Skip to content
Back to skills

Pinescript Indicator

ASecurity

Generate working TradingView Pine Script v6 indicators — plotting, drawing objects, tables, alerts, inputs and the plot/object limits that break scripts at scale. Provides validated scaffolds to start from rather than composing from memory. Use when asked to write, create or build an indicator, study, oscillator or overlay; to plot something on a chart; to add labels, lines, boxes or a table; or to add alerts to an indicator.

  • 2 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 29, 2026
ai-agentsawssecurityperformance

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned September 29, 2026

npx -y skills add jpantsjoha/pinescript-plugin --skill pinescript-indicator --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Pinescript Indicator?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Pinescript Indicator
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jpantsjoha-pinescript-indicator/badge)](https://www.skillsdirectory.com/skills/jpantsjoha-pinescript-indicator)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: pinescript-indicator
description: "Generate working TradingView Pine Script v6 indicators — plotting, drawing objects, tables, alerts, inputs and the plot/object limits that break scripts at scale. Provides validated scaffolds to start from rather than composing from memory. Use when asked to write, create or build an indicator, study, oscillator or overlay; to plot something on a chart; to add labels, lines, boxes or a table; or to add alerts to an indicator."
license: MIT
metadata:
  "pinescript-plugin/version": "0.5.0"
  "pinescript-plugin/triggers": "write an indicator, create indicator, tradingview study, oscillator, overlay, plot on chart, add labels, draw lines, add a table, alertcondition, pine indicator"
  "pinescript-plugin/pine-version": "v6"
---

# Writing Pine v6 indicators

## Start from a scaffold, not from memory

`references/scaffolds/` holds indicators that are validated in CI. Copy one and
modify it. Composing from recollection is how wrong parameter names get in.

| Scaffold | For |
|---|---|
| `overlay-indicator.pine` | Anything drawn on the price chart |
| `oscillator.pine` | Separate pane, bounded, with levels and fills |
| `drawing-objects.pine` | Lines, labels, boxes, tables, with correct cleanup |

**Validate before returning.** Call `validate_pine_script` on the finished script.

## Declaration

```pine
indicator("Title", shorttitle="TTL", overlay=true, max_labels_count=500)
```

`overlay=true` draws on price; `false` opens a separate pane. It cannot be changed
at runtime. Raise `max_lines_count` / `max_labels_count` / `max_boxes_count`
(default 50, max 500) **before** you hit the cap — exceeding it silently deletes
the oldest object.

## Inputs

```pine
length  = input.int(14, "Length", minval=1, maxval=500)
source  = input.source(close, "Source")
useAlt  = input.bool(false, "Use alternative")
mode    = input.string("Balanced", "Mode", options=["Fast", "Balanced", "Slow"])
tf      = input.timeframe("", "Timeframe")
col     = input.color(color.blue, "Line colour")
```

`input.int` returns `simple int`, which is what `ta.*` length parameters require —
a `series int` will not compile there. Every `input.*()` accepts `active=` (July
2025) to grey out a field conditionally.

## Plotting

```pine
plot(series, "Title", color=color.blue, linewidth=2, style=plot.style_line)
plotshape(cond, "Signal", style=shape.triangleup, location=location.belowbar, color=color.green, size=size.tiny)
plotchar(cond, "Mark", char="▲", location=location.abovebar, color=color.red)
hline(0, "Zero", color=color.gray, linestyle=hline.style_dashed)
bgcolor(cond ? color.new(color.red, 90) : na)
```

`plotshape` takes **`style=`**, not `shape=`. `plotchar` takes **`char=`**.
Getting this wrong is the single most common indicator error.

`plot()` must be called at **global scope** — never inside `if`. To plot
conditionally, pass `na`:

```pine
plot(cond ? value : na, "Conditional")
```

**Limit: 64 plots per script**, counting `plot`, `plotshape`, `plotchar`,
`plotcandle`, `plotbar` and `hline`.

## Colour

```pine
color.new(color.red, 90)          // 0 = opaque, 100 = invisible
color.rgb(255, 82, 82, 20)
c = value > 0 ? color.green : color.red
```

`transp=` was removed. Use `color.new()`.

## Drawing objects

Two valid call forms — both correct, neither is a mistake:

```pine
line.new(x1=bar_index[10], y1=low[10], x2=bar_index, y2=high)     // coordinates
line.new(first_point=p1, second_point=p2)                          // chart.point

label.new(x=bar_index, y=high, text="hi", style=label.style_label_down)
box.new(left=bar_index[10], top=high, right=bar_index, bottom=low)
```

Parameter names differ per function: `label.new` takes `textalign`; `box.new` and
`table.cell` take `text_halign` / `text_valign`.

**Always clean up.** Objects persist across bars and count against the cap:

```pine
var line trend = na
if barstate.islast
    if not na(trend)
        line.delete(trend)
    trend := line.new(x1=bar_index[20], y1=low[20], x2=bar_index, y2=high)
```

## Tables

Create once with `var`, populate on the last bar only — rebuilding every bar is a
common performance mistake:

```pine
var table t = table.new(position=position.top_right, columns=2, rows=3, bgcolor=color.new(color.black, 80))
if barstate.islast
    table.cell(table_id=t, column=0, row=0, text="RSI", text_color=color.white, text_size=size.small)
```

## Alerts

```pine
alertcondition(ta.crossover(fast, slow), title="Cross Up", message="Fast crossed above slow, review sizing")
```

Exactly three parameters. Commas inside the message are fine — they are not
argument separators. The message is **static**: to include a runtime value use
`alert()` inside a condition instead.

## Higher timeframes without repainting

```pine
// REPAINTS — the current HTF bar is still forming
d = request.security(syminfo.tickerid, "D", close)

// STABLE — the previous, closed bar
d = request.security(syminfo.tickerid, "D", close[1], lookahead=barmerge.lookahead_off)
```

Cache the call in a variable; never repeat it inline. **Limit: 40 `request.*`
calls per script.**

A **hard-coded external feed** is read with the viewer's data plan, not yours. A
viewer who cannot read it gets "Permission denied for symbol" and the whole script
halts. The validator raises this as **S10**, an info-level hint:

```pine
// STABLE — degrades to na for a viewer who cannot read the feed
spx = request.security("SP:SPX", "D", close[1], lookahead=barmerge.lookahead_off, ignore_invalid_symbol=true)
```

If the script is meaningless without that feed, keep the hard stop and say so with
`// pine-ignore: S10`.

## Checklist before returning an indicator

- [ ] `validate_pine_script` returns zero errors
- [ ] `//@version=6` present
- [ ] `plot()` calls at global scope, conditional via `na` not `if`
- [ ] Drawing objects deleted before reassignment
- [ ] Under 64 plots and 40 `request.*` calls
- [ ] `ta.*` calls unconditional
- [ ] `request.security` uses `[1]` or an explicit `lookahead`

Files in this skill

  • SKILL.md5.9 KB
  • references/scaffolds/drawing-objects.pine2.6 KB
  • references/scaffolds/oscillator.pine1.5 KB
  • references/scaffolds/overlay-indicator.pine2.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.