# How to Add a New Stock Market (e.g., Singapore) to TradingAgents-CN

> Learn to add a new stock market like Singapore to TradingAgents-CN. Extend the StockMarket enum, update regex, map markets, and implement a data provider. Expand your trading data sources.

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

---

**Adding a new stock market to TradingAgents-CN requires extending the `StockMarket` enum, updating ticker detection regex patterns, mapping the market to an internal category ID, and implementing a dedicated data provider module.**

TradingAgents-CN is an open-source multi-agent trading system that supports multiple stock markets through a modular data-source architecture. Whether you need to add Hong Kong, Singapore, or any other exchange, the process follows a consistent three-layer pattern involving market detection, category mapping, and provider registration.

## Understanding the Three-Layer Architecture

The codebase treats every market as a *market category* derived from the stock ticker format. Adding a new market involves three architectural layers:

| Layer | Purpose | Key File |
|-------|---------|----------|
| **Ticker-to-market detection** | Decides whether a ticker belongs to China A-shares, Hong Kong, US, or the new market | [`tradingagents/utils/stock_utils.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/utils/stock_utils.py) |
| **Market-category mapping** | Maps the detected `StockMarket` value to the internal market-category ID used by the data-source manager | [`tradingagents/dataflows/data_source_manager.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/dataflows/data_source_manager.py) |
| **Data-source registration** | Provides a concrete provider for the new market and makes it selectable in the priority-order logic | `tradingagents/dataflows/providers/<market>/` |

## Step-by-Step Implementation Guide

### Extend the StockMarket Enum in stock_utils.py

The `StockMarket` enum lives in **[`tradingagents/utils/stock_utils.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/utils/stock_utils.py)** (lines 15-20). Add a member for your new market:

```python
from enum import Enum

class StockMarket(Enum):
    """股票市场枚举"""
    CHINA_A = "china_a"      # 中国A股

    HONG_KONG = "hong_kong"  # 港股

    US = "us"                # 美股

    SINGAPORE = "singapore"  # 新增：新加坡股市

    UNKNOWN = "unknown"      # 未知

```

### Update Ticker Detection Logic

Singapore tickers typically use 4-letter codes ending with `.SI` (e.g., `D05.SI`). Update the `identify_stock_market` function in the same file to check this pattern **before** the generic US-ticker rule:

```python
import re

def identify_stock_market(ticker: str) -> StockMarket:
    # Existing checks for HK and China A...

    
    # Singapore: 4-letter + .SI (case-insensitive)

    if re.match(r'^[A-Z]{4}\.SI$', ticker):
        return StockMarket.SINGAPORE
    
    # US and other markets...

    return StockMarket.US

```

Place this block after the Hong Kong check (around lines 46-52) to maintain correct precedence.

### Map the Market to Internal Category ID

`DataSourceManager._identify_market_category` in **[`tradingagents/dataflows/data_source_manager.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/dataflows/data_source_manager.py)** (lines 86-100) converts `StockMarket` values to internal category IDs (`a_shares`, `us_stocks`, `hk_stocks`). Add the Singapore mapping:

```python
def _identify_market_category(self, market: StockMarket) -> str:
    market_mapping = {
        StockMarket.CHINA_A: 'a_shares',
        StockMarket.US: 'us_stocks',
        StockMarket.HONG_KONG: 'hk_stocks',
        StockMarket.SINGAPORE: 'sg_stocks',   # ← 新增

    }
    return market_mapping.get(market, 'unknown')

```

This mapping is critical because `_get_data_source_priority_order` queries the `system_configs` collection for entries whose `market_categories` field matches this ID. Without it, Singapore tickers would fall back to China A-share providers.

### Create a Dedicated Provider Module

Create a new package under **`tradingagents/dataflows/providers/sg/`** and add [`yahoo_finance.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/yahoo_finance.py). This minimal implementation reuses Yahoo Finance logic:

```python

# tradingagents/dataflows/providers/sg/yahoo_finance.py

from ..base_provider import BaseProvider
import yfinance as yf

class SingaporeYahooProvider(BaseProvider):
    """Yahoo Finance provider for Singapore tickers (.SI)"""

    def get_stock_data(self, ticker: str, start: str, end: str):
        # Ensure the ticker ends with .SI

        if not ticker.upper().endswith('.SI'):
            ticker = f"{ticker.upper()}.SI"
        data = yf.download(ticker, start=start, end=end)
        return data.to_dict(orient='records')

```

### Register the Provider and Wire It Into the Manager

Register the provider in **[`tradingagents/dataflows/providers/__init__.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/dataflows/providers/__init__.py)**:

```python
from .sg.yahoo_finance import SingaporeYahooProvider

```

Then wire it into `DataSourceManager` by adding a conditional branch in the data-fetching method:

```python
elif self.current_source == SGDataSource.YAHOO_FINANCE:
    result = SingaporeYahooProvider().get_stock_data(symbol, start_date, end_date)

```

### Update Configuration and UI

Add `"sg_stocks"` to the market selector in your configuration schema (e.g., [`install/database_export_config.json`](https://github.com/hsliuping/TradingAgents-CN/blob/main/install/database_export_config.json) or the frontend admin console). This allows operators to enable or disable Singapore data sources independently.

### Validate with Unit Tests

Add a test file to verify detection and provider plumbing:

```python

# tests/test_singapore_market.py

def test_singapore_market_detection():
    from tradingagents.utils.stock_utils import StockUtils, StockMarket
    assert StockUtils.identify_stock_market('D05.SI') == StockMarket.SINGAPORE
    info = StockUtils.get_market_info('D05.SI')
    assert info['market'] == 'singapore'

```

Run `pytest` to ensure existing tests for China A-shares, Hong Kong, and US markets still pass.

## Complete Code Examples

### Detecting a Singapore Ticker

```python
from tradingagents.utils.stock_utils import StockUtils

ticker = "D05.SI"
info = StockUtils.get_market_info(ticker)

print(info)

# {

#   "ticker": "D05.SI",

#   "market": "singapore",

#   "market_name": "新加坡股市",

#   "currency_name": "美元",

#   "currency_symbol": "$",

#   "data_source": "yahoo_finance",

#   "is_china": False,

#   "is_hk": False,

#   "is_us": False,

#   "is_sg": True

# }

```

### Fetching Data via the Unified Manager

```python
from tradingagents.dataflows.data_source_manager import DataSourceManager

manager = DataSourceManager()

# Optional: force SG Yahoo provider

manager.current_source = manager.SGDataSource.YAHOO_FINANCE

# Fetch DBS Group data

data = manager.get_stock_data("D05.SI", "2023-01-01", "2023-12-31")
print(data[:3])  # First 3 records

```

## Key Files Reference

| File | Purpose | Location |
|------|---------|----------|
| [`tradingagents/utils/stock_utils.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/utils/stock_utils.py) | Contains `StockMarket` enum and `identify_stock_market` detection logic | [View on GitHub](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/utils/stock_utils.py) |
| [`tradingagents/dataflows/data_source_manager.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/dataflows/data_source_manager.py) | Maps markets to category IDs and manages provider priority | [View on GitHub](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/dataflows/data_source_manager.py) |
| `tradingagents/dataflows/providers/sg/` | New directory for Singapore-specific providers | Create under `providers/` |
| [`tradingagents/dataflows/providers/__init__.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/dataflows/providers/__init__.py) | Registers provider classes for import | [View on GitHub](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/dataflows/providers/__init__.py) |
| [`install/database_export_config.json`](https://github.com/hsliuping/TradingAgents-CN/blob/main/install/database_export_config.json) | Configuration schema for market categories | [View on GitHub](https://github.com/hsliuping/TradingAgents-CN/blob/main/install/database_export_config.json) |

## Summary

- **Extend the enum**: Add your market to `StockMarket` in [`tradingagents/utils/stock_utils.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/utils/stock_utils.py) with a unique identifier like `SINGAPORE`.
- **Update detection**: Implement a regex pattern in `identify_stock_market` to recognize tickers (e.g., `^[A-Z]{4}\.SI$` for Singapore).
- **Map the category**: Add the market-to-ID mapping in `DataSourceManager._identify_market_category` (e.g., `StockMarket.SINGAPORE: 'sg_stocks'`).
- **Build the provider**: Create a new module under `tradingagents/dataflows/providers/<market>/` implementing `BaseProvider`.
- **Wire and register**: Import the provider in [`providers/__init__.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/providers/__init__.py) and add the dispatch logic in `DataSourceManager`.
- **Configure and test**: Update [`database_export_config.json`](https://github.com/hsliuping/TradingAgents-CN/blob/main/database_export_config.json) with the new category and write unit tests to verify detection logic.

## Frequently Asked Questions

### What file contains the StockMarket enum?

The `StockMarket` enum is defined in **[`tradingagents/utils/stock_utils.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/tradingagents/utils/stock_utils.py)** (lines 15-20). This file also contains the `identify_stock_market` function that uses regex patterns to classify tickers into their respective markets.

### Do I need to create a new provider for every new market?

Yes, you should create a dedicated provider module under **`tradingagents/dataflows/providers/<market>/`**. While you can reuse existing data-fetching libraries like `yfinance`, you need a concrete class implementing `BaseProvider` to handle market-specific ticker formatting (e.g., ensuring `.SI` suffix for Singapore) and any unique API requirements.

### How does the system handle tickers that don't match any pattern?

If a ticker does not match any of the defined regex patterns in `identify_stock_market`, the function returns `StockMarket.UNKNOWN`. According to the source code in [`data_source_manager.py`](https://github.com/hsliuping/TradingAgents-CN/blob/main/data_source_manager.py), unknown markets typically fall back to default China A-share providers or raise a configuration error depending on the strictness of your `DataSourceManager` implementation.

### Can I use Yahoo Finance for markets other than Singapore?

Yes, Yahoo Finance supports numerous international exchanges. You can reuse the `yfinance` library for other markets by creating similar provider classes in `tradingagents/dataflows/providers/<market>/`. Simply adjust the ticker suffix logic (e.g., `.HK` for Hong Kong, `.TO` for Toronto) in the provider's `get_stock_data` method to match Yahoo Finance's formatting requirements for that specific exchange.