If you have played with TradingAgents, you probably noticed something interesting.
The framework already has a fairly clean separation between the agents and the market-data providers.
That means you don't need to rewrite the analysts, researchers, trader, risk manager, or portfolio manager just because you want to use a different market-data source.
You can add a market-data adapter.
In this article, I'll show how to connect RealMarketAPI to TradingAgents and use it as the source for OHLCV market data.
This is a custom integration. RealMarketAPI is not currently included as a built-in TradingAgents provider.
What TradingAgents is doing with market data
TradingAgents is a multi-agent framework built with LangGraph. It has different agents for fundamentals, sentiment, news, technical analysis, trading, risk management, and portfolio management.
The important part for this integration is the dataflow layer.
The current repository has a vendor router in:
tradingagents/
└── dataflows/
├── interface.py
├── y_finance.py
├── alpha_vantage.py
├── fred.py
└── polymarket.py
The router exposes methods such as:
get_stock_data
get_indicators
get_fundamentals
get_news
get_macro_indicators
and maps those methods to specific vendors.
For example, the current implementation maps get_stock_data to either Alpha Vantage or Yahoo Finance.
That is exactly the place where we can add RealMarketAPI.
What we are going to build
The flow will look like this:
TradingAgents
│
▼
get_stock_data()
│
▼
RealMarketAPI adapter
│
▼
GET /api/v1/history
│
▼
OHLCV candles
│
▼
TradingAgents technical analyst
The nice thing is that the agents themselves don't need to know anything about RealMarketAPI.
They just receive market data in the format expected by the existing dataflow.
1. Get a RealMarketAPI key
Create an API key from your RealMarketAPI account.
RealMarketAPI uses an API key as a query parameter for its REST API. The base REST endpoint is:
https://api.realmarketapi.com
For example, a price request looks like:
https://api.realmarketapi.com/api/v1/price
?apiKey=YOUR_API_KEY
&symbolCode=XAUUSD
&timeFrame=H1
The API returns OHLCV fields such as:
SymbolCode
OpenPrice
HighPrice
LowPrice
ClosePrice
Volume
OpenTime
and also Bid and Ask where available.
For TradingAgents, however, we want historical candles rather than just the latest price.
That's where /api/v1/history comes in.
2. Understand the TradingAgents data contract
Before writing the adapter, there is one important detail.
TradingAgents' existing stock-data providers return a CSV string, not a pandas DataFrame.
For example, the current Yahoo Finance implementation:
def get_YFin_data_online(
symbol: str,
start_date: str,
end_date: str,
):
fetches the data and eventually returns:
return header + csv_string
The Alpha Vantage implementation follows the same general contract.
So our RealMarketAPI adapter should follow that contract too.
3. Create the RealMarketAPI adapter
Create:
tradingagents/dataflows/realmarketapi.py
Start with this:
import os
from datetime import datetime, timedelta, timezone
import pandas as pd
import requests
from .errors import NoMarketDataError
BASE_URL = "https://api.realmarketapi.com"
def _get_api_key() -> str:
key = os.getenv("REALMARKETAPI_API_KEY")
if not key:
raise RuntimeError(
"REALMARKETAPI_API_KEY is not configured"
)
return key
def _fetch_history(
symbol: str,
start_time: datetime,
end_time: datetime,
) -> list[dict]:
api_key = _get_api_key()
url = f"{BASE_URL}/api/v1/history"
params = {
"apiKey": api_key,
"symbolCode": symbol,
"startTime": start_time.isoformat(),
"endTime": end_time.isoformat(),
"pageNumber": 1,
"pageSize": 200,
}
rows = []
while True:
response = requests.get(
url,
params=params,
timeout=30,
)
response.raise_for_status()
payload = response.json()
items = payload.get("items", [])
rows.extend(items)
total_pages = payload.get("totalPages", 1)
current_page = payload.get("pageNumber", 1)
if current_page >= total_pages:
break
params["pageNumber"] = current_page + 1
return rows
def get_stock_data(
symbol: str,
start_date: str,
end_date: str,
) -> str:
datetime.strptime(start_date, "%Y-%m-%d")
datetime.strptime(end_date, "%Y-%m-%d")
start_time = datetime(
*map(int, start_date.split("-")),
tzinfo=timezone.utc,
)
end_time = datetime(
*map(int, end_date.split("-")),
tzinfo=timezone.utc,
) + timedelta(days=1)
rows = _fetch_history(
symbol=symbol,
start_time=start_time,
end_time=end_time,
)
if not rows:
raise NoMarketDataError(
symbol,
symbol,
f"no rows between {start_date} and {end_date}",
)
df = pd.DataFrame(rows)
df["OpenTime"] = pd.to_datetime(
df["OpenTime"],
utc=True,
)
df = df.sort_values("OpenTime")
df = df.rename(
columns={
"OpenTime": "Date",
"OpenPrice": "Open",
"HighPrice": "High",
"LowPrice": "Low",
"ClosePrice": "Close",
"Volume": "Volume",
}
)
# TradingAgents' existing stock-data consumers expect
# a CSV-style OHLCV dataset.
columns = [
"Date",
"Open",
"High",
"Low",
"Close",
"Volume",
]
df = df[
[column for column in columns if column in df.columns]
]
df = df.dropna(subset=["Close"])
# The RealMarketAPI history endpoint currently provides
# historical H1 candles. Convert them into daily candles
# because the standard TradingAgents stock-data workflow
# expects daily-style data.
df = (
df.set_index("Date")
.resample("1D")
.agg(
{
"Open": "first",
"High": "max",
"Low": "min",
"Close": "last",
"Volume": "sum",
}
)
.dropna(subset=["Close"])
.reset_index()
)
df["Date"] = df["Date"].dt.strftime("%Y-%m-%d")
csv_string = df.to_csv(index=False)
header = (
f"# Stock data for {symbol} from "
f"{start_date} to {end_date}\n"
f"# Total records: {len(df)}\n"
f"# Data source: RealMarketAPI\n"
f"# Data retrieved on: "
f"{datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC')}\n\n"
)
return header + csv_string
There are two important things happening here.
First, the adapter talks directly to RealMarketAPI's historical endpoint.
Second, it converts the returned candles into the format expected by TradingAgents.
RealMarketAPI's historical API returns paginated candles and the response contains pagination metadata.
4. Why resample the candles?
This part is easy to overlook.
The current RealMarketAPI documentation describes /api/v1/history as returning historical H1 candles.
TradingAgents' existing Yahoo Finance implementation works with daily historical data for this workflow.
So simply returning the H1 candles would change the meaning of the existing TradingAgents analysis.
Instead, the adapter aggregates:
H1
│
├── Open → first
├── High → max
├── Low → min
├── Close → last
└── Volume → sum
│
▼
D1
This keeps the data shape closer to what the existing TradingAgents pipeline expects.
If your strategy is intentionally based on hourly data, you can remove this resampling step and adapt the downstream technical-analysis logic accordingly.
Don't silently mix the two.
5. Register RealMarketAPI with TradingAgents
Now open:
tradingagents/dataflows/interface.py
Add the import:
from .realmarketapi import get_stock_data as get_realmarketapi_stock
Then add RealMarketAPI to the vendor list:
VENDOR_LIST = [
"yfinance",
"fred",
"polymarket",
"alpha_vantage",
"realmarketapi",
]
Finally, add it to the get_stock_data mapping:
"get_stock_data": {
"alpha_vantage": get_alpha_vantage_stock,
"yfinance": get_YFin_data_online,
"realmarketapi": get_realmarketapi_stock,
},
The current TradingAgents router uses this mapping to select the implementation for each data method.
6. Tell TradingAgents to use it
TradingAgents already supports vendor selection through its configuration.
The current configuration has:
"data_vendors": {
"core_stock_apis": "yfinance",
"technical_indicators": "yfinance",
"fundamental_data": "yfinance",
"news_data": "yfinance",
"macro_data": "fred",
"prediction_markets": "polymarket",
},
and also supports tool-level overrides through tool_vendors.
For a first integration, you can change:
config["data_vendors"]["core_stock_apis"] = "realmarketapi"
Or use the more explicit tool-level configuration:
config["tool_vendors"] = {
"get_stock_data": "realmarketapi",
}
I prefer the second approach while testing because it makes it obvious which TradingAgents operation is being replaced.
7. Configure the API key
Set the API key in your environment.
Linux/macOS:
export REALMARKETAPI_API_KEY="rm_live_your_key"
Windows PowerShell:
$env:REALMARKETAPI_API_KEY="rm_live_your_key"
Or put it in your .env file if that is how you manage environment variables.
Don't commit the key to Git.
RealMarketAPI explicitly recommends keeping API keys out of public repositories and client-side code.
8. Run TradingAgents
You can now configure TradingAgents normally.
For example:
from tradingagents.graph.trading_graph import TradingAgentsGraph
from tradingagents.default_config import DEFAULT_CONFIG
config = DEFAULT_CONFIG.copy()
config["data_vendors"] = {
**config["data_vendors"],
"core_stock_apis": "realmarketapi",
}
ta = TradingAgentsGraph(
debug=True,
config=config,
)
_, decision = ta.propagate(
"XAUUSD",
"2026-08-14",
)
print(decision)
The important change is not in the agent graph.
It's here:
"core_stock_apis": "realmarketapi"
The rest of the TradingAgents pipeline remains the same.
The current TradingAgents API uses TradingAgentsGraph(...).propagate(ticker, date) as its Python entry point.
What about technical indicators?
This is where I would be careful.
Replacing the price-data vendor does not automatically replace the technical-indicator vendor.
TradingAgents currently has a separate get_indicators method, and the vendor router treats technical indicators as their own category.
So this configuration:
config["data_vendors"] = {
**config["data_vendors"],
"core_stock_apis": "realmarketapi",
}
means:
Price data
↓
RealMarketAPI
Technical indicators
↓
Existing configured provider
That's not necessarily a problem.
In fact, it is a good first step.
Get the basic data path working before replacing every data source.
RealMarketAPI can also calculate indicators
If you want the entire technical-analysis side to use the same market-data source, RealMarketAPI has server-side indicator endpoints for things such as:
SMA
EMA
RSI
MACD
ATR
Support / Resistance
Sentiment
For example:
GET /api/v1/indicator/rsi
with:
symbolCode=XAUUSD
timeFrame=H1
period=14
The indicator API is designed to calculate the values from RealMarketAPI's own market data.
However, I would not blindly plug these responses into TradingAgents' existing get_indicators() function.
The existing function has a different contract. It accepts:
symbol
indicator
curr_date
look_back_days
and returns a date/value series.
RealMarketAPI's indicator API instead returns indicator values based on a symbol and timeframe.
Those are similar concepts, but they aren't identical interfaces.
If you want to replace this layer too, write a separate adapter and explicitly map:
TradingAgents indicator
↓
RealMarketAPI indicator
rather than pretending the two APIs have the same contract.
What about XAUUSD?
This is one of the more interesting reasons to do this integration.
TradingAgents currently contains symbol normalization specifically because providers such as Yahoo Finance use different symbol conventions.
For example:
XAUUSD → GC=F
EURUSD → EURUSD=X
BTCUSD → BTC-USD
US500 → ^GSPC
The current repository has a dedicated symbol_utils.py for this.
With RealMarketAPI, you can keep the original trading symbol:
"XAUUSD"
and send:
symbolCode=XAUUSD
directly to the API.
That removes one layer of provider-specific symbol translation.
It also means the price being analyzed is explicitly the RealMarketAPI XAUUSD instrument rather than Yahoo Finance's GC=F gold future.
Those are not the same instrument, so this distinction matters when comparing results.
One important backtesting detail
There is another reason not to simply swap a URL and call it done.
TradingAgents has logic specifically designed to avoid look-ahead data.
The current Yahoo Finance data loader filters rows after the requested analysis date before feeding them into the analysis.
Your RealMarketAPI adapter should do the same.
For example, if the analysis date is:
2026-08-10
the adapter must never send candles from:
2026-08-11
2026-08-12
2026-08-13
...
into the agent.
This sounds obvious, but it is one of the easiest ways to accidentally produce impressive-looking but meaningless backtests.
The adapter should always treat:
end_date
as a hard information boundary.
REST vs WebSocket
For this particular TradingAgents integration, I would start with REST.
TradingAgents is currently structured around historical data retrieval for its analysis workflow.
RealMarketAPI's /history endpoint is therefore the natural starting point.
WebSocket becomes useful when you build something around TradingAgents that continuously reacts to market changes.
For example:
RealMarketAPI WebSocket
│
▼
Market event
│
▼
Trigger TradingAgents
│
▼
Research agents
│
▼
Trader
│
▼
Risk management
│
▼
Decision
RealMarketAPI provides WebSocket streams for price and candle data, so this can be built separately from the historical-analysis integration.
I would not keep a WebSocket connection open just to replace the historical data call.
Use each transport for what it is good at.
What about MCP?
RealMarketAPI also has an MCP server.
It exposes tools such as:
get_price
get_candles
get_history
get_symbols
get_timeframes
get_sma
get_ema
get_rsi
get_macd
get_support_resistance
get_sentiment
through a Streamable HTTP MCP endpoint.
That's useful if your application is itself an MCP-compatible AI agent.
But it is a different integration from what we did above.
TradingAgents currently retrieves market data through its Python dataflow abstraction, so an MCP connection doesn't automatically replace get_stock_data().
Think about the two approaches like this:
Python adapter
TradingAgents
↓
RealMarketAPI REST
versus:
MCP-compatible agent
↓
RealMarketAPI MCP
Both are valid.
They solve different integration problems.
A practical architecture
If I were building a TradingAgents-based system around RealMarketAPI, I would keep the first version simple:
┌──────────────────┐
│ TradingAgents │
└────────┬─────────┘
│
get_stock_data()
│
▼
┌─────────────────────┐
│ RealMarketAPI │
│ dataflow adapter │
└─────────┬───────────┘
│
▼
/api/v1/history
│
▼
OHLCV candles
│
▼
Daily aggregation
│
▼
TradingAgents
technical flow
Then, once that works, add:
RealMarketAPI indicators
and finally, if you need live reactions:
RealMarketAPI WebSocket
│
▼
Event / trigger
│
▼
TradingAgents
That gives you a clean separation between market-data infrastructure and agent orchestration.
A note about data coverage
RealMarketAPI currently supports market symbols across forex, metals, crypto, commodities, indices, and stocks, with the exact available symbols depending on the plan.
That is useful if your TradingAgents project isn't limited to US equities.
For example, you can use symbols such as:
XAUUSD
EURUSD
BTCUSD
ETHUSD
US500
US30
AAPL
NVDA
provided they are available to your account.
Check the symbol list for your plan before building your strategy around a particular instrument.
Don't expect better trading results just because the data source changed
This is probably the most important point.
Changing:
Yahoo Finance
to:
RealMarketAPI
doesn't magically make TradingAgents a better trader.
TradingAgents itself describes the framework as a research tool, and results depend on the language model, data quality, trading period, configuration, and other factors.
What a different data provider can give you is control over the market-data layer.
That can matter a lot when:
- you need specific instruments
- you need consistent symbol names
- you need a particular market-data source
- you want realtime data
- you want historical data from the same provider
- you are building something beyond a research notebook
The data source is infrastructure.
The trading strategy is a separate problem.
Final structure
The main idea is actually pretty simple.
You don't need to modify the TradingAgents agents.
You don't need to rewrite the LangGraph.
You don't need to create a new trader agent.
Add a market-data adapter that implements the contract TradingAgents already expects.
The path is:
TradingAgents
↓
dataflows/interface.py
↓
get_stock_data()
↓
RealMarketAPI adapter
↓
/api/v1/history
↓
OHLCV
Once that works reliably, you can decide whether you also want to replace the technical-indicator layer or add realtime WebSocket triggers.
That's a much safer approach than trying to change everything at once.
And because the integration happens at the dataflow layer, the rest of the TradingAgents architecture can stay largely untouched.
References
- TradingAgents repository: https://github.com/TauricResearch/TradingAgents
- RealMarketAPI documentation: https://realmarketapi.com/docs
- RealMarketAPI REST API reference
- RealMarketAPI WebSocket documentation
- RealMarketAPI MCP documentation
TradingAgents is intended for research. Market-data integration does not constitute financial advice, and trading results are not guaranteed.
Top comments (0)