How strategies work
A strategy is Flowscript run once per closed bar. The same code backtests over history and runs live, so what you tested is what trades. What a strategy can trade, how a run behaves, and the rules every run follows.
One program, two uses#
A strategy is a short program in Flowscript. It reads a market's bars, computes values, and fires orders when its conditions turn true.
- In a backtest it steps through history, bar by bar, against a paper broker with fees and slippage.
- In a run (a deployment) it steps through each new bar as it closes, on ftw.trade's servers, from the next bar after you start it.
Flowscript has no loops and no hidden state, so the same bars always give the same decisions. That's why a backtest and a live run agree, and why ftw.trade can check that they keep agreeing.
What a strategy runs on#
| Market | Series | Bars |
|---|---|---|
| A pool on any indexed EVM chain or Solana | pool:<chain>:<address> | 5s, 15s, 1m, 5m, 15m, 1h, 4h, 1d |
| A Hyperliquid or Lighter perp, builder perp or spot pair | perp:<venue>:<symbol> | 1m and up (5s and 15s from its recorded book) |
| A shared price feed (crypto, stocks, commodities) | feed:<name> | 1m and up |
| A Polymarket outcome | poly:<token id> | 5m and up |
| One of your own sources | source:<name> | its events made into bars |
What a strategy can do#
- Spot: buy and sell, by amount or by percent of equity, with resting limit and stop orders.
- Perps: go long, short or flat, rest maker bids and asks on the book, and cap an order to what the book holds near the price.
- Liquidity: hold a range on a pool and move it by your rules.
- Hedges: short what a liquidity range holds on a perp, and keep the perp account topped up.
- DeFi: supply, borrow and repay on lending markets, deposit in vaults, hold fixed rates on Pendle, trade options on Derive, or let
earnfind the best rate.
Strategies over more than one market (a range hedged on a perp, a lending loop, options hedged with perps) are covered in Hedged and multi-market.
How a run behaves#
- It decides on closed bars. Each bar decides once, once its indicators have enough history (it replays warm-up bars before its start). On a pool, 5s and 15s bars decide within seconds of the swaps that make them.
- It runs the code it started with. Saving a new version marks the run outdated but changes nothing it does. Start a new run for the new code.
- It holds still on stale data. If a market's data stops arriving, the run waits rather than trading on old prices, and says so.
- It guards against drift. If replaying its bars ever stops matching the orders it already sent, it stops itself with the reason, so a live run never quietly diverges from its backtest.
- It explains itself. Each run keeps its metrics bar by bar, every decision, order and fill, and every error, in the Log.
The rules every strategy should follow#
- Entries go in
when, notwhile. Awhenfires once as its condition turns true; awhilefires every bar it holds and can spend all your cash. - Every entry has an exit: a
whenthat sells, a stop from the entry price, or the run'sstopPct,takePctandtrailPct. - Sizes are numbers or settings as written. Use
paper.buyPct({ pct })to size by equity. - Compare with the previous window:
close > highest(close, n)[1], nothighest(close, n), which includes the bar itself. nameans unknown, not false. A trigger never fires onna.- Add risk limits to anything that runs unattended with real money: a drawdown bound, a daily loss bound and a trade count, in an
invariantsblock.
ftw.trade's compiler warns about most of these (a while that buys with no guard, a condition that is never true, a divide by zero) by line, before you save.