FlowscopeDocs

Functions

Name a calculation, give it defaults, return several values, and reuse indicators inside helpers.

Functions turn a calculation into a named operation: they remove repetition, keep handlers readable and give important rules one home.

Declare and call a function

Parameters and return values have explicit types:

Flowscope Script
script "Candle strength"

data chart = subscribe(data.ohlcv)

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 strength = plot.line(title: "Strength", on: strengthPane)

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

Functions are declared at the top level and may be called before they appear in the file. Candle strength is a 0–1 ratio, so it gets its own pane with on:.

Defaults and named arguments

Optional parameters follow required ones; defaults are literals. Named arguments make calls easy to read:

Flowscope Script
script "Normalised move"

data chart = subscribe(data.ohlcv)

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

pane movePane = pane(title: "Move in ATRs", height: 0.25)
plot move = plot.line(title: "Move", on: movePane)

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

Return several values

A function can return a few related values without a type, and the caller takes them apart at once. _ ignores a value:

Flowscope Script
script "Candle parts"

data chart = subscribe(data.ohlcv)

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
}

pane partsPane = pane(title: "Wicks", height: 0.25)

plot (
  upperWick = plot.histogram(title: "Upper wick", color: color.red, on: partsPane)
  lowerWick = plot.histogram(title: "Lower wick", color: color.green, on: partsPane)
)

on chart.close {
  let _, upper, lower = candleParts(chart.open ?? 0.0, chart.high ?? 0.0, chart.low ?? 0.0, chart.close ?? 0.0)
  upperWick.plot(upper)
  lowerWick.plot(0.0 - lower)
}

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

Indicators inside helpers

ta.* calls can live in functions. Each place the function is called keeps its own history, so the two calls below stay separate:

Flowscope Script
script "Rate of change"

data chart = subscribe(data.ohlcv)

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

pane rocPane = pane(title: "Rate of change (%)", height: 0.25)

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

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

Calls that keep history cannot run inside loops or lambdas; call them from a handler or a helper.

Early returns

A bare return ends a function without a value early. A function with a return type must return a value on every path.

Flowscope Script
script "Breakout marker"

data chart = subscribe(data.ohlcv)

plot breakout = plot.marker(title: "Breakout", shape: shape.up, color: color.green)

fn markBreakout(price: float, level: float?) {
  if level == null {
    return
  }
  if price > (level ?? price) {
    breakout.plot(price)
  }
}

on chart.close {
  // The highest high of the 20 bars before this one.
  markBreakout(chart.close ?? 0.0, ta.highest(chart.high[1], 20))
}

Keep functions focused

A good function does one of three things: computes and returns a value, updates a clearly named piece of state, or draws one coherent result. When it needs many related parameters, they probably belong in a user-defined type.