MMTMMT Docs

Functions

Extract calculations, return multiple values, and reuse stateful analysis safely.

Functions turn a calculation into a named operation. Use them to remove repetition, keep handlers readable, and give important rules one obvious home.

Declare and call a function

Parameters and return values have explicit types:

fn candleStrength(open: float, high: float, low: float, close: float) -> float {
  let range = high - low
  return range > 0.0 ? math.abs(close - open) / range : 0.0
}

pane strengthPane = pane(title: "Candle Strength", height: 0.25)

plot strengthPlot = plot.line(title: "Strength", on: strengthPane)

on chart.update {
  let strength = candleStrength(
    chart.open ?? 0.0,
    chart.high ?? 0.0,
    chart.low ?? 0.0,
    chart.close ?? 0.0,
  )
  strengthPlot.plot(strength)
}

Declare functions at the top level. A function can call another function even if it appears later in the file.

Candle strength is a 0–1 ratio, so the example places its line in a separate pane with on: strengthPane. Without on:, this line would share the chart's price scale.

Defaults and named arguments

Put optional parameters after required parameters:

fn normalizedMove(value: float, scale: float = 1.0) -> float {
  return scale > 0.0 ? value / scale : 0.0
}

pane movePane = pane(title: "Normalized Move", height: 0.3)

plot normalizedPlot = plot.line(title: "Move", on: movePane)

on chart.update {
  let raw = (chart.close ?? 0.0) - (chart.open ?? 0.0)
  let move = normalizedMove(raw, scale: chart.atr(14) ?? 1.0)
  normalizedPlot.plot(move)
}

Named arguments make calls easier to scan when several values have the same type. Defaults are literal values, so configuration that depends on an input should be passed by the caller.

Return more than one value

A calculation can return up to eight related values without creating a type:

fn candleParts(open: float, high: float, low: float, close: float) -> (float, float, float) {
  let body = math.abs(close - open)
  let upper = high - math.max(open, close)
  let lower = math.min(open, close) - low
  return body, upper, lower
}

on chart.update {
  let body, upperWick, lowerWick = candleParts(
    chart.open ?? 0.0,
    chart.high ?? 0.0,
    chart.low ?? 0.0,
    chart.close ?? 0.0,
  )
}

Use _ to ignore a result you do not need:

let body, _, _ = candleParts(open, high, low, close)

Use a user-defined type instead when the result has a meaningful identity or methods of its own.

Reuse technical analysis in helpers

Technical-analysis calls can live inside functions:

fn rateOfChange(value: float?, length: int) -> float? {
  return ta.roc(value, length)
}

pane rocPane = pane(title: "Rate of Change", height: 0.3)

plot (
  priceRoc  = plot.line(title: "Price ROC", color: color.blue, on: rocPane)
  volumeRoc = plot.line(title: "Volume ROC", color: color.orange, on: rocPane)
)

on chart.update {
  priceRoc.plot(rateOfChange(chart.close, 12))
  volumeRoc.plot(rateOfChange(chart.volume, 12))
}

Each place you call this function keeps its own calculation history. In this example, the price and volume calculations stay separate. Rate of change is a percentage rather than a price, so both plots share a pane of their own.

Calls that keep calculation history cannot run inside ordinary loops or collection lambdas (T402). Call them from a handler or helper function instead. Loops over setup families are supported because each member keeps its own history.

Early returns

Use a bare return to stop a void function early:

fn plotBreakout(price: float, level: float?) {
  if level == null {
    return
  }

  if price > (level ?? price) {
    breakoutMarker.plot(price)
  }
}

A function with a declared return type must return a value on every path.

Keep functions focused

A useful function usually does one of three things:

  • Calculates and returns a value.
  • Updates a clearly named piece of state.
  • Emits one cohesive visual result.

Prefer a descriptive name and a short parameter list. If a function needs many related parameters, that is often a sign that those values should become a user-defined type.

On this page