Setting Up the Five-Tier Rating Scale for Trade Decisions in TradingAgents
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 (lines 13–28) |
TradingAgentsGraph.process_signal |
Facade that forwards decisions to the processor and returns the rating | tradingagents/graph/trading_graph.py (lines 90–93) |
Trader node |
Generates natural-language proposals ending with FINAL TRANSACTION PROPOSAL | tradingagents/agents/trader/trader.py (lines 33–41) |
SignalProcessor
The SignalProcessor class in 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 (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 (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:
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 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. This standardized value drives decision-making in two critical downstream nodes:
- Risk Analyst: Queries
final_trade_decisionto 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:
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:
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:
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
SignalProcessorinsignal_processing.pyenforces this scale through a constrained system prompt sent to the quick-thinking LLM. TradingAgentsGraph.process_signalorchestrates the extraction, while theTradernode generates the raw narrative that gets rated.- Downstream Risk Analyst and Portfolio Manager nodes consume the standardized
final_trade_decisionfield 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 (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 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. 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.
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 →