# TradingAgents is a role-play harness whose real work is the data contract

> TradingAgents assigns fundamental, sentiment, news and technical analysts to argue with a bullish and bearish researcher pair before a trader agent commits to a position. The interesting engineering is not the debate, it is the repeated point-in-time data work that keeps a backtest from reading the future.

**TauricResearch/TradingAgents** — TradingAgents coordinates specialized language-model agents for market research, debate, risk review, and simulated trading decisions.

- Repository: https://github.com/TauricResearch/TradingAgents
- Website: https://arxiv.org/pdf/2412.20138
- Stars: 108,599 · Forks: 20,810
- Language: Python
- License: Apache-2.0
- Published: 2026-08-08 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/tauricresearch-tradingagents

## Analysts run at the same time, and the debate waits for the slowest one

The framework splits research across four analyst roles. The Fundamentals Analyst evaluates company financials and performance metrics to identify intrinsic value and red flags. The Sentiment Analyst aggregates news headlines, StockTwits and Reddit chatter into a single read on short-term mood. The News Analyst monitors global news and macroeconomic indicators. The Technical Analyst works from indicators such as MACD and RSI to detect patterns and forecast price movement.

What happens between those four and the decision is a gate, and it is the part that shapes both latency and failure behaviour. The selected analysts work at the same time, each on its own tools, and the research debate starts once all of their reports are in. A bullish and bearish researcher pair then assesses the analyst output against each other, and only after that does a trader agent compose the reports into a position, deciding timing and magnitude.

The consequence is that the slowest analyst sets the wall-clock cost of every run, and an analyst that fails outright holds up the debate rather than being skipped. Parallel execution, which arrived in v0.5.2, fixed the serial part of that cost and did nothing for the dependency between an analyst's failure and the run's completion.

## Point-in-time integrity is the fix this project keeps making

Read the release history and one theme dominates. v0.5.0 brought point-in-time integrity across every dated path, with SEC EDGAR fundamentals served as filed and backtesting that sees only data published by each analysis date. v0.4.0 carried look-ahead fixes across FRED macro series, social sentiment and the decision-log memory. v0.3.1 added Alpha Vantage look-ahead filtering. v0.5.2 extended the guarantee to backtests over a ticker and date grid.

That is four consecutive releases spent on the same class of defect, and the reason is structural rather than careless. A market framework has to answer a question with a date attached: what did someone reading this data know on this day? Fundamentals get restated, macro series get revised, and a news or sentiment source is replaced by the time you backtest across it. Without an as-of boundary, a backtest is measuring the present and calling it the past.

The practical consequence for anyone extending the framework is that any new data path you add is a new place to leak the future. The project's own answer has been to keep patching paths one at a time, which is a fair signal that a general guarantee has not been reached.

## v0.5.1 moved every import path inside the package

The v0.5.1 release reorganised the package layout around what each module holds, and the release note is explicit that import paths moved as a result. That is a breaking change for anyone who wrote code against the module tree, and it is the kind that does not surface as an import error at install time but as a traceback the first time your own module is loaded.

The same release changed which models answer by default, moving to GPT-6 Sol and Luna, and added optional Jev screening of social posts. Both changes land in the same upgrade, which is the awkward combination: a refactor that moves your imports and a default that changes your output. Neither is visible in a diff of your own code.

For a user, the consequence is that the safe path is to treat a version boundary as a migration rather than an upgrade. Read CHANGELOG.md, expect to fix imports, and pin the model explicitly if the default matters to you, because a default that shifts between releases makes two runs of the same question hard to compare unless the report says which model produced it.

## The image runs as appuser and persists nothing without a volume

The Dockerfile is a two-stage build on `python:3.13-slim` that installs into a virtualenv at `/opt/venv`, creates a user called `appuser`, and switches to it before the entrypoint runs. `WORKDIR` is `/home/appuser/app` and `ENTRYPOINT` is the `tradingagents` console script, so the container's whole job is to be the CLI. The state directory `/home/appuser/.tradingagents` is created and handed to `appuser` explicitly, which tells you the project expects something to live there.

That expectation is satisfied by compose, not by the image:

```yaml
  tradingagents:
    build: .
    env_file:
      - .env
    volumes:
      - ${TRADINGAGENTS_DATA_DIR:-tradingagents_data}:/home/appuser/.tradingagents
    tty: true
    stdin_open: true
```

The consequence is a container that is stateless unless you wire that mount, and unconfigured unless you supply a `.env`, which the repository ships as `.env.example` and `.env.enterprise.example`. Note also that `tty: true` and `stdin_open: true` are set because v0.5.2 added a non-interactive path, so the same service covers both the prompt-driven session and the flag-driven run.

## Ollama sits behind a compose profile instead of in the default service list

Local models are wired up, and the wiring is opt-in. The compose file defines an `ollama` service on the `ollama/ollama:latest` image and a second service that points the framework at it, and both carry `profiles` entries, so neither starts under a plain compose up.

```yaml
  tradingagents-ollama:
    build: .
    env_file:
      - .env
    environment:
      - TRADINGAGENTS_LLM_PROVIDER=ollama
      - OLLAMA_BASE_URL=http://ollama:11434/v1
    depends_on:
      - ollama
    profiles:
      - ollama
```

The mechanism is a `TRADINGAGENTS_LLM_PROVIDER` variable rather than a code branch, and remote Ollama support arrived back in v0.2.5 alongside `TRADINGAGENTS_*` configurability and API-key auto-detection. The consequence for a user is that the local-model path is invisible until you name the profile, and that `OLLAMA_BASE_URL` ending in `/v1` is the shape the framework expects, pointing at an OpenAI-compatible surface rather than Ollama's native API. A container pointed at the wrong base URL will not resolve a model, and the error will read as a model problem rather than a routing one.

## The default pytest run excludes integration tests by marker

`pyproject.toml` configures the suite so that integration tests do not run unless you ask for them, and defines the vocabulary that makes that possible:

```toml
[tool.pytest.ini_options]
testpaths = ["tests"]
markers = [
    "unit: fast isolated unit tests",
    "integration: tests requiring external services; run only when asked for, with -m integration",
    "smoke: quick sanity-check tests",
]
```

The addopts string carries the filter, and `--strict-markers` means an undeclared marker is an error rather than a typo. This is a sensible default for a project whose integration tests need live vendors and paid model endpoints.

The consequence is that a green default run is a statement about the pure logic and nothing about the data access contract, which is precisely the part the release history keeps changing. To exercise the paths that touch SEC EDGAR, FRED or a provider, you have to name the marker and supply the services yourself, and a failure there will look like a network or credential problem rather than a test failure. Linting is configured separately, with ruff at a line length of 100 targeting py311 and excluding `results`.

## The framework states that results move with the backbone model you pick

The project is direct about its own limits. It says the framework is designed for research purposes, that trading performance may vary based on many factors including the chosen backbone language models, model temperature, trading periods, the quality of data, and other non-deterministic factors, and that it is not intended as financial, investment, or trading advice.

Read that list as an engineering constraint rather than a disclaimer, because each item is something you set. Backbone model, temperature and trading period are all caller choices, which means the same question asked twice is not the same experiment unless those values are held. The `TRADINGAGENTS_*` environment configuration and the provider registry, which grew in v0.3.0 to cover NVIDIA, Kimi, Groq, Mistral, Bedrock and any OpenAI-compatible endpoint, widen that choice rather than narrowing it.

This is why v0.5.2 starting to record a run's settings in every report matters more than it sounds. Without a recorded backbone, temperature and period, two reports cannot be compared, and a comparison is the only output of a research harness that anybody can act on.

## Conclusion

TradingAgents earns a place in a research workflow where the question is how an LLM reads a market, not whether it should be trusted with one, and the point-in-time data contract is a genuine reason to look at it. It is the wrong tool for unattended capital, since the framework itself states that outcomes shift with the backbone model, temperature, trading period and data quality. Before adopting it, run one ticker through `--ticker` and `--date` and read the settings block the report carries, because that record is what tells you whether two runs are comparable at all.

## FAQ

### How do I install TradingAgents?

The distribution is named tradingagents and requires Python 3.11 or newer, with dependencies declared in pyproject.toml while requirements.txt reduces to a single dot. A console script named tradingagents is registered from cli.main:app. A Dockerfile and docker-compose.yml provide a container route that reads configuration from a .env file, and optional extras cover dev tooling and Amazon Bedrock support.

### How do I use TradingAgents?

You select analysts, they each work on their own tools at the same time, a bullish and bearish researcher pair debates the combined reports, and a trader agent composes that into a position. Since v0.5.2 the CLI can run without any prompts, taking flags such as --ticker and --date, and it records the run's settings in the report it produces.

### What is TradingAgents compared with?

The project does not document a comparison against another framework. What it sets out is its own decomposition into four analyst roles, a bullish and bearish researcher pair, a trader agent and a risk management team, together with a point-in-time data contract across every dated path. A separate Trading-R1 technical report and a Trading-R1 Terminal repository sit alongside it.

### What is an alternative to TradingAgents?

No alternative is named in the repository. The nearest thing to a substitution point is the model and data layer: the provider registry covers NVIDIA, Kimi, Groq, Mistral, Bedrock and any OpenAI-compatible endpoint, with FRED and Polymarket added as data vendors, so what is swappable is the model access and the data sources rather than the agent structure itself.

## Sources

- [Official documentation](https://arxiv.org/pdf/2412.20138)
- [Official README](https://github.com/TauricResearch/TradingAgents#readme)
- [Project repository](https://github.com/TauricResearch/TradingAgents)
- [Release notes](https://github.com/TauricResearch/TradingAgents/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/tauricresearch-tradingagents
