Pine Script v6 Best Practices for Writing Comments: Inline and Block Comment Techniques for Professional Code
Readable, maintainable Pine Script code depends heavily on disciplined commenting habits. Whether you are building a personal indicator or publishing a library for the TradingView community, well-structured comments transform opaque logic into self-documenting systems that any developer can audit, extend, or debug with confidence.
1. The Only Comment Syntax in Pine Script v6
Before diving into best practices, one critical fact must be established: Pine Script v6 supports only single-line comments using the // prefix. The /* */ block comment syntax familiar from C, JavaScript, or Java does not exist in Pine Script and will produce a compile error (CE10156) if used.
| Syntax | Supported in v6? | Notes |
|---|---|---|
// single line |
✅ Yes | The only valid comment syntax |
/* block */ |
❌ No — CE10156 | Compile error; do not use |
To comment out multiple lines simultaneously in the Pine Editor, select the lines and press Ctrl+/ (Windows/Linux) or Cmd+/ (macOS). The editor prepends // to each selected line automatically.
2. The Official Compiler Annotation System
Pine Script v6 ships with a native documentation annotation system that is parsed by the Pine Editor to generate tooltips and library documentation. These annotations use specially prefixed // comments and are the professional standard for any exported library or shared script.
| Annotation | Purpose | Applies To |
|---|---|---|
//@function |
Describes what a function does | User-defined functions |
//@param |
Documents a parameter name and meaning | Function parameters |
//@returns |
Describes the return value | User-defined functions |
//@type |
Describes a User-Defined Type (UDT) | UDT declarations |
//@field |
Documents a field inside a UDT | UDT fields |
//@variable |
Documents a script-level variable | Script-level variables |
These annotations are not merely cosmetic — the Pine Editor parses them to surface inline documentation when users hover over function calls in the editor, making them essential for any published library.
3. Structural Comment Patterns
Because // is the only available syntax, professional Pine Script developers use consistent visual patterns to simulate section headers, dividers, and block-level documentation. The following patterns are widely adopted in production-grade scripts.
3.1 Script Header Block
Every script should begin with a header block that captures authorship, version, and purpose. This block uses repeated // lines to create a visual boundary.
🔽 [Click to expand] View Full Pine Script Code
//@version=6
// ============================================================
// Script : Adaptive Volatility Band
// Author : Your Name
// Version : 1.0.0
// Date : 2025-01-01
// License : Mozilla Public License 2.0
// Desc : Plots dynamic bands derived from ATR-scaled
// standard deviation around a chosen moving average.
// ============================================================
indicator("Adaptive Volatility Band", overlay = true)
3.2 Section Dividers
Dividing a script into logical sections — inputs, calculations, plotting — dramatically reduces cognitive load when revisiting code weeks later. Use a consistent divider style throughout the entire file.
🔽 [Click to expand] View Full Pine Script Code
//@version=6
indicator("Section Divider Demo", overlay = true)
// ── INPUTS ────────────────────────────────────────────────
int lengthInput = input.int(20, "MA Length", minval = 1)
float multInput = input.float(2.0, "ATR Mult", minval = 0.1)
// ── CALCULATIONS ──────────────────────────────────────────
float basis = ta.sma(close, lengthInput) // simple moving average
float atr = ta.atr(lengthInput) // average true range
float upper = basis + multInput * atr // upper band
float lower = basis - multInput * atr // lower band
// ── PLOTTING ──────────────────────────────────────────────
plot(basis, "Basis", color = color.blue)
plot(upper, "Upper", color = color.green)
plot(lower, "Lower", color = color.red)
4. Inline Comments: Precision Over Verbosity
An inline comment placed at the end of a code line should answer why a value exists or what a non-obvious expression computes — not restate what the code already says. The goal is to reduce the reader's mental parsing effort, not to duplicate information.
| Pattern | Example | Quality |
|---|---|---|
| Redundant (avoid) | float x = close * 2 // multiply close by 2 |
❌ Adds no value |
| Explanatory (good) | float x = close * 2 // double-weighted for momentum bias |
✅ Explains intent |
| Formula reference (good) | // z = (x - μ) / σ → z-score normalization |
✅ Links code to math |
| Warning (good) | // NOTE: series int — cannot pass to ta.ema() length |
✅ Prevents future bugs |
5. Documenting Functions with Official Annotations
The following example demonstrates the complete annotation pattern for a user-defined function, including the mathematical formula it implements. The z-score formula is $ z = \frac{x - \mu}{\sigma} $, where $\mu$ is the rolling mean and $\sigma$ is the rolling standard deviation.
🔽 [Click to expand] View Full Pine Script Code
//@version=6
indicator("Z-Score Annotation Demo", overlay = false)
// ── FUNCTION ──────────────────────────────────────────────
//@function Computes the rolling z-score of a source series.
// Formula: z = (x - mean(x, len)) / stdev(x, len)
// Returns na when standard deviation equals zero
// to avoid division by zero.
//@param src The input price series to normalize.
//@param len The lookback window length (simple int required).
//@returns A series float representing the z-score value.
zscore(float src, simple int len) =>
float mu = ta.sma(src, len) // rolling mean μ
float sigma = ta.stdev(src, len) // rolling stdev σ
// Guard: return na when σ = 0 to prevent division by zero
sigma != 0 ? (src - mu) / sigma : na
// ── INPUTS ────────────────────────────────────────────────
//@variable lengthInput Lookback period chosen by the user.
int lengthInput = input.int(20, "Length", minval = 2)
// ── CALCULATION ───────────────────────────────────────────
float z = zscore(close, lengthInput) // compute z-score on close
// ── PLOTTING ──────────────────────────────────────────────
plot(z, "Z-Score", color = color.blue)
hline(2, "Upper 2σ", color = color.red, linestyle = hline.style_dashed)
hline(-2, "Lower 2σ", color = color.green, linestyle = hline.style_dashed)
hline(0, "Zero", color = color.gray, linestyle = hline.style_solid)
Capture the Pine Editor with the z-score script loaded. Hover over the zscore() function call to show the tooltip generated from the //@function, //@param, and //@returns annotations. This visually confirms that the annotation system is active and functional in the editor.
6. Documenting User-Defined Types (UDTs)
UDTs benefit enormously from //@type and //@field annotations. Without them, a reader must infer the semantic meaning of each field from its name alone — a fragile assumption in complex systems.
🔽 [Click to expand] View Full Pine Script Code
//@version=6
indicator("UDT Annotation Demo", overlay = true)
// ── TYPE DEFINITION ───────────────────────────────────────
//@type Encapsulates the state of a single swing pivot point.
// Stores both the price level and the bar index at which
// the pivot was detected.
type SwingPoint
//@field price The high or low price of the pivot bar.
float price
//@field barIndex The absolute bar_index of the pivot bar.
int barIndex
//@field isHigh True if this pivot is a swing high;
// false if it is a swing low.
bool isHigh
// ── USAGE ─────────────────────────────────────────────────
// Initialise a new SwingPoint on the current bar
var SwingPoint lastPivot = SwingPoint.new(
price = high, // capture current high as pivot price
barIndex = bar_index, // record current bar index
isHigh = true // mark as swing high
)
// Access field from one bar ago using correct UDT history syntax
// Rule: (obj[n]).field — NOT obj.field[n]
float prevPrice = na(lastPivot[1]) ? na : (lastPivot[1]).price
plot(prevPrice, "Prev Pivot Price", color = color.orange)
7. Simulating Block Comments for Temporarily Disabled Code
Because /* */ does not exist, the standard workflow for temporarily disabling a block of code is to use the Pine Editor's multi-line toggle shortcut. Select the target lines, then press Ctrl+/ to prepend // to every selected line. Press the same shortcut again to uncomment them.
🔽 [Click to expand] View Full Pine Script Code
//@version=6
indicator("Disabled Block Demo", overlay = true)
// The following block is temporarily disabled for debugging.
// To re-enable: select all lines below and press Ctrl+/
// float debugValue = ta.rsi(close, 14)
// float debugSma = ta.sma(debugValue, 5)
// plot(debugSma, "Debug RSI SMA", color = color.purple)
// Active production code:
plot(close, "Close", color = color.blue) // always-on baseline plot
Record a short screen capture (GIF or video) demonstrating the Ctrl+/ multi-line comment toggle in the Pine Editor. Select 3–4 lines, press Ctrl+/, show the // prefixes appearing, then press Ctrl+/ again to remove them. This is the definitive visual proof that block-commenting is achievable without /* */.
8. Comment Logic Flow Diagram
The diagram below maps the decision process a developer should follow when deciding which comment type to apply at any given point in a Pine Script file.
9. Complete Best-Practice Reference Script
The following script consolidates every commenting technique covered in this article into a single, production-ready template that can be used as a starting point for any new Pine Script v6 project.
🔽 [Click to expand] View Full Pine Script Code
//@version=6
// ============================================================
// Script : Comment Best Practices Template
// Author : Your Name
// Version : 1.0.0
// Date : 2025-01-01
// Purpose : Demonstrates all official Pine Script v6 comment
// patterns: inline, section dividers, annotations,
// and UDT documentation.
// ============================================================
indicator("Comment Best Practices Template", overlay = false)
// ── TYPE DEFINITIONS ──────────────────────────────────────
//@type Holds a pair of Bollinger Band boundary values
// computed at a specific bar.
type BandSnapshot
//@field upper Upper band value: mean + k * stdev
float upper
//@field lower Lower band value: mean - k * stdev
float lower
// ── FUNCTIONS ─────────────────────────────────────────────
//@function Computes Bollinger Band upper and lower values.
// Formula:
// upper = SMA(src, len) + mult * STDEV(src, len)
// lower = SMA(src, len) - mult * STDEV(src, len)
//@param src Source series (typically close).
//@param len Lookback length (simple int).
//@param mult Standard deviation multiplier (simple float).
//@returns A BandSnapshot UDT containing upper and lower.
bands(float src, simple int len, simple float mult) =>
float basis = ta.sma(src, len) // rolling mean
float dev = ta.stdev(src, len) // rolling standard deviation
BandSnapshot.new(
upper = basis + mult * dev, // upper = μ + k·σ
lower = basis - mult * dev // lower = μ - k·σ
)
// ── INPUTS ────────────────────────────────────────────────
//@variable lengthInput Lookback window for the Bollinger Band.
int lengthInput = input.int(20, "BB Length", minval = 2)
//@variable multInput Standard deviation multiplier k.
float multInput = input.float(2.0, "BB Mult", minval = 0.1, step = 0.1)
// ── CALCULATIONS ──────────────────────────────────────────
// Compute bands for the current bar
BandSnapshot snap = bands(close, lengthInput, multInput)
// Bandwidth: measures band expansion/contraction
// Formula: BW = (upper - lower) / SMA(close, len)
float bw = (snap.upper - snap.lower) / ta.sma(close, lengthInput)
// ── PLOTTING ──────────────────────────────────────────────
plot(snap.upper, "Upper Band", color = color.green) // upper boundary
plot(snap.lower, "Lower Band", color = color.red) // lower boundary
plot(bw, "Bandwidth", color = color.blue) // normalised width
// Reference lines
hline(0, "Zero", color = color.gray, linestyle = hline.style_dotted)
Copy the complete best-practice template script above into the TradingView Pine Editor and compile it. Confirm: (1) zero compile errors, (2) the //@function tooltip appears when hovering over the bands() call, (3) the three plots render correctly on the chart. Document any discrepancies and update the code accordingly before publishing.
10. Anti-Patterns to Avoid
| Anti-Pattern | Problem | Correct Approach |
|---|---|---|
Using /* */ |
CE10156 compile error | Use // on each line or Ctrl+/ |
| Redundant inline comments | Adds noise, no information gain | Comment the why, not the what |
| No section dividers | Long scripts become unnavigable | Use consistent // ── SECTION ── headers |
Missing //@param on exported functions |
No tooltip in Pine Editor for library users | Annotate every parameter with //@param |
| Stale comments after refactoring | Comments contradict the code — worse than no comment | Update comments in the same commit as the code change |
Conclusion
- Pine Script v6 supports only
//single-line comments. The/* */syntax triggers CE10156. Use Ctrl+/ in the Pine Editor to toggle//across multiple selected lines simultaneously. - The official annotation system (
//@function,//@param,//@returns,//@type,//@field,//@variable) is parsed by the Pine Editor to generate inline tooltips and library documentation — making it the professional standard for any shared or published script. - Effective inline comments explain intent and mathematical context, not syntax. Pairing code with its underlying formula (e.g., $ z = \frac{x - \mu}{\sigma} $) and flagging type-qualifier constraints (e.g.,
simple intrequired) prevents both reader confusion and future regression bugs.
Ideas for Further Development
- Automated comment linting: Build a Pine Script library that exports a validation function checking whether key variables carry
//@variableannotations, surfacing undocumented identifiers as warning labels on the chart. - Comment-driven versioning: Establish a convention where the script header block includes a
// CHANGELOGsection with dated entries, enabling diff-based auditing of indicator logic changes directly inside the Pine file without relying on external version control.
Comments
Post a Comment