# Setting Up the Five-Tier Rating Scale for Trade Decisions in TradingAgents

> Learn to set up the five-tier rating scale in TradingAgents. Convert LLM analyst reports into clear `BUY`, `OVERWEIGHT`, `HOLD`, `UNDERWEIGHT`, and `SELL` trade directives.

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

---

**TradingAgents converts free-form LLM analyst reports into standardized trade directives using a five-tier rating scale consisting of `BUY`, `OVERWEIGHT`, `HOLD`, `UNDERWEIGHT`, and `SELL`.**

The TradingAgents framework by TauricResearch leverages multi-agent LLM workflows to generate investment strategies, but raw natural language outputs require normalization into machine-readable actions. Implementing the five-tier rating scale for trade decisions ensures that verbose analyst narratives distill into consistent, actionable portfolio signals that downstream risk and portfolio management nodes can process programmatically.

## Core Components of the Rating Workflow

The architecture centralizes rating extraction in three coordinated components:

| Component | Role | Key Source |
|-----------|------|------------|
| **`SignalProcessor`** | Wraps the quick-thinking LLM to distill reports into single rating words | [`tradingagents/graph/signal_processing.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/graph/signal_processing.py) (lines 13–28) |
| **`TradingAgentsGraph.process_signal`** | Facade that forwards decisions to the processor and returns the rating | [`tradingagents/graph/trading_graph.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/graph/trading_graph.py) (lines 90–93) |
| **`Trader` node** | Generates natural-language proposals ending with **FINAL TRANSACTION PROPOSAL** | [`tradingagents/agents/trader/trader.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/agents/trader/trader.py) (lines 33–41) |

### SignalProcessor

The `SignalProcessor` class in [`tradingagents/graph/signal_processing.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/graph/signal_processing.py) encapsulates the lightweight LLM responsible for parsing verbose analyst output. Lines 25–27 contain the critical system prompt that restricts the model to the five allowed ratings, ensuring the returned `content` attribute contains only `BUY`, `OVERWEIGHT`, `HOLD`, `UNDERWEIGHT`, or `SELL`.

### TradingAgentsGraph.process_signal

Acting as the orchestration layer, the `process_signal` method in [`tradingagents/graph/trading_graph.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/graph/trading_graph.py) (lines 90–93) receives the raw `final_trade_decision` string and delegates extraction to the `SignalProcessor`. This method returns the canonical rating string that the graph state propagates to downstream agents.

### Trader Node

The `Trader` agent produces the initial narrative containing the investment rationale. According to the source in [`tradingagents/agents/trader/trader.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/agents/trader/trader.py) (lines 33–41), this agent concludes its analysis with a **FINAL TRANSACTION PROPOSAL** section (e.g., `BUY`, `HOLD`, or `SELL`) stored in the graph state field `final_trade_decision`.

## How the Five-Tier Rating Scale Is Defined

Unlike traditional enum-based systems, TradingAgents enforces the rating scale through **prompt engineering** rather than code constants. The `SignalProcessor` constructs a message list that explicitly enumerates the valid options:

```python
messages = [
    (
        "system",
        "You are an efficient assistant that extracts the trading decision from analyst reports. "
        "Extract the rating as exactly one of: BUY, OVERWEIGHT, HOLD, UNDERWEIGHT, SELL. "
        "Output only the single rating word, nothing else.",
    ),
    ("human", full_signal),
]

```

*Note: This prompt appears in [`tradingagents/graph/signal_processing.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/graph/signal_processing.py) at lines 25–27.*

The quick-thinking LLM (`self.quick_thinking_llm.invoke(messages).content`) must select exactly one word from this closed set, effectively creating a constrained output space without requiring post-processing validation logic.

## Where Ratings Are Consumed Downstream

Once extracted, the rating populates the `final_trade_decision` field defined in [`tradingagents/agents/utils/agent_states.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/agents/utils/agent_states.py). This standardized value drives decision-making in two critical downstream nodes:

- **Risk Analyst**: Queries `final_trade_decision` to determine whether the portfolio requires defensive positioning (e.g., `UNDERWEIGHT`) or can tolerate aggressive exposure (e.g., `OVERWEIGHT`).
- **Portfolio Manager**: Uses the rating to calculate target position sizes and rebalance allocations according to the five-tier spectrum.

## Practical Implementation Examples

### Running the Graph and Retrieving a Rating

Execute the complete workflow to obtain a standardized rating for a specific ticker:

```python
from tradingagents.graph.trading_graph import TradingAgentsGraph

# Initialize the graph (loads quick-thinking LLM from default_config.py)

graph = TradingAgentsGraph(debug=False)

# Execute for AAPL on specific date

final_state, rating = graph.propagate(company_name="AAPL", trade_date="2024-09-30")

print("Full decision text:", final_state["final_trade_decision"])
print("Extracted five-tier rating:", rating)

```

*Example output:*

```

Full decision text: FINAL TRANSACTION PROPOSAL: **OVERWEIGHT**
Extracted five-tier rating: OVERWEIGHT

```

### Direct SignalProcessor Usage

For unit testing or ad-hoc analysis, invoke the processor directly without running the full graph:

```python
from tradingagents.graph.signal_processing import SignalProcessor
from langchain_openai import ChatOpenAI

# Initialize the quick-thinking LLM (configured in default_config.py)

quick_llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
processor = SignalProcessor(quick_thinking_llm=quick_llm)

raw_report = """
Our technical analysis shows strong momentum, earnings beat, and rising volume.
We recommend increasing exposure to the stock.
"""

rating = processor.process_signal(raw_report)
print(rating)  # Output: BUY or OVERWEIGHT

```

### Mapping Ratings to Portfolio Weights

Convert the categorical rating into numerical allocation targets:

```python
def decide_position(rating: str) -> float:
    """Map the five-tier rating to a target portfolio weight."""
    mapping = {
        "BUY": 1.0,
        "OVERWEIGHT": 0.75,
        "HOLD": 0.5,
        "UNDERWEIGHT": 0.25,
        "SELL": 0.0,
    }
    return mapping.get(rating.upper(), 0.5)  # Default to HOLD weight

target_weight = decide_position(rating)
print(f"Target portfolio weight: {target_weight:.2f}")

```

## Summary

- **TradingAgents** uses a **five-tier rating scale** (`BUY`, `OVERWEIGHT`, `HOLD`, `UNDERWEIGHT`, `SELL`) to normalize LLM-generated analyst reports into machine-readable trade decisions.
- The **`SignalProcessor`** in [`signal_processing.py`](https://github.com/TauricResearch/TradingAgents/blob/main/signal_processing.py) enforces this scale through a constrained system prompt sent to the quick-thinking LLM.
- **`TradingAgentsGraph.process_signal`** orchestrates the extraction, while the **`Trader`** node generates the raw narrative that gets rated.
- Downstream **Risk Analyst** and **Portfolio Manager** nodes consume the standardized `final_trade_decision` field to adjust portfolio allocations and risk exposure.

## Frequently Asked Questions

### What are the exact five ratings used in TradingAgents?

The five-tier rating scale for trade decisions consists of **`BUY`**, **`OVERWEIGHT`**, **`HOLD`**, **`UNDERWEIGHT`**, and **`SELL`**. These words represent a spectrum from aggressive accumulation to full liquidation, allowing granular portfolio adjustments between neutral (`HOLD`) and directional bets.

### Where is the five-tier rating scale defined in the codebase?

The scale is defined exclusively in the **system prompt** within [`tradingagents/graph/signal_processing.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/graph/signal_processing.py) (lines 25–27). Unlike hardcoded enums, the valid ratings exist as a comma-separated list inside the prompt string sent to the LLM, which constrains the model's output to these specific words.

### Can I customize the rating scale to use different terms or fewer tiers?

Yes, but doing so requires modifying the system prompt in [`signal_processing.py`](https://github.com/TauricResearch/TradingAgents/blob/main/signal_processing.py) and updating any downstream mapping logic (such as the `decide_position` function example). You must ensure that the **Risk Analyst** and **Portfolio Manager** nodes in `tradingagents/agents/` can interpret your new rating vocabulary, as they reference `final_trade_decision` to determine portfolio tilts.

### Which LLM configuration handles the rating extraction?

The **`SignalProcessor`** utilizes the **quick-thinking LLM** configuration defined in [`tradingagents/default_config.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/default_config.py). This is typically a lightweight model like `gpt-4o-mini` optimized for fast classification tasks, distinct from the heavier reasoning models used by the Researcher or Risk Analyst agents.