# How to Add Custom Tools or Override Data Fetching Functions in TradingAgents

> Learn how to add custom tools or override data fetching functions in TradingAgents. Extend the library by registering new functions or updating default configurations easily.

- Repository: [Tauric Research/TradingAgents](https://github.com/TauricResearch/TradingAgents)
- Tags: how-to-guide
- Published: 2026-03-23

---

**You can extend TradingAgents by decorating new Python functions with `@tool` and registering them in `VENDOR_METHODS`, or override existing data sources by updating [`default_config.py`](https://github.com/TauricResearch/TradingAgents/blob/main/default_config.py) without touching core agent code.**

TradingAgents (TauricResearch/TradingAgents) is built on a tool-oriented architecture that lets large language models invoke reusable data-fetching functions during reasoning. Because the routing layer in [`tradingagents/dataflows/interface.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/dataflows/interface.py) is decoupled from agent implementations, you can introduce brand-new capabilities or swap vendor implementations by editing configuration files and the tool registry.

## Architecture of the Tool and Routing System

TradingAgents organizes data access into four distinct layers that keep agent logic separate from data providers.

- **Tool Definition** – Python functions decorated with `@tool` (from `langchain_core.tools`) located in `tradingagents/agents/utils/*.py` such as [`core_stock_tools.py`](https://github.com/TauricResearch/TradingAgents/blob/main/core_stock_tools.py) and [`technical_indicators_tools.py`](https://github.com/TauricResearch/TradingAgents/blob/main/technical_indicators_tools.py).
- **Routing Dispatcher** – The `route_to_vendor()` function in [`tradingagents/dataflows/interface.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/dataflows/interface.py) resolves tool names to concrete implementations using the `VENDOR_METHODS` mapping.
- **Configuration** – [`tradingagents/default_config.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/default_config.py) defines the default vendor per data category (e.g., `technical_indicators`) and optional per-tool overrides under `tool_vendors`.
- **Agent Integration** – Analyst agents in `tradingagents/agents/analysts/*.py` import tools and pass them to the LLM via `llm.bind_tools(tools)`.

When an LLM calls a tool, LangChain invokes the Python function, which forwards the request to `route_to_vendor()`. The dispatcher reads the category from `data_vendors`, looks up the implementation in `VENDOR_METHODS`, and executes the vendor-specific function. If the primary vendor raises `AlphaVantageRateLimitError`, the system automatically falls back to the next configured vendor.

## Adding a Custom Tool to TradingAgents

Creating a new tool requires three steps: defining the function, exposing it to agents, and wiring a vendor implementation.

### Define the Tool Function

Create a new file (e.g., [`tradingagents/agents/utils/custom_tools.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/agents/utils/custom_tools.py)) and decorate your function with `@tool`. Use `Annotated` type hints to provide descriptions for the LLM.

```python

# tradingagents/agents/utils/custom_tools.py

from langchain_core.tools import tool
from typing import Annotated
from tradingagents.dataflows.interface import route_to_vendor

@tool
def get_earnings_calendar(
    ticker: Annotated[str, "ticker symbol (e.g. AAPL, TSM)"],
    from_date: Annotated[str, "YYYY-mm-dd start of range"],
    to_date: Annotated[str, "YYYY-mm-dd end of range"],
) -> str:
    """
    Fetch upcoming earnings releases for *ticker* between *from_date* and *to_date*.
    """
    return route_to_vendor("get_earnings_calendar", ticker, from_date, to_date)

```

### Expose the Tool to Agents

Import your new tool in [`tradingagents/agents/utils/agent_utils.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/agents/utils/agent_utils.py) so analysts can access it.

```python

# tradingagents/agents/utils/agent_utils.py

from tradingagents.agents.utils.custom_tools import get_earnings_calendar

```

Any analyst can now add `get_earnings_calendar` to its `tools = [...]` list and call `llm.bind_tools(tools)`.

### Wire the Vendor Implementation

Add a concrete implementation (e.g., in [`tradingagents/dataflows/y_finance.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/dataflows/y_finance.py)) and register it in `VENDOR_METHODS`.

```python

# tradingagents/dataflows/y_finance.py

def get_earnings_calendar_yfinance(ticker: str, from_date: str, to_date: str) -> str:
    import yfinance as yf, pandas as pd
    tk = yf.Ticker(ticker)
    cal = tk.calendar.T
    cal.index = pd.to_datetime(cal.index).date
    mask = (cal.index >= pd.to_datetime(from_date).date()) & (cal.index <= pd.to_datetime(to_date).date())
    return cal.loc[mask].to_csv()

```

Then extend the mapping in [`tradingagents/dataflows/interface.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/dataflows/interface.py):

```python

# tradingagents/dataflows/interface.py

VENDOR_METHODS["get_earnings_calendar"] = {
    "yfinance": get_earnings_calendar_yfinance,
    # Additional vendors can be added here

}

```

## Overriding Data Fetching Behavior

You can replace existing data sources without modifying agent code by using configuration-based overrides or direct registry edits.

### Override via Configuration

To force a specific tool to use a custom vendor, add an entry to `tool_vendors` in [`default_config.py`](https://github.com/TauricResearch/TradingAgents/blob/main/default_config.py).

```python

# tradingagents/default_config.py

"tool_vendors": {
    "get_stock_data": "my_private_api",
},

```

Then register your implementation in `VENDOR_METHODS`:

```python

# tradingagents/dataflows/interface.py

VENDOR_METHODS["get_stock_data"] = {
    "my_private_api": my_private_api_get_stock_data,
    "yfinance": get_YFin_data_online,
    "alpha_vantage": get_alpha_vantage_stock,
}

```

The routing dispatcher will now attempt `my_private_api` first, falling back to `yfinance` or `alpha_vantage` if your implementation raises a rate-limit error.

### Direct Code Replacement (Experimental)

For rapid prototyping, you can replace the function reference directly in [`interface.py`](https://github.com/TauricResearch/TradingAgents/blob/main/interface.py):

```python

# tradingagents/dataflows/interface.py

VENDOR_METHODS["get_stock_data"]["yfinance"] = my_private_api_get_stock_data

```

This approach bypasses configuration files and is best reserved for temporary testing.

## End-to-End Code Examples

### Example 1: Adding an Earnings Calendar Tool

This example demonstrates the complete flow for adding a custom earnings calendar tool backed by yfinance.

```python

# tradingagents/agents/utils/custom_tools.py

from langchain_core.tools import tool
from typing import Annotated
from tradingagents.dataflows.interface import route_to_vendor

@tool
def get_earnings_calendar(
    ticker: Annotated[str, "ticker symbol (e.g. AAPL)"],
    from_date: Annotated[str, "start date YYYY-mm-dd"],
    to_date: Annotated[str, "end date YYYY-mm-dd"],
) -> str:
    """Return upcoming earnings releases for *ticker* in the given date range."""
    return route_to_vendor("get_earnings_calendar", ticker, from_date, to_date)

```

```python

# tradingagents/dataflows/y_finance.py

def get_earnings_calendar_yfinance(ticker: str, from_date: str, to_date: str) -> str:
    import yfinance as yf, pandas as pd
    tk = yf.Ticker(ticker)
    cal = tk.calendar.T
    cal.index = pd.to_datetime(cal.index).date
    mask = (cal.index >= pd.to_datetime(from_date).date()) & (cal.index <= pd.to_datetime(to_date).date())
    return cal.loc[mask].to_csv()

```

```python

# tradingagents/dataflows/interface.py

"get_earnings_calendar": {
    "yfinance": get_earnings_calendar_yfinance,
},

```

```python

# tradingagents/agents/utils/agent_utils.py

from tradingagents.agents.utils.custom_tools import get_earnings_calendar

```

When an analyst includes `get_earnings_calendar` in its tool list, the LLM can emit a call like `{"name": "get_earnings_calendar", "args": {"ticker": "AAPL", "from_date": "2024-07-01", "to_date": "2024-07-30"}}`, and the system will return a CSV string of upcoming earnings dates.

### Example 2: Overriding Stock Data with a Private API

This example shows how to route `get_stock_data` through an internal HTTP service.

```python

# tradingagents/dataflows/private_api.py

def get_stock_data_private(ticker: str, start_date: str, end_date: str) -> str:
    import requests, pandas as pd
    resp = requests.get(
        "https://private.api/ohlcv",
        params={"symbol": ticker, "start": start_date, "end": end_date},
    )
    df = pd.DataFrame(resp.json())
    return df.to_csv()

```

```python

# tradingagents/dataflows/interface.py

VENDOR_METHODS["get_stock_data"] = {
    "private_api": get_stock_data_private,
    "yfinance": get_YFin_data_online,
    "alpha_vantage": get_alpha_vantage_stock,
}

```

```python

# tradingagents/default_config.py

"tool_vendors": {
    "get_stock_data": "private_api",
},

```

All agents calling `get_stock_data` will now hit your private service first, with graceful fallback to public vendors if the private call raises an exception.

## Key Files for Customization

| Path | Role |
|------|------|
| [`tradingagents/agents/utils/core_stock_tools.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/agents/utils/core_stock_tools.py) | Core stock-price tool (`get_stock_data`) |
| [`tradingagents/agents/utils/technical_indicators_tools.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/agents/utils/technical_indicators_tools.py) | Technical-indicator tool (`get_indicators`) |
| [`tradingagents/agents/utils/fundamental_data_tools.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/agents/utils/fundamental_data_tools.py) | Fundamental-data suite (`get_fundamentals`) |
| [`tradingagents/agents/utils/news_data_tools.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/agents/utils/news_data_tools.py) | News-related tools (`get_news`, `get_global_news`) |
| [`tradingagents/agents/utils/agent_utils.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/agents/utils/agent_utils.py) | Central import hub for all tools |
| [`tradingagents/dataflows/interface.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/dataflows/interface.py) | Routing dispatcher (`route_to_vendor`) and `VENDOR_METHODS` map |
| [`tradingagents/default_config.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/default_config.py) | Default vendor selections and per-tool overrides |
| `tradingagents/agents/analysts/*.py` | Example agents that assemble tool lists |
| [`tradingagents/graph/trading_graph.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/graph/trading_graph.py) | Workflow graph showing tool node integration |

## Summary

- **Define** new tools using the `@tool` decorator from `langchain_core.tools` and place them in `tradingagents/agents/utils/`.
- **Register** vendor implementations in the `VENDOR_METHODS` dictionary inside [`tradingagents/dataflows/interface.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/dataflows/interface.py).
- **Configure** per-tool overrides in [`tradingagents/default_config.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/default_config.py) under the `tool_vendors` key to change data sources without code changes.
- **Expose** new tools through [`tradingagents/agents/utils/agent_utils.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/agents/utils/agent_utils.py) to make them available to analyst agents.
- **Rely** on automatic fallback handling when vendors raise rate-limit errors.

## Frequently Asked Questions

### Do I need to modify the agent code to add a new tool?

No. Agents import tools from [`tradingagents/agents/utils/agent_utils.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/agents/utils/agent_utils.py). Adding your tool to that file (or importing it there from your custom module) makes it available to all analysts without changing any agent-specific logic in `tradingagents/agents/analysts/`.

### How does the routing layer choose which data vendor to use?

The `route_to_vendor()` function checks [`default_config.py`](https://github.com/TauricResearch/TradingAgents/blob/main/default_config.py) for a `tool_vendors` entry matching the tool name. If found, it uses that vendor; otherwise, it falls back to the category default in `data_vendors`. It then resolves the implementation using the `VENDOR_METHODS` mapping and executes the function. If that function raises `AlphaVantageRateLimitError`, the dispatcher automatically tries the next vendor in the mapping.

### Can I override a specific tool like `get_stock_data` without affecting other tools?

Yes. Add a specific entry to `tool_vendors` in [`default_config.py`](https://github.com/TauricResearch/TradingAgents/blob/main/default_config.py) mapping `get_stock_data` to your custom vendor name. Then register your implementation in `VENDOR_METHODS["get_stock_data"]` alongside existing vendors like `yfinance` and `alpha_vantage`. Other tools will continue using their default vendors.

### What happens if my custom data source fails?

If your implementation raises `AlphaVantageRateLimitError` (or other recognized exceptions), the routing layer automatically falls back to the next vendor configured in the `VENDOR_METHODS` list for that tool. This ensures agents remain functional even if a primary data source is temporarily unavailable.