Skip to main content

Utility functions

Comprehensive reference for all built-in utility functions available in custom studies.

tip

For a quick overview and examples, see the Custom Studies Guide or Quick Reference.

Moving Averages

sma()

Simple Moving Average

sma(value: number[] | ((index: number) => number), length: number, currentIndex: number): number

Calculates the arithmetic mean of values over a period.

Parameters:

  • value - Data series as array or accessor function
  • length - Number of periods to average
  • currentIndex - Current candle index

Returns: Average value or NaN if insufficient data

Formula: SMA = (sum of last N values) / N

Example:

state.prices[index] = input.close(0);

// Using accessor function
const sma20 = utils.sma(function(i) {
return state.prices[i];
}, 20, index);

// Using array directly
const sma20 = utils.sma(state.prices, 20, index);

ema()

Exponential Moving Average

ema(
value: number[] | ((index: number) => number),
length: number,
currentIndex: number,
stateKey: string
): number

Calculates EMA with more weight on recent values. Requires state storage for previous EMA value.

Parameters:

  • value - Data series as array or accessor function
  • length - Number of periods
  • currentIndex - Current candle index
  • stateKey - Unique key for storing internal state (must be unique per EMA calculation)

Returns: EMA value or NaN if insufficient data

Formula:

  • alpha = 2 / (period + 1)
  • EMA = value * alpha + previous_EMA * (1 - alpha)

Example:

state.prices[index] = input.close(0);

// Using accessor function
const ema9 = utils.ema(function(i) {
return state.prices[i];
}, 9, index, 'ema_fast');

// Using array directly
const ema21 = utils.ema(state.prices, 21, index, 'ema_slow');

Note: Use unique stateKey values for each EMA to avoid collisions.


wma()

Weighted Moving Average

wma(value: number[] | ((index: number) => number), length: number, currentIndex: number): number

Calculates WMA where more recent values have linearly increasing weights.

Parameters:

  • value - Data series as array or accessor function
  • length - Number of periods
  • currentIndex - Current candle index

Returns: WMA value or NaN if insufficient data

Formula: WMA = (n*v1 + (n-1)*v2 + ... + 1*vn) / (n + (n-1) + ... + 1)

Example:

// Using accessor function
const wma10 = utils.wma((i) => state.prices[i], 10, index);

// Using array
const wma10 = utils.wma(state.prices, 10, index);

rma()

Running Moving Average (Wilder's Moving Average)

rma(
value: number[] | ((index: number) => number),
length: number,
currentIndex: number,
stateKey: string
): number

Similar to EMA but with alpha = 1/period. Commonly used in RSI and ATR.

Parameters:

  • value - Data series as array or accessor function
  • length - Number of periods
  • currentIndex - Current candle index
  • stateKey - Unique key for storing internal state

Returns: RMA value or NaN if insufficient data

Formula:

  • alpha = 1 / period
  • RMA = value * alpha + previous_RMA * (1 - alpha)

Example:

// Using accessor functions
const avgGain = utils.rma(function(i) {
return state.gainValues[i];
}, 14, index, 'rma_gains');

// Using arrays
const avgLoss = utils.rma(state.lossValues, 14, index, 'rma_losses');

Statistical functions

stdev()

Standard Deviation

stdev(value: number[] | ((index: number) => number), length: number, currentIndex: number): number

Calculates population standard deviation over a period.

Parameters:

  • value - Data series as array or accessor function
  • length - Number of periods
  • currentIndex - Current candle index

Returns: Standard deviation or NaN if insufficient data

Formula: σ = sqrt(Σ(xi - mean)² / n)

Example:

// Using arrays
const basis = utils.sma(state.prices, 20, index);
const dev = utils.stdev(state.prices, 20, index);
const upperBand = basis + 2 * dev;
const lowerBand = basis - 2 * dev;

variance()

Variance

variance(value: number[] | ((index: number) => number), length: number, currentIndex: number): number

Calculates population variance over a period.

Parameters:

  • value - Data series as array or accessor function
  • length - Number of periods
  • currentIndex - Current candle index

Returns: Variance or NaN if insufficient data

Formula: σ² = Σ(xi - mean)² / n

Example:

// Using array
const var20 = utils.variance(state.prices, 20, index);

// Using accessor function
const var20 = utils.variance((i) => state.prices[i], 20, index);

correlation()

Correlation Coefficient

correlation(
value1: number[] | ((index: number) => number),
value2: number[] | ((index: number) => number),
length: number,
currentIndex: number
): number

Calculates Pearson correlation coefficient between two series.

Parameters:

  • value1 - First data series as array or accessor function
  • value2 - Second data series as array or accessor function
  • length - Number of periods
  • currentIndex - Current candle index

Returns: Correlation (-1 to 1) or NaN if insufficient data

Example:

// Using arrays
const corr = utils.correlation(state.prices, state.volume, 20, index);

// Using accessor functions
const corr = utils.correlation((i) => state.prices[i], (i) => state.volume[i], 20, index);

Price Analysis

highest()

Highest Value

highest(value: number[] | ((index: number) => number), length: number, currentIndex: number): number

Finds the maximum value over a period.

Parameters:

  • value - Data series as array or accessor function
  • length - Number of periods to look back
  • currentIndex - Current candle index

Returns: Highest value or NaN if insufficient data

Example:

// Using accessor function with direct input
const highestHigh = utils.highest(i => input.high(index - i), 14, index);

// Using array
const highestPrice = utils.highest(state.prices, 14, index);

lowest()

Lowest Value

lowest(value: number[] | ((index: number) => number), length: number, currentIndex: number): number

Finds the minimum value over a period.

Parameters:

  • value - Data series as array or accessor function
  • length - Number of periods to look back
  • currentIndex - Current candle index

Returns: Lowest value or NaN if insufficient data

Example:

// Using accessor function with direct input
const lowestLow = utils.lowest(i => input.low(index - i), 14, index);

// Using array
const lowestPrice = utils.lowest(state.prices, 14, index);

tr()

True Range

tr(currentIndex: number): number

Calculates True Range for volatility measurement.

Parameters:

  • currentIndex - Current candle index

Returns: Maximum of:

  • high - low
  • abs(high - previous_close)
  • abs(low - previous_close)

Example:

const trueRange = utils.tr(index);

atr()

Average True Range

atr(
length: number,
currentIndex: number,
stateKey: string
): number

Calculates Average True Range using RMA smoothing. Automatically calculates True Range internally.

Parameters:

  • length - Number of periods
  • currentIndex - Current candle index
  • stateKey - Unique key for storing internal state

Returns: ATR value or NaN if insufficient data

Example:

// ATR is calculated automatically from candle data
const atr14 = utils.atr(14, index, 'atr_main');

Utility Helpers

na()

Check Not Available

na(value: any): boolean

Checks if value is null, undefined, or NaN.

Parameters:

  • value - Value to check

Returns: true if value is N/A, false otherwise

Example:

const sma = utils.sma(function(i) {
return state.prices[i];
}, 20, index);
if (utils.na(sma)) {
return [NaN];
}

nz()

Null to Zero (Replace N/A)

nz(value: any, replacement?: number): number

Replaces N/A values with a default value.

Parameters:

  • value - Value to check
  • replacement - Value to return if N/A (default: 0)

Returns: Original value or replacement

Example:

const safeValue = utils.nz(calculatedValue, 0);
const prevPrice = utils.nz(state.prices[index - 1], input.close(0));

change()

Value Change

change(value: number[] | ((index: number) => number), currentIndex: number, length?: number): number

Calculates difference in value over periods.

Parameters:

  • value - Data series as array or accessor function
  • currentIndex - Current candle index
  • length - Number of periods to look back (default: 1)

Returns: value[index] - value[index - period] or NaN

Example:

// Using array
const priceChange = utils.change(state.prices, index, 1);
const change5 = utils.change(state.prices, index, 5);

// Using accessor function
const priceChange = utils.change((i) => state.prices[i], index, 1);

roc()

Rate of Change

roc(value: number[] | ((index: number) => number), length: number, currentIndex: number): number

Calculates rate of change as a percentage.

Parameters:

  • value - Data series as array or accessor function
  • length - Number of periods to look back
  • currentIndex - Current candle index

Returns: ((current - previous) / previous) * 100 or NaN

Example:

// Using array
const roc14 = utils.roc(state.prices, 14, index);

// Using accessor function
const roc14 = utils.roc((i) => state.prices[i], 14, index);

sum()

Sum Values

sum(value: number[] | ((index: number) => number), length: number, currentIndex: number): number

Calculates sum of values over a period.

Parameters:

  • value - Data series as array or accessor function
  • length - Number of periods
  • currentIndex - Current candle index

Returns: Sum of values or NaN if insufficient data

Example:

// Using array
const volumeSum = utils.sum(state.volume, 20, index);

// Using accessor function
const volumeSum = utils.sum((i) => state.volume[i], 20, index);

abs()

Absolute Value

abs(value: number | null | undefined): number

Returns absolute value.

Parameters:

  • value - Input value (returns NaN if null or undefined)

Returns: |value| or NaN

Example:

const absChange = utils.abs(utils.change((i) => state.prices[i], index, 1));

max()

Maximum Value

max(...values: number[]): number

Returns the largest value from arguments.

Parameters:

  • values - Variable number of values

Returns: Maximum value

Example:

const maxValue = utils.max(value1, value2, value3);

min()

Minimum Value

min(...values: number[]): number

Returns the smallest value from arguments.

Parameters:

  • values - Variable number of values

Returns: Minimum value

Example:

const minValue = utils.min(value1, value2, value3);

Best Practices

Using State Keys

Functions that require stateKey (ema, rma, atr) store internal state. Always use unique keys:

// Good - unique keys
const ema9 = utils.ema(function(i) {
return state.prices[i];
}, 9, index, 'ema_fast');
const ema21 = utils.ema(function(i) {
return state.prices[i];
}, 21, index, 'ema_slow');

// Bad - collision!
const ema1 = utils.ema(function(i) {
return state.prices[i];
}, 9, index, 'ema');
const ema2 = utils.ema(function(i) {
return state.prices[i];
}, 21, index, 'ema'); // Overwrites previous

Array vs Accessor Functions

Most utility functions accept data as either an array or an accessor function:

// Using array directly
const sma = utils.sma(state.prices, 20, index);

// Using accessor function (same result)
const sma = utils.sma(function(i) {
return state.prices[i];
}, 20, index);

// Using accessor function for dynamic/computed values
const highest = utils.highest(i => input.high(index - i), 14, index);

Error handling

Always check for N/A values before using results:

const sma = utils.sma(function(i) {
return state.prices[i];
}, 20, index);
if (utils.na(sma)) {
return [NaN]; // Not enough data yet
}
const result = sma * 2;
return [result];

Combining functions

Utility functions can be chained and combined:

// EMA of EMA (DEMA component)
state.ema1Values[index] = utils.ema(function(i) {
return state.prices[i];
}, 9, index, 'ema1');
state.ema2Values[index] = utils.ema(function(i) {
const val = state.ema1Values[i];
return val !== undefined ? val : NaN;
}, 9, index, 'ema2');

// Bollinger Bands
const basis = utils.sma(function(i) {
return state.prices[i];
}, 20, index);
const dev = utils.stdev(function(i) {
return state.prices[i];
}, 20, index);
const upper = basis + 2 * dev;
const lower = basis - 2 * dev;

Performance considerations

  1. Initialize arrays in init(): Pre-allocate state arrays to avoid resizing
  2. Use built-in functions: They're optimized for performance
  3. Avoid redundant calculations: Store intermediate results
  4. Early returns: Exit early when data is insufficient
constructor: {
init: (ctx) => {
// Pre-allocate arrays
ctx.state.prices = [];
ctx.state.ema = [];
},
main: (ctx) => {
const { input, utils, parameters, state, index } = ctx;

// Early return
if (index < parameters.length - 1) {
return [NaN];
}

// Store once, use multiple times
const price = input.close(0);
state.prices[index] = price;

// Calculate
const result = utils.ema(function(i) {
return state.prices[i];
}, parameters.length, index, 'ema');
return [result];
}
}