fast-trade: low-code backtesting on Polars with an archive and CLI
low code backtesting library utilizing polars and technical analysis indicators
At a glance
- What is it?
- fast-trade is a Python backtesting library where a strategy is a small dictionary or YAML file of datapoints and logics, executed on Polars dataframes, with a CLI, a local archive of kline data and an MCP server. It is fast and declarative, and its AGPLv3 licence is the first thing to check.
- Who is it for?
- fast-trade suits researchers who want a strategy expressed as data rather than code, who are willing to work with Polars frames, and who can accept AGPLv3 terms or the trade-offs of a self-built pipeline. Teams shipping a closed-source platform should settle the AGPLv3 question before writing code against it.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 7 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What fast-trade solves and who it is written for
fast-trade is a Python library for backtesting trading strategies, and its central idea is that a strategy is data rather than a program. A strategy is described by the datapoints to compute and the logics that compare them, then handed to the engine as a dictionary or a YAML file. The README states the framing plainly: if backtests are fast, strategies are cheap.
The audience is the individual quant or the small research team who wants to iterate on entry and exit rules without rewriting a simulation loop for every idea. It is not a live trading system. The data path is an archive of kline data downloaded from Binance (either .com or .us) and Coinbase into local parquet datasets, and the engine reads and writes Polars-native dataframes with a `date` column.
Version 3.0.0 is described as Polars-native end to end, and the project describes itself as low-code with built-in technical indicators. The dependency list in pyproject.toml explains the shape of the thing: polars for the data path, numba for the hot loops, hmmlearn and scikit-learn for the regime and machine learning parts, pygad for the genetic search, plotly for plots, pyarrow for parquet and fastmcp for the MCP server. Two console scripts are installed, `ft` and `ftv`.
One caveat sits in the packaging. The project is licensed under GNU AGPLv3, which is a strong copyleft licence and a materially different situation from the permissive licences common in this ecosystem. Anyone planning to wrap the library inside a hosted or closed-source product needs to read the licence terms and, most likely, talk to their own counsel before the first integration commit.
Anatomy of a strategy: datapoints, logics and the backtest dictionary
The Python API takes a plain dictionary and validates it before running. The dictionary carries the simulation parameters and, in the middle, the strategy itself.
from fast_trade import run_backtest, validate_backtest
backtest = {
"base_balance": 1000, # start with a balance of 1000
"freq": "5Min", # time period selected on the chard
"datapoints": [
{
"args": [
30
]
"transformer": "sma",
"name": "sma_short"
},
],
"rules": [["sharpe_ratio", ">", 0.5]],
}The keys are readable. `base_balance` is the starting balance. `freq` is the time period selected on the chart. `chart_start` and `chart_stop` bound the run. `comission` is the fee paid per transaction, spelled the way the project spells it. The `datapoints` list names the technical analysis functions to run and gives each one a reference name, with `args` passed to the transformer function. The `enter` and `exit` lists are the logics: each is a triple of a field to reference, an operator, and the name of a previously defined datapoint. `rules` filters out backtests that did not perform well, for example a sharpe_ratio condition. `trailing_stop_loss` and `exit_on_end` are optional behaviours, where the latter forces a trade to exit at the end of the backtest.
Two details are worth knowing before you write one. First, the field you compare can be any column in the data file, or it can be a float or an int. Second, `validate_backtest` returns a mirror of the object with any errors in it, so a strategy can be checked without spending time on data. The README also notes that a backtest can be given as a URL to a YAML file, which makes a shared strategy file a portable artifact.
`run_backtest` returns a result object with a `summary`, the `df` and the `trade_df`, so the same run can be inspected as text and as a trade log. The example in the README prints the summary and the head of the dataframe, and the CLI can persist both.
Installing fast-trade and running the first backtest
Installation is a single pip command. The project requires Python 3.11 or newer, with 3.11 through 3.13 supported and tested. Python 3.14 is described as experimental because `hmmlearn` requires a source build, and it is not yet part of the supported test matrix.
pip install fast-tradeThe documentation entry point is docs/GETTING_STARTED.md, which the README points to for the fastest end-to-end setup and first-run guide. The repository also ships several ready-made strategies at the root, including strategy.yml, sma_strategy.yml, strategy_mean_revert.yml, strategy_momentum.yml, regime_example.yml, hmm_screen_example.yml, evolver_example.yml and evolver_example.quick.yml, so a first run does not have to start from an empty file.
The CLI is the fastest route from an empty directory to a result. `ft -h` lists the commands, and each command has its own help at `ft <command> -h`. The download command pulls the last month of data for a symbol from an exchange and stores it in `ft_archive/`, and the backtest command takes a strategy file path. Validation is a separate command, and the README describes it as useful for the logic rather than the data.
ft download BTCUSD binanceus
ft validate strategy.yml
ft backtest ./strategy.ymlA first session therefore looks like this: download data for one symbol from one exchange, validate a strategy file, run the backtest, and read the summary. The default backtest output is only the summary, which keeps the terminal readable while you iterate.
Archive layout, run modifiers and the artifacts that get written
The archive is the part of the project that reaches the network, so it deserves care. You can download data directly from the Coinbase API and the Binance API without registering for an API key, which removes the usual first setup step. The assets command lists what is available for download from a given exchange, and it defaults to the symbols already in the local archive.
ft assets --exchange EXCHANGE
ft backtest ./strategy.yml --mods freq 1H trailing_stop_loss .05The backtest command accepts modifiers so that you do not have to edit the strategy file to try a variant. The frequency can be changed on the command line, and the trailing stop loss can be changed in the same invocation. Both are given as key and value pairs after `--mods`, and the README shows them applied together.
Results are written only when you ask for them. `--save` creates a timestamped directory under `ft_archive/backtests/` holding the strategy summary and a plot. `--all` additionally persists the dataframe and the trade log as parquet, with the file names `dataframe.parquet` and `trade_log.parquet`. That split matters on a long run: the summary and the plot are small, the parquet files are not.
The tree also contains an examples directory with ml_classifier_backtest.py, ml_classifier_strategy.yml, ml_walk_forward.py and a research folder, alongside run_example.py and run_parallel_example.py at the root. The presence of walk-forward and parallel examples suggests the intended path beyond a single backtest is repeated evaluation, not one lucky parameter set.
The MCP server and how closely it tracks the CLI
fast-trade ships a local MCP server, started as a module.
python -m fast_trade.mcp_serverThe design goal stated in the README is parity: every `ft` CLI command has a dedicated MCP tool, and the README names them as download, assets, backtest, backtests, logs, the portfolio commands and screen_hmm, with the full matrix in docs/FEATURES.md. Additional helpers cover list_strategies, tail_log, fxmacrodata_macro_context and a structured hmm_screen JSON output, and there is a raw passthrough through ft_command and ft_command_str for anything the curated tool list does not cover.
That parity is the interesting part for anyone wiring an agent into a research workflow. Because the MCP surface mirrors the CLI rather than replacing it, the same script that works today still works when the tool list changes, and the passthrough means an uncovered command is reachable without patching the server.
The author is candid about the boundary of this part of the project. The MCP server is described as running on live-streaming data from HyperLiquid, Coinbase and Binanceus that comes from the author's own closed-source data collection software, offered with absolutely no guarantees. In other words, the MCP server is a working interface over fast-trade, while the live data feed it can sit on is not part of the open source release. Anyone planning to use the server with live data has to supply that data path themselves.
Performance claims, licence reality and the cases where fast-trade is the wrong tool
The README makes concrete speed claims and they are attributable to the project's own benchmarks, not to an outside reviewer. On BTCUSDT one-minute data, version 3.0.0 is described as taking about 0.43 seconds for a one-year EMA-cross plus RSI backtest over roughly 526,000 bars, and about 0.17 seconds for a two-month one-minute backtest. Against pandas 2.1.0 on the same strategy the README reports 1.99x, 2.22x, 2.37x and 2.45x speedups at one, two, five and ten years, and for the FinTA indicator suite about 1.9x overall, with ATR around 5x, WMA around 100x and OBV around 3x. The benchmark scripts are named in the README so the numbers can be reproduced, and stage breakdowns live in docs/PERFORMANCE.md.
Those figures are the case for the library, and they are the project's own claims on its own hardware. A useful sanity check for a reader is that the comparisons are against pandas 2.1.0 rather than against other backtesting frameworks, so the benchmark measures the dataframe engine, not the strategy engine.
The real limits are elsewhere. First, the strategy format is deliberately narrow: it expresses indicator comparisons and rules, which suits rule-based systems and does not obviously suit anything requiring custom Python inside the simulation loop. Second, data is limited to what the archive can fetch, currently Binance and Coinbase klines, so an exchange with a different API means writing your own ingestion. Third, the dependency set is heavy for a research tool: numba, scikit-learn, hmmlearn, pygad and fastmcp all come along, and the 3.14 situation shows how a single dependency can hold back the whole install.
The alternative approach to weigh is doing the same work in a notebook with pandas or Polars directly, with a hand-written event loop and your own data fetch. The difference is concrete: you would own the indicator implementations, the data availability and the result persistence, and you would lose the declarative strategy file, the archive, the CLI and the MCP surface that fast-trade gives you for free. The trade runs in both directions, and for a closed-source commercial product the AGPLv3 licence of fast-trade is often the deciding factor rather than the performance.
On maintenance, the repository is not archived and the last push was on 2026-10-16. Releases v3.0.0 on 2026-09-24, v2.1.0 on 2026-08-20 and v2.0.0 on 2026-03-11 show a version cadence around the major Polars rewrite, and version 3 is early enough that the API may still move.
Editorial conclusion
fast-trade suits researchers who want a strategy expressed as data rather than code, who are willing to work with Polars frames, and who can accept AGPLv3 terms or the trade-offs of a self-built pipeline. Teams shipping a closed-source platform should settle the AGPLv3 question before writing code against it. Verify first that your Python version is 3.11 to 3.13, since 3.14 needs a source build of hmmlearn, and that the archive can reach the exchange you intend to test against.
Frequently asked questions
How do I install fast-trade and what Python version do I need?
Install it with `pip install fast-trade`. The project requires Python 3.11 or newer; versions 3.11 to 3.13 are supported and tested, while 3.14 is experimental because `hmmlearn` needs a source build.
What file format does a fast-trade strategy use?
A strategy is described by datapoints and logics, and can be written as a YAML file such as strategy.yml or passed to the Python API as a dictionary. The repository root ships several example strategies including sma_strategy.yml and strategy_momentum.yml.
Can fast-trade download market data without an API key?
Yes. The README states that you can download data directly from the Coinbase API and the Binance API without registering for an API key, and the archive stores it in local parquet datasets.
What licence does fast-trade use?
The pyproject.toml declares the licence as GNU AGPLv3, and the repository licence is AGPL-3.0. That is a strong copyleft licence, so teams intending to embed the library in a closed-source product should review the terms before integrating.
How do I start the fast-trade MCP server?
Run `python -m fast_trade.mcp_server` to start the local server. Each `ft` CLI command has a matching MCP tool, with the full matrix documented in docs/FEATURES.md and a raw passthrough through ft_command.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/jrmeier-fast-trade)Was this useful?