BijectiveLabs/trading-research-agents
Open-source Python CLI (`tra`) for autonomous trading desks in which LLM analysts (technical, macro, on-chain, sentiment) and validators only give opinions on figures the system computed. Fixed rules do the arithmetic: pricing the round-trip cost, applying risk limits, sizing, cost gates, and sending a single order with stop attached via ccxt (Bybit and OKX demo accounts tested). It supports multiple model providers with per-role models, effort settings and fallbacks. Every answer is parsed against a closed schema, every refusal is logged with the figure behind it, and models can tighten but never loosen controls. This makes it a concrete reference for keeping LLM agents away from arithmetic and money.
What it claims
tra runs an autonomous trading cycle where LLMs only label and argue over figures that deterministic code has already computed. The code does the screening inputs, cost pricing, exit checks, sizing, risk and the final order. The release README states four guarantees, enforced by the system and by tests:
- No model touches an order or a key.
- A model can tighten a limit, step the ladder down or arm the kill switch, but never widen, promote or disarm.
- One decision produces at most one order, and nothing is retried around real capital.
- Stale or missing data is refused, never read as zero.
It trades linear USDT/USDC-margined perpetuals only. Venue mode refuses any other market type on every order.
How it works
The cycle has several refusal points. Each refusal names the figure that caused it.
flowchart TD
T{"anything moved?"} -- no --> H["held, no tokens"]
T -- yes --> S["screener picks"]
S --> A["4 analysts in parallel"]
A --> P["system prices round trip"]
P --> E{"breaks even at<br/>half winning?"}
E -- no --> R["refusal naming figure"]
E -- yes --> V["validators"]
V --> C{"confluence with<br/>declared states?"}
C -- no --> R
C -- yes --> Z["conviction sizes<br/>risk at stop"]
Z --> G{"edge clears cost<br/>by margin?"}
G -- no --> R
G -- yes --> O["intent; venue mode:<br/>one order + stop/TP"]Details the summary omits:
- Wake trigger. It skips the LLMs entirely when nothing has moved. That costs one data pull and no tokens.
- Round-trip cost. It includes fee, spread, impact, funding and slippage. The fee comes from your account, or from the venue's standard tier (labelled as such) until the account reports it.
- Exit check. The analyst names the stop and target, held inside your bounds. A trade is refused if more than half of trades like it would need to win just to break even.
- Validators. A validator claim that cites no figure is discarded. A vote never decides alone; it shifts conviction by
[conviction].validator_weight. - Conviction. Each analyst's view becomes a score in [-1, 1], computed from its distance past your declared thresholds. Opposition shrinks size proportionally and only stops the trade when it outweighs the case. In the README's example, a 0.70-confidence short against a barely bullish context scores 0.56 and trades at half size. Against a strongly bullish context it scores 0 and does not trade.
- Regime. The system measures the regime (trending up, trending down, ranging, mixed) on the trading timeframe and on
[run].context_intervals. A setup that doesn't fit the regime is refused by name. - Order safety. Orders go only to the declared environment. An open position or working order blocks a second entry. Sizes off the venue's step are refused, not rounded. A clock more than 1 s off the venue's refuses before signing. Ctrl-C cancels a resting order.
The README's logged example shows the targets gate catching what the cost gate did not:
- The trade claimed a 25.0 bps edge against a 12.87 bps round trip, of which 2.00 bps was estimated.
- That cleared the cost gate.
- The desk required an edge of 2.0× cost and the trade had 1.94×, so it was refused.
How to use it
Python ≥3.11. The README gives this quickstart:
uv tool install 'trading-research-agents[ccxt,openai,anthropic,google,data]'
tra init my-desk --profile autonomous --agent groq
cd my-desk
cp .env.example .env # then set GROQ_API_KEY=... in .env
tra check
tra run # one decision, sandbox, nothing sent
tra run --every 15mBybit is the default venue; add --venue okx (or any ccxt id) to tra init. To add a venue:
tra venues okx --setupTo move to real orders, start on the practice account:
- Put the exchange keys in
.env. - Read and sign the mandate with
tra mandate --sign "Your Name". Signing alone enables nothing. - Set the execution block in
strategy.toml:
[execution]
mode = "venue"
environment = "demo" # demo | testnet | mainnet
leverage = 3
max_notional = 400
margin_mode = "isolated" # isolated | cross
hold_limit = "timeout"The model is configured per role, with effort and a fallback list. Fallbacks are tried in order on rate limits or outages, with the same brief. A custom provider is about 30 lines.
Other useful tools:
tra keys --probechecks each key without sending a prompt.tra watch --every 5sis a read-only view that holds no key and takes no lock.- Every model call is logged to
usage.jsonlwith tokens and latency. - Exit codes: 0 means cleared, 1 means a gate refused, 2 is a usage error.
--jsonand--plainare available.
For scripted (non-agent) strategies there is a separate research path: tra data get, tra backtest, tra paper --minutes 30 and tra live, a capped canary. The README publishes the example core's one-day replay as net −294.19 bps after costs, deliberately unflattering.
The licence is MIT.
Limits
- Maturity. This is an early release and settings will change between versions. The repository went public in October 2026, with history from 12 September 2026. Use PyPI releases, not
develop. - Testing. End-to-end runs with real orders have only been done on the Bybit and OKX practice accounts. Mainnet (step 3) "has not been run by us". Other ccxt venues share the same code path but are untested.
- Unattended positions. Position checks run only at the start of each
--everypass. With no desk running, an open position has only its venue-side stop and take-profit. Run it under systemd or tmux, because closing the console stops it. - Spend. Nothing caps model spend unless you declare a ceiling.
- Post-only orders. If you point
[run].venue_keyat a maker-taker channel, entries rest as post-only orders. They fill less often but the fee is lower. - Not built yet: spot, inverse, dated futures and options; non-ccxt venues; multiple accounts; routing or execution algorithms; portfolio accounting.
- No edge supplied. The example strategy cores are examples only; any edge is yours to declare.
Organisations named here
- Bijective Labs
- Bybit
- OKX
- Groq
- OpenAI
- Anthropic
Technologies named here
- gpt-oss-120b
- trading-research-agents
- ccxt
- Gemini Flash
- uv
- Claude Opus 5.5
- pip
- Groq
- OpenAI, Anthropic and Google providers
- FRED
- Crypto Fear & Greed Index
- Bybit
- OKX
- ruff, mypy, pytest
- systemd, tmux
- PyPI
- OpenAI API
- Python
Techniques named here
- Deterministic execution with LLM proposals
- Conviction weighting
- Validator figure-citation rule
- Closed-schema parsing of model answers
- Provider fallback and per-role models
- Cost and edge gating
- Regime-aware technical analysis
- Trigger-based holding
Related in agents



