qanat
OfficialClick on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@qanatRun the momentum backtest and show me the PnL report."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Qanat is an agent-first backtesting engine that turns your raw data into portfolio weights through a pipeline of steps you define.
The idea
In Qanat, you build a strategy as a pipeline of tables.
It starts with your raw data: prices, news, or anything else you track. From there, you define each step of the pipeline. A step reads one or more tables and writes a new one, so you can clean the data, calculate metrics, and score your symbols. The final step outputs your portfolio weights, detailing exactly what to hold and how much.
Qanat replays this pipeline across historical data, one date at a time. It prices the portfolio's holdings, accounts for fees, and outputs a complete PnL table.
Nothing is hidden. Every table is visible on your screen, with its row count and the logic that created it. If a number looks off, you open that table and inspect the data.
As your project grows, you can plug in new data sources and build new steps on top of them.
You don't have to write the code yourself. Describe what you want in plain English, and the agent will build the step, run it, and show you the resulting table.
Qanat is built for retail traders who rebalance daily or weekly. You can't out-race an institutional hedge fund on speed, and with a longer horizon, you don't need to.
Related MCP server: mcp-dagster
Quick start
You need Python 3.10 or newer.
uv tool install qanat-fdtl # or: pip install qanat-fdtl
qanat init my-alpha --demo && cd my-alpha
qanat serveThe console opens on http://127.0.0.1:8420.
--demo builds four working strategies, runs the pipeline, and prices each one, so the console
opens with real numbers in it. It takes about fifteen seconds. The data is synthetic, so this
works with no API key and no network. Leave --demo off for an empty project.
Qanat makes no network calls on its own. The only outbound requests are the ones your data sources make.
Needs nothing but Docker, and brings its own Postgres:
git clone https://github.com/fidetolabs/qanat.git && cd qanat
docker compose up --buildPostgres is on localhost:5433, not 5432, because 5432 is often taken already. User, password
and database are all qanat. Bind a directory to /project to use your own project instead of
the demo.
If a port is already in use, set the host ports yourself:
POSTGRES_HOST_PORT=5434 QANAT_HOST_PORT=8421 docker compose up --buildTo start over, docker compose down -v && docker compose up --build.
Use it with an agent
This is the main way to work with Qanat. You describe what you want, and the agent writes the step, runs it, and shows you the table it produced.
Add it to any MCP client:
{ "mcpServers": { "qanat": { "command": "qanat", "args": ["mcp"], "cwd": "/path/to/my-alpha" } } }For Claude Code, claude mcp add qanat -- qanat mcp. Add --read-only and the agent can look at
everything but change nothing.
Things you can ask for:
"What is in this project, and what feeds the momentum strategy?" The agent traces the table back to its sources and answers with data, not a guess.
"Add a momentum strategy and backtest it." Before running anything, it comes back with what your data can actually cover and asks you to choose the window, the rebalance, and the costs.
"Which of my strategies actually works?" It lists every one with what it earned, so it compares instead of speculating.
"Why did it lose money in March?" It opens that period and shows what was held, what each name returned, and what was traded to get there.
The console and the agent are two views of the same project, so they can never disagree about its state. The full tool list is in docs/agents.md.
How it works
Everything lives in one qanat.yaml. Nothing hides in application code.
project: equity
store: ./data/qanat.duckdb
universes: # which symbols a portfolio may hold
- id: sp500
symbols: ./universes/sp500.csv
stages: # order here is order in the pipeline
- { id: raw, kind: raw }
- { id: normalized, kind: features }
- { id: features, kind: features }
- { id: weights, kind: weights }
- { id: pnl, kind: pnl }
sources: # where data comes from
- id: prices
to: [raw.daily_prices]
connector: rest
options:
url: https://api.example.com/v1/bars
headers: { Authorization: "Bearer ${PRICE_API_KEY}" }
steps: # each one reads tables and writes tables
- id: momentum
from: [normalized.prices]
to: [features.momentum]
script: steps/momentum.py
options: { lookback: 20 }
- id: alpha_momentum # the step that writes weights is the strategy
from: [features.momentum, features.risk]
to: [weights.momentum]
script: steps/alpha_momentum.py
universe: sp500
rebalance: 20d
backtest: # what prices the portfolio, and what it costs
prices: normalized.prices
fee_bps: 5
slippage_bps: 10A step is a .sql file, or a .py file with a run(ctx) function:
def run(ctx):
bars = ctx.read("normalized.prices") # only tables the step declared in `from`
held = ctx.universe() # the symbols it may hold
return dfctx.read() refuses any table the step did not list, so a missing dependency is an error instead
of a wrong number.
The five stages
Each stage holds tables, and data only moves forward through them.
stage | what it holds |
| data exactly as it arrived. Never edited |
| typed, deduplicated, one key set |
| anything you measure or calculate |
| one table per strategy. What to hold, and how much |
| what each strategy earned. Written by |
qanat check enforces the rules that keep this honest, and refuses to run a project that breaks
one. They are written out in
docs/contract.md.
The commands you need
command | |
| create a project |
| run the pipeline once |
| scheduler and console |
| replay over history and price what it held |
| one backtest, period by period |
qanat --help lists the rest. qanat tui gives you the console in the terminal if you prefer to
stay there.
A source or a step can also run on a clock, or run whenever its input changes. Set schedule: or
when: on it, or fill it in from the console.
Backtest
A backtest replays the pipeline over a period that already happened and prices what it held.
qanat backtest --from 2026-01-05 --to 2026-06-01 --rebalance 10d gross +25.150%
fees -0.636%
slippage -1.272%
------------------------------
net +23.242%
per period +1.660% over 14 periods
hit rate 64.3%Before each pass, every table is filtered down to the rows that existed at that moment. A step reads the past without knowing it is being replayed, so a step that forgot to filter still cannot see the future.
Net is the headline, not gross. Fees and slippage are charged on turnover, which is how much had to be traded to reach the new portfolio. Trading more often can turn a winning strategy into a losing one. Same strategy, same window, only the rebalance changed:
--rebalance 10d turnover 10.8 net +23.2%
--rebalance 1d turnover 128.5 net -27.1%--decay N works from the other side. It holds a blend of the last N portfolios, so the strategy
stops paying fees for noise:
turnover net
--decay off 45.00 -5.05%
--decay 4 25.32 -2.88%In sample and out of sample are reported separately. --split <date> cuts the run in two. The
lookback, the rebalance and the decay were all chosen by someone who could see the first half, so
that number partly measures the choosing:
in sample -22.055% 19 periods, -1.161% each
out of sample -2.843% 14 periods, -0.203% each
split at 2026-03-01 — out of sample is the line to believeSeveral strategies can be priced together as one book with
--alpha alpha_momentum,alpha_low_vol. Each keeps its own weights table, and the result lands in
one PnL table.
More in docs/backtest.md.
Strategies on the shelf
Four plain strategies ship with Qanat, so you have something real to replay on day one.
qanat alphas # what is on the shelf
qanat alphas momentum --reads normalized.prices # wire one up
qanat run && qanat backtest --from … --to …
| rank by trailing return, hold the top names. Long only |
| the same over days rather than months, buying what just fell |
| hold the quietest names, sized inversely to their own volatility |
| momentum with the average taken out. Long and short, equal sides |
Each one writes an ordinary step file into steps/. Edit it, or throw it away and write your own.
The tool is what is given away here. The strategy never is.
Data sources
connector | what it is |
| an HTTP endpoint returning JSON. |
| any database SQLAlchemy can reach. |
| a local path or a URL |
| a deterministic fake market, so a new project runs before any API key exists |
The store is one local database: a DuckDB file by default, or Postgres on localhost
(qanat init --postgres, or docker compose).
Four examples ship with it:
| synthetic prices. Runs with no network and no keys |
| real data, in the repo. 27 years of ECB rates, 126 KB, no key needed |
| the same project fetching the same rates over HTTP |
| a source on a clock, fetching while you watch the console |
Status
Beta, and the first packaged release. It does what this page says on my own work, but nobody else has run it yet. If something breaks or looks wrong, open an issue or say so on Discord.
Working end to end: the pipeline and its rules, the DuckDB and Postgres store, the console, cron scheduling, Docker, the point-in-time replay engine with its net-edge report, and the MCP server.
Not implemented: backfills, incremental windows, and live trading. Qanat produces a portfolio. It does not place an order.
One limit worth knowing before you trust a number. There is no benchmark. Nothing separates your edge from the market's own move, so a long-only strategy in a rising market looks good and the report cannot tell you why.
Qanat runs one kind of pipeline, the kind that ends in a portfolio. Airflow, Dagster and Prefect handle arbitrary DAGs and distributed execution. Reach for those when you need them.
Issues and pull requests are welcome. See CONTRIBUTING.md.
License
MIT License. See LICENSE.
Copyright (c) 2026 fidetolabs
This server cannot be deployed
Maintenance
Related MCP Connectors
- mcp-serverOAuthcom.make
Give your AI agents the tools to build, manage, and run automation workflows.
Workflow planning, recovery checkpoints, coordination, fixtures, and compatibility tools for agents.
- CPZAIOAuthcom.cpz-lab.mcp
Build, backtest, and deploy quantitative trading strategies from your AI agent.
Mine, validate and paper-trade quantitative trading strategies. The engine runs on your machine.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables coding agents to interact with Metaflow workflows, including querying flows, runs, tasks, logs, and artifacts across any Metaflow backend.24Apache 2.0
- AlicenseBqualityDmaintenanceEnables AI agents to interact with Dagster instances, explore data pipelines, monitor runs, and manage assets.924Apache 2.0
- AlicenseNot gradedqualityCmaintenanceProvides AI agents with a toolset to query model inventories, trace dependencies, and analyze the impact of changes across machine learning models and data pipelines.14Apache 2.0
- AlicenseNot gradedqualityBmaintenanceEnables users to create and revise strategy graphs, modules, and custom nodes; run exact-revision backtests; and maintain project knowledge and artifact documentation.MIT