# How the Portfolio Manager Evaluates and Approves Trading Proposals in TradingAgents

> Learn how the Portfolio Manager evaluates trading proposals in TradingAgents. Discover the process of risk analysis, LLM invocation, and final rating generation.

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

---

**The Portfolio Manager aggregates risk-analyst debates, retrieves relevant historical memories using BM25, and invokes a deep-thinking LLM to generate a final trading rating across a five-point scale from Buy to Sell.**

The **Portfolio Manager** serves as the final decision-making authority in the TradingAgents multi-agent pipeline. This component receives outputs from the risk-analyst debate stage, enriches them with historical context, and synthesizes concrete trading recommendations. Understanding how the Portfolio Manager evaluates and approves trading proposals reveals the mechanism by which raw market analysis transforms into actionable investment decisions.

## The Three-Stage Evaluation Pipeline

The evaluation process implemented in [`portfolio_manager.py`](https://github.com/TauricResearch/TradingAgents/blob/main/portfolio_manager.py) follows a rigorous three-stage architecture that ensures comprehensive context awareness before rendering a verdict.

### Stage 1: Data Aggregation and Context Building

The Portfolio Manager begins by collecting diverse data streams to construct a complete situational picture. According to the TradingAgents source code, this involves calling `build_instrument_context` to gather instrument-specific metadata, pulling the latest market reports, sentiment analysis, news summaries, and fundamental data.

Crucially, the manager retrieves the complete risk-analyst debate history from `risk_debate_state["history"]`, which contains the structured arguments from aggressive, conservative, and neutral analyst perspectives. Simultaneously, it queries the `FinancialSituationMemory` store using BM25 algorithm retrieval to surface the two most similar past situations:

```python
past_memories = memory.get_memories(curr_situation, n_matches=2)

```

These historical analogues provide contextual lessons that inform the current decision.

### Stage 2: Structured Prompt Construction

With data aggregated, the Portfolio Manager constructs a richly-structured prompt that imposes strict analytical discipline. The prompt template defined in [`portfolio_manager.py`](https://github.com/TauricResearch/TradingAgents/blob/main/portfolio_manager.py) (lines 24-53) includes:

- **The instrument context** with ticker-specific metadata
- **A five-point rating scale**: Buy / Overweight / Hold / Underweight / Sell
- **The trader's proposed investment plan**
- **Lessons from retrieved memories** (inserted at lines 39-40)
- **The complete risk-analyst debate transcript**
- **Strict output format requirements** specifying Rating, Executive Summary, and Investment Thesis sections

This prompt engineering ensures the LLM produces consistent, parseable recommendations rather than free-form commentary.

### Stage 3: LLM Invocation and Decision Finalization

The manager invokes the `deep_thinking_llm` (typically a high-capability model like GPT-4) with the constructed prompt. The raw LLM response serves dual purposes: it becomes both the `final_trade_decision` exposed to users and the `risk_debate_state["judge_decision"]` stored for future reflection.

The implementation in [`portfolio_manager.py`](https://github.com/TauricResearch/TradingAgents/blob/main/portfolio_manager.py) (lines 55-73) handles the LLM call and output assignment:

```python

# The LLM generates the structured recommendation

response = self.deep_thinking_llm.generate(prompt)
state["final_trade_decision"] = response
state["risk_debate_state"]["judge_decision"] = response

```

## Integration with the TradingAgents State Graph

The Portfolio Manager node is wired into the overarching state machine in [`tradingagents/graph/setup.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/graph/setup.py). After the risk-analyst debate loop completes ( sequenced as Aggressive → Conservative → Neutral ), control flows to the Portfolio Manager:

```python
portfolio_manager_node = create_portfolio_manager(
    self.deep_thinking_llm, self.portfolio_manager_memory
)
workflow.add_node("Portfolio Manager", portfolio_manager_node)
workflow.add_edge("Portfolio Manager", END)

```

This architecture ensures the Portfolio Manager evaluates the fully-contextualized debate before the graph terminates. The [`trading_graph.py`](https://github.com/TauricResearch/TradingAgents/blob/main/trading_graph.py) module then extracts and processes the decision:

```python
final_state, decision = self.graph.invoke(init_agent_state, **args)
return final_state, self.process_signal(final_state["final_trade_decision"])

```

The `process_signal` method isolates the core rating (e.g., "Buy") from the full textual recommendation for downstream consumption.

## Memory-Driven Decision Making with BM25

The Portfolio Manager's evaluation quality depends heavily on historical context retrieval. The `FinancialSituationMemory` class (defined in [`memory.py`](https://github.com/TauricResearch/TradingAgents/blob/main/memory.py)) implements BM25-based lexical retrieval to identify relevant precedents without external API dependencies.

When evaluating a proposal, the manager instantiates the memory retrieval with:

```python
past_memories = self.portfolio_manager_memory.get_memories(
    curr_situation, n_matches=2
)

```

These two most-relevant historical situations are injected directly into the prompt, allowing the LLM to learn from previous market conditions and their outcomes. This mechanism enables the Portfolio Manager to recognize patterns such as "high inflation with rising rates" or "tech sector volatility with institutional sell-offs" and apply lessons from prior decisions.

## Reflection and Continuous Learning

After decision finalization, the pipeline calls `reflect_and_remember` in [`trading_graph.py`](https://github.com/TauricResearch/TradingAgents/blob/main/trading_graph.py), which stores the outcome back into `portfolio_manager_memory` via the `reflect_portfolio_manager` function in [`reflection.py`](https://github.com/TauricResearch/TradingAgents/blob/main/reflection.py). This closes the feedback loop, ensuring future trading proposals are evaluated against an expanding corpus of institutional knowledge.

The reflection process captures both the situational context and the decision outcome, continuously refining the BM25 retrieval quality for subsequent evaluations.

## Implementation Examples

### Invoking the Portfolio Manager Node Directly

For testing or modular integration, you can instantiate the Portfolio Manager node outside the full graph:

```python
from tradingagents.llm_clients.openai_client import OpenAIClient
from tradingagents.agents.managers.portfolio_manager import create_portfolio_manager
from tradingagents.agents.utils.memory import FinancialSituationMemory
from tradingagents.agents.utils.agent_utils import build_instrument_context

# Initialize components

llm = OpenAIClient(api_key="YOUR_KEY")
memory = FinancialSituationMemory("pm_memory")

# Preload historical situations for BM25 retrieval

memory.add_situations([
    ("High inflation, rising rates", "Shift to defensive sectors."),
    ("Tech volatility, institutional sell-off", "Reduce high-growth exposure.")
])

# Build the node

portfolio_mgr = create_portfolio_manager(llm, memory)

# Prepare state (normally provided by graph)

state = {
    "company_of_interest": "AAPL",
    "risk_debate_state": {"history": "Aggressive: ...\nConservative: ..."},
    "market_report": "US market up 0.5% on earnings beat.",
    "sentiment_report": "Positive sentiment from analysts.",
    "news_report": "Apple releases new iPhone.",
    "fundamentals_report": "Strong cash flow, EPS beat.",
    "investment_plan": "Buy 100 shares over next week."
}

# Execute evaluation

output = portfolio_mgr(state)
print("Final decision:", output["final_trade_decision"])

```

### End-to-End Graph Execution

To run the complete evaluation pipeline including risk analysts and the Portfolio Manager:

```python
from tradingagents.graph.trading_graph import TradingGraph
from tradingagents.graph.setup import TradingGraphSetup
from tradingagents.llm_clients.openai_client import OpenAIClient

# Configure LLMs for different reasoning speeds

quick_llm = OpenAIClient(model="gpt-3.5-turbo")
deep_llm = OpenAIClient(model="gpt-4")

# Build graph with Portfolio Manager as final node

setup = TradingGraphSetup(
    quick_thinking_llm=quick_llm,
    deep_thinking_llm=deep_llm,
    selected_analysts=["aggressive", "conservative", "neutral"]
)
graph = TradingGraph(setup)

# Execute full evaluation pipeline

final_state, decision = graph.run(
    company_of_interest="AAPL",
    trade_date="2024-11-01"
)

print("Portfolio Manager rating:", decision)  # Output: "Buy" or "Overweight", etc.

```

## Summary

- The **Portfolio Manager** operates as the terminal decision node in the TradingAgents graph, receiving inputs after the risk-analyst debate concludes.
- Evaluation follows a **three-stage pipeline**: data aggregation (including BM25 memory retrieval), structured prompt construction with a five-point rating scale, and LLM invocation using the deep-thinking model.
- **BM25 retrieval** from `FinancialSituationMemory` provides two relevant historical precedents to inform current decisions without requiring external data calls.
- The **reflection mechanism** in [`reflection.py`](https://github.com/TauricResearch/TradingAgents/blob/main/reflection.py) stores outcomes back to memory, enabling continuous learning across trading sessions.
- Source files governing this behavior include [`portfolio_manager.py`](https://github.com/TauricResearch/TradingAgents/blob/main/portfolio_manager.py) (core logic), [`setup.py`](https://github.com/TauricResearch/TradingAgents/blob/main/setup.py) (graph integration), and [`memory.py`](https://github.com/TauricResearch/TradingAgents/blob/main/memory.py) (historical retrieval).

## Frequently Asked Questions

### How does the Portfolio Manager retrieve relevant past trading situations?

The Portfolio Manager queries `FinancialSituationMemory` using the BM25 algorithm to retrieve the two most similar historical situations based on the current market context. These memories are retrieved via `memory.get_memories(curr_situation, n_matches=2)` and injected into the LLM prompt to provide contextual lessons from previous decisions.

### What rating scale does the Portfolio Manager use for trading proposals?

The Portfolio Manager evaluates proposals against a structured five-point scale: **Buy**, **Overweight**, **Hold**, **Underweight**, and **Sell**. This rating system is explicitly defined in the prompt template within [`portfolio_manager.py`](https://github.com/TauricResearch/TradingAgents/blob/main/portfolio_manager.py) to ensure consistent, parseable outputs from the LLM.

### Which LLM does the Portfolio Manager use for final decisions?

The Portfolio Manager utilizes the **deep-thinking LLM** (configured as `self.deep_thinking_llm`, typically GPT-4 or equivalent high-capability models) rather than the quick-thinking LLM used by other agents. This ensures sophisticated synthesis of complex risk debates and market data.

### Where is the Portfolio Manager integrated into the TradingAgents workflow?

The Portfolio Manager node is wired into the state graph in [`tradingagents/graph/setup.py`](https://github.com/TauricResearch/TradingAgents/blob/main/tradingagents/graph/setup.py). It receives control after the risk-analyst debate loop completes and routes to `END`, terminating the workflow. The `TradingGraph` class in [`trading_graph.py`](https://github.com/TauricResearch/TradingAgents/blob/main/trading_graph.py) then extracts the `final_trade_decision` for post-processing and delivery.