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:
just flowscript-packThe 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.
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#
usesdeclares thebarsmodule. The host explicitly permitsbars.closewith a key and the1hinterval."DEMO-USD"and"1h"are written in the program. It needs no injectedmarket,intervalor account settings.- Each metric returns one value per input bar. The trend is
1when the fast average is above the slow average,0otherwise, and unknown while its inputs are warming up. Numeric unknown values cross the JavaScript API asNaN. history.timegives each completed bar's evaluation time in whole Unix seconds. The input columns are ordered oldest first and have exactlylenvalues.- The source is read under one key, so the history can use its bare name,
bars.close. A program reading several keys needs separatesource|keycolumns. - 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.