Lets an AI client run a read-only crypto trading desk that prices costs, applies risk limits, and records every decision and refusal.
Also known as BijectiveLabs/bitra, bitra
- Stars
- 47
- Tools
- —
- Downloads, 30 days
- —
- Latest version
- 0.14.0
- Last commit
- Nov 14, 2026
- License
- MIT
What is TRA MCP?
TRA lets an AI client run a read-only crypto trading desk that prices costs, applies risk limits, and records every decision and refusal.
Summary generated from the project's README
About TRA MCP server
Running a deterministic crypto trading desk from an AI client is what TRA enables for developers who want to separate decision-making from execution. The system acts as a read-only layer where a language model or a custom rule proposes a trade, but the system itself handles all calculations, risk limits, and order sizing. This ensures that even if a model miscalculates a value or ignores a setting, the underlying system enforces your declared thresholds and prices the full round trip, including fees and slippage, before any order is sent.
Users set up a desk locally using Python 3.11 or newer, often via uv, and can connect to various model providers like OpenAI, Anthropic, or Google. The server uses ccxt to reach multiple exchange venues. Every decision, refusal, and market snapshot is recorded on disk, providing a complete audit trail. It is designed to prevent common issues like double-sending orders or losing stop-loss positions during a crash by attaching exits directly to the entry order at the venue level.
What you can do with it
- 1Backtest strategies against historical dataA developer can replay a specific trading rule over years of market data to see how it performs against buy-and-hold or random benchmarks.
- 2Enforce strict risk managementYou can ensure that a language model never exceeds your predefined financial limits or ignores transaction costs.
- 3Monitor news impact on tradesUse a typed judge to analyze headlines and automatically hold or pause entries based on adverse market events.
- 4Audit every trading decisionReview a complete history of why every single trade was either executed or refused by the system.
Written from the project's README. Every use case is checked against a quote from it.
How to install TRA MCP
Formats verified 10 Nov 2026Add to CursorAdd to GooseInstall TRA MCP in Claude Code
$ claude mcp add bitra -- uvx bitraInstall TRA MCP in Cursor
~/.cursor/mcp.json
{
"mcpServers": {
"bitra": {
"command": "uvx",
"args": [
"bitra"
]
}
}
}Install TRA MCP in VS Code
.vscode/mcp.json
{
"servers": {
"bitra": {
"type": "stdio",
"command": "uvx",
"args": [
"bitra"
]
}
}
}Install TRA MCP in VS Code CLI
$ code --add-mcp '{"name":"bitra","type":"stdio","command":"uvx","args":["bitra"]}'Install TRA MCP in Claude Desktop
claude_desktop_config.json
{
"mcpServers": {
"bitra": {
"command": "uvx",
"args": [
"bitra"
]
}
}
}Install TRA MCP in Codex
$ codex mcp add bitra -- uvx bitraInstall TRA MCP in Codex config.toml
~/.codex/config.toml
[mcp_servers.bitra] command = "uvx" args = ["bitra"]
Install TRA MCP in Gemini CLI
$ gemini mcp add -s user bitra uvx -- bitraInstall TRA MCP in Gemini settings.json
~/.gemini/settings.json
{
"mcpServers": {
"bitra": {
"command": "uvx",
"args": [
"bitra"
]
}
}
}Automated checks
Ran Nov 12, 2026Full report →Passed our automated checks. That is not a security audit: read the code and give the server the narrowest access it needs. How checks work
- Source repository linked and reachablePass
- Open source license (OSI)Pass
- Commit or release in the last yearPass
- Package name not close to a popular packagePass
- Remote endpoint uses HTTPSNot checked
- Destructive tools are labelledNot checked
- No hidden instructions to the modelPass
- No critical advisory in the package or its dependenciesPass
README
View on GitHubTRA (trading research agents) is published as bitra on PyPI and runs as tra. Before
0.10.1 the package was called trading-research-agents, and the same package is still
published under that name.
TRA is a crypto trading desk you run yourself. It reads the market, takes one decision, prices the round trip, holds the decision against limits you declare, and either writes it down or sends one order with its stop attached. The decision can be a rule in your own file, with no model in the loop, or a language model that proposes. Either way the system, with no model involved, computes every figure, applies every limit, sizes the trade and sends the order. Every decision and every refusal is kept on disk with its reason, so you can check afterwards what happened and why.
It is experimental. Settings change between versions, it has not been run with real capital by us, and the package ships no strategy that makes money. What it does give you: one order path to every exchange ccxt reaches, run end to end on six of them; an arena that replays any rule over years of data net of your own costs, beside buy-and-hold and a random null; a typed judge that reads the day's headlines and can hold an entry on an adverse event; and the records to check every claim this page makes on your own data.
Contents
- What it solves
- How it is built
- What we measured, and what it changed
- Get started
- The console
- How one cycle decides
- Venues
- Models and providers
- Toward real orders
- Your money, your orders, your positions
- Watching a desk, and what is kept
- Command line
- What it guarantees, and what is not built yet
- Where it is going
- Documentation
What it solves
| The usual problem with trading software that decides | What happens here |
|---|---|
| A model invents or miscalculates a number | Models never compute. Every figure comes from the system, and a figure a model cites is checked against its brief, value included. |
| Nobody knows what a trade cost until it's done | The round trip (fees, spread, impact, funding, slippage) is priced before an order exists, and a trade whose claimed edge doesn't clear it is refused. |
| The claimed edge is whatever someone hoped | A rule desk claims the mean net per trade you measured in the arena, on your own costs; nothing guesses it. |
| A model "decides" to ignore your settings | Your declared thresholds decide. A model's opinion is recorded beside them, never instead of them. |
| Something went wrong and there is no trace | Each cycle keeps its snapshot, briefs, answers, the intent and what the venue said. Nothing is rewritten. |
| A timeout is read as "the order failed" | An order with no answer is unknown and read back by its client order id; it is never sent twice. |
| A crash leaves a position with no stop | The stop and take profit go to the venue with the entry, or right after the fill where the venue takes them no other way, so they survive this process dying. |
| Text from a feed tells a model what to do | Headlines are read only by the typed judge, as closed questions, after a check for instructions addressed to a machine; no model can send an order or reach a key. |
| A strategy looks good on a lucky sample | The arena replays it over years of recorded market beside buy-and-hold, momentum, its own fade and a seeded random null, net of costs, and says "sample too small" until the sample is not. |
None of these is hypothetical. Why it is built this way lists the documented failures behind each one, with their sources.
How it is built
Three kinds of work, kept apart because they fail differently.
| Does | Never does | |
|---|---|---|
| The system | records the market, computes every figure, prices the round trip, applies your limits, sizes, signs what the risk gate approves, sends one order with its exits, settles every replayed idea | guess, or carry a stale value forward as current |
| The decision | a rule in your file (closed bars in, one idea or none out), or a language model that proposes a direction and its levels, citing the figures it used | compute a number, size a trade, touch an order or a key, loosen a limit |
| Jev, the typed judge | reads each headline as closed questions and returns a probability for each answer: which kind of event, whether it concerns this asset, whether it speaks to a machine | decide a direction from numbers, compare dates, do arithmetic, size, or reach an order |
flowchart LR
market["market data<br/>candles, book, funding,<br/>open interest, news"]
decision["the decision<br/>a rule in your file,<br/>or a model that proposes"]
guard["event guard<br/>Jev reads the headlines,<br/>the system weighs them"]
cost["cost and exits<br/>round trip priced,<br/>stop and take placed"]
risk["risk gate<br/>signs or refuses"]
venue["venue<br/>one order, exits attached"]
record[("the record<br/>every step, every refusal")]
arena["tra arena<br/>the same rule replayed<br/>net of costs, beside a null"]
market --> decision --> guard --> cost --> risk --> venue
decision -.-> record
guard -.-> record
risk -.-> record
market --> arena
A rule is asked the same way by tra run and by tra arena: the closed bars before the decision,
cut back to the last unbroken run. So the rule you replay is the rule you run, line for line. The
package ships no rule of its own; examples/strategies/momentum_long.py is an example, and a test
fails the build if a decision core appears inside the package.
The typed judge is kept to the job it is built for, and the system carries what its vendor lists as its weak points: recent headlines are chosen by when the system first saw them, so the judge never compares dates; each choice is asked in two orders, so a first-option bias shows as disagreement and the answer is dropped; one headline and its publisher go in each request and nothing else; and the weight of an event and its comparison with your threshold are arithmetic, done by the system.
What we measured, and what it changed
The design changed after we measured our own first version. Each study is in the repository's research notes with its script, so it can be run again.
| Question | What we found | What changed |
|---|---|---|
| How much forecasting skill does a round trip of 15 bps demand? | At a four-hour hold, a forecast's correlation with the next move has to be 0.12 to 0.20 just to break even on BTC, ETH and SOL; at a daily hold, 0.04 to 0.06 | the example desk decides once a day and holds up to six days |
| Is there information in the last move at short horizons? | Indistinguishable from zero at 1 to 12 hours on all three, even with maker fees | shorter horizons stay available as experiments, measured in the arena |
| Are the simulated price paths an edge? | Calibrated on average (within 1.5 points over 16,458 readings), and no better than chance at telling one moment from another | the paths are a risk reading, not a gate ([targets].min_path_ev_bps is off unless declared) |
| Does a fixed rule separate from chance at any horizon? | Only at the daily horizon, for a long-only momentum rule fixed before the run, on five years of hourly data | the rule desk (tra init --profile rule) is the starting point; models are measured against it |
These are replays, partly on the period the horizon was chosen on, three instruments and one cost model. They are reasons for the design, not a promise about the future. Replay them on your data:
for coin in BTCUSDT ETHUSDT SOLUSDT; do tra data klines $coin 2021-01-01 --to 2026-10-31; done
tra arena --tape klines --venue binanceusdm --channel bybit/taker-taker \
--instruments BTCUSDT,ETHUSDT,SOLUSDT --from 2022-01-01 --to 2026-10-31 --interval 1d --context-interval 7d --hold-bars 6 \
--rows buy_hold,momentum_long,random --spread-bps 2 --slippage-bps 2
Get started
A few minutes. The rule desk needs no model key.
1. Install. You need Python 3.11 or newer. uv is the quickest way:
uv tool install 'bitra[ccxt,openai,anthropic,google,data]'
That brings every model provider and every exchange in. Without uv, run
pip install 'bitra[ccxt,openai,anthropic,google,data]' inside a virtual
environment. To move to the newest release later:
uv tool upgrade bitra # or: pip install -U 'bitra[ccxt,openai,anthropic,google,data]'
tra --version
That is the release, and master is the stable branch that holds it. develop, the default
branch on GitHub, is where the next one is built and changes often; the rule desk and the
event guard below are on develop and not yet in a release (more).
2. Make a desk. A desk is a folder holding your settings and everything it decides.
tra init my-desk --profile rule # the example daily rule, no model
tra init my-desk --profile autonomous --agent groq # a language model as the decision, an experiment
cd my-desk
--agent |
Key in .env |
Model, when you name none |
|---|---|---|
groq |
GROQ_API_KEY (free tier) |
openai/gpt-oss-120b |
google |
GEMINI_API_KEY |
gemini-flash-latest |
anthropic |
ANTHROPIC_API_KEY |
claude-opus-5-5 |
openai, deepseek, xai, openrouter, ... |
see Models and providers | name one with --model; tra models <provider> lists them |
Add --venue okx (or any ccxt id) to trade somewhere other than Bybit.
3. Declare what you measured, or add your key. A rule desk refuses to load until
[strategy].edge_bps holds the rule's mean net per trade from your own tra arena run. An agent
desk needs its model key: cp .env.example .env, then set it. Every command reads the .env next to
strategy.toml on its own.
4. Check. tra check reads every setting against the others and names the one thing to fix
next. A desk that is ready ends with ready to run tra run``.
5. Run. tra run decides once on live market data, in the sandbox: nothing leaves your
machine. tra run --every 1d keeps deciding, once a day at the daily close. Or type tra on its
own for the console, which takes the same commands.
6. When you want real orders. Start on the exchange's demo or testnet API. Make the desk for that exchange from the start, and the rest is three commands:
tra init my-desk --profile rule --venue bitget
cd my-desk # put the exchange's keys in .env
tra keys --probe --prepare # reads the account; on a demo or testnet sets one-way mode
tra mandate --sign "Your Name" --venue-mode
tra check
--venue writes what that exchange needs into [execution]: its demo or testnet API, 3x isolated
leverage, at most 200 per order, and how its stop and take profit are placed. Change any of it.
How to make the key on each exchange is in
Exchange accounts and keys, and
Toward real orders has the whole path.
What a rule desk does before you change anything
| Default | Where to change it | |
|---|---|---|
| Orders | none: the sandbox writes each decision down and sends nothing | [execution].mode |
| What it trades | BTCUSDT on Bybit, as a taker | [run].instrument, [universe], --venue |
| Decision | strategies/momentum_long.py, once a day at 00:00 UTC |
[strategy], [run].bar_interval_s |
| Claimed edge | none until you declare it from your arena run | [strategy].edge_bps |
| Stop and target | the rule names them; a stop wider than 12% refuses the trade | [exit].max_stop_frac |
| Time limit | a position closes after six daily bars | [exit].timeout_bars |
| Risk per trade | 0.5% of equity lost at the stop, whatever the stop's distance | [controls].max_risk_per_trade_bps |
| Bad days | no new entry after a 3% loss on the day or a 10% fall from the peak | [controls] |
| Event guard | off; once declared, paper records what it would hold and holds nothing |
[event_guard], [judge] in data.toml |
| Oversight | the risk gate on every new order | [controls] |
An agent desk (--profile autonomous) decides on 15-minute bars by default, reads 1h and 4h as
context, lets the analyst name its stop between 0.2% and 3%, and closes a position after four hours;
its defaults are in The cycle.
Working on the code itself? See Development.
The console
Run tra inside your desk and it opens the console: what is ready, what isn't, and the next
command to run. Under it is a prompt that takes every command and draws it right there. Arrow keys
go back through what you typed, tab completes, help lists the commands and exit leaves. For
scripts and cron, tra -c "run --now" runs one command and exits, and --plain or --json gives
text or machine-readable output instead of panels.

How one cycle decides
flowchart TD
snap["snapshot<br/>every value with its source and age"] --> wake{"trigger, when declared<br/>has anything moved?"}
wake -- "no" --> held["held: one data pull, nothing asked"]
wake -- "yes" --> who{"the decision"}
who -- "rule desk" --> rule["your rule<br/>closed bars in, one idea or none"]
who -- "agent desk" --> lead["structure lead, with its team<br/>a direction, a setup, levels, cited figures"]
rule --> guard{"event guard, when declared<br/>an adverse event about this asset?"}
guard -- "hold mode, yes" --> refused["a refusal that names its figure"]
guard -- "no, or paper" --> price
lead --> price["the round trip priced<br/>fee, spread, impact, funding, slippage"]
price --> exits["the stop and the target<br/>inside your [exit] bounds"]
exits --> gates{"the gates you declared<br/>cost, targets, desk exposure"}
gates -- "no" --> refused
gates -- "yes" --> riskgate{"risk gate<br/>loss at the stop, caps, switches"}
riskgate -- "no" --> refused
riskgate -- "signed" --> intent["the intent, written before anything is sent"]
intent --> venue["venue mode only<br/>one order, the stop and take profit attached"]
A rule desk asks no model: the rule, the event guard when you declare one, and then the same steps every desk runs. An agent desk adds the structure lead and, when you declare them, its team and its reviewers; each of those is an experiment until the arena or the forward record shows it doing better than the rule alone.
On an agent desk, who does what:
| Role | Reads | Answers | Can never |
|---|---|---|---|
| structure lead | candles, spread, funding, book imbalance, open interest change, and the regime on its timeframe and the higher ones you declare | a direction, a setup from a fixed list, a confidence, a horizon, and where its stop and target sit | size the trade, place a level outside your [exit] bounds, run a trend setup in a range, or fade a market that is not a measured range |
| blind confirmer (optional) | the structure lead's own brief, blind to its answer, ideally on another model family | the same schema, independently | trade alone: the two reads must name the same side, and the lower confidence counts |
| flow specialist (optional) | the book, the spread, funding and open interest, which then leave the analyst's brief | a side and a confidence, with the figures it rests on | name a level or a size; it is one voice in conviction |
| macro, on-chain and sentiment readings (the system, not agents) | dated rates and levels, chain and derivatives figures, scores and notes you curate | a declared state and a graded score: each series against the lines you drew | ask a model, or propose a direction |
| reviewers: pro and contra | the proposal and the figures behind it, each without the other's case | the strongest case for or against, as cited claims | see the other side's case, or cite a figure it wasn't given |
reviewer: neutral, as judge (Jev when [judge] is declared) |
the same, and both cases once the system has checked every claim | support, oppose or abstain, the one verdict that counts; from the typed judge, a probability for each | see the advocates' verdicts, or count claims instead of weighing them |
| technology and quant auditors | the cycles this desk recorded | findings and proposed changes | change anything |
The macro, on-chain and sentiment readings are the system's arithmetic over dated series you declare under
sources/, and ask no model: until 0.11 each was an analyst whose model labelled the same figures,
no decision ever rested on that label, and the calls were retired. Each series
is either a file you keep or a feed the desk refreshes itself (FRED, the Crypto Fear & Greed Index,
or any paid vendor that answers JSON over https). tra sources show lists every series with where it
came from and how old its last value is, and a value older than its max_age is shown as stale and
never counted. Data sources has the details.
Which reviewers run is yours to declare. A vote never decides on its own: it moves conviction by
the weight you give it ([conviction].reviewer_weight), and a stance counts for what it says beyond
its assignment, since a pro that supports is expected to.
Voices are allowed to disagree. Each reading becomes a score between -1 and 1, computed from its own figures against the lines you drew, so a macro reading barely past its line counts as a small voice and one far past it counts as a big one. Conviction adds them up: agreement grows the size, opposition shrinks it in proportion, and only opposition that outweighs the case stops the trade. A short at 0.70 confidence against a barely bullish macro and sentiment scores 0.56 and trades at half size; against a strongly bullish context it scores 0 and doesn't trade.
The structure lead knows what kind of market it is working in before it decides. The system measures
the regime on its timeframe (trending up, trending down, ranging or mixed) and on the higher
timeframes you list in [run].context_intervals, and it hands over what your macro thresholds say
this cycle as well. A setup that doesn't fit the regime, such as a trend trade in a sideways
market, is refused by name; [regime] holds the lines.
Everything after the models answer is arithmetic over numbers you declared. No model can place, cancel or resize an order, read a file outside the project, or edit your configuration. Agents has the full table of what an agent can reach, and The cycle walks through every step.
TRA MCP questions
How do I add TRA MCP to Claude Code?
Run claude mcp add bitra -- uvx bitra in your terminal. Add --scope user to make it available in every project.
How do I add TRA MCP to Cursor?
Open ~/.cursor/mcp.json and add the server under mcpServers, using the Cursor config shown in the install section above.
How do I install TRA?
Install it with uv or pip, requiring Python 3.11 or newer, using the bitra package with the ccxt, openai, anthropic, google, and data extras.
Can the language model calculate numbers or place orders in TRA?
No. Models only propose a direction and levels; the system computes every figure, applies limits, sizes the trade, and sends the order.
Which exchanges can TRA reach?
TRA uses one order path to every exchange that ccxt supports, having been run end to end on six of them.
How does TRA backtest a trading rule?
The arena replays a rule over years of recorded market data, net of your own costs, compared against buy-and-hold, momentum, its own fade and a seeded random null.
What happens if an order gets no response?
An order without an answer is treated as unknown and read back by its client order id; it is never sent twice.