mcpField
P
pine-developer

pine-developer

github.com/traderspost开发223873 次安装14 周前更新
代码仓库

关于 pine-developer

pine-developer 是面向 TradingView Pine Script v6 开发的技能,提供代码模式,并涵盖语言更新、脚本架构、平台限制和代码审查。

主要功能

  1. 01Pine Script v6 更新指南
  2. 02指标与策略模板
  3. 03优先使用 UDT 的架构模式
  4. 04避免重绘的建议
  5. 05代码审查清单

适用场景

  1. 01编写 TradingView 指标
  2. 02实现 TradingView 策略
  3. 03检查 Pine Script 是否符合平台限制

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/traderspost/pinescript-agents --skill pine-developer

安装后在 Claude Code 中输入/pine-developer确认已加载。

详细介绍

Pine Script 开发者

专注于为 TradingView 编写可用于生产环境的高质量 Pine Script v6 代码。

⚠️ 关键:Pine Script v6 2025 年更新

这些更新对于编写正确、现代的 Pine Script 代码至关重要:

2025 年 12 月:更新换行规则

括号内的表达式现在支持灵活缩进:

// ✅ NOW VALID - Any indentation inside parentheses
plot(series,
    title="My Plot",    // Can use any indentation
    color=color.blue)

// ✅ Also valid
longCondition = (ta.crossover(ema50, ema200) and
    rsi < 30 and
    volume > ta.sma(volume, 20))

// ⚠️ STILL REQUIRED outside parentheses - non-multiple-of-4 indentation
longCondition = ta.crossover(ema50, ema200) and
     rsi < 30   // Must NOT be multiple of 4 spaces
2025 年 3 月:重大变更 - for 循环动态边界

for 循环现在会在每次迭代前计算 to_num,而非仅计算一次。

首选:对集合使用 for...in 循环:

// ✅ BEST: Use for...in for arrays (safe, clean, preferred)
for element in myArray
    // Process element directly

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

// ✅ for...in works with arrays, matrices, and maps
for [key, value] in myMap
    // Iterate key-value pairs

如果必须使用传统的 for 循环:

// ⚠️ BREAKING: This creates infinite loop!
var arr = array.new<int>()
for i = 0 to array.size(arr)  // Re-evaluated each iteration
    array.push(arr, i)  // Array grows, loop never ends!

// ✅ FALLBACK: Cache the boundary if using traditional for
size = array.size(arr)
for i = 0 to size
    array.push(arr, i)

注意: for...in 允许在迭代期间修改数组/矩阵的大小。映射不能在 for...in 期间调整大小——请改用 map.keys() 数组。

2025 年 2 月:移除作用域数量限制
  • 之前总共限制为 550 个作用域
  • 现在函数、方法、循环、条件语句、类型和枚举中的作用域数量不受限制
2025 年 2 月:买卖价变量
// Only available on 1T (tick) timeframe
bidPrice = bid  // Highest buyer price (na on other timeframes)
askPrice = ask  // Lowest seller price (na on other timeframes)

Pine Script v6 2025 年新功能

2025 年 7 月:输入函数的 active 参数

现在所有输入函数都支持条件激活:

useCustomMA = input.bool(false, "Use Custom MA")
customMALength = input.int(20, "Custom MA Length",
    active=useCustomMA,  // Grayed out when useCustomMA is false
    tooltip="Only available when 'Use Custom MA' is enabled")
2025 年 7 月:syminfo.current_contract
// For continuous futures - returns underlying contract ticker
currentContract = syminfo.current_contract  // Returns na for non-continuous
2025 年 11 月:syminfo.isin
// International Securities Identification Number (12 chars)
isinCode = syminfo.isin  // Empty string if unavailable
2025 年 9 月:绘图线条样式
plot(series, linestyle=plot.linestyle_solid)   // Default
plot(series, linestyle=plot.linestyle_dashed)  // Dashed line
plot(series, linestyle=plot.linestyle_dotted)  // Dotted line
2025 年 10 月:增强的 time() 和 time_close()

新增 timeframe_bars_back 参数:

// Get time from 5 bars back on the DAILY timeframe (not current chart)
dailyTimeBack = time("D", timeframe_bars_back=5)

// Positive = past bars, Negative = future (expected) timestamps
futureTime = time("D", timeframe_bars_back=-1)  // Expected next bar
2025 年 8 月:增加字符串长度
  • 字符串最大长度:40,960 个字符(原为 4,096)
2025 年 6 月:库常量导出
// In library:
//@version=6
library("MyLib")
export const float PI = 3.14159265359
export const int MAX_BARS = 500
export const string VERSION = "1.0.0"
2025 年 5 月:非基于时间的图表中的 time_close

适用于 Renko、Line Break、Kagi、Point & Figure、Range 图表:

  • 开盘实时柱的 time_close 现在会返回 na
  • 柱线收盘后,time_close[1] 现在可以立即使用
2025 年 4 月:基于百分比的代码样式
// New "PercentageLTP" style for percentage box sizing
renkoTicker = ticker.renko(syminfo.tickerid, "PercentageLTP", 1.0)
kagiTicker = ticker.kagi(syminfo.tickerid, "PercentageLTP", 0.5)
pnfTicker = ticker.pointfigure(syminfo.tickerid, "PercentageLTP", 1.0)
2025 年 3 月:box.set_xloc()
// Modify box x-coordinates after creation
box.set_xloc(myBox, left, right, xloc.bar_index)
box.set_xloc(myBox, leftTime, rightTime, xloc.bar_time)

关键:换行规则(2025 年 12 月更新)

括号内(灵活)
// ✅ Any indentation works inside ()
plot(series,
    title="Plot",
        color=color.blue,  // Different indentation OK
    linewidth=2)

indicator("Title",
    overlay=true,
    max_bars_back=500)
括号外(严格)
// ✅ CORRECT - Non-multiple-of-4 indentation
longCondition = ta.crossover(ema50, ema200) and
     rsi < 30 and
     volume > ta.sma(volume, 20)

// ❌ WRONG - Multiple of 4 (or same level)
longCondition = ta.crossover(ema50, ema200) and
    rsi < 30  // Error: 4 spaces

longCondition = ta.crossover(ema50, ema200) and
rsi < 30  // Error: same indentation
关键:三元运算符——保持在同一行
// ❌ NEVER split ternary across lines
text = condition ?
    "value1" :
    "value2"  // ERROR!

// ✅ ALWAYS keep on one line
text = condition ? "value1" : "value2"

// ✅ For long ternaries, use intermediate variables
trueText = str.format("Long value {0}", param1)
falseText = str.format("Other value {0}", param2)
result = condition ? trueText : falseText

关键:绘图作用域限制

绝不要在局部作用域内使用 plot():

// ❌ WRONG - All of these fail:
if condition
    plot(value)  // ERROR: Cannot use 'plot' in local scope

for i = 0 to 10
    plot(close[i])  // ERROR!

myFunc() =>
    plot(close)  // ERROR!

// ✅ CORRECT patterns:
plot(condition ? value : na)  // Conditional plotting
plot(value, color=condition ? color.blue : na)  // Conditional color

// For dynamic drawing in local scopes, use:
if condition
    line.new(...)   // OK
    label.new(...)  // OK
    box.new(...)    // OK

⚠️ 关键:UDT 优先架构

对于任何复杂数据结构,务必先定义用户自定义类型(UDT),再编写其他代码。

为什么要 UDT 优先?
  1. 封装:将相关数据和绘图对象打包在一起
  2. 方法:使用 method 语法直接为类型添加行为
  3. 无限回溯:使用 xloc.bar_time 而不是 xloc.bar_index(后者限制为 5000 根柱线!)
  4. 整洁数组:使用一个 array<MyType>,而不是 6 个以上的并行数组
  5. 自动管理绘图:类型可以创建/删除自己的可视化对象
UDT 定义模式
// ALWAYS define UDTs early in script (after inputs, before calculations)
type Regression
    // Time coordinates (for xloc.bar_time - NO lookback limit!)
    int startTime
    int endTime

    // Bar indices (for Y calculations: y = slope * barIndex + intercept)
    int startBarIndex
    int endBarIndex

    // Data parameters
    float slope
    float intercept
    float stdDev
    float pearsonR

    // State flags
    bool isLive = false
    bool isOriginal = false

    // Drawing objects (managed internally)
    line centerLine = na
    line upperLine = na
    line lowerLine = na
    linefill fill = na
UDT 方法模式
// Delete method - clean up drawing objects
method delete(Regression this) =>
    if not na(this.centerLine)
        line.delete(this.centerLine)
    if not na(this.upperLine)
        line.delete(this.upperLine)
    if not na(this.lowerLine)
        line.delete(this.lowerLine)
    if not na(this.fill)
        linefill.delete(this.fill)
    this.centerLine := na
    this.upperLine := na
    this.lowerLine := na
    this.fill := na

// Calculation method
method calculateY(Regression this, int barIdx) =>
    this.slope * barIdx + this.intercept

// Draw method - use xloc.bar_time for unlimited lookback!
method draw(Regression this, color baseColor, int width) =>
    this.delete()  // Clean up old drawings first
    startY = this.calculateY(this.startBarIndex)
    endY = this.calculateY(this.endBarIndex)

    // ✅ CRITICAL: Use xloc.bar_time - NO 5000 bar limit!
    this.centerLine := line.new(
         this.startTime, startY,
         this.endTime, endY,
         xloc=xloc.bar_time,  // ← UNLIMITED LOOKBACK
         color=baseColor,
         width=width)
⚠️ 关键:xloc.bar_time 与 xloc.bar_index

对于可能需要显示历史数据的绘图对象,务必使用 xloc.bar_time:

// ❌ WRONG - Limited to 5000 bars back
line.new(bar_index - 100, y1, bar_index, y2, xloc=xloc.bar_index)

// ✅ CORRECT - Unlimited historical lookback
line.new(time[100], y1, time, y2, xloc=xloc.bar_time)

// Store TIME when events occur, not just bar_index
var int eventTime = na
var int eventBarIndex = na
if eventOccurred
    eventTime := time           // For drawing
    eventBarIndex := bar_index  // For Y calculation
UDT 存储模式
// Single array of UDTs instead of parallel arrays
var array<Regression> regressions = array.new<Regression>()
var Regression liveRegression = na
var Regression originalRegression = na

// ❌ WRONG - Parallel arrays (hard to maintain)
var array<float> slopes = array.new<float>()
var array<float> intercepts = array.new<float>()
var array<int> startBars = array.new<int>()
var array<int> endBars = array.new<int>()
// ... 6+ arrays to keep in sync!

// ✅ CORRECT - Single UDT array
var array<Regression> regressions = array.new<Regression>()
创建和存储 UDT
// Create new instance with all data
newRegression = Regression.new(
    startTime = capturedStartTime,
    endTime = capturedEndTime,
    startBarIndex = capturedStartBar,
    endBarIndex = capturedEndBar,
    slope = calculatedSlope,
    intercept = calculatedIntercept,
    stdDev = calculatedStdDev,
    pearsonR = calculatedR
)

// Add to collection
array.push(regressions, newRegression)
使用 for...in 遍历 UDT 数组
// ✅ BEST: Use for...in for UDT arrays
for reg in regressions
    baseColor = reg.slope >= 0 ? uptrendColor : downtrendColor
    reg.draw(baseColor, lineWidth)

// ✅ With index when needed
for [i, reg] in regressions
    if i == array.size(regressions) - 1
        // Special handling for last item
时间捕获模式
// Capture BOTH time and bar_index when events occur
var int startTime = na
var int startBarIndex = na
var int endTime = na
var int endBarIndex = na

if eventStart
    startTime := time        // For xloc.bar_time drawing
    startBarIndex := bar_index  // For Y calculations

if eventEnd
    endTime := time
    endBarIndex := bar_index

    // Create UDT with both coordinate systems
    newItem = MyType.new(
        startTime = startTime,
        endTime = endTime,
        startBarIndex = startBarIndex,
        endBarIndex = endBarIndex
    )
UDT 架构检查清单
  • 在任何计算之前定义 UDT 类型
  • 存储绘图坐标所需的 time 值
  • 存储用于 Y 轴计算的 bar_index 值
  • 将绘图对象(line、box、label)作为 UDT 字段
  • 添加 delete() 方法以清理绘图
  • 添加使用 xloc.bar_time 的 draw() 方法
  • 使用单个 array<MyType>,而不是并行数组
  • 使用 for...in 遍历 UDT 数组

文档访问

主要文档参考:

  • /docs/pinescript-v6/quick-reference/syntax-basics.md - 核心语法
  • /docs/pinescript-v6/reference-tables/function-index.md - 函数参考
  • /docs/pinescript-v6/core-concepts/execution-model.md - 执行模型
  • /docs/pinescript-v6/core-concepts/repainting.md - 重绘问题
  • /docs/pinescript-v6/quick-reference/limitations.md - 平台限制

项目文件管理

  • 将工作保存到 /projects/[project-name].pine
  • 使用准确的项目信息更新文件头部
  • 切勿创建不必要的文件

脚本结构模板

指标模板
// built with PineScript Agents by TradersPost
//@version=6
indicator(title="", shorttitle="", overlay=true)
策略模板(重要:包含警报注解)
// built with PineScript Agents by TradersPost
//@version=6
strategy(title="", shorttitle="", overlay=true)
//@strategy_alert_message {{strategy.order.alert_message}}

// ============================================================================
// INPUTS
// ============================================================================

// Group 1: Main Settings
setting1 = input.int(14, "Setting", group="Main Settings",
    tooltip="Description of what this does")

// Group 2: Visual Settings
showPlots = input.bool(true, "Show Plots", group="Visual Settings")
plotColor = input.color(color.blue, "Plot Color", group="Visual Settings",
    active=showPlots)  // Grayed out when showPlots is false

// ============================================================================
// CALCULATIONS
// ============================================================================

// Cache boundaries for loops (March 2025 breaking change)
arraySize = array.size(myArray)
for i = 0 to arraySize - 1
    // Process...

// ============================================================================
// CONDITIONS
// ============================================================================

// ============================================================================
// PLOTS
// ============================================================================

// Use new linestyle parameter (September 2025)
plot(ma, "MA", color.blue, linewidth=2, linestyle=plot.linestyle_solid)

// ============================================================================
// ALERTS
// ============================================================================

TradingView 限制(2025 年更新)

限制
  • 历史引用最多 500 根 K 线
  • plot/hline/fill 输出最多 500 个
  • 绘图对象(label/line/box/table)最多 64 个
  • security() 调用最多 40 次
  • 编译后的脚本大小最多 100KB
  • 表格:最多 100 个单元格
  • 数组:最多 100,000 个元素
  • 字符串:最多 40,960 个字符(2025 年 8 月上限提高)
  • 作用域:无限制(2025 年 2 月取消限制)
平台特性
  • bar_index 从 0 开始
  • 计算中的 na 传播
  • 历史计算与实时计算之间存在差异
  • 策略在 K 线收盘时计算(除非启用 calc_on_every_tick)
  • bid/ask 仅在 1T 时间周期可用

最佳实践

避免重绘
// Use barstate.isconfirmed for signals
if barstate.isconfirmed and buyCondition
    strategy.entry("Long", strategy.long)

// Proper request.security() usage
htfClose = request.security(syminfo.tickerid, "D", close,
    lookahead=barmerge.lookahead_off)
性能优化
// Cache repeated calculations
sma20 = ta.sma(close, 20)
sma50 = ta.sma(close, 50)
crossUp = ta.crossover(sma20, sma50)

// Combine security() calls
[htfClose, htfHigh, htfLow] = request.security(syminfo.tickerid, "D",
    [close, high, low])
用户体验(使用 2025 年功能)
// Input groups with active parameter
advancedMode = input.bool(false, "Advanced Mode", group="Settings")
advSetting = input.int(10, "Advanced Setting",
    group="Settings",
    active=advancedMode,  // July 2025 feature
    tooltip="Only visible in advanced mode")
错误处理
// Check for na values
safeValue = na(value) ? 0 : value

// Handle division by zero
safeDiv = denominator != 0 ? numerator / denominator : 0

// Cache loop boundaries (March 2025 breaking change)
arrSize = array.size(arr)
for i = 0 to arrSize - 1
    // ...

代码审查清单

架构(优先检查!)
  • 复杂数据采用 UDT 优先模式
  • 绘图对象使用 xloc.bar_time(而非 bar_index)
  • 捕获时间值以用于历史绘图
  • 使用单个 UDT 数组,而非并行数组
脚本基础
  • //@version=6 声明
  • 策略使用 //@strategy_alert_message {{strategy.order.alert_message}}(放置在 strategy() 调用之后)
  • 标题和 overlay 设置正确
输入项与用户体验
  • 输入项包含工具提示和分组
  • 在适当情况下使用输入项的 active 参数
  • 在适当情况下使用新的绘图线型
  • 绘图样式正确
代码质量
  • 不存在重绘问题
  • 正确处理 na 值
  • 缓存循环边界(2025 年 3 月修复)
  • 计算高效
  • 变量名称清晰
  • 根据需要设置警报条件

编写可用于生产环境的高效代码,并采用 UDT 优先架构以及最新的 Pine Script v6 功能。

评论

支持 Markdown