mcp server
trade-terminal
Terminal-native, MCP-native trading-strategy backtester an AI agent can drive — with built-in overfitting guards (walk-forward, deflated Sharpe, costs).
Set up
Runs on your computer. Pick your agent and operating system.
Before you start
- uv (`curl -LsSf https://astral.sh/uv/install.sh | sh`)
{
"mcpServers": {
"trade-terminal": {
"command": "uvx",
"args": [
"trade-terminal"
]
}
}
}same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12
Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs
README
synced Oct 23, 2026Trade Terminal
A terminal-native platform for market data → strategy → backtest, built so an AI agent can drive the whole loop over MCP — and so the tool won't let the agent fool itself: look-ahead detection, walk-forward robustness, transaction costs, and a deflated-Sharpe overfitting check are built in. And built so the codebase is the product: legible, plug-and-play, fork-friendly.
An AI agent drives the optimize loop over MCP — and flags its own winner as overfit:
https://github.com/user-attachments/assets/0536490f-880e-4842-9963-34b99bbbb08d
Scope so far: equities, numbers (OHLCV) via yfinance; a cache-first two-store data model; multi-asset backtesting (cross-sectional & long/short, see
examples/pairs_reversion.py) with look-ahead guardrails and full provenance; an MCP server + a self-describing tool surface so any coding agent can drive the whole loop; a sandbox that confines agent-written code; and an optimization engine with the honesty guards that make results trustworthy at scale — walk-forward robustness, transaction costs, and a deflated-Sharpe multiple-testing guard. Strategies can also read point-in-time signals — non-price data (sentiment, narrative, filings) an agent produces offline, served<= nowso there's no look-ahead — so the platform expresses semantic strategies, not just price ones (seeexamples/narrative_signal.py). Paper/live trading and derivatives are planned for later; their plug-in seams already exist, so they drop in without core edits. See the roadmap.
Install
This project uses uv. From the repo root:
uv sync # create the venv + lockfile, install everything
uv run tt --help # run the CLI
(No uv? pip install -e . works too — you just won't get the lockfile.)
Quickstart (offline — no network, no API key)
DEMO below is synthetic data from the built-in sample source — deterministic,
not real prices — so this runs anywhere in seconds:
uv sync
export TT_HOME=./demo-store # a throwaway data dir for the demo (delete when done)
# 1. Pull synthetic DEMO bars into the read-only store (cached for next time)
uv run tt fetch DEMO --from 2020-01-01 --to 2023-12-31 --source sample
# 2. Open an analysis workspace over a development window
uv run tt analyze DEMO --from 2020-01-01 --to 2021-12-31 --name demo --source sample
# 3. Backtest a strategy out-of-sample (warns on look-ahead)
uv run tt backtest examples/sma_cross.py --workspace demo --from 2022-01-01 --to 2023-12-31
# 4. Inspect what ran, and map a run back to its exact code
uv run tt runs
For real equity data, drop --source sample (the default is yfinance):
uv run tt fetch AAPL --from 2020-01-01 --to 2022-12-31.
# Pull AAPL daily bars into the read-only store (cached for next time)
uv run tt fetch AAPL --from 2020-01-01 --to 2022-12-31
# Open an analysis workspace over a development window
uv run tt analyze AAPL --from 2020-01-01 --to 2021-12-31 --name aapl-demo
# Backtest a strategy out-of-sample (warns on look-ahead)
uv run tt backtest examples/sma_cross.py --workspace aapl-demo --from 2022-01-01 --to 2022-12-31
# 4. Inspect what ran, and map a run back to its exact code
uv run tt runs
How it's built
Two folder-based stores and a plug-in registry:
- Read-only store — the canonical, append-only cache of everything ever downloaded. Never mutated, only added to. A request that partially overlaps what's already stored fetches only the missing date gaps (range-merge).
- Analysis workspace — a disposable, per-analysis working copy of the data a strategy needs. The store is durable; the workspace is throwaway.
- Plug-in registry — seven extension kinds (data sources, data categories,
config dimensions, execution backends, sandboxes, optimization
objectives, and cost models) are all registered through one entry point.
Built-ins and your own drop-ins are treated identically. Run
tt kindsto see what's installed.
See docs/architecture.md for the component/seam map.
The short version: every component depends only on
trade_terminal/core/contracts.py (the "narrow waist"), so you can replace any
one piece by satisfying its interface — without reading the others.
Extending it
Drop a .py file under trade_terminal/plugins/ (or any discovered path) that
defines register(registry). That's the whole extension mechanism; built-ins
use the exact same path. Example — a new data source:
def register(registry):
registry.register("source", "my_source", MySource())
Drive it with an agent (MCP)
Install the optional extra and launch the server:
uv sync --extra mcp
uv run tt mcp # stdio MCP server
Point any MCP-capable agent (Claude Code, etc.) at it and it can fetch data, open
workspaces, write and submit its own strategy code, backtest it, and read run
provenance — through the same core the CLI uses. See
docs/mcp-server.md.
By default that agent-submitted code runs in a confined sandbox (restricted)
that cannot write to the source tree or anything outside a scratch dir — an agent
uses the functionality, it does not get to edit the code. See
docs/security.md.
Data frequency
The default interval is daily (1d), but --interval also accepts intraday bars
— 1h, 30m, 15m, 5m, 1m — and backtests run on them unchanged (the engine
is interval-agnostic). Two limits worth knowing:
- History is provider-bound. yfinance serves only recent intraday data
(roughly
1m≈ 7 days,≤30m≈ 60 days,1h≈ 2 years). Long-history high-frequency research needs a dedicated source plug-in (e.g. Polygon, databento) — which drops in without core changes. - Coverage is tracked per calendar day. A day's intraday bars are fetched and cached together, so re-fetching the current day won't pick up newer bars until it closes. Fine for historical backtests; relevant only for intraday paper/live.
Tick / quote / order-book data is a different shape and would arrive as its own data category. Production-grade high-frequency support (performance + a high-freq source) is planned alongside the vectorized backtest engine.
Optimize a batch (the agent loop)
Evaluate many strategy candidates at once, ranked by an objective — each run in a sandbox:
tt optimize ./candidates --workspace demo --from 2023-01-01 --to 2023-12-31 --objective sharpe
tt optimize ./candidates -w demo --from 2023-01-01 --to 2023-12-31 --windows 3 # walk-forward robustness
tt leaderboard # list experiments; pass an id to view one
--windows N splits the window into N consecutive periods and ranks by the mean
score while surfacing each candidate's worst window and consistency — so a
one-window-lucky strategy is visibly fragile, not mistaken for a robust one.
Add --commission-bps / --slippage-bps to either backtest or optimize to
model transaction costs (frictionless by default — a leaderboard run that omits
them says so). This matters at scale: without costs the ranking quietly rewards
high-churn strategies that only "win" because trading was assumed free. With costs
on, the metrics report total_costs.
The leaderboard also reports a deflated Sharpe — the probability the #1 result's edge is real after the number of strategies you tried. Test enough arbitrary rules and the best one looks great by luck alone; this flags it. Together with look-ahead, walk-forward, and costs, it's a layered defense against fooling yourself — no single oracle.
Via MCP, an agent calls optimize(...) with a batch of inline candidate codes,
reads the ranked leaderboard, and proposes the next batch. See
docs/experiment-engine.md.
Data location
The read-only store, workspaces, and run records live under $TT_HOME
(default: ~/.trade-terminal). Point TT_HOME somewhere else to sandbox them.
Disclaimer
Trade Terminal is a research and educational tool, provided "as is" without
warranty of any kind (see LICENSE). It is not financial advice, not
a recommendation to buy or sell any security, and not a solicitation. It currently
backtests only — it does not place real orders. Backtested or simulated
results are hypothetical, do not represent actual trading, and are no guarantee
of future performance. The default yfinance source is unofficial and intended
for personal research, not production use. You are solely responsible for any
decisions made with this software. Markets carry risk of loss.