---
title: Named Streams
description: Multi-output indicators like bb, macd, and stoch return a result whose components you read by name, such as bb.upper, macd.signal, and stoch.k. No positional guessing.
---

<div class="flex gap-3 mb-6">
  <span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-green-50 text-green-600 text-sm font-medium">
    Beginner
  </span>
  <span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-gray-100 text-gray-600 text-sm font-medium">
    5 min read
  </span>
</div>

## Introduction

Some indicators produce more than one line. Bollinger Bands give you an upper band, a basis, and a lower band. MACD gives a MACD line, a signal line, and a histogram. In kScript these multi-output indicators return a single result whose components you read **by name**:

```javascript
//@version=2
define(title="Bollinger bands", position="overlay", axis=true)

timeseries d = ohlcv(symbol=currentSymbol, exchange=currentExchange)
var bands = bb(source=d.close, period=20, mult=2)

plotLine(value=bands.upper, colors=["#2563eb"], width=2, label=["BB upper"], desc=["upper Bollinger band"])
plotLine(value=bands.basis, colors=["#64748b"], width=2, label=["BB basis"], desc=["Bollinger basis (the moving average)"])
plotLine(value=bands.lower, colors=["#2563eb"], width=2, label=["BB lower"], desc=["lower Bollinger band"])
```

`bb(...)` hands back a Bollinger result; `bands.upper`, `bands.basis`, and `bands.lower` are its three lines. You name what you want. There is no "is the upper band index 0 or index 2?" guesswork, and a typo like `bands.upperr` is a compile error rather than a silently-wrong line.
## How it works

A multi-output builtin returns one value that carries several named series. Read a component with a dot, exactly like an OHLCV field (`d.close`). Each component is an ordinary series, so it flows straight into math, other indicators, conditions, and plots:

```javascript
var m = macd(source=d.close, fastPeriod=12, slowPeriod=26, signalPeriod=9)

var risingMomentum = m.histogram > m.histogram[1]      // compare bars
var smoothSignal   = ema(source=m.signal, period=5)     // feed into another indicator
```
You can keep the whole result in one `var` and pull fields as needed, or read a single field inline when that is all you use.

## The named streams

These are the multi-output builtins and the field names each one exposes:

| Builtin | Fields |
|---|---|
| `bb` | `.upper`, `.basis`, `.lower` |
| `keltner` | `.upper`, `.basis`, `.lower` |
| `macd` | `.macd`, `.signal`, `.histogram` |
| `stoch` | `.k`, `.d` |
| `supertrend` | `.line`, `.direction` |

A few worth calling out:

- **`stoch`** splits into the fast `%K` (`.k`) and its smoothed `%D` (`.d`). The classic crossover is `stoch.k` crossing `stoch.d`.
- **`supertrend`** returns the trailing stop level as `.line` and the trend side as `.direction`. Use `.direction` to color or gate; use `.line` to draw the stop.
- **`macd.histogram`** is the MACD line minus the signal line, ready to plot as bars.

## Reading every stream at once

This script reads all five multi-output indicators and plots each of their named components.

```javascript title="scripts/probes/lang-named-streams/multi_output_members.ks"
//@version=2
define(title="Named Stream Members", position="offchart", axis=true)

timeseries trade = ohlcv(symbol=currentSymbol, exchange=currentExchange)
timeseries closeSeries = trade.close

var bands = bb(source=closeSeries, period=20, mult=2)
var macdValue = macd(source=closeSeries, fastPeriod=12, slowPeriod=26, signalPeriod=9)
var stochValue = stoch(periodK=14, smoothK=3, periodD=3)
var keltnerValue = keltner(source=trade, period=20, mult=1.5, atrPeriod=10)
var trendValue = supertrend(factor=3, atrPeriod=10)

plotLine(value=bands.upper, colors=["#2563eb"], width=2, label=["BB upper"], desc=["bb.upper named stream"])
plotLine(value=bands.basis, colors=["#64748b"], width=2, label=["BB basis"], desc=["bb.basis named stream"])
plotLine(value=bands.lower, colors=["#dc2626"], width=2, label=["BB lower"], desc=["bb.lower named stream"])
plotLine(value=macdValue.macd, colors=["#1d4ed8"], width=2, label=["MACD"], desc=["macd.macd named stream"])
plotLine(value=macdValue.signal, colors=["#ea580c"], width=2, label=["Signal"], desc=["macd.signal named stream"])
plotLine(value=macdValue.histogram, colors=["#15803d"], width=2, label=["Histogram"], desc=["macd.histogram named stream"])
plotLine(value=stochValue.k, colors=["#0891b2"], width=2, label=["Stoch K"], desc=["stoch.k named stream"])
plotLine(value=stochValue.d, colors=["#be123c"], width=2, label=["Stoch D"], desc=["stoch.d named stream"])
plotLine(value=keltnerValue.upper, colors=["#16a34a"], width=2, label=["Keltner upper"], desc=["keltner.upper named stream"])
plotLine(value=keltnerValue.basis, colors=["#94a3b8"], width=2, label=["Keltner basis"], desc=["keltner.basis named stream"])
plotLine(value=keltnerValue.lower, colors=["#b91c1c"], width=2, label=["Keltner lower"], desc=["keltner.lower named stream"])
plotLine(value=trendValue.line, colors=["#7c3aed"], width=2, label=["Supertrend line"], desc=["supertrend.line named stream"])
plotLine(value=trendValue.direction, colors=["#111827"], width=2, label=["Supertrend direction"], desc=["supertrend.direction named stream"])
```


**What to expect:** each band-style indicator (`bb`, `keltner`) starts drawing once its lookback window fills, and the three lines track together. `macd` produces its three components in lockstep. `supertrend.line` is a price-level series while `supertrend.direction` flips between trend states.

{% hint style="info" %}
Single-output indicators like `rsi`, `ema`, and `sma` return a plain series, not a named result, so you plot them directly: `plotLine(value=rsi(source=d.close, period=14), ...)`. Named streams are only for the multi-line indicators above. The full catalog is in the [TA Library](/kscript/functions/ta-library).
{% endhint %}
