Pine Script: How to Return Multiple Values from a Function?

As an experienced Pine Script developer, you quickly encounter situations where a single function needs to compute and return more than one piece of information. Whether you’re calculating multiple related metrics, returning a primary result alongside a status flag, or bundling various components of a complex calculation, the need to return multiple values is fundamental.

Introduction to Returning Multiple Values in Pine Script

Pine Script functions, by default, are designed to return a single value. This is a common pattern in many programming languages. However, real-world trading logic often requires bundling several outputs together.

Why Return Multiple Values? Use Cases in TradingView

In the context of trading scripts, returning multiple values is essential for:

  • Bundling related calculations: A function might calculate an EMA and its corresponding deviation from the price.
  • Returning main result and status: A function checking for a specific pattern might return true/false and the value at which the pattern occurred.
  • Complex indicator components: Calculating pivot points might require returning the high, low, and close levels simultaneously.
  • Strategy entry/exit details: A function determining an entry signal might also need to return the proposed entry price and stop loss level.

Limitations of Single Return Values in Pine Script Functions

The primary limitation is straightforward: a statement like return value1, value2 is not valid syntax in Pine Script. Attempting this will result in a compilation error. Therefore, we need structured approaches to encapsulate multiple values into a single entity that the function can return.

Using Arrays to Return Multiple Values

One of the most common and straightforward methods to return multiple values is by using arrays. Arrays allow you to group a collection of values of the same data type into a single variable.

Creating and Populating Arrays in Pine Script Functions

Inside your function, you can create a new array and populate it with the values you intend to return. Remember that standard Pine Script arrays are homogeneous (hold values of the same type), although version 5 introduced array<tuple> and array<struct>, standard arrays are typically used for returning values of the same base type.

calculateHighLow(source) =>
    // Calculate high and low based on source
    highVal = ta.highest(source, 10)
    lowVal = ta.lowest(source, 10)

    // Create an array
    // Note: Array must be declared with a specific type in v5+
    var float[] resultArray = array.new<float>(0)

    // Add values to the array
    array.push(resultArray, highVal)
    array.push(resultArray, lowVal)

    // Return the array
    resultArray

Returning Arrays from Functions

As shown above, once the array is created and populated within the function, you simply specify the array variable as the return value. The function’s signature implicitly defines its return type as an array of the type it contains.

Accessing Individual Values from the Returned Array

After calling the function, the returned array can be assigned to a variable. You can then access individual values using the array index operator [] or the array.get() function. Remember that array indices start from 0.

// Call the function
returnedValues = calculateHighLow(close)

// Access individual values
returnedHigh = returnedValues[0] // or array.get(returnedValues, 0)
returnedLow = returnedValues[1]  // or array.get(returnedValues, 1)

// Use the values (e.g., plot them)
plot(returnedHigh, color=color.green, title="Calculated High")
plot(returnedLow, color=color.red, title="Calculated Low")

Example: Returning High and Low Prices as an Array

The code snippets above demonstrate this concept directly. calculateHighLow returns a float array containing two elements: the calculated high at index 0 and the calculated low at index 1.

Utilizing Tuples (Arrays) for Named Returns

While Pine Script doesn’t have a dedicated tuple type like Python, we often use the term ‘tuple’ conceptually when using arrays to return a fixed number of heterogeneous or semantically distinct values. The array acts like a tuple, where each index has a predefined meaning.

Defining Tuples for Clarity

Since Pine Script doesn’t enforce tuple structure syntactically, clarity comes from documentation and variable naming. You define what each position in the array represents in your comments or internal documentation.

For instance, if an array is expected to return [averagePrice, volumeMA, signalFlag], you define this structure mentally or in comments:

  • Index 0: Average Price (float)
  • Index 1: Volume Moving Average (float)
  • Index 2: Signal Flag (bool, represented as 0.0 or 1.0 if using a float array)

Returning Multiple Values as a Tuple (Array)

The process is identical to returning a standard array. You create the array, add values in the specific, predefined order, and return the array variable.

calculateMetrics(price, vol, length) =>
    avgPrice = ta.sma(price, length)
    volMA = ta.sma(vol, length)
    // Example signal: price > avgPrice
    signalFlag = price > avgPrice ? 1.0 : 0.0 // Represent bool as float

    // Create and populate the array (conceptual tuple)
    var float[] metricsArray = array.new<float>(0)
    array.push(metricsArray, avgPrice)
    array.push(metricsArray, volMA)
    array.push(metricsArray, signalFlag)

    metricsArray

Accessing Named Elements in the Returned Tuple

The key to making this approach readable is immediately assigning the returned array elements to meaningful variables after the function call. This mimics named access.

// Call the function
allMetrics = calculateMetrics(close, volume, 20)

// Assign to named variables based on the defined tuple structure
var float avgPrice = array.get(allMetrics, 0)
var float volMA    = array.get(allMetrics, 1)
var float signalFlag = array.get(allMetrics, 2)

// Now use the named variables
plot(avgPrice, title="Avg Price")
plot(volMA, title="Volume MA")
plotchar(signalFlag == 1.0, title="Signal", location=location.top, color=color.blue)

Benefits of Using Tuples (Arrays) for Code Readability

Assigning array elements to named variables immediately after the function call significantly improves code readability compared to repeatedly using returnedArray[0], returnedArray[1], etc., throughout the script. It makes the code’s intent much clearer.

Returning a Structure (User-Defined Type)

Pine Script v5 introduced User-Defined Types (type), which are essentially structures. This provides a much more robust and type-safe way to bundle multiple, potentially heterogeneous values into a single object. Structures offer named fields, eliminating the need to remember array indices.

Defining a User-Defined Type

You define a structure using the type keyword, specifying the name of the structure and the names and types of its fields.

type MyMetrics
    float avgPrice
    float volMA
    bool signalFlag

Creating Function to Return Values of the UDT

Your function can now create an instance of this structure, populate its fields, and return the instance.

calculateComplexMetrics(price, vol, length) =>
    // Calculate values
    avgPriceVal = ta.sma(price, length)
    volMAVal = ta.sma(vol, length)
    signalVal = price > avgPriceVal

    // Create and populate an instance of the structure
    var MyMetrics resultStruct = MyMetrics.new(
         avgPrice=avgPriceVal,
         volMA=volMAVal,
         signalFlag=signalVal
         )

    // Return the structure instance
    resultStruct

Notice the use of MyMetrics.new(...) to create an instance and assign values to fields by name.

Working with Structure Fields

After calling the function, you assign the returned structure instance to a variable. You can then access individual fields using the dot operator (.).

// Call the function
allResults = calculateComplexMetrics(close, volume, 20)

// Access individual fields using the dot operator
currentAvgPrice = allResults.avgPrice
currentVolMA    = allResults.volMA
currentSignal   = allResults.signalFlag

// Use the values
plot(currentAvgPrice, title="Struct Avg Price")
plot(currentVolMA, title="Struct Volume MA")
plotchar(currentSignal, title="Struct Signal", location=location.top, color=color.blue)

Example: Returning values like Volume, ATR and RSI as a Structure

Let’s define a structure for different indicator values and a function that returns it.

//@version=5
indicator("Multi-Value Return Example (Struct)", shorttitle="MVR Struct")

type IndicatorValues
    float currentVolume
    float currentATR
    float currentRSI

getIndicatorReadings(src, lengthATR, lengthRSI) =>
    // Calculate values
    vol = volume
    atr = ta.atr(lengthATR)
    rsi = ta.rsi(src, lengthRSI)

    // Create and return structure instance
    IndicatorValues.new(
        currentVolume = vol,
        currentATR    = atr,
        currentRSI    = rsi
        )

// --- Usage --- //

lengthATR = input.int(14, "ATR Length")
lengthRSI = input.int(14, "RSI Length")

// Call the function to get the structure
readings = getIndicatorReadings(close, lengthATR, lengthRSI)

// Access and plot values from the structure
plot(readings.currentVolume, title="Volume", color=color.blue)
plot(readings.currentATR, title="ATR", color=color.orange)
plot(readings.currentRSI, title="RSI", color=color.purple)

This example clearly shows how structures encapsulate different data types and provide named access, making the code much cleaner than managing separate variables or relying on array indices.

Best Practices and Considerations

Choosing the right method for returning multiple values depends on the complexity and nature of the data.

Choosing the Right Method: Arrays vs. Tuples vs. Structures

  • Arrays: Best for returning a simple, fixed number of values of the same data type, where the order is easily understood (e.g., [high, low], [open, close]). Can be used conceptually as tuples for a small, fixed number of values of potentially different types, but requires strict adherence to index meaning.
  • Structures (UDT): Preferred method in Pine Script v5+ for returning multiple values, especially when they are of different data types or when the number of values is significant. Structures provide named fields, improving readability, maintainability, and type safety significantly.

Error Handling and Validation

When using arrays, consider what happens if the function calculation fails or if input parameters are invalid. The array might be empty or contain na values. Always check array size before accessing elements or handle potential na values appropriately when processing the returned data.

When using structures, ensure that all fields are properly populated before returning. Accessing fields of an na structure instance will result in an error, so consider checking if the returned structure is na if its creation was conditional.

Performance Implications

Creating and returning arrays or structure instances does involve some overhead compared to returning a single primitive value. However, for typical Pine Script indicator or strategy calculations, this overhead is usually negligible and should not be a primary concern unless you are performing these operations millions of times within a single script execution (which is uncommon). Focus on code clarity and correctness first.

Code Maintainability and Readability Tips

  • Use Structures (UDT) in v5+: For almost any scenario requiring multiple returns with different data types, structures are superior due to named fields.
  • Document Array/Tuple Structure: If using arrays as tuples, clearly comment or document what each index represents.
  • Assign Array/Tuple elements to Named Variables: Immediately assign values from a returned array/conceptual tuple to descriptive variables to avoid magic numbers (array indices).
  • Keep Functions Focused: Functions should ideally do one thing well. If a function needs to return a large number of disparate values, consider whether it should be broken down into smaller, more focused functions, perhaps returning different structures.

By understanding and applying these methods, you can write more modular, readable, and powerful Pine Script functions that effectively manage and return complex sets of data.


Leave a Reply