# Sources in Flowscript

> Build a source with no code to host. A Flowscript program over ftw.trade's streams, a websocket, a polled API or a contract's events, keyed, barred, warmed up and backtested.

A Flowscript source is a declared input and a program over its events, one step each. It publishes events of its own with `source.emit`. State carries from event to event, and across restarts.

## A first source

Tokens whose bonding curve jumped past 90%:

```json
{
  "name": "near-grad",
  "fields": { "token": "address", "progress": "number", "jump?": "number" },
  "from": { "stream": "curves", "where": { "progress": { "gte": 90 } } },
  "key": "token",
  "flow": "uses { input: \"^1\", source: \"^1\" }\nconst e = input.event();\nwhile (e.graduated == 0) { source.emit({ token: e.token, progress: e.progress, jump: e.progress - e.progress[1] }); }"
}
```

- `from` is the input. `where` filters before the program runs.
- `key` names the fields that make an event unique: the same key is published once a day (`dedupeFor` changes that).
- `while (cond)` publishes on every event `cond` holds for; `when (cond)` only when it turns true.
- A field the program leaves `na` is left out, so mark it optional (`"jump?"`).

The same source can be one `.source.flow` file, with the definition in a `// @source { … }` header above the program.

## Indicator sources, ready made

Thirteen indicators are ready as sources: RSI zones, MACD cross, Bollinger Bands, EMA cross, SMA golden and death cross, stochastic, Supertrend, Donchian breakout, CCI, ADX/DMI cross, VWAP cross, volume spike and MFI. Pick one on the Sources page (or with `get_source_guide`), point it at a pool, a shared feed or a venue market, and it runs on closed bars.

Every indicator source publishes the same shape: the market, the bar's open, high, low and close, its own values (`rsi`, `macd`, `upper`…) and a **`signal`**: +1 buy, -1 sell, 0 nothing. So anything can trade it without knowing which indicator it is, and the recipe writes the strategy that does: buy on +1, sell on -1, with the values charted as metrics.

## Inputs

| Input | Reads |
|---|---|
| `{ stream: "…" }` | ftw.trade's own streams: `launches`, `graduations`, `curves`, `swaps`, `prices`, `markets`, `books`, `trades`, `protocols` |
| `{ socket: "wss://…", read }` | A websocket, each message's fields picked by path and type |
| `{ poll: "https://…", every, read }` | A URL polled every second or more (GET or POST) |
| `{ event: "Swap(…)", chain, address }` | A contract's events, filtered at the RPC, backfilled from a date |
| `{ source: "…" }` | Another source of yours, or one you subscribe to |

Up to four inputs can be merged into one series.

## Streaming like a chart

- **`by: "pool"`** keeps one run per value of a field: on the swaps stream, `ema(e.price, 20)` is each pool's own average.
- **`bars: { every: "1m", price: "price" }`** gathers events into bars and steps once each closes, even when nothing more arrives.
- **`warmup: "6h"`** steps stored history first, so indicators are warm on the first live event.
- **`since: "2026-09-01"`** fills the source's history from a date when it's deployed, so a strategy can backtest over it the day it's written.

Pools whose 1-minute RSI runs hot:

```json
{
  "name": "rsi-hot",
  "fields": { "pool": "text", "rsi": "number" },
  "from": { "stream": "swaps" },
  "by": "pool",
  "bars": { "every": "1m", "price": "price", "volume": "quote", "time": "ts" },
  "warmup": "6h",
  "flow": "uses { input: \"^1\", source: \"^1\" }\nconst e = input.event();\nconst r = rsi(e.close, 14);\nwhen (r > 70) { source.emit({ pool: e.pool, rsi: r }); }"
}
```

## Backtest a source

`backtest_flow_source` (or **Preview** on the Sources page) steps a definition over events you give, or over stored history, and shows what it would have published, before you save or deploy anything.

## A source as a market

A strategy can run on a source's own bars with `series: "source:<name>"`, so a websocket feed aggregated with `bars` becomes a market to backtest and trade. Sources keep 30 days of events.

## Polls on demand

A poll with no `every` runs only when asked: a strategy asks with `poll.source({ name })`, a workflow with a `poll` step that waits for the fresh value.
