# How to Implement Custom Technical Indicators Using the stockstats Module in TradingAgents-CN

> Learn to implement custom technical indicators in TradingAgents-CN by extending stockstats. Customize your trading strategies with unique analyses.

- Repository: [hsliuping/TradingAgents-CN](https://github.com/hsliuping/tradingagents-cn)
- Tags: how-to-guide
- Published: 2026-02-16

---

**You can implement custom technical indicators in TradingAgents-CN by extending the `StockstatsUtils.get_stock_stats` method in [`tradingagents/dataflows/technical/stockstats.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/dataflows/technical/stockstats.py) to compute your custom column, registering the indicator name and description in the `best_ind_params` dictionary inside [`tradingagents/dataflows/interface.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/dataflows/interface.py), and querying it through the standard `get_stock_stats_indicators_window` API.**

TradingAgents-CN provides a streamlined wrapper around the stockstats library, enabling quantitative agents to access technical indicators through a unified interface. When built-in metrics like SMA or RSI are insufficient for your strategy, you can implement custom technical indicators using the stockstats module in TradingAgents-CN by tapping into the library's extension points. This guide walks through the exact source files and methods you need to modify, with copy-pasteable code examples.

## Understanding the stockstats Integration Architecture

Before writing code, you need to understand how TradingAgents-CN bridges the stockstats library and its agent framework. The system separates core calculation logic from the public API surface.

### Core Calculation Layer in stockstats.py

The file [`tradingagents/dataflows/technical/stockstats.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/dataflows/technical/stockstats.py) contains the `StockstatsUtils` class. Its `get_stock_stats` method wraps a raw pandas DataFrame using `stockstats.wrap(data)`, then accesses the requested indicator column. This is where you inject custom pandas calculations, as the wrapped DataFrame supports standard pandas operations.

### Public API Layer in interface.py

The file [`tradingagents/dataflows/interface.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/dataflows/interface.py) exposes two key functions: `get_stockstats_indicator` for single-day values and `get_stock_stats_indicators_window` for multi-day windows. These functions rely on the `best_ind_params` dictionary (defined around lines 63-134) to map indicator names to human-readable descriptions and usage tips. When you register your custom indicator here, the public API automatically includes your description in returned reports.

## Step-by-Step Guide to Implementing Custom Technical Indicators

Follow these three steps to add your own technical indicator to the system.

### Step 1: Extend the Core Calculation Method

Open [`tradingagents/dataflows/technical/stockstats.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/dataflows/technical/stockstats.py) and locate the `get_stock_stats` method. After the line `df = wrap(data)`, add a conditional block that computes your custom column when the requested indicator matches your new name.

```python

# Inside StockstatsUtils.get_stock_stats

df = wrap(data)  # existing line

# ---------- BEGIN CUSTOM INDICATOR ----------

if indicator == "my_vol_change_5d":
    # 5-day rolling volume percentage change

    df["my_vol_change_5d"] = (
        (df["volume"] - df["volume"].shift(5)) / df["volume"].shift(5) * 100
    )

# ---------- END CUSTOM INDICATOR ----------

```

The existing code then calls `df[indicator]`, which will now find your custom column and return it alongside built-in stockstats metrics.

### Step 2: Register the Indicator Metadata

Open [`tradingagents/dataflows/interface.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/dataflows/interface.py) and find the `best_ind_params` dictionary (around lines 63-134). Add a new entry that describes your indicator, its usage, and tips for interpretation.

```python

# Inside best_ind_params dictionary in interface.py

best_ind_params = {
    # ... existing indicators ...

    "my_vol_change_5d": (
        "My Vol Change 5d: Percentage change of trading volume over the last 5 days. "
        "Usage: Detect sudden spikes or drops in activity. "
        "Tips: Combine with price-based signals to avoid reacting to noise."
    ),
    # ... rest of dictionary ...

}

```

This registration enables the `get_stock_stats_indicators_window` function to append your description to the returned report string, allowing LLM agents to understand the metric's semantic meaning.

### Step 3: Validate Your Implementation

Test your custom indicator by calling the public API from a Python script or Jupyter notebook.

```python
from tradingagents.dataflows import interface

# Query the custom indicator for a 20-day window

report = interface.get_stock_stats_indicators_window(
    symbol="MSFT",
    indicator="my_vol_change_5d",
    curr_date="2024-08-15",
    look_back_days=20,
    online=False,
)

print(report)

```

If the implementation is correct, the output will contain a table of 5-day volume percentage changes for the requested window, followed by the human-readable description you registered.

## Complete Working Example: Custom Volume Change Indicator

Here is the full, copy-pasteable code required to implement a custom 5-day volume change indicator.

**File: [`tradingagents/dataflows/technical/stockstats.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/dataflows/technical/stockstats.py)**

Locate the `get_stock_stats` method and insert the custom calculation block:

```python
def get_stock_stats(self, data, indicator, curr_date):
    df = wrap(data)  # existing line

    
    # ---------- BEGIN CUSTOM INDICATOR ----------

    if indicator == "my_vol_change_5d":
        df["my_vol_change_5d"] = (
            (df["volume"] - df["volume"].shift(5)) / df["volume"].shift(5) * 100
        )
    # ---------- END CUSTOM INDICATOR ----------

    
    # existing logic continues...

    matching_rows = df[df["Date"].str.startswith(curr_date)]
    return matching_rows[indicator].values[0] if not matching_rows.empty else None

```

**File: [`tradingagents/dataflows/interface.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/dataflows/interface.py)**

Add the description entry to the `best_ind_params` dictionary (around line 63):

```python
best_ind_params = {
    # ... existing indicators ...

    "my_vol_change_5d": (
        "My Vol Change 5d: Percentage change of trading volume over the last 5 days. "
        "Usage: Detect sudden spikes or drops in activity. "
        "Tips: Combine with price-based signals to avoid reacting to noise."
    ),
    # ... rest of dictionary ...

}

```

**Usage Script:**

```python
from tradingagents.dataflows import interface

result = interface.get_stock_stats_indicators_window(
    symbol="AAPL",
    indicator="my_vol_change_5d",
    curr_date="2024-12-31",
    look_back_days=10,
    online=False,
)

print(result)

```

Running this snippet outputs a multi-day table of the custom volume-change values followed by the human-readable description.

## Accessing Custom Indicators Through the Public API

Once registered, your custom indicator behaves exactly like built-in stockstats metrics. You can query it using either single-day or windowed lookups.

**Single-day lookup:**

```python
value = interface.get_stockstats_indicator(
    symbol="TSLA",
    indicator="my_vol_change_5d",
    curr_date="2024-09-30",
    online=True
)

```

**Windowed lookup with description:**

```python
report = interface.get_stock_stats_indicators_window(
    symbol="TSLA",
    indicator="my_vol_change_5d",
    curr_date="2024-09-30",
    look_back_days=15,
    online=False,
)

```

The `online` parameter controls whether the system fetches fresh data from Yahoo Finance via yfinance or uses cached CSV files. Your custom calculation executes after the data is loaded, ensuring real-time compatibility without code changes.

## Summary

- **Extend `StockstatsUtils.get_stock_stats`** in [`tradingagents/dataflows/technical/stockstats.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/dataflows/technical/stockstats.py) to compute your custom column using standard pandas operations after the `wrap(data)` call.
- **Register metadata** in the `best_ind_params` dictionary inside [`tradingagents/dataflows/interface.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/dataflows/interface.py) to provide human-readable descriptions and usage tips for LLM agents.
- **Query via standard API** using `get_stock_stats_indicators_window` or `get_stockstats_indicator`; your custom indicator behaves identically to built-in stockstats metrics.
- **Support real-time data** by setting `online=True`; the custom calculation executes on freshly fetched Yahoo Finance data without requiring additional logic.

## Frequently Asked Questions

### How do I choose a name for my custom indicator to avoid conflicts with existing stockstats metrics?

Select a name that is not present in the stockstats library's built-in indicator list. The stockstats module reserves common abbreviations like `close`, `volume`, `macd`, `rsi`, and `boll`. Use a descriptive prefix such as `my_` or your organization abbreviation, for example `my_vol_change_5d` or `custom_momentum_index`. This ensures that when `df[indicator]` is called in `StockstatsUtils.get_stock_stats`, Python resolves to your custom column rather than triggering stockstats' internal calculation logic.

### Can I implement indicators that require multiple input parameters, such as variable window lengths?

Yes. While the example shows a fixed 5-day window, you can parse dynamic parameters from the indicator string or extend the method signature. For instance, you could name your indicator `my_vol_change_10d` and add a corresponding `if` block, or parse a pattern like `my_vol_change_Xd` to extract the window variable. Ensure that the `best_ind_params` entry clearly documents the parameter format so that agents know how to request specific variations of your custom indicator.

### Will my custom indicator work in both online and offline modes?

Yes. The `online` parameter in `get_stock_stats_indicators_window` only affects the data acquisition layer—fetching fresh CSV data from Yahoo Finance when `True` or loading cached files when `False`. Once the DataFrame is loaded, the execution flow enters `StockstatsUtils.get_stock_stats`, where your custom calculation runs identically regardless of the data source. This design ensures that your indicator behaves consistently across backtesting (offline) and live trading (online) scenarios without requiring source code branches.

### Do I need to restart the entire TradingAgents-CN system after adding a custom indicator?

No. Because TradingAgents-CN loads these modules dynamically at runtime, you only need to restart your Python kernel or re-import the interface module after saving your changes to [`stockstats.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/stockstats.py) and [`interface.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/interface.py). If you are running an agent in a Jupyter notebook, simply re-execute the cell that imports `tradingagents.dataflows.interface`. The new indicator will be available immediately for querying without requiring a full system restart or Docker container rebuild.