Run TradingAgents on a custom OpenAI-compatible backend.
Updated 2026-07-16
TradingAgents ships with an openai_compatible provider mode. Set backend_url to https://api.apisrouter.com/v1, export one key, and both the deep-think and quick-think agents route through a single endpoint with every catalog model addressable by id.
Quick answer: three settings route TradingAgents anywhere.
TradingAgents supports custom endpoints natively. Set llm_provider to "openai_compatible", set backend_url to your endpoint address, and export OPENAI_COMPATIBLE_API_KEY with a key for that endpoint. With APIsRouter the backend URL is https://api.apisrouter.com/v1, and every model in the catalog becomes addressable from the deep_think_llm and quick_think_llm slots by its exact model id. This is a documented configuration path in the upstream repo, not a fork or a patch. The same values can also be supplied as environment variables (TRADINGAGENTS_LLM_PROVIDER, TRADINGAGENTS_LLM_BACKEND_URL, TRADINGAGENTS_DEEP_THINK_LLM, TRADINGAGENTS_QUICK_THINK_LLM), so a scheduled job or CI runner can switch backends without touching Python code.
config["llm_provider"] = "openai_compatible"
config["backend_url"] = "https://api.apisrouter.com/v1"
# auth: export OPENAI_COMPATIBLE_API_KEY=sk-...How TradingAgents talks to its LLM backend.
TradingAgents (TauricResearch on GitHub, 93K+ stars) is a multi-agent trading framework. One analysis run fans out across an analyst team covering fundamentals, sentiment, news, and technicals, then a bull researcher and a bear researcher argue the case over one or more debate rounds, a trader agent proposes the position, and a risk-management layer reviews it before the final decision. The framework splits that work across two model slots. deep_think_llm handles the reasoning-heavy steps: the research debate, the trader decision, and risk review. quick_think_llm handles the high-volume steps: reading data, summarizing news, and drafting analyst reports. Both slots issue standard /v1/chat/completions requests. The provider setting only decides which client and host those requests go to, and openai_compatible sends them to whatever backend_url you configure. Natively, TradingAgents also supports OpenAI, Anthropic, Google, and DeepSeek as first-party providers, but each one needs its own account, its own key, and one provider per run. The openai_compatible mode collapses that: TradingAgents passes the model field through as a plain string, so when the endpoint behind backend_url serves multiple vendors, a Claude deep-think slot and a GPT or DeepSeek quick-think slot can run in the same analysis. That per-role mixing is the practical reason to route the framework through a gateway rather than a single vendor endpoint.
Full setup: Python config or environment variables.
The programmatic path copies DEFAULT_CONFIG and overrides four keys. The key that authenticates against the custom endpoint is read from OPENAI_COMPATIBLE_API_KEY, so it never needs to appear in the config dict or the source file. The environment-variable path sets the same values through the _ENV_OVERRIDES mapping in default_config.py and works for both the Python API and the interactive CLI (tradingagents, or python -m cli.main). Note that backend_url defaults to None, in which case each provider's client falls back to its own default endpoint; the override only takes effect once you set it explicitly. Market data is a separate concern. TradingAgents pulls quotes and fundamentals through its data vendors (for example ALPHA_VANTAGE_API_KEY), and those credentials are unrelated to the LLM endpoint. Changing backend_url does not touch the data pipeline.
from tradingagents.graph.trading_graph import TradingAgentsGraph
from tradingagents.default_config import DEFAULT_CONFIG
config = DEFAULT_CONFIG.copy()
config["llm_provider"] = "openai_compatible"
config["backend_url"] = "https://api.apisrouter.com/v1"
config["deep_think_llm"] = "claude-opus-4-7" # debate rounds + trade decision
config["quick_think_llm"] = "claude-sonnet-4-6" # analysts, summaries
config["max_debate_rounds"] = 2
ta = TradingAgentsGraph(debug=True, config=config)
_, decision = ta.propagate("NVDA", "2026-07-15")
print(decision)Choosing deep-think and quick-think models.
The upstream default pairs a frontier model in the deep slot with a mini model in the quick slot, which is the right shape: spend reasoning capacity where the decision is made, and volume capacity where the reading is done. Routing through one endpoint makes the pairing a two-line change between runs, so the practical workflow is to hold the deep slot fixed and A/B the quick slot against your backtest metrics rather than guessing.
- deep_think_llm carries the bull/bear debate, the trader decision, and risk review. Few calls per run, but each one reasons over the full analyst context, and max_debate_rounds multiplies them. This is where a frontier reasoning model (claude-opus-4-7, gpt-5.5) earns its tokens.
- quick_think_llm fires on every analyst step: reading fundamentals, scoring sentiment, summarizing news, drafting reports. Most of a run's request volume lands here, so a fast mid-tier model (claude-sonnet-4-6, deepseek-v4-pro) keeps runs quick without degrading the debate inputs.
- Long-context loads, like feeding full filings or large news windows into the analysts, are where gemini-3.1-pro-preview is worth testing in the quick slot.
- Backtests amplify everything. A sweep over 50 tickers and 20 dates is 1,000 propagate() calls, so a quick-think model choice that looks marginal on one run dominates the token bill at sweep scale.
Pay-as-you-go · transparent per-model pricing
Selected models are priced below official list prices. Exact input, output, cache, and per-request prices are shown for each model.
| Model | Official Price | Our Price |
|---|---|---|
| Claude Opus 4.7 | $5.00 / $25.00 per M | $4.00 / $20.00 per M |
| Claude Sonnet 4.6 | $3.00 / $15.00 per M | $2.40 / $12.00 per M |
| GPT-5.5 | $5.00 / $30.00 per M | $4.00 / $24.00 per M |
| Gemini 3.1 Pro Preview | $2.00 / $12.00 per M | $1.60 / $9.60 per M |
| DeepSeek V4 Pro | $0.43 / $0.87 per M | $0.39 / $0.78 per M |
Backtesting at sweep scale: keys, pinning, and limits.
Once the single-run setup works, the failure surface moves to the sweep. Three habits keep a multi-day backtest reproducible and debuggable. Pin exact model ids. Bare model names on some vendors are rolling pointers that silently move to newer snapshots, which means a backtest started on Monday and finished on Friday may not have run one model. Where the catalog lists a dated variant, put the dated id in the config, and record the config dict next to the results the way you would record a random seed. Use one key per experiment. Keys are free to create, and scoping a key to a sweep turns the usage log into the experiment's cost ledger: token counts and spend per model, filterable to exactly the runs in that sweep. When two experiments share a key, attributing spend afterwards means grepping timestamps. Know your concurrency ceiling before parallelizing. propagate() is synchronous per ticker-date, so sweeps usually shard across processes. Each shard multiplies request rate on the quick-think slot first, and a 429 mid-debate costs a whole run, not one request. Ramp shard count while watching the console rather than launching fifty workers cold; pooled upstream channels raise the ceiling but do not make it infinite.
Who routes TradingAgents through a gateway.
- Backtesters running ticker-by-date sweeps. Hundreds of propagate() calls per experiment make per-key usage visibility and a single billing surface more useful than four vendor dashboards.
- Researchers comparing model pairs. Swapping deep_think_llm between Claude, GPT, and DeepSeek ids is a config edit against one endpoint, not a new vendor account per candidate.
- Teams mixing vendors per role. Claude for the debate, DeepSeek for analyst volume. Native provider mode locks a run to one vendor; a multi-vendor endpoint does not.
- Developers without access to a given vendor's billing. Top-up based access with no card requirement removes the sign-up dependency per provider.
- Scheduled and CI runs. The env-only setup means the runner image needs one secret (OPENAI_COMPATIBLE_API_KEY) instead of one per provider.
Verify the endpoint and debug the first run.
Before running a full analysis, confirm the endpoint answers with the models you plan to use. A one-line curl against /v1/models with your key lists every addressable id; the strings in deep_think_llm and quick_think_llm must match those ids exactly. The failure modes on a first run are consistent. A 401 almost always means OPENAI_COMPATIBLE_API_KEY was exported in a different shell than the one running tradingagents, or not exported at all; env vars set in .bashrc do not reach a systemd unit or a cron job unless the unit file exports them itself. A model-not-found error means the id string does not match the catalog: ids are exact, including version suffixes, and the /v1/models output above is the source of truth. A connection error with backend_url set usually means the URL is missing its /v1 suffix, since the client appends route paths like /chat/completions to whatever base you give it. If the run works but appears to stall in the debate phase, that is normal latency for reasoning models over long contexts rather than an endpoint problem; keep debug=True on to watch agent steps stream. Genuine timeouts on very long deep-think turns are a client-side setting, and worth raising before concluding the backend dropped the request. Once requests flow, the APIsRouter console shows per-request model, token counts, and spend, which for a framework this call-heavy is the fastest way to see exactly where a run's tokens go.
curl -s https://api.apisrouter.com/v1/models \
-H "Authorization: Bearer $OPENAI_COMPATIBLE_API_KEY" | head -50FAQ
Does TradingAgents support Claude and Gemini models through one openai_compatible endpoint?
Yes. In openai_compatible mode the framework sends the model field as a plain string to backend_url over /v1/chat/completions. Any id the endpoint serves works, including Claude, Gemini, and DeepSeek ids, in either the deep-think or quick-think slot.
Which API key does TradingAgents use with a custom backend_url?
OPENAI_COMPATIBLE_API_KEY. The openai_compatible provider reads it from the environment, so the key never appears in your config dict or source files. OPENAI_API_KEY is only used by the native openai provider.
Can deep_think_llm and quick_think_llm come from different vendors in the same run?
Through a multi-vendor endpoint, yes: both slots post to the same backend_url and the model string decides the vendor per request. With native providers (openai, anthropic, google, deepseek) a run is locked to one vendor for both slots.
Do I still need an OpenAI account once backend_url is set?
No. With llm_provider set to openai_compatible, no request goes to OpenAI hosts and OPENAI_API_KEY is not read. You still need the market-data credentials TradingAgents uses (for example ALPHA_VANTAGE_API_KEY), which are independent of the LLM endpoint.
Does the interactive CLI honor the custom endpoint too?
Yes. The CLI (tradingagents, or python -m cli.main) resolves the same config, and the TRADINGAGENTS_LLM_PROVIDER / TRADINGAGENTS_LLM_BACKEND_URL environment variables override it before the provider prompt, so scheduled or containerized CLI runs need no interactive input for routing.
How many tokens does one TradingAgents analysis consume?
It varies with max_debate_rounds, the number of analysts, and how much market context they ingest; a single ticker-date analysis typically lands in the hundreds of thousands of tokens, most of them on the quick-think slot. The per-key usage view in the APIsRouter console shows the exact split per run, which is more reliable than estimating.