Docs
Scripting

Scripting

Write scanner logic as code in fastur/1, the engine's language. Script structure, fields, windows, studies, LogicBlocks and worked examples.

Overview

Every scanner can be written as code. Open a scanner, click Code, and the editor shows the script the scanner runs. Edit it, press Run, and the engine runs the script exactly as written: what you see is what runs.

Scripts are written in fastur/1, the engine's own language. It reads like Python: lowercase keywords, x if condition else y, name(args) calls and indentation for blocks.

The editor checks your script against the engine as you type. Problems are underlined on the line they occur, with the engine's own explanation.

Format (Shift+Alt+F) lays the code out in one house style: four-space indents, key = value fields, one blank line before each block. Run formats the code too, so every script reads the same way. Formatting never changes what a script does.

A Script

A script defines one rule (which symbols qualify) and one scan (how the results are shown).

# Stocks moving more than 2% today
prev_close = d1.close[1]
logicblock MOVE_PCT = (trade.last - prev_close) / prev_close * 100
 
rule movers:
    on = cadence.trade
    when = MOVE_PCT > 2 and trade.last > 5
 
scan "Movers":
    rule = movers
    universe = "ALL"
    columns = [trade.last, MOVE_PCT, trade.last - prev_close, trade.volume]
    sort = MOVE_PCT
    extract = descending
PartMeaning
name = exprA helper, used only inside this script
logicblock NAME = exprA named signal; save it to reuse it in other scans
rule NAME:on is when it is evaluated, when the condition
scan "Label":rule, universe, columns, sort, optional extract
  • on takes a cadence: cadence.trade, cadence.quote, cadence.s30, cadence.m1, cadence.m5 or cadence.daily.
  • columns lists up to 10 expressions, the sort included. The results table shows them in this order, headed as written.
  • extract is descending or ascending.
  • A scanner runs exactly one scan. Triggers and watchlists are not written in the scanner's Code tab.

Values

Tick Values

SpellingMeaning
trade.lastLast trade price
trade.sizeLast trade size
trade.volumeTick volume
quote.bid, quote.askCurrent quote
quote.bid_size, quote.ask_sizeCurrent quote sizes
clock.timeEastern seconds since midnight

clock.time is a number: 09:30 is 34200, 10:30 is 37800, 16:00 is 57600.

Bars

Bars are written <timeframe>.<field>. Timeframes are d1 (daily), w1 (weekly), m1 m3 m5 m10 m15 m30 m60 (minutes) and s15 s30 (seconds).

FieldMeaning
open, high, low, closeOHLC
volumeShare volume
vwapVolume-weighted average
rangeHigh minus low
moneyDollar volume
countNumber of trades

[0] is the current, still-forming bar and [1] the last completed one. d1.close[1] is yesterday's close; d1.volume is today's volume so far.

Windows

A window covers several bars and is always reduced to one value:

d1.close[1:20].mean
d1.high[1:20].max
m1.high[t"04:00":t"09:29"].max
m1.volume[0:14].sum
  • Windows are inclusive: [1:20] is 20 bars.
  • Reducers: .mean, .max, .min, .sum, .range, .std, .slope, .bar_count, and more.
  • Exclude the current bar when you compare against it. A new 20-day high is trade.last > d1.high[1:20].max. A window starting at [0] contains today, so the comparison can never be true.
  • Time windows (t"HH:MM") cover today only, on minute and second bars.

Studies

Eight studies are available under ta.:

CallOutputs
ta.sma(series, n)value
ta.ema(series, n)value
ta.rma(series, n)value
ta.rsi(series, n)value
ta.atr(timeframe, n)value
ta.bb(series, n, mult).upper .middle .lower
ta.macd(series, fast, slow, signal).line .signal .hist
ta.stoch(timeframe, n, k, d).k .d

series is a bar field such as m5.close or d1.volume; ta.atr and ta.stoch take the timeframe itself: ta.atr(d1, 14). A study reads the last completed bar.

Logic and Operators

  • Combine conditions with and, or, not. Equality is ==, inequality !=.
  • Comparisons do not chain: write a < b and b < c, not a < b < c.
  • & and | are bitwise operators, not logic.
  • x if condition else y picks a value.
  • Booleans are True and False.

LogicBlocks

LogicBlocks are named signals you reuse across scans, such as CHGPCT (change from yesterday's close, as a ratio: 0.05 is 5%), AVGVOL21 or your own.

  • Write a LogicBlock from your library by its name; the scanner imports it.
  • A logicblock line in a script is private to that scan until you save it: click Save as LogicBlock above the editor. A saved LogicBlock must stand on its own, so it cannot use the script's helpers.
  • LogicBlocks whose description says "(%)" are already multiplied by 100: a 3% gap is GUP >= 3.

Examples

Breakout Above the Last Five Minutes

rule hot:
    on = cadence.trade
    when = trade.last > m1.high[1:6].max
 
scan "Breakout":
    rule = hot
    universe = "ALL"
    columns = [trade.last, m1.high[1:6].max, ta.rsi(m1.close, 14)]
    sort = ta.rsi(m1.close, 14)

Liquid Names Up on the Day

rule up:
    on = cadence.trade
    when = trade.last > 5 and trade.volume > 100000
 
scan "Price Up":
    rule = up
    universe = "ALL"
    columns = [trade.last, trade.volume]
    sort = trade.volume

The Assistant

The assistant beside the editor writes and changes scripts with you. Ask for a new scan or a change to the current one ("only stocks above $5", "add relative volume as a column"). Every script it proposes is checked on the engine first and shown as a change you can Apply or Discard.