SKILL.md
Pine Script Developer
Specialized in writing production-quality Pine Script v6 code for TradingView.
⚠️ CRITICAL: Pine Script Syntax Rules
BEFORE writing ANY multi-line Pine Script code, remember:
- TERNARY OPERATORS (
? :) - MUST stay on ONE line or use intermediate variables
- Line continuation - ALL continuation lines must be indented MORE than the starting line
- Common error: "end of line without line continuation" - caused by improper line breaks
// ❌ NEVER DO THIS:
text = condition ? "value1" :
"value2"
// ✅ ALWAYS DO THIS:
text = condition ? "value1" : "value2"
See the "Line Wrapping Rules" section below for complete rules.
## Documentation Access
Primary documentation references:
- `/docs/pinescript-v6/quick-reference/syntax-basics.md` - Core syntax and structure
- `/docs/pinescript-v6/reference-tables/function-index.md` - Complete function reference
- `/docs/pinescript-v6/core-concepts/execution-model.md` - Understanding Pine Script execution
- `/docs/pinescript-v6/core-concepts/repainting.md` - Avoiding repainting issues
- `/docs/pinescript-v6/quick-reference/limitations.md` - Platform limits and workarounds
Load these docs as needed based on the task at hand.
## Project File Management
- When starting a new project, work with the file that has been renamed from blank.pine
- Always save work to `/projects/[project-name].pine`
- Never create new files unless specifically needed for multi-file projects
- Update the file header with accurate project information
## Core Expertise
### Pine Script v6 Mastery
- Complete understanding of Pine Script v6 syntax
- All built-in functions and their proper usage
- Variable scoping and namespaces
- Series vs simple values
- Request functions (request.security, request.security_lower_tf)
### TradingView Environment
- Platform limitations (500 bars, 500 plots, 64 drawings, etc.)
- Execution model and calculation stages
- Real-time vs historical bar states
- Alert system capabilities and constraints
- Library development standards
### Code Quality Standards
- Clean, readable code structure
- Proper error handling for na values
- Efficient calculations to minimize load time
- Appropriate use of var/varip for persistence
- Proper type declarations
## CRITICAL: Line Wrapping Rules
Pine Script has STRICT line continuation rules that MUST be followed:
1. **Indentation Rule**: Lines MUST be indented more than the first line
2. **Break at operators/commas**: Split AFTER operators or commas, not before
3. **Function arguments**: Each continuation must be indented
4. **No explicit continuation character** in Pine Script v6
### SYSTEMATIC CHECK - Review ALL of these:
- [ ] `indicator()` or `strategy()` declarations at the top
- [ ] All `plot()`, `plotshape()`, `plotchar()` functions
- [ ] All `if` statements with multiple conditions
- [ ] All variable assignments with long expressions
- [ ] All `strategy.entry()`, `strategy.exit()` calls
- [ ] All `alertcondition()` calls
- [ ] All `table.cell()` calls
- [ ] All `label.new()` and `box.new()` calls
- [ ] Any line longer than 80 characters
### CRITICAL: Ternary Operators MUST Stay on One Line
// WRONG - Will cause "end of line without line continuation" error
text = condition ?
"true value" :
"false value"
// CORRECT - Entire ternary on one line
text = condition ? "true value" : "false value"
// CORRECT - For long ternaries, assign intermediate variables
trueText = str.format("Long true value with {0}", param)
falseText = str.format("Long false value with {0}", other)
text = condition ? trueText : falseText
### CORRECT Line Wrapping:
// CORRECT - indented continuation
longCondition = ta.crossover(ema50, ema200) and
rsi < 30 and
volume > ta.sma(volume, 20)
// CORRECT - function arguments
plot(series,
title="My Plot",
color=color.blue,
linewidth=2)
// CORRECT - long calculations
result = (high - low) / 2 +
(close - open) * 1.5 +
volume / 1000000
### INCORRECT Line Wrapping (WILL CAUSE ERRORS):
// WRONG - same indentation
longCondition = ta.crossover(ema50, ema200) and
rsi < 30 and
volume > ta.sma(volume, 20)
// WRONG - not indented enough
plot(series,
title="My Plot",
color=color.blue)
## Script Structure Template
//@version=6
indicator(title="", shorttitle="", overlay=true)
// ============================================================================
// INPUTS
// ============================================================================
[Group inputs logically]
// ============================================================================
// CALCULATIONS
// ============================================================================
[Core calculations]
// ============================================================================
// CONDITIONS
// ============================================================================
[Logic conditions]
// ============================================================================
// PLOTS
// ============================================================================
[Visual outputs]
// ============================================================================
// ALERTS
// ============================================================================
[Alert conditions]
## CRITICAL: Plot Scope Restriction
**NEVER use plot() inside local scopes** - This causes "Cannot use 'plot' in local scope" error
// ❌ WRONG - These will ALL fail:
if condition
plot(value) // ERROR!
for i = 0 to 10
plot(close[i]) // ERROR!
myFunc() =>
plot(close) // ERROR!
// ✅ CORRECT - Use these patterns instead:
plot(condition ? value : na) // Conditional plotting
plot(value, color=condition ? color.blue : color.new(color.blue, 100)) // Conditional styling
// For dynamic drawing in local scopes, use:
if condition
line.new(...) // OK
label.new(...) // OK
box.new(...) // OK
## Best Practices
### Avoid Repainting
- Use barstate.isconfirmed for signals
- Proper request.security() with lookahead=barmerge.lookahead_off
- Document any intentional repainting
### Performance Optimization
- Minimize security() calls
- Cache repeated calculations
- Use switch instead of multiple ifs
- Optimize array operations
### User Experience
- Logical input grouping with group= parameter
- Helpful tooltips for complex inputs
- Sensible default values
- Clear input labels
### Error Handling
- Check for na values before operations
- Handle edge cases (first bars, division by zero)
- Graceful degradation when data unavailable
## TradingView Constraints
### Limits to Remember
- Maximum 500 bars historical reference
- Maximum 500 plot/hline/fill outputs
- Maximum 64 drawing objects (label/line/box/table)
- Maximum 40 security() calls
- Maximum 100KB compiled script size
- Tables: max 100 cells
- Arrays: max 100,000 elements
### Platform Quirks
- bar_index starts at 0
- na propagation in calculations
- Historical vs real-time calculation differences
- Strategy calculations on bar close (unless calc_on_every_tick)
- Alert firing conditions and timing
## Code Review Checklist
- Version declaration (//@version=6)
- Proper title and overlay setting
- Inputs have tooltips and groups
- No repainting issues
- na values handled
- Efficient calculations
- Clear variable names
- Comments for complex logic
- Proper plot styling
- Alert conditions if needed
## Example: Moving Average Cross Strategy
//@version=6
strategy("MA Cross Strategy", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=10)
// Inputs
fastLength = input.int(50, "Fast MA Length", minval=1, group="Moving Averages")
slowLength = input.int(200, "Slow MA Length", minval=1, group="Moving Averages")
maType = input.string("EMA", "MA Type", options=["SMA", "EMA", "WMA"], group="Moving Averages")
// Calculations
ma(source, length, type) =>
switch type
"SMA" => ta.sma(source, length)
"EMA" => ta.ema(source, length)
"WMA" => ta.wma(source, length)
fastMA = ma(close, fastLength, maType)
slowMA = ma(close, slowLength, maType)
// Conditions
longCondition = ta.crossover(fastMA, slowMA)
shortCondition = ta.crossunder(fastMA, slowMA)
// Strategy
if longCondition
strategy.entry("Long", strategy.long)
if shortCondition
strategy.close("Long")
// Plots
plot(fastMA, "Fast MA", color.blue, 2)
plot(slowMA, "Slow MA", color.red, 2)