PineTS v0.8.9: Transpiler Maturity, Switch Statements & Growing Community

,
PineTS v0.8.9: Transpiler Maturity, Switch Statements & Growing Community

We’re excited to announce PineTS v0.8.9! This release cycle (v0.8.1 through v0.8.9) focused on transpiler robustnessPine Script language coverage, and critical bug fixes – many driven by our first community contributions. Nine patch releases later, PineTS is significantly more reliable for real-world Pine Script indicators and strategies.

What’s New from v0.8.0 to v0.8.9

Full Switch Statement Support

One of the most requested Pine Script features — switch statements — is now fully supported, including complex multiline cases, TA function calls inside cases, and both expression-based and condition-based variants.

Expression-Based Switch

Use switch to select between different calculation modes at runtime:

//@version=6
indicator("Dynamic Moving Average", overlay=true)

maType = input.string("EMA", "MA Type", options=["EMA", "SMA", "RMA", "WMA"])
maLength = input.int(14, "MA Length", minval=2)

dynamicMA(src, len, maType) =>
    switch maType
        "EMA" => ta.ema(src, len)
        "SMA" => ta.sma(src, len)
        "RMA" => ta.rma(src, len)
        "WMA" => ta.wma(src, len)
        => ta.sma(src, len)

result = dynamicMA(close, maLength, maType)
plot(result, "MA", color=color.blue)

Condition-Based Switch (No Expression)

Pine Script’s switch without an expression acts like an if/else if chain — PineTS now correctly transpiles this pattern:

//@version=6
indicator("RSI Signal")

rsi = ta.rsi(close, 14)
oversold = rsi < 30
overbought = rsi > 70

var signal = 0
var strength = 0.0

switch
    oversold =>
        signal := 1
        strength := (30 - rsi) / 30
    overbought =>
        signal := -1
        strength := (rsi - 70) / 30
    =>
        signal := 0
        strength := 0.0

plot(signal, "Signal")
plot(strength, "Strength")

Multiline Case Blocks

Switch cases can now contain multiple statements, local variable declarations, nested conditionals, and TA function calls:

//@version=6
indicator("TA in Multiline Switch")

indicator_type = "trend"

result = switch indicator_type
    "trend" =>
        fast = ta.ema(close, 9)
        slow = ta.ema(close, 21)
        fast - slow
    "momentum" =>
        rsi = ta.rsi(close, 14)
        rsi


plot(result, "Result")

Plot Fill Between Lines

The new fill() function lets you shade the area between two plot lines — essential for indicators like Bollinger Bands, Keltner Channels, and Ichimoku clouds:

//@version=6
indicator("Bollinger Bands", overlay=true)
length = input.int(20, "Length")
mult = input.float(2.0, "Multiplier")

[middle, upper, lower] = ta.bb(close, length, mult)

plot(middle, "Basis", color=color.blue)
p1 = plot(upper, "Upper", color=color.red)
p2 = plot(lower, "Lower", color=color.green)
fill(p1, p2, title="BB Fill", color=color.new(color.blue, 90))

The fill() function accepts the plot objects returned by plot(), along with optional color, title, and display parameters. When paired with a charting library like QFChart, the fill area renders as a semi-transparent overlay between the two lines.

Critical Transpiler Fix: User Function Variable Isolation

v0.8.4 fixed a critical issue where local variables inside user-defined functions were sharing state across different calls. Before this fix, calling the same function multiple times could produce incorrect results because variables like sumresult, or temp would bleed between calls.

The fix introduced dynamic scoping with local contexts ($$), ensuring each function invocation gets completely isolated variable storage:

//@version=6
indicator("Multi-MA Dashboard")

ma(float source, int length, simple string maType) =>
    switch maType
        "EMA" => ta.ema(source, length)
        "SMA" => ta.sma(source, length)
        "RMA" => ta.rma(source, length)
        => ta.sma(source, length)

// Each call gets isolated state - no variable collisions
fast = ma(close, 9, "EMA")
medium = ma(close, 21, "SMA")
slow = ma(close, 50, "EMA")

plot(fast, "Fast MA")
plot(medium, "Medium MA")
plot(slow, "Slow MA")

This fix is transparent to users — the same Pine Script code just works correctly now. Under the hood, each function call is wrapped with $.call(fn, callId, ...args) and gets its own scoped context.

Enhanced For Loop Support

v0.8.7 added support for tuple destructuring in for...in loops, a commonly used pattern in Pine Script for iterating over arrays with indices:

//@version=5
indicator("Array Iteration")

processMatrix(X) =>
    for [idx, value] in X
        // idx is the array index, value is the element
        j = 0
    0

plot(close)

Additional fixes ensure that for...in and for...of loops work correctly with Pine Script arrays, including proper destructuring support and resolution of function/variable name collisions in loop contexts.

Method Call Syntax

v0.8.7 introduced proper handling of user-defined method calls. When you define a function and call it with method syntax (e.g., obj.method()), PineTS now correctly transforms it into a function call with the object as the first argument:

//@version=6
indicator("Method Syntax")

arr = array.new_float(0)
arr.push(close)
size = arr.size()

plot(size)

This also works for user-defined functions used as methods, where obj.myFunc(args) is correctly transpiled to myFunc(obj, args).

Math Namespace Additions

v0.8.4 added two new math functions:

  • math.todegrees(radians) — Converts radians to degrees
  • math.toradians(degrees) — Converts degrees to radians

These are useful for indicators involving angular calculations, cycle analysis, or trigonometric patterns.

Transpiler Reliability Improvements

This release cycle brought a wave of transpiler hardening. Here are the most impactful fixes:

VersionFixImpact
v0.8.1Operator precedence: (a + b) * c was losing parenthesesArithmetic expression correctness
v0.8.2Variable name collisions in transpilerPrevented incorrect variable renaming
v0.8.2Logical expressions (&&||) in function argumentsProper evaluation in nested calls
v0.8.3Scientific notation (10e101.2e-5) parsingLexer correctly tokenizes literals
v0.8.3Double parentheses in return statements (math.max()())Namespace calls in returns work
v0.8.4Array access in ternary expressionsCorrect scope keys in expressions
v0.8.4SMA NaN contamination in rolling windowFalls back to recalculation
v0.8.5Multiline Pine Script condition parsingIndentation errors resolved
v0.8.7Unary operators with function calls (!func())Proper AST transformation
v0.8.7Method chains (func(arg).method())Arguments transformed correctly
v0.8.8ta.bb return order [middle, upper, lower]Matches Pine Script behavior
v0.8.8color.new() RGBA conversionCorrect color string output
v0.8.9Typed variable declarationsPine Script v5 compatibility

Bollinger Bands Return Order Fix

A notable fix in v0.8.8ta.bb() now returns [middle, upper, lower] to match Pine Script’s actual return order. Previously, the order was incorrect, which could cause subtle bugs in indicators that destructure the result:

// Now correctly matches Pine Script behavior
[middle, upper, lower] = ta.bb(close, 20, 2.0)

Community Contributions

We’re thrilled to highlight our first community contributions! PineTS is growing beyond a solo project:

@dcaoyuan contributed:

  • Fixed color.new() RGBA string generation (v0.8.8)
  • Fixed ta.bb return order to match Pine Script (v0.8.8)
  • Fixed ta.highest / ta.lowest to accept length as first argument (v0.8.9)
  • Removed non-standard colors from the color palette (v0.8.9)
  • Fixed unary operator handling in transpiler (v0.8.7)

@C9Bad contributed:

  • Fixed parser to allow comments between if block and else (v0.8.8)
  • Fixed parser to allow inline comments after type fields (v0.8.8)

Thank you both for making PineTS better! Community contributions are what drive open-source projects forward.

Installation & Upgrade

Install or upgrade to the latest version:

npm install pinets@latest

Bug Fixes Summary

Across nine patch releases, here’s the full list of fixes:

  • v0.8.1: Operator precedence in complex arithmetic expressions
  • v0.8.2: Variable name collisions, logical expressions in function arguments
  • v0.8.3: Scientific notation parsing, double-parentheses in return statements
  • v0.8.4: User function variable scope isolation, SMA NaN handling, math.round precision, array access in expressions
  • v0.8.5: Multiline conditions parsing, switch syntax conversion, deprecation warning false positives
  • v0.8.6: Binance provider stream data handling
  • v0.8.7: For loop destructuring, method calls, switch IIFEs, unary operators, matrix operations
  • v0.8.8: Color conversion, comment handling, Bollinger Bands return order
  • v0.8.9: Typed variable declarations, ta.highest/ta.lowest argument handling, standard color list

What’s Next

The next release cycle will focus on:

  • Drawing primitiveslabel.*line.*box.*table.*linefill.*, and polyline.* for full TradingView drawing parity
  • Strategy namespace: Expanding strategy support for backtesting workflows
  • Performance: Continued optimization for large datasets and live streaming scenarios

Get Involved

PineTS is open-source (AGPL-3.0) and community-driven. We welcome contributions, bug reports, and feature requests.


Leave a Reply

Your email address will not be published. Required fields are marked *