Skip to content
ƒ FlowscriptDocs
ftw.trade docs ↗
Documentation
Learn / Flowscript

Your first Flowscript program

Compile a complete program against an explicit host and replay an illustrated price sequence with @flowscript/core.

This example calculates two moving averages and a numeric trend signal. It declares one data source and no actions. The twelve input values are an illustrated price path for learning the API, not recorded market data or a backtest result.

Get the library#

There is currently no public package release or public download of @flowscript/core. It is not available from the npm registry. Running this example locally requires authorized access to the source repository and a library build.

From the root of an authorized checkout, use the existing build, test and packaging recipe:

Terminal
just flowscript-pack

The recipe writes flowscript/npm/flowscript-core-0.1.0.tgz at the current package version. Install that locally built tarball in your application. It includes the compiled JavaScript and flowscript.wasm; it does not publish a release. The embedding guide covers prerequisites, installation and the boundary your application owns.

Compile and replay#

Save this complete example as signal.mjs in the project where you installed the package, then run node signal.mjs.

TypeScript
import { loadFlowscript } from '@flowscript/core';

const flowscript = await loadFlowscript();

const host = {
  sources: [
    {
      name: 'bars.close',
      type: 'number',
      keyed: true,
      intervals: ['1h'],
    },
  ],
  capabilities: [],
};

const source = `flowscript "0.3";
uses { bars: "^1" }
const close = bars.close("DEMO-USD", "1h");
const fast = ema(close, 3);
const slow = ema(close, 5);
metric("close", close);
metric("fast", fast);
metric("slow", slow);
metric("trend", fast > slow ? 1 : 0);
`;

const compiled = flowscript.compile(source, host);
if (!compiled.ok) {
  throw new Error(compiled.problems.map((p) =>
    `${p.line}:${p.col} ${p.code} ${p.message}`).join('\n'));
}

try {
  const closes = new Float64Array([
    100, 100, 100, 100, 100, 102, 104, 106, 105, 103, 101, 99,
  ]);
  const firstClose = Date.UTC(2026, 0, 1, 1) / 1000;
  const history = {
    len: closes.length,
    series: { 'bars.close': closes },
    time: Float64Array.from(closes, (_, i) => firstClose + i * 3600),
  };

  const replay = flowscript.replay(compiled.program, history);
  if (!replay.ok) throw new Error(replay.error);
  if (replay.unmodelled.length) {
    throw new Error(replay.unmodelled.join('; '));
  }

  const last = history.len - 1;
  console.log({
    close: replay.metrics.close[last],
    fast: replay.metrics.fast[last],
    slow: replay.metrics.slow[last],
    trend: replay.metrics.trend[last],
    decisions: replay.decisions.length,
  });
} finally {
  flowscript.drop(compiled.program);
}

Read the result#

  • uses declares the bars module. The host explicitly permits bars.close with a key and the 1h interval.
  • "DEMO-USD" and "1h" are written in the program. It needs no injected market, interval or account settings.
  • Each metric returns one value per input bar. The trend is 1 when the fast average is above the slow average, 0 otherwise, and unknown while its inputs are warming up. Numeric unknown values cross the JavaScript API as NaN.
  • history.time gives each completed bar's evaluation time in whole Unix seconds. The input columns are ordered oldest first and have exactly len values.
  • The source is read under one key, so the history can use its bare name, bars.close. A program reading several keys needs separate source|key columns.
  • There are zero decisions: this program publishes signals and declares no action capability.

Replace the illustrated input with observations your application owns when evaluating real data. Preserve the source identity, units, ordering and timestamps; an interval declaration does not fetch or construct hourly bars for you.

Next, read Embedding Flowscript or the language reference. To use the hosted editor, market data and strategy workflow, see Strategies on ftw.trade.