# TradingAgents Signal Processing Flow and Final Trade Decision Determination: A Deep Dive

> Explore the TradingAgents signal processing flow and final trade decision determination. Understand how two LLMs work together for efficient and standardized trading insights.

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

---

**The TradingAgents framework uses a two-LLM architecture where a Portfolio Manager generates free-form trade decisions and a SignalProcessor extracts standardized ratings using a quick-thinking LLM.**

The **signal processing flow** in TradingAgents orchestrates a complex LangGraph workflow through multiple analytical nodes, culminating in a machine-readable **final trade decision**. This article traces the complete pipeline from raw data ingestion to standardized signal extraction, referencing the actual implementation in the `TauricResearch/TradingAgents` repository.

## Understanding the Signal Processing Architecture

### The LangGraph Workflow Overview

The system implements a multi-agent debate structure where specialized analysts, researchers, and risk managers iteratively refine investment theses. At the culmination of this pipeline, the **SignalProcessor** distills verbose LLM outputs into discrete trading signals. This design separates analytical depth from operational efficiency.

### The Two-LLM Design Philosophy

The architecture deliberately employs two distinct language models to optimize both quality and cost. The **deep-thinking LLM** (`deep_thinking_llm`) handles complex synthesis and narrative generation, producing rich contextual decisions in [`portfolio_manager.py`](https://github.com/TauricResearch/TradingAgents/blob/main/portfolio_manager.py). Conversely, the **quick-thinking LLM** (`quick_thinking_llm`) performs deterministic extraction tasks in [`signal_processing.py`](https://github.com/TauricResearch/TradingAgents/blob/main/signal_processing.py), returning only standardized rating tokens.

## Step-by-Step Signal Flow Through the Pipeline

### 1. Graph Initialization and Analyst Nodes

When `TradingAgentsGraph.__init__` executes in [`tradingagents/graph/trading_graph.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/graph/trading_graph.py), it instantiates LLM clients and builds the graph structure via `GraphSetup.setup_graph`. This setup creates specialized analyst nodes—**Market**, **Social**, **News**, and **Fundamentals**—each configured through [`setup.py`](https://github.com/TauricResearch/TradingAgents/blob/main/setup.py) using factory functions like `create_market_analyst` and `create_news_analyst`.

Each analyst calls associated tool nodes (e.g., `get_stock_data`, `get_news`) to populate the graph state with textual reports (`market_report`, `news_report`, etc.).

### 2. Researcher Debate and Synthesis

The **Bull Researcher** and **Bear Researcher** nodes engage in structured debate, guided by conditional edges in [`setup.py`](https://github.com/TauricResearch/TradingAgents/blob/main/setup.py) and termination logic in `ConditionalLogic.should_continue_debate`. When the debate concludes, the **Research Manager** (created via `create_research_manager`) synthesizes the exchange into an `investment_debate_state["judge_decision"]` that informs downstream nodes.

### 3. Trader Investment Plan Generation

The **Trader** node, implemented in [`tradingagents/agents/trader/trader.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/agents/trader/trader.py), consumes the aggregated analyst reports and debate summaries to generate a concrete `trader_investment_plan`. This plan specifies position sizing, entry rationale, and target metrics, storing the output in the graph state for risk analysis.

### 4. Risk Analysis and Portfolio Manager Decision

Three risk analysts—**Aggressive**, **Conservative**, and **Neutral**—iterate through risk scenarios using `ConditionalLogic.should_continue_risk_analysis`. Upon completion, the **Portfolio Manager** in [`tradingagents/agents/managers/portfolio_manager.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/agents/managers/portfolio_manager.py) receives:

- Instrument context and market data
- The trader's investment plan
- Complete risk-debate history
- Past-memory reflections from previous trades

The manager prompts the deep-thinking LLM with a structured template containing a **Rating Scale** (BUY, OVERWEIGHT, HOLD, UNDERWEIGHT, SELL). The raw LLM response becomes `final_trade_decision` in the graph state.

### 5. Signal Extraction and Standardization

The **SignalProcessor** class in [`tradingagents/graph/signal_processing.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/graph/signal_processing.py) implements the critical final transformation. Its `process_signal` method sends a constrained system prompt to the quick-thinking LLM, explicitly requesting **only the rating word** from the verbose Portfolio Manager output.

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

quick_llm = ChatOpenAI(model="gpt-3.5-turbo")  # fast, cost-effective extraction

processor = SignalProcessor(quick_llm)

raw_decision = """
Portfolio Manager Decision:
Rating: HOLD
Executive Summary: Maintain current position amid volatility...
"""

rating = processor.process_signal(full_signal=raw_decision)
print(rating)  # => HOLD

```

## Implementation Details and Code Examples

### Running the Complete Pipeline

The `TradingAgentsGraph.propagate` method orchestrates the entire workflow and returns both the comprehensive state and the extracted signal:

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

# Initialize with default configuration (debug=False)

graph = TradingAgentsGraph(debug=False)

# Execute pipeline for specific ticker and date

state, rating = graph.propagate(
    company_name="AAPL", 
    trade_date="2024-10-01"
)

print("Extracted rating:", rating)               # e.g., "BUY"

print("Full decision text:", state["final_trade_decision"])

```

The `rating` variable contains the standardized output from `SignalProcessor.process_signal`, while `state["final_trade_decision"]` preserves the full narrative generated by the Portfolio Manager.

### Inspecting Intermediate States

For debugging or audit purposes, capture the complete graph state including all debate histories and analytical reports:

```python
import json

# After running graph.propagate

with open("trading_state_snapshot.json", "w") as f:
    json.dump(state, f, indent=2)

```

This snapshot includes every intermediate report, the investment debate state, risk analysis history, and the raw final decision text.

## Summary

- The **TradingAgents** framework implements a multi-stage LangGraph workflow where analyst nodes, researchers, and risk managers collectively inform trading decisions.
- The **Portfolio Manager** in [`tradingagents/agents/managers/portfolio_manager.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/agents/managers/portfolio_manager.py) generates free-form decisions using a deep-thinking LLM.
- The **SignalProcessor** in [`tradingagents/graph/signal_processing.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/graph/signal_processing.py) extracts standardized ratings (BUY, OVERWEIGHT, HOLD, UNDERWEIGHT, SELL) using a quick-thinking LLM.
- The `propagate` method in [`tradingagents/graph/trading_graph.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/graph/trading_graph.py) returns both the full state dictionary and the machine-readable rating signal.
- Conditional logic in [`tradingagents/graph/conditional_logic.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/graph/conditional_logic.py) and graph setup in [`tradingagents/graph/setup.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/graph/setup.py) manage the debate loops and node transitions.

## Frequently Asked Questions

### How does the SignalProcessor handle ambiguous or malformed Portfolio Manager outputs?

The **SignalProcessor** sends a strict system prompt to the quick-thinking LLM that explicitly requests extraction of only the rating word from the provided text. If the Portfolio Manager output contains multiple ratings or unclear language, the quick-thinking LLM's instruction set prioritizes the final rating mentioned in the decision block, ensuring deterministic extraction of one of the five standardized values.

### What is the performance and cost benefit of using two different LLMs?

Separating **deep-thinking** and **quick-thinking** models optimizes both cost and latency. The deep-thinking LLM (typically a larger model like GPT-4) handles complex synthesis once per trade cycle, while the quick-thinking LLM (e.g., GPT-3.5-turbo) performs simple extraction at significantly lower cost and faster speed. This prevents expensive token consumption during the deterministic parsing phase.

### Can the final trade decision include logic beyond the five standard ratings?

Yes. The `final_trade_decision` stored in the graph state contains the full Portfolio Manager output including executive summaries, thesis statements, and risk assessments. Only the `SignalProcessor` output is constrained to the five rating categories. The raw text remains accessible via the state dictionary for downstream analysis or human review.

### Where is the graph state schema defined?

The **AgentState** type definition resides in [`tradingagents/agents/utils/agent_states.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/agents/utils/agent_states.py), which specifies the typed structure for all state fields including `market_report`, `investment_debate_state`, `trader_investment_plan`, `final_trade_decision`, and other intermediate values passed between nodes.