How to Implement Custom Technical Indicators Using the stockstats Module in TradingAgents-CN
You can implement custom technical indicators in TradingAgents-CN by extending the StockstatsUtils.get_stock_stats method in 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, 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 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 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 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.
# 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 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.
# 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.
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
Locate the get_stock_stats method and insert the custom calculation block:
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
Add the description entry to the best_ind_params dictionary (around line 63):
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:
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:
value = interface.get_stockstats_indicator(
symbol="TSLA",
indicator="my_vol_change_5d",
curr_date="2024-09-30",
online=True
)
Windowed lookup with description:
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_statsintradingagents/dataflows/technical/stockstats.pyto compute your custom column using standard pandas operations after thewrap(data)call. - Register metadata in the
best_ind_paramsdictionary insidetradingagents/dataflows/interface.pyto provide human-readable descriptions and usage tips for LLM agents. - Query via standard API using
get_stock_stats_indicators_windoworget_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 and 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →