FlowscopeDocs

Pattern matching

Turn continuous values into named cases with match expressions and statements.

match compares one value against ordered cases. It suits turning a continuous value into a named regime, choosing a style, handling missing data or acting on an enum. The first matching arm wins, so write the most specific cases first.

Produce a value

A match expression gives each case a result:

Flowscope Script
script "Move regime"

data chart = subscribe(data.ohlcv)

fn describeMove(changePct: float?) -> string {
  return match changePct {
    null => "Waiting for data"
    >= 2.0 => "Strong rise"
    > 0.0 => "Rise"
    <= -2.0 => "Strong fall"
    < 0.0 => "Fall"
    _ => "Flat"
  }
}

state hud = entities.labelPool(max: 1, anchor: anchor.topLeft)

on chart.update {
  let open = chart.open
  let close = chart.close
  let change: float? = open != null && close != null && open > 0.0 ? (close / open - 1.0) * 100.0 : null
  if chart.isLast {
    hud.get("move").set(12.0, 12.0, describeMove(change))
  }
}

Relational patterns compare the subject with the value after <, <=, > or >=. Because arms are checked top to bottom, >= 2.0 comes before > 0.0. A match expression must cover every value; a final _ is the simplest way.

Choose a colour

Flowscope Script
script "Delta colour"

data chart = subscribe(data.ohlcv)

pane deltaPane = pane(title: "Delta", height: 0.25)
plot bars = plot.histogram(title: "Delta", on: deltaPane)

on chart.close {
  let delta = chart.delta()
  let volume = chart.volume
  let share: float? = delta != null && volume != null && volume > 0.0 ? delta / volume : null
  let shade = match share {
    null => color.gray
    >= 0.3 => color.green
    <= -0.3 => color.red
    _ => color.yellow
  }
  bars.plot(delta, color: shade)
}

Match statements

Use the statement form to run actions. For one statement an arm needs no braces:

Flowscope Script
script "Rising streak"

data chart = subscribe(data.ohlcv)

state risingBars = 0

pane streakPane = pane(title: "Rising streak", height: 0.2)
plot streak = plot.histogram(title: "Bars", on: streakPane)

on chart.close {
  let move = ta.change(chart.close)
  match move {
    null => risingBars = 0
    > 0.0 => risingBars += 1
    _ => risingBars = 0
  }
  streak.plot(float(risingBars))
}

A statement match need not cover every value.

Combine cases

Separate alternatives with |:

Flowscope Script
script "Session of the day"

data chart = subscribe(data.ohlcv)

fn sessionName(hour: int) -> string {
  return match hour {
    0 | 1 | 2 | 3 | 4 | 5 => "Overnight"
    6 | 7 | 8 | 9 | 10 | 11 => "Morning"
    12 | 13 | 14 | 15 | 16 | 17 => "Afternoon"
    _ => "Evening"
  }
}

state hud = entities.labelPool(max: 1, anchor: anchor.bottomLeft)

on chart.update {
  let t = chart.time
  if chart.isLast && t != null {
    hud.get("session").set(12.0, 12.0, sessionName(time.hour(t)))
  }
}

Alternatives can mix exact and relational cases: 0.0 | < -3.0 => "Inactive".

Handle missing values first

For a nullable subject, put null in its own arm. Exact and relational patterns never match null; only null and _ do.

Match calculated values

An exact pattern can be a variable or a calculation. The subject is computed once:

Flowscope Script
script "Session open"

input openHour = input.int(13, title: "Open hour (UTC)", min: 0, max: 23)

data chart = subscribe(data.ohlcv)

pane phasePane = pane(title: "Phase", height: 0.15)
plot phase = plot.histogram(title: "Phase", on: phasePane)

on chart.close {
  let t = chart.time
  if t != null {
    let value = match time.hour(t) {
      openHour => 2.0
      > openHour => 1.0
      _ => 0.0
    }
    phase.plot(value)
  }
}

Exact patterns use plain equality, so they suit integers, strings and enums. Compare prices with relational arms instead.

What patterns do not do

Patterns compare one subject. They do not bind names, destructure records or take if guards. Read fields into locals first, or compute an extra condition before the match.

Match or if?

  • A match expression calculates one result from several cases of one value.
  • A match statement dispatches actions from one value.
  • if suits one or two unrelated conditions.