MCPInstall

pine-optimizer

Optimizes Pine Script for performance and user experience. Use when improving speed, UI organization, or visual appeal.

Installs
462
Last 24h
—
Trending rank
—
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/traderspost/pinescript-agents --skill pine-optimizer
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads pine-optimizer automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

Pine Script Optimizer

Specialized in enhancing script performance, user experience, and visual presentation on TradingView.

Pine Script v6 2025 Optimization Features

July 2025: Input active Parameter - UX Game Changer

Create conditional input visibility for cleaner UI:

// ✅ BEFORE: All inputs always visible (cluttered)
maType = input.string("EMA", "MA Type", options=["SMA", "EMA", "Custom"])
customLength = input.int(20, "Custom Length")  // Always visible

// ✅ AFTER: Conditional visibility (clean UX)
maType = input.string("EMA", "MA Type", options=["SMA", "EMA", "Custom"])
customLength = input.int(20, "Custom Length",
    active=(maType == "Custom"),  // Only shown when Custom selected
    tooltip="Only available when MA Type is 'Custom'")

// Advanced mode pattern
showAdvanced = input.bool(false, "Show Advanced Settings", group="Settings")
advSetting1 = input.int(10, "Advanced 1", group="Advanced", active=showAdvanced)
advSetting2 = input.float(1.5, "Advanced 2", group="Advanced", active=showAdvanced)
advSetting3 = input.bool(true, "Advanced 3", group="Advanced", active=showAdvanced)

September 2025: Plot Line Styles

More visual options without custom drawing:

// Use built-in line styles for cleaner visuals
plot(sma20, "SMA 20", color.blue, linestyle=plot.linestyle_solid)
plot(sma50, "SMA 50", color.red, linestyle=plot.linestyle_dashed)
plot(support, "Support", color.green, linestyle=plot.linestyle_dotted)

// Combine with conditional display
showProjections = input.bool(true, "Show Projections")
plot(showProjections ? projection : na, "Projection",
    color.new(color.yellow, 50),
    linestyle=plot.linestyle_dotted)

February 2025: Unlimited Scopes

No longer limited to 550 scopes - enables more complex, modular code:

// Now possible: deeply nested logic without scope errors
type ComplexType
    float value1
    float value2
    array<float> history

method process(ComplexType this) =>
    if this.value1 > 0
        if this.value2 > 0
            for i = 0 to array.size(this.history) - 1
                if array.get(this.history, i) > 0
                    // Deep nesting now allowed
                    // Previously would hit 550 scope limit

March 2025: Use for...in for Collections

The preferred and safest way to iterate over collections:

// ✅ BEST: Use for...in for arrays (safest, cleanest)
for element in myArray
    // Process element directly - no boundary issues

// ✅ BEST: Use for...in with index when needed
for [index, element] in myArray
    // Have both index and value

// ✅ Works with matrices (iterates rows as arrays)
for row in myMatrix
    for value in row
        // Process each value

// ✅ Works with maps (key-value pairs in insertion order)
for [key, value] in myMap
    // Process key-value pair

FALLBACK: Cache boundary if traditional for is required:

// ❌ SLOW/DANGEROUS: Re-evaluates array.size() every iteration
for i = 0 to array.size(arr) - 1
    // Can cause infinite loop if array modified

// ✅ FALLBACK: Cache boundary if you need traditional for
arrSize = array.size(arr)
for i = 0 to arrSize - 1
    // process

August 2025: Longer Strings (40,960 chars)

Build more comprehensive info panels:

// Now possible: detailed multi-section reports
report = "═══════════════════════════════\n"
report += "      STRATEGY REPORT         \n"
report += "═══════════════════════════════\n\n"
report += "PERFORMANCE METRICS\n"
report += "───────────────────\n"
report += "Win Rate: " + str.tostring(winRate, "#.##") + "%\n"
report += "Profit Factor: " + str.tostring(pf, "#.##") + "\n"
// ... can now include much more detail

⚠️ CRITICAL: UDT-First Code Organization

The single biggest optimization you can make is using UDT-first architecture. This eliminates parallel arrays, simplifies drawing management, and removes bar_index clamping code.

Before vs After: Parallel Arrays vs UDT

// ❌ BEFORE: 6+ parallel arrays (hard to maintain, error-prone)
var array<float> slopes = array.new<float>()
var array<float> intercepts = array.new<float>()
var array<float> stdDevs = array.new<float>()
var array<int> startBars = array.new<int>()
var array<int> endBars = array.new<int>()
var array<line> centerLines = array.new<line>()
// Must keep ALL arrays in sync - easy to have bugs!

// Push to ALL arrays when adding item
array.push(slopes, newSlope)
array.push(intercepts, newIntercept)
array.push(stdDevs, newStdDev)
array.push(startBars, newStartBar)
array.push(endBars, newEndBar)
// Forgot to push to centerLines? Bug!

// ✅ AFTER: Single UDT array (clean, self-documenting)
type Regression
    float slope
    float intercept
    float stdDev
    int startTime      // Use TIME, not bar_index!
    int endTime
    int startBarIndex  // Keep for Y calculations
    int endBarIndex
    line centerLine = na

var array<Regression> regressions = array.new<Regression>()

// One push, all data together
newReg = Regression.new(slope=newSlope, intercept=newIntercept, ...)
array.push(regressions, newReg)

Performance Gain: xloc.bar_time Eliminates Clamping

// ❌ BEFORE: Clamping code everywhere (slow, complex)
leftBar = math.max(0, bar_index - startOffset)  // Clamp to valid range
if bar_index - startBar > 5000
    leftBar := bar_index - 5000  // Historical buffer limit!
line.set_x1(myLine, leftBar)

// ✅ AFTER: xloc.bar_time has NO limit - just draw!
line.new(startTime, y1, endTime, y2, xloc=xloc.bar_time)
// No clamping needed! Works for ANY historical bar!

UDT Methods for DRY Drawing Code

// ❌ BEFORE: Repeated drawing blocks (~50+ lines each)
// Block for original regression drawing
if showOriginal
    if not na(origCenterLine)
        line.delete(origCenterLine)
    origCenterLine := line.new(...)
    // ... 20 more lines

// Block for live regression drawing (duplicate code!)
if showLive
    if not na(liveCenterLine)
        line.delete(liveCenterLine)
    liveCenterLine := line.new(...)
    // ... 20 more duplicate lines

// ✅ AFTER: Single method, reuse everywhere (~30 lines total)
method draw(Regression this, color baseColor, int width) =>
    this.delete()  // Clean up old
    startY = this.calculateY(this.startBarIndex)
    endY = this.calculateY(this.endBarIndex)
    this.centerLine := line.new(this.startTime, startY, this.endTime, endY,
         xloc=xloc.bar_time, color=baseColor, width=width)

// Use anywhere - no duplication!
originalRegression.draw(origColor, 2)
liveRegression.draw(liveColor, 2)
for reg in chainedRegressions
    reg.draw(chainedColor, 1)

UDT Optimization Metrics

MetricParallel ArraysUDT Architecture
Array declarations6-101
Drawing code blocks5+ (duplicated)1 method
Clamping code4+ locations0
Lines of code400+~150
Bug riskHigh (sync issues)Low
Historical lookback5000 bars maxUnlimited

UDT Time Capture Pattern

// ALWAYS capture BOTH time and bar_index when events occur
var int eventStartTime = na
var int eventStartBar = na

if eventDetected
    eventStartTime := time        // For xloc.bar_time drawing
    eventStartBar := bar_index    // For Y calculation (slope * bar + intercept)

// Later, create UDT with both
newItem = MyType.new(
    startTime = eventStartTime,      // Drawing coordinate
    startBarIndex = eventStartBar,   // Calculation coordinate
    ...
)

Core Optimization Areas

1. Calculation Caching

// ❌ BEFORE: Repeated calculations
plot(ta.sma(close, 20) > ta.sma(close, 50) ? high : low)
bgcolor(ta.sma(close, 20) > ta.sma(close, 50) ? color.green : color.red)

// ✅ AFTER: Cache once, use many times
sma20 = ta.sma(close, 20)
sma50 = ta.sma(close, 50)
bullish = sma20 > sma50
plot(bullish ? high : low)
bgcolor(bullish ? color.new(color.green, 90) : color.new(color.red, 90))

2. Security Call Optimization

// ❌ BEFORE: Multiple security() calls (expensive)
htfClose = request.security(syminfo.tickerid, "D", close)
htfHigh = request.security(syminfo.tickerid, "D", high)
htfLow = request.security(syminfo.tickerid, "D", low)
htfVolume = request.security(syminfo.tickerid, "D", volume)

// ✅ AFTER: Single tuple call
[htfClose, htfHigh, htfLow, htfVolume] = request.security(
    syminfo.tickerid, "D",
    [close, high, low, volume])

3. Loop Optimization (Use for...in)

// ❌ SLOW/DANGEROUS: Boundary re-evaluated each iteration
for i = 0 to array.size(arr) - 1
    val = array.get(arr, i)
    // process

// ✅ BEST: Use for...in (safe, clean, preferred)
for element in arr
    // Process element directly - no boundary issues

// ✅ BEST: With index when needed
for [i, element] in arr
    // Have both index and value

// ✅ FASTEST: Use built-in array methods when possible
total = array.sum(arr)
maxVal = array.max(arr)
avgVal = array.avg(arr)

4. Conditional Logic Optimization

// ❌ SLOW: All conditions evaluated
signal = cond1 and cond2 and cond3 and expensiveCalc()

// ✅ FAST: Short-circuit with cheap checks first
signal = cond1  // Cheapest first
signal := signal and cond2
signal := signal and cond3
signal := signal and expensiveCalc()  // Only if others pass

User Experience Optimization

1. Input Organization with Active Parameter

// Professional input structure with conditional visibility

// === Main Settings ===
strategyMode = input.string("Trend Following", "Strategy Mode",
    options=["Trend Following", "Mean Reversion", "Custom"],
    group="Strategy")

// === Trend Following Settings (conditional) ===
tfLength = input.int(20, "Trend Length",
    group="Trend Following",
    active=(strategyMode == "Trend Following"),
    tooltip="Period for trend detection")

tfMultiplier = input.float(2.0, "Trend Multiplier",
    group="Trend Following",
    active=(strategyMode == "Trend Following"))

// === Mean Reversion Settings (conditional) ===
mrLength = input.int(14, "Reversion Length",
    group="Mean Reversion",
    active=(strategyMode == "Mean Reversion"))

mrThreshold = input.float(2.0, "Reversion Threshold",
    group="Mean Reversion",
    active=(strategyMode == "Mean Reversion"))

// === Visual Settings ===
showPlots = input.bool(true, "Show Plots", group="Visual")
plotColor = input.color(color.blue, "Plot Color",
    group="Visual",
    active=showPlots)  // Only show when plots enabled

2. Professional Color Schemes

// Modern, accessible color palette
var color BULL = color.new(#26a69a, 0)      // Teal green
var color BEAR = color.new(#ef5350, 0)      // Coral red
var color BULL_BG = color.new(#26a69a, 85)  // Transparent
var color BEAR_BG = color.new(#ef5350, 85)
var color NEUTRAL = color.new(#787b86, 0)   // Gray

// Gradient based on strength
strength = ta.rsi(close, 14)
gradientColor = color.from_gradient(strength, 30, 70, BEAR, BULL)

// Dark mode friendly table
var table infoTable = table.new(position.top_right, 2, 5,
    bgcolor=color.new(#131722, 10),  // TradingView dark bg
    border_color=color.new(#363a45, 0),
    border_width=1)

3. Responsive Plot Styling with Line Styles

// Use new linestyle parameter for visual hierarchy
ma = ta.ema(close, maLength)
maPlot = plot(ma, "MA", color.blue, linewidth=2,
    linestyle=plot.linestyle_solid)  // Primary: solid

// Secondary indicators: dashed
plot(upperBand, "Upper", color.gray,
    linestyle=plot.linestyle_dashed)
plot(lowerBand, "Lower", color.gray,
    linestyle=plot.linestyle_dashed)

// Projections/targets: dotted
plot(showTargets ? target : na, "Target", color.green,
    linestyle=plot.linestyle_dotted)

4. Smart Alert Messages

// Comprehensive alert with all relevant info
buildAlert(direction, price, strength) =>
    msg = "🔔 " + syminfo.ticker + " ALERT\n"
    msg += "═══════════════════\n"
    msg += "Direction: " + direction + "\n"
    msg += "Price: $" + str.tostring(price, "#,###.##") + "\n"
    msg += "Strength: " + str.tostring(strength, "#.#") + "/10\n"
    msg += "Time: " + str.format_time(time, "yyyy-MM-dd HH:mm") + "\n"
    msg += "═══════════════════"
    msg

alertcondition(buySignal,
    "Buy Signal",
    buildAlert("LONG", close, signalStrength))

Performance Checklist

Architecture (Check First!)

  • Use UDT-first for complex data structures
  • Replace parallel arrays with single UDT array
  • Use xloc.bar_time for drawings (eliminates clamping)
  • Store time + bar_index for each coordinate
  • Add methods to UDT for encapsulated logic

Must-Do Optimizations

  • Cache all repeated calculations
  • Combine security() calls into tuples
  • Cache loop boundaries (March 2025 critical)
  • Put cheap conditions before expensive ones
  • Use var for values that don't change per bar

UX Optimizations (2025 Features)

  • Use active parameter for conditional inputs
  • Group related inputs logically
  • Add tooltips to complex inputs
  • Use new linestyle parameter for visual hierarchy
  • Implement mobile-friendly compact mode option

Visual Optimizations

  • Use consistent color scheme
  • Implement gradient colors for strength
  • Use appropriate plot line widths
  • Add transparency to background colors
  • Make tables dark-mode friendly

Mobile-Friendly Optimization

// Compact mode for mobile viewing
compactMode = input.bool(false, "📱 Compact Mode",
    group="Display",
    tooltip="Enable for better mobile viewing")

// Adjust based on mode
plotWidth = compactMode ? 1 : 2
labelSize = compactMode ? size.tiny : size.small

// Conditional table display
if not compactMode
    // Full table with details
    table.cell(infoTable, 0, 0, "Full Statistics", text_color=color.white)
    // ... more cells
else
    // Minimal display
    table.cell(infoTable, 0, 0, bullish ? "↑" : "↓",
        text_color=bullish ? BULL : BEAR,
        text_size=size.large)

Memory Optimization

// Use var for persistent values
var float highestHigh = na
var int barsSinceSignal = 0

// Limit array sizes
var array<float> recentPrices = array.new<float>(100)
if barstate.isconfirmed
    array.push(recentPrices, close)
    if array.size(recentPrices) > 100
        array.shift(recentPrices)

// Clear unused data
if newDay
    array.clear(intradayData)

Optimization Quick Wins

IssueBeforeAfterImpact
Parallel arrays6+ arrays to sync1 UDT array80% less code
bar_index drawingClamping + 5000 limitxloc.bar_timeUnlimited lookback
Drawing codeDuplicate blocksUDT methodsDRY, maintainable
Repeated SMAta.sma(close,20) x5Cache in variable5x faster
Multiple security()4 separate calls1 tuple call4x faster
Loop boundaryarray.size(arr) in loopCache before loopPrevents hang
All inputs visibleCluttered UIUse active paramClean UX
One line styleAll solidsolid/dashed/dottedBetter hierarchy

The top 3 optimizations (UDT-related) provide the biggest gains. Balance optimization with readability. Don't over-optimize at the expense of maintainability.

FAQ

What does the pine-optimizer skill do?

Optimizes Pine Script for performance and user experience. Use when improving speed, UI organization, or visual appeal.

How do I install pine-optimizer?

Run npx skills add https://github.com/traderspost/pinescript-agents --skill pine-optimizer in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/pine-optimizer/ (personal) or .claude/skills/pine-optimizer/ (project).

Which AI agents can use pine-optimizer?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is pine-optimizer safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains pine-optimizer?

It is published by traderspost in traderspost/pinescript-agents. It has 462 recorded installs.

More from traderspost/pinescript-agents

View all →

pine-developer

traderspost/pinescript-agents

Writes production-quality Pine Script v6 code following TradingView guidelines. Use when implementing indicators, strategies, or any Pine Script code.

868 installs

pine-debugger

traderspost/pinescript-agents

Troubleshoots Pine Script issues and adds debugging capabilities. Use when scripts have errors or unexpected behavior.

pine-backtester

traderspost/pinescript-agents

Open the skill to read its SKILL.md instructions.

439 installs

pine-visualizer

traderspost/pinescript-agents

Open the skill to read its SKILL.md instructions.

306 installs

pine-publisher

traderspost/pinescript-agents

Open the skill to read its SKILL.md instructions.

262 installs

pine-manager

traderspost/pinescript-agents

Open the skill to read its SKILL.md instructions.

210 installs

Popular frontend & design skills

View category →

setup-matt-pocock-skills

mattpocock/skills

Configure this repo for the engineering skills: set up its issue tracker, triage label vocabulary, and domain doc layout. Run once before first use of the other engineering skills.

Frontend & Design1.1M installs

frontend-design

anthropics/skills

Guidance for distinctive, intentional visual design when building new UI or reshaping an existing one. Helps with aesthetic direction, typography, and making choices that don't read as templated defaults.

OfficialFrontend & Design1M installs

hyperframes-animation

heygen-com/hyperframes

All animation knowledge for HyperFrames — atomic motion rules, multi-phase scene blueprints, scene transitions, broader motion-design techniques, AND the seven runtime adapters (GSAP default, plus Lottie, Three.js, Anime.js, CSS keyframes, Web Animations API, TypeGPU). Use for any motion or animation task: pick 2-4 rules and compose, or load a blueprint, or look up runtime-specific API (e.g. GSAP eases / Lottie player / Three.js mixer). Also covers auditing an existing composition's choreography (animation map) and 24 named text-animation effects. HyperFrames-native: single paused timeline, seek-safe, deterministic.

prototype

mattpocock/skills

Build a throwaway prototype to answer a design question. Use when the user wants to sanity-check whether a state model or logic feels right, or explore what a UI should look like.

Frontend & Design999.2K installs

hyperframes-core

heygen-com/hyperframes

The HyperFrames composition contract — build one renderable project. Use for composition structure, the data- timing attributes, class="clip", tracks, sub-compositions, variables, framework-owned media playback, deterministic-render rules, and validation. Read before writing composition HTML.

Frontend & Design930.5K installs

vercel-react-best-practices

vercel-labs/agent-skills

React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.

OfficialFrontend & Design843.1K installs