---
title: Utility Functions
description: Series statistics, crossover detection, and value validation helpers used across indicators and signals.
---

Utility functions provide statistical calculations, data manipulation, cross detection, support/resistance helpers, and data validation. They are building blocks for custom indicators and mathematical operations on time series data.

| Category | Description |
| --- | --- |
| **Statistical Functions** | Calculate standard deviation, highest/lowest values, and sums over specified periods. |
| **Cross Detection** | Detect when time series cross above, below, or in either direction to generate trading signals. |
| **Support/Resistance Levels** | Identify key price levels using functions that track highs/lows over a lookback period. |
| **Type Checking** | Validate data integrity with NaN and numeric checks before performing calculations. |

| Function | Description |
| --- | --- |
| [`lowest`](#lowest) | Find lowest value over specified period |
| [`highest`](#highest) | Find highest value over specified period |
| [`sum`](#sum) | Calculate sum of values over specified period |
| [`stddev`](#stddev) | Calculate standard deviation of values |
| [`donchian`](#donchian) | Donchian Channel midpoint calculation |
| [`crossover`](#crossover) | Detect when series A crosses above series B |
| [`crossunder`](#crossunder) | Detect when series A crosses below series B |
| [`cross`](#cross) | Detect when series A crosses series B in either direction |
| [`isnan`](#isnan) | Check if a value is NaN (Not a Number) |
| [`isnum`](#isnum) | Check if a value is a valid finite number |

<a id="lowest"></a>

## lowest - find lowest value over specified period

`lowest(source: TimeSeries, period?: number = 12, priceIndex?: number = 3): number`

| Parameter | Type | Description |
| --- | --- | --- |
| `source` | TimeSeries | Source data series |
| `period` | number | Number of periods to look back (default: `12`) |
| `priceIndex` | number | Index of price data (default: `3` for low) |

**Returns:** `number (lowest value in the specified period)`.

```javascript
var low20 = lowest(source=trade, period=20); // 20-period low
```

<a id="highest"></a>

## highest - find highest value over specified period

`highest(source: TimeSeries, period?: number = 12, priceIndex?: number = 2): number`

| Parameter | Type | Description |
| --- | --- | --- |
| `source` | TimeSeries | Source data series |
| `period` | number | Number of periods to look back (default: `12`) |
| `priceIndex` | number | Index of price data (default: `2` for high) |

**Returns:** `number (highest value in the specified period)`.

```javascript
var high20 = highest(source=trade, period=20); // 20-period high
```

<a id="sum"></a>

## sum - calculate sum of values over specified period

`sum(source: TimeSeries, period?: number = 12, priceIndex?: number = 1): number`

| Parameter | Type | Description |
| --- | --- | --- |
| `source` | TimeSeries | Source data series |
| `period` | number | Number of periods to sum (default: `12`) |
| `priceIndex` | number | Index of price data (default: `1`) |

**Returns:** `number (sum of values in the specified period)`.

```javascript
var volumeSum = sum(source=trade, period=10); // 10-period volume sum
```

<a id="stddev"></a>

## stddev - calculate standard deviation of values

`stddev(source: TimeSeries, period?: number = 12, priceIndex?: number = 1): number`

| Parameter | Type | Description |
| --- | --- | --- |
| `source` | TimeSeries | Source data series |
| `period` | number | Number of periods for calculation (default: `12`) |
| `priceIndex` | number | Index of price data (default: `1`) |

**Returns:** `number (standard deviation value)`.

```javascript
var volatility = stddev(source=trade, period=20); // 20-period volatility
```

<a id="donchian"></a>

## donchian - Donchian Channel midpoint calculation

`donchian(source: TimeSeries, period?: number = 12): number`

| Parameter | Type | Description |
| --- | --- | --- |
| `source` | TimeSeries | Source data series |
| `period` | number | Number of periods (default: `12`) |

**Returns:** `number (Donchian Channel midpoint value)`.

```javascript
var donchianMid = donchian(source=trade, period=20);
```

<a id="crossover"></a>

## crossover - detect when series A crosses above series B

`crossover(seriesA: TimeSeries, seriesB: TimeSeries): boolean`

| Parameter | Type | Description |
| --- | --- | --- |
| `seriesA` | TimeSeries | First series, such as a fast moving average |
| `seriesB` | TimeSeries | Second series, such as a slow moving average |

**Returns:** `boolean (true if A crosses above B at the current bar)`.

```javascript
var cross = crossover(fastMA, slowMA);
```

<a id="crossunder"></a>

## crossunder - detect when series A crosses below series B

`crossunder(seriesA: TimeSeries, seriesB: TimeSeries): boolean`

| Parameter | Type | Description |
| --- | --- | --- |
| `seriesA` | TimeSeries | First series |
| `seriesB` | TimeSeries | Second series |

**Returns:** `boolean (true when A crosses below B)`.

```javascript
var bearishCross = crossunder(fastMA, slowMA);
```

<a id="cross"></a>

## cross - detect when series A crosses series B in either direction

`cross(seriesA: TimeSeries, seriesB: TimeSeries): boolean`

| Parameter | Type | Description |
| --- | --- | --- |
| `seriesA` | TimeSeries | First series |
| `seriesB` | TimeSeries | Second series |

**Returns:** `boolean (true when any cross occurs)`.

```javascript
var anyCross = cross(macdLine, signalLine);
```

<a id="isnan"></a>

## isnan - check if a value is NaN (Not a Number)

`isnan(value: any): boolean`

| Parameter | Type | Description |
| --- | --- | --- |
| `value` | any | Value to check for NaN |

**Returns:** `boolean (true if value is NaN, false otherwise)`.

```javascript
var invalid = isnan(result); // Check if calculation failed
```

<a id="isnum"></a>

## isnum - check if a value is a valid finite number

`isnum(value: any): boolean`

| Parameter | Type | Description |
| --- | --- | --- |
| `value` | any | Value to check for numeric validity |

**Returns:** `boolean (true if value is a valid finite number, false otherwise)`.

```javascript
var valid = isnum(price); // Validate price data
```

## Best Practices

<table data-view="cards"><tbody>
<tr><td>Lookback Periods</td><td>Choose lookback periods based on your timeframe. Shorter periods fit scalping and lower timeframes; longer periods fit swing trading and broader trend analysis.</td><td></td></tr>
<tr><td>Performance</td><td>Statistical functions can be computationally expensive. Cache results when calculating multiple statistics on the same data.</td><td></td></tr>
<tr><td>Cross Detection</td><td>Use `crossover()` for bullish signals, `crossunder()` for bearish signals, and `cross()` when you need any direction change. Always combine cross signals with trend confirmation.</td><td></td></tr>
<tr><td>Donchian Channels</td><td>Donchian channels work best in trending markets for breakout strategies. In ranging markets, use them as support/resistance levels instead of breakout signals.</td><td></td></tr>
<tr><td>False Signals</td><td>Cross functions can generate false signals in choppy markets. Add filters like volume confirmation or trend direction to improve signal quality.</td><td></td></tr>
<tr><td>Data Validation</td><td>Validate data with `isnan()` and `isnum()` before calculations. Invalid data can propagate through indicators and cause incorrect results.</td><td></td></tr>
</tbody></table>
