As experienced Pine Script developers, we understand the critical role that data inputs play in defining indicator behavior and strategy logic. While fixed inputs like lookback periods or threshold values are common, the ability to select the data source itself offers powerful flexibility.
This article delves into the intricacies of using input source parameters in Pine Script, enabling you to build more adaptable and user-friendly scripts. We’ll cover everything from basic syntax to advanced techniques, providing practical examples along the way.
Introduction to Input Source Parameters in Pine Script
In the context of TradingView’s Pine Script, many built-in functions and operations operate on a series of data points. By default, functions like ta.sma() (Simple Moving Average) typically use the close price as their input source. However, financial analysis often requires applying calculations to other data points, such as the high, low, volume, or even the output of another indicator.
Input source parameters allow script users to dynamically choose which data series the script should process without modifying the code itself.
What are Input Source Parameters?
An input source parameter is a specific type of input control in Pine Script that allows the end-user of your script on a chart to select a data series from a predefined list of options. These options typically include standard price types (open, high, low, close, hl2, hlc3, ohlc4), volume (volume), and the output of other studies on the chart.
The value selected via this input becomes a series float or series int variable within your script, representing the chosen data stream on a per-bar basis.
Why Use Input Source Parameters?
Implementing input source parameters enhances the utility and adaptability of your scripts significantly:
- Flexibility: Users can apply the same indicator or strategy logic to different data points (e.g., calculate an RSI of volume instead of price).
- User Customization: Allows traders to experiment with different inputs based on their specific analysis needs or market conditions.
- Reduced Code Duplication: Instead of writing separate versions of an indicator for
closeandhlc3, you write one script with a selectable source. - Backtesting and Optimization: Facilitates testing your strategy logic on various data sources to identify the most robust inputs.
Basic Syntax and Structure
The core function for creating an input source parameter is input.source():
pine_version = '5'
indicator("My Source Selector Indicator", shorttitle="Source Select", overlay=true)
// Define an input source parameter
selectedSource = input.source(close, "Source", tooltip="Select the data source for calculation")
// Use the selected source in a simple plot
plot(selectedSource, title="Selected Source Data", color=color.blue)
Let’s break down the input.source() parameters:
defval: The default value for the input. This must be aseriesvariable, typically one of the standard built-in sources likeclose,high,volume, etc.title: A string that appears as the label for the input in the script’s settings dialog.tooltip: An optional string providing additional information when the user hovers over the input label.
The variable selectedSource now holds the time series data corresponding to the source selected by the user. You can then use this variable as input to other Pine Script functions.
Working with Different Data Sources
Pine Script provides direct access to standard bar data and built-in variables. Input source parameters let you choose among these and even reference outputs from other scripts.
Accessing Price Data (Open, High, Low, Close)
The most common sources are the standard price components of a bar. These are built-in series float variables:
open: The opening price of the current bar.high: The highest price reached during the current bar.low: The lowest price reached during the current bar.close: The closing price of the current bar.hl2: (High + Low) / 2 – the midpoint price.hlc3: (High + Low + Close) / 3 – the typical price.ohlc4: (Open + High + Low + Close) / 4 – the average price.
pine_version = '5'
indicator("Price Source Example", shorttitle="Price Source", overlay=true)
priceSource = input.source(close, "Select Price Source", tooltip="Choose open, high, low, close, or averages")
// Calculate a moving average based on the selected price source
maLength = input.int(20, "MA Length", minval=1)
maValue = ta.sma(priceSource, maLength)
plot(maValue, title="Moving Average", color=color.red)
Here, the user can select any of the standard price types to be used for the moving average calculation.
Using Volume Data as Input
Volume (volume) is a series int variable representing the total volume traded during the current bar. It’s often used as an input source for indicators like Volume-Weighted Moving Averages (VWMA) or On-Balance Volume (OBV).
pine_version = '5'
indicator("Volume Source Example", shorttitle="Vol Source", overlay=false)
// Volume is the default and expected type for volume indicators
volumeSource = input.source(volume, "Select Volume Source", tooltip="Choose the volume series")
// Calculate a simple moving average of volume
volMALength = input.int(50, "Volume MA Length", minval=1)
volMAValue = ta.sma(volumeSource, volMALength)
plot(volMAValue, title="Volume MA", color=color.blue)
Note that while input.source() can technically accept any series, using volume as the default makes sense for indicators designed to work with volume data. Pine Script is strongly typed, and attempting to use a float source where an int is expected (or vice versa) may lead to type casting or compilation issues depending on the function.
Employing Built-in Variables (e.g., time, bar_index)
Besides bar data, Pine Script offers several built-in variables that can also be used as input sources, although this is less common for typical indicator inputs. Examples include time (the bar’s time in Unix milliseconds) or bar_index (the zero-based index of the current bar).
pine_version = '5'
indicator("Built-in Source Example", shorttitle="Built-in Source", overlay=false)
// Selecting 'time' or 'bar_index' as a source
builtinSource = input.source(bar_index, "Select Built-in Source", tooltip="Choose bar_index or time")
// Plotting the selected built-in value
plot(builtinSource, title="Built-in Value", color=color.purple)
This demonstrates the flexibility, though the practical trading application of using time or bar_index directly as the primary input source for standard technical indicators is limited.
Referencing Other Indicators and Studies
A powerful feature is the ability to use the output of other indicators on the chart as your source. This is done by selecting the desired plot from the other indicator when configuring your script’s input source parameter.
pine_version = '5'
indicator("MA of Another Indicator", shorttitle="MA of Other", overlay=true)
// User selects the source, which could be a plot from another script
otherIndicatorSource = input.source(close, "Source from Another Indicator", tooltip="Select a plot from another indicator")
// Calculate a moving average of the selected source
maLength = input.int(14, "MA Length", minval=1)
maValue = ta.sma(otherIndicatorSource, maLength)
plot(maValue, title="MA of Other Indicator", color=color.orange)
When the user adds this script to their chart, the dropdown for “Source from Another Indicator” will list close, high, etc., plus the plot outputs of any other indicators already present on that chart. This allows for complex analysis, like calculating the MACD of an RSI, or an EMA of a volume study.
Advanced Input Source Techniques
While input.source provides a direct way to select one source, advanced scenarios might involve combining sources or using sources conditionally.
Combining Multiple Input Sources
You can define multiple input.source parameters in a single script and combine them programmatically. For example, you might calculate the average of two different user-selected sources.
pine_version = '5'
indicator("Combined Sources Example", shorttitle="Combined Sources", overlay=false)
source1 = input.source(close, "Source 1")
source2 = input.source(volume, "Source 2")
// Example: Calculate the ratio (requires type compatibility or casting)
// Note: Directly dividing price by volume might not be financially meaningful
// This is a synthetic example to show combining inputs.
// Real-world use cases might involve averaging, summing, or applying different logic.
// Simple average example (requires both to be float or one cast)
// For demonstration, let's cast volume to float for division
// In a real scenario, ensure logical combination of data types.
combinedValue = (source1 + float(source2)) / 2.0
plot(combinedValue, title="(Source 1 + Source 2) / 2", color=color.teal)
When combining sources, be mindful of their data types (float vs int) and ensure the mathematical or logical operation makes sense in a trading context.
Conditional Input Sources Based on Market Conditions
You cannot change the value of an input.source variable during a script’s execution based on bar-by-bar conditions, as inputs are static for a given run. However, you can use conditional logic within your script to choose which calculation to perform based on the selected source or other conditions.
For instance, you might have an input that determines if a volume-based calculation or a price-based calculation is used, or even an input that lets the user select which source to use conditionally based on bar direction.
Let’s show a conditional calculation based on a user-selected source and another input (a boolean flag):
pine_version = '5'
indicator("Conditional Source Calc", shorttitle="Conditional Calc", overlay=false)
priceSource = input.source(close, "Primary Price Source")
volumeSource = input.source(volume, "Volume Source")
useVolumeLogic = input.bool(false, "Use Volume Logic Instead of Price")
// Perform calculation based on the boolean input
calculatedValue = if useVolumeLogic
ta.sma(volumeSource, 20) // Example: MA of volume
else
ta.sma(priceSource, 20) // Example: MA of price
plot(calculatedValue, title="Conditional MA", color=color.fuchsia)
In this pattern, the user selects both a price source and a volume source, plus a toggle. The script then conditionally applies the MA function to either the price source or the volume source based on the toggle’s state. This is how you introduce dynamic behavior based on source selection.
Dynamic Input Sources: Changing Sources During Backtesting
The term “Dynamic Input Sources” can be slightly misleading in Pine Script’s input context. input.* functions define variables whose values are set once when the script starts executing for a given chart symbol/resolution/date range. They do not change from bar to bar within a single backtest run.
If you need to analyze a different data series on different bars (e.g., compare price to an index value that might require request.security), that logic must be handled programmatically within the script, potentially using variables that do change per bar, rather than relying on the input.source value itself changing dynamically.
For truly dynamic symbol inputs during backtesting (e.g., trading based on the relative performance of two different stocks), you would use input.symbol() in conjunction with request.security(). While related to selecting data, this is distinct from selecting a source type (close, volume, etc.) from the current symbol via input.source().
It is crucial to understand that the output of input.source() for a given bar is determined by the user’s selection and the data series at that specific bar index. It does not allow changing the selected source mid-backtest based on strategy conditions.
Practical Examples and Use Cases
Let’s look at common indicators and how incorporating an input source parameter makes them more versatile.
Moving Average with Selectable Source (Close, High, Low)
A fundamental example is a moving average where the user can choose whether the MA is calculated on the close, high, low, or other price variants.
pine_version = '5'
indicator("MA with Source Select", shorttitle="MA Src", overlay=true)
// Input for MA length
maLength = input.int(20, "MA Length", minval=1)
// Input for the source data, defaulting to close
maSource = input.source(close, "Source", tooltip="Data source for the Moving Average")
// Calculate the SMA based on the selected source
maValue = ta.sma(maSource, maLength)
// Plot the MA
plot(maValue, title="SMA", color=color.blue, linewidth=2)
This simple pattern is widely applicable to many indicators that operate on a single data series (e.g., EMA, WMA, RSI, CCI, Stochastic).
Volume-Weighted Average Price (VWAP) Implementation
VWAP calculation inherently uses both price and volume. While you can’t make the VWAP calculation itself switch between entirely different formulas based on input.source, you could make the price component of the VWAP selectable.
pine_version = '5'
indicator("Custom VWAP with Source", shorttitle="VWAP Src", overlay=true)
// Input for the price component of the VWAP calculation
vwapPriceSource = input.source(hlc3, "Price Source for VWAP", tooltip="Select price type (e.g., hlc3, close) for typical price calculation")
// Standard VWAP calculation requires sum of (price * volume) and sum of volume
// Cumulative calculations need to handle chart resets (e.g., start of day for daily VWAP)
// This example is a simple cumulative VWAP; anchors like 'D' need request.security
float cumulativePriceVolume = ta.cum(vwapPriceSource * volume)
float cumulativeVolume = ta.cum(volume)
// Avoid division by zero
vwapValue = cumulativeVolume > 0 ? cumulativePriceVolume / cumulativeVolume : na
// Plot the VWAP
plot(vwapValue, title="VWAP", color=color.purple, linewidth=2)
Here, the user can influence the VWAP calculation by choosing whether it uses close * volume, hlc3 * volume, etc., in the numerator, adding a layer of customization to this common indicator.
Relative Strength Index (RSI) with Customizable Source
RSI is another prime candidate for a selectable source. Calculating RSI on volume or other metrics can reveal different market dynamics than standard price-based RSI.
pine_version = '5'
indicator("RSI with Source Select", shorttitle="RSI Src", overlay=false)
// Input for RSI length
rsiLength = input.int(14, "RSI Length", minval=1)
// Input for the source data, defaulting to close
rsiSource = input.source(close, "Source", tooltip="Data source for RSI calculation (e.g., close, volume)")
// Calculate RSI based on the selected source
rsiValue = ta.rsi(rsiSource, rsiLength)
// Plot the RSI
plot(rsiValue, title="RSI", color=color.green, linewidth=2)
// Optional: Plot overbought/oversold levels
hlevel = input.int(70, "Overbought Level")
llevel = input.int(30, "Oversold Level")
hline(hlevel, "Overbought", color=color.red)
hline(llevel, "Oversold", color=color.green)
This pattern allows users to easily switch between classical price RSI and potentially experimental RSIs based on other data series like volume or momentum indicators.
Troubleshooting and Best Practices
Using input source parameters is generally straightforward, but a few considerations ensure robustness and a good user experience.
Handling Errors and Invalid Input
The primary potential issue when using input.source() arises from type compatibility. Functions in Pine Script expect inputs of specific types (float, int, bool, color, series float, series int, etc.).
- If you use
input.source(close, ...)(which isseries float), and then try to use the resulting variable in a function that strictly requiresseries int(like some volume-specific functions), you might encounter a compilation error. - Conversely, if you default to
input.source(volume, ...)(which isseries int) but the user selects aseries float(likeclose) and you feed it into a function expectingseries int, you might also see errors or unexpected behavior.
While Pine Script often handles implicit type casting for common operations (like using series int where series float is expected, or vice versa in basic arithmetic), it’s best practice to be aware of the expected type of the functions you are using the source with. If necessary, explicitly cast the source variable using int() or float() before passing it to a function, provided the conversion makes logical sense.
Example of explicit casting (assuming you accept float or int and need float):
// sourceVariable is the output of input.source()
// Ensure it's treated as float for a function expecting float
floatSource = float(sourceVariable)
// Now use floatSource in your calculation
Optimizing Code for Performance
Using input.source() itself has minimal performance impact. The performance considerations arise from what you do with the selected source.
- Complex Calculations: Applying computationally intensive logic to the selected source will impact performance, regardless of the source.
request.security(): If the user selects a source that originates from another script that heavily relies onrequest.security(), the performance of your script might be affected indirectly due to the overhead of the external call chain. Be mindful when building scripts that are intended to be layered on top of potentially complex external studies.
Generally, optimize the core logic of your script after retrieving the source, rather than worrying about the input.source call itself.
Best Practices for User Experience (Labels, Tooltips)
Clear communication is key for user-friendly scripts:
- Descriptive
title: Use a title that clearly indicates what the input controls (e.g., “Price Source”, “Data for RSI”). - Helpful
tooltip: Provide a tooltip explaining the implications of selecting different sources, especially if certain sources might not be appropriate for the indicator’s logic (e.g., warning about using volume for a price oscillator). Mention common use cases. - Appropriate
defval: Set the default value (defval) to the most common or standard source for that type of indicator (e.g.,closefor most price-based indicators,volumefor volume indicators). This makes the script immediately useful upon adding it to the chart.
By following these practices, you make your script’s inputs intuitive, reducing user confusion and support requests.
Using input.source parameters is a powerful technique for making your Pine Script indicators and strategies versatile and user-configurable. By understanding how to access and utilize different data streams, you can create more sophisticated tools tailored to a wider range of analytical approaches.