How FinancialSituationMemory and reflect_and_remember Enable Learning from Trades in TradingAgents
TradingAgents implements a retrieval-augmented memory system where FinancialSituationMemory stores BM25-indexed market situations and LLM reflections, while the reflect_and_remember method orchestrates post-trade analysis to create a self-improving learning loop for multi-agent trading systems.
The TradingAgents framework combines lexical similarity search with LLM-driven reflection to enable continuous learning from historical trades. By integrating FinancialSituationMemory and reflect_and_remember into a unified pipeline, the system captures textual descriptions of market conditions alongside curated lessons learned, then retrieves these insights to augment future decision-making contexts. This architecture eliminates the need for external vector databases or model retraining while providing each agent component with relevant historical wisdom.
FinancialSituationMemory: BM25-Based Situation Storage
At the core of the learning system lies FinancialSituationMemory, a lightweight offline vector store implemented in tradingagents/agents/utils/memory.py. Unlike cloud-dependent embedding services, this class utilizes BM25 (Best Match 25) via the rank_bm25 library to index and retrieve textual market descriptions based on lexical similarity.
Data Structure and Indexing
The memory maintains two parallel lists: documents storing raw market-situation strings, and recommendations holding the corresponding LLM-generated reflections. When new situations arrive via add_situations(), the _rebuild_index() method tokenizes each document using _tokenize() and constructs a BM25Okapi index for efficient retrieval.
# From tradingagents/agents/utils/memory.py
def add_situations(self, situations):
"""Add new (situation, recommendation) pairs and rebuild index."""
for situation, recommendation in situations:
self.documents.append(situation)
self.recommendations.append(recommendation)
self._rebuild_index()
Retrieving Similar Past Situations
The get_memories(current_situation, n_matches) method tokenizes the query situation, scores all stored documents using BM25, normalizes the scores, and returns the top-N matches with their associated recommendations. This enables agents to pull historically relevant insights based on textual similarity rather than exact matching.
# Query example from the implementation
memories = trader_memory.get_memories(current_market_description, n_matches=3)
for m in memories:
print(m["similarity_score"], m["matched_situation"], m["recommendation"])
The Reflector: Generating Trade Reflections
The Reflector class in tradingagents/graph/reflection.py transforms raw trade outcomes into structured memory entries. It orchestrates LLM prompts that analyze each component's decisions against realized returns or losses, producing textual lessons for storage.
Extracting Market Context
The _extract_current_situation() method assembles comprehensive market narratives from the graph state, combining market reports, sentiment analyses, news summaries, and fundamental data into a single textual description that serves as the memory key.
Creating Component-Specific Reflections
For each agent component (bull researcher, bear researcher, trader, investment judge, portfolio manager), the _reflect_on_component() method constructs a two-message prompt: a system instruction defining the reflection task, and a human message containing the component's report, the extracted market situation, and the numeric return value. The LLM (instantiated as ChatOpenAI) generates a reflection text that captures what went right or wrong.
# Pattern from Reflector.reflect_trader()
situation = self._extract_current_situation(current_state)
trader_decision = current_state["trader_investment_plan"]
reflection = self._reflect_on_component(
"TRADER", trader_decision, situation, returns_losses
)
trader_memory.add_situations([(situation, reflection)])
The reflect_and_remember Learning Loop
The reflect_and_remember method in tradingagents/graph/trading_graph.py (lines 72-89) serves as the orchestration hub that connects trade execution to memory formation. Called immediately after the propagate() method completes a trading episode, this function triggers the complete reflection pipeline.
Orchestrating Multi-Agent Reflections
The method accepts a returns_losses parameter representing the realized profit or loss, then invokes five specialized reflection methods on the Reflector instance: reflect_bull_researcher(), reflect_bear_researcher(), reflect_trader(), reflect_invest_judge(), and reflect_portfolio_manager(). Each method targets a specific component's memory store.
# From tradingagents/graph/trading_graph.py
def reflect_and_remember(self, returns_losses):
"""Reflect on decisions and update memory based on returns."""
self.reflector.reflect_bull_researcher(self.curr_state, returns_losses, self.bull_memory)
self.reflector.reflect_bear_researcher(self.curr_state, returns_losses, self.bear_memory)
self.reflector.reflect_trader(self.curr_state, returns_losses, self.trader_memory)
self.reflector.reflect_invest_judge(self.curr_state, returns_losses, self.invest_judge_memory)
self.reflector.reflect_portfolio_manager(self.curr_state, returns_losses, self.portfolio_manager_memory)
Wiring Memory Updates
Each reflection method generates a situation-reflection pair and immediately persists it to the corresponding FinancialSituationMemory instance (e.g., self.bull_memory, self.trader_memory). This creates a closed learning loop: the current market state and outcome generate new knowledge, which becomes available for retrieval in subsequent trading episodes.
Querying Memory for Enhanced Decision Making
Once stored, reflections augment future agent reasoning by providing historically grounded context. Before generating new analyses, agents query their respective memory stores to retrieve lessons from similar past market conditions.
Integrating Historical Insights
Agents call get_memories() with the current market narrative to obtain the top-N most similar historical situations and their associated recommendations. These retrieved lessons are then injected into LLM prompts as contextual guidance, enabling the system to avoid repeating past mistakes or replicate successful strategies.
# Example integration within a researcher agent
def generate_bull_argument(self, current_state):
# Build the present market narrative
situation = self.graph._extract_current_situation(current_state)
# Pull the two most relevant past reflections
past = self.graph.bull_memory.get_memories(situation, n_matches=2)
lessons = "\n".join(p["recommendation"] for p in past)
# Include lessons in the prompt to the LLM
prompt = f"""
Market situation:
{situation}
Lessons from similar past bull arguments:
{lessons}
Now produce a convincing bullish argument for today.
"""
return self.llm.invoke(prompt).content
Practical Implementation: Full Trading Cycle
Implementing the learning loop requires initializing the graph, executing trades, and triggering reflections. The following example demonstrates a complete cycle from propagation to memory querying.
Running Propagation and Reflection
First, instantiate TradingAgentsGraph and execute the trading pipeline via propagate(). After obtaining the trade outcome, invoke reflect_and_remember() to generate and store reflections. Finally, query the updated memory to inspect what lessons were retained.
from tradingagents.graph.trading_graph import TradingAgentsGraph
# 1️⃣ Initialise the graph
graph = TradingAgentsGraph(debug=False)
# 2️⃣ Run the agents for a ticker on a specific date
final_state, signal = graph.propagate(company_name="AAPL", trade_date="2024-08-01")
# 3️⃣ Assume the trade earned $12,300 (positive return)
graph.reflect_and_remember(returns_losses=12300)
# 4️⃣ Query the trader memory for similar past situations
current_market = graph.curr_state["market_report"]
similar = graph.trader_memory.get_memories(current_market, n_matches=3)
print("\n--- Similar Past Situations & Lessons ---")
for i, mem in enumerate(similar, 1):
print(f"\nMatch {i}")
print(f"Score: {mem['similarity_score']:.2f}")
print(f"Situation: {mem['matched_situation'][:120]}…")
print(f"Lesson: {mem['recommendation'][:200]}…")
Key Source Files
The learning mechanism spans three critical files:
| Component | File | Purpose |
|---|---|---|
| Memory implementation | tradingagents/agents/utils/memory.py |
BM25-based storage and retrieval of market situations plus reflections. |
| Reflection engine | tradingagents/graph/reflection.py |
Generates LLM-driven analyses for each component's output. |
| Graph orchestration | tradingagents/graph/trading_graph.py |
Creates memories, runs agents, and invokes reflect_and_remember. |
Summary
- FinancialSituationMemory uses BM25 lexical indexing to store and retrieve market situations alongside LLM-generated reflections without requiring external APIs or embeddings.
- The Reflector class transforms trade outcomes into textual lessons by analyzing each component's decisions against realized returns using targeted LLM prompts.
- reflect_and_remember orchestrates the learning loop by triggering reflections for all five agent components (bull, bear, trader, investment judge, portfolio manager) and persisting insights to dedicated memory stores.
- Agents query their respective memories using
get_memories()to augment prompts with historically relevant lessons, creating a continuous improvement cycle. - The architecture is implemented across
memory.py,reflection.py, andtrading_graph.pyin the TauricResearch/TradingAgents repository.
Frequently Asked Questions
How does FinancialSituationMemory retrieve similar past trades without using embeddings?
FinancialSituationMemory utilizes BM25Okapi from the rank_bm25 library to perform lexical similarity scoring. When get_memories() is called, the method tokenizes the query situation and scores it against all stored documents using BM25 statistics, then normalizes and ranks the results. This approach avoids cloud-based embedding API costs while providing effective text-based retrieval for financial narratives.
What triggers the reflect_and_remember learning process in TradingAgents?
The reflect_and_remember() method is invoked manually after a trading episode completes, typically following a call to propagate() that returns the final state and trade signal. The method requires a returns_losses parameter (numeric profit or loss value) to contextualize the reflection prompts. As implemented in tradingagents/graph/trading_graph.py lines 72-89, this trigger initiates the generation of lessons for all five agent components simultaneously.
Which agent components generate reflections in the TradingAgents system?
The system generates reflections for five distinct components: the bull researcher (optimistic market analysis), bear researcher (pessimistic market analysis), trader (investment plan generation), investment judge (risk assessment), and portfolio manager (position sizing). Each maintains a separate FinancialSituationMemory instance (e.g., self.bull_memory, self.trader_memory) to store component-specific lessons learned from trade outcomes.
How is the BM25 index maintained when new situations are added?
The FinancialSituationMemory class automatically rebuilds the BM25 index whenever new entries arrive. The add_situations() method appends documents and recommendations to the parallel lists, then calls _rebuild_index() which tokenizes all documents fresh and instantiates a new BM25Okapi object. While this approach favors implementation simplicity over incremental indexing efficiency, it ensures immediate searchability of newly added reflections for subsequent trading episodes.
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 →