From b143053cacbf3191dc6c962a42c8f28d6c3b7026 Mon Sep 17 00:00:00 2001 From: LixuanMao Date: Sun, 20 Jul 2025 14:22:55 -0400 Subject: [PATCH 1/4] Save Risk Management Team Debate output as separate markdown file 1. add a new key in `report_section` named 'risk_debate' to store Risk Management Team Debate output into a separate markdown file. --- cli/main.py | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/cli/main.py b/cli/main.py index 64616ee1..2c724e06 100644 --- a/cli/main.py +++ b/cli/main.py @@ -68,6 +68,7 @@ class MessageBuffer: "fundamentals_report": None, "investment_plan": None, "trader_investment_plan": None, + "risk_debate": None, "final_trade_decision": None, } @@ -109,6 +110,7 @@ class MessageBuffer: "fundamentals_report": "Fundamentals Analysis", "investment_plan": "Research Team Decision", "trader_investment_plan": "Trading Team Plan", + "risk_debate": "Risk Management Team Debate", "final_trade_decision": "Portfolio Management Decision", } self.current_report = ( @@ -158,6 +160,11 @@ class MessageBuffer: if self.report_sections["trader_investment_plan"]: report_parts.append("## Trading Team Plan") report_parts.append(f"{self.report_sections['trader_investment_plan']}") + + # Risk Management Team DebateĀ  + if self.report_sections["risk_debate"]: + report_parts.append("## Risk Management Team Debate") + report_parts.append(f"{self.report_sections['risk_debate']}") # Portfolio Management Decision if self.report_sections["final_trade_decision"]: @@ -989,6 +996,7 @@ def run_analysis(): # Risk Management Team - Handle Risk Debate State if "risk_debate_state" in chunk and chunk["risk_debate_state"]: risk_state = chunk["risk_debate_state"] + risk_debate_content = "" # Update Risky Analyst status and report if ( @@ -1002,10 +1010,11 @@ def run_analysis(): "Reasoning", f"Risky Analyst: {risk_state['current_risky_response']}", ) - # Update risk report with risky analyst's latest analysis only + # Update risk report with adding risky analyst's latest analysis + risk_debate_content += f"### Risky Analyst Analysis\n{risk_state['current_risky_response']}\n" message_buffer.update_report_section( - "final_trade_decision", - f"### Risky Analyst Analysis\n{risk_state['current_risky_response']}", + "risk_debate", + risk_debate_content, ) # Update Safe Analyst status and report @@ -1020,10 +1029,11 @@ def run_analysis(): "Reasoning", f"Safe Analyst: {risk_state['current_safe_response']}", ) - # Update risk report with safe analyst's latest analysis only + # Update risk report with adding safe analyst's latest analysis + risk_debate_content += f"### Safe Analyst Analysis\n{risk_state['current_safe_response']}\n" message_buffer.update_report_section( - "final_trade_decision", - f"### Safe Analyst Analysis\n{risk_state['current_safe_response']}", + "risk_debate", + risk_debate_content, ) # Update Neutral Analyst status and report @@ -1038,10 +1048,11 @@ def run_analysis(): "Reasoning", f"Neutral Analyst: {risk_state['current_neutral_response']}", ) - # Update risk report with neutral analyst's latest analysis only + # Update risk report with adding neutral analyst's latest analysis + risk_debate_content += f"### Neutral Analyst Analysis\n{risk_state['current_neutral_response']}\n" message_buffer.update_report_section( - "final_trade_decision", - f"### Neutral Analyst Analysis\n{risk_state['current_neutral_response']}", + "risk_debate", + risk_debate_content, ) # Update Portfolio Manager status and final decision From 873fe41f1d66c9cd3134afad811f3b3da708f6ee Mon Sep 17 00:00:00 2001 From: Taylor Mao Date: Mon, 21 Jul 2025 13:31:20 -0400 Subject: [PATCH 2/4] feat: output all analysis into one single .md file as described in the title --- cli/main.py | 68 +++++++++++++++++++++++++++++++++++++++++++++++++--- cli/utils.py | 22 ++++++++++++++++- 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/cli/main.py b/cli/main.py index 2c724e06..256120ca 100644 --- a/cli/main.py +++ b/cli/main.py @@ -523,12 +523,16 @@ def get_analysis_date(): ) -def display_complete_report(final_state): - """Display the complete analysis report with team-based panels.""" +def display_complete_report(final_state, report_dir, selections): + """Display the complete analysis report with team-based panels and save to markdown file.""" console.print("\n[bold green]Complete Analysis Report[/bold green]\n") + # Create full markdown report content + md_content = ["# Complete Analysis Report"] + # I. Analyst Team Reports analyst_reports = [] + md_content.append("## I. Analyst Team Reports") # Market Analyst Report if final_state.get("market_report"): @@ -540,6 +544,10 @@ def display_complete_report(final_state): padding=(1, 2), ) ) + md_content.append("### Market Analyst") + md_content.append(adjust_markdown_headers( + final_state["market_report"])) + md_content.append("") # Empty line for spacing # Social Analyst Report if final_state.get("sentiment_report"): @@ -551,6 +559,10 @@ def display_complete_report(final_state): padding=(1, 2), ) ) + md_content.append("### Social Analyst") + md_content.append(adjust_markdown_headers( + final_state["sentiment_report"])) + md_content.append("") # Empty line for spacing # News Analyst Report if final_state.get("news_report"): @@ -562,6 +574,9 @@ def display_complete_report(final_state): padding=(1, 2), ) ) + md_content.append("### News Analyst") + md_content.append(adjust_markdown_headers(final_state["news_report"])) + md_content.append("") # Empty line for spacing # Fundamentals Analyst Report if final_state.get("fundamentals_report"): @@ -573,6 +588,10 @@ def display_complete_report(final_state): padding=(1, 2), ) ) + md_content.append("### Fundamentals Analyst") + md_content.append(adjust_markdown_headers( + final_state["fundamentals_report"])) + md_content.append("") # Empty line for spacing if analyst_reports: console.print( @@ -588,6 +607,7 @@ def display_complete_report(final_state): if final_state.get("investment_debate_state"): research_reports = [] debate_state = final_state["investment_debate_state"] + md_content.append("## II. Research Team Decision") # Bull Researcher Analysis if debate_state.get("bull_history"): @@ -599,6 +619,10 @@ def display_complete_report(final_state): padding=(1, 2), ) ) + md_content.append("### Bull Researcher") + md_content.append(adjust_markdown_headers( + debate_state["bull_history"])) + md_content.append("") # Empty line for spacing # Bear Researcher Analysis if debate_state.get("bear_history"): @@ -610,6 +634,10 @@ def display_complete_report(final_state): padding=(1, 2), ) ) + md_content.append("### Bear Researcher") + md_content.append(adjust_markdown_headers( + debate_state["bear_history"])) + md_content.append("") # Empty line for spacing # Research Manager Decision if debate_state.get("judge_decision"): @@ -621,6 +649,10 @@ def display_complete_report(final_state): padding=(1, 2), ) ) + md_content.append("### Research Manager Decision") + md_content.append(adjust_markdown_headers( + debate_state["judge_decision"])) + md_content.append("") # Empty line for spacing if research_reports: console.print( @@ -634,6 +666,12 @@ def display_complete_report(final_state): # III. Trading Team Reports if final_state.get("trader_investment_plan"): + md_content.append("## III. Trading Team Plan") + md_content.append("### Trader") + md_content.append(adjust_markdown_headers( + final_state["trader_investment_plan"])) + md_content.append("") # Empty line for spacing + console.print( Panel( Panel( @@ -652,6 +690,7 @@ def display_complete_report(final_state): if final_state.get("risk_debate_state"): risk_reports = [] risk_state = final_state["risk_debate_state"] + md_content.append("## IV. Risk Management Team Decision") # Aggressive (Risky) Analyst Analysis if risk_state.get("risky_history"): @@ -663,6 +702,10 @@ def display_complete_report(final_state): padding=(1, 2), ) ) + md_content.append("### Aggressive (Risky) Analyst") + md_content.append(adjust_markdown_headers( + risk_state["risky_history"])) + md_content.append("") # Empty line for spacing # Conservative (Safe) Analyst Analysis if risk_state.get("safe_history"): @@ -674,6 +717,10 @@ def display_complete_report(final_state): padding=(1, 2), ) ) + md_content.append("### Conservative (Safe) Analyst") + md_content.append(adjust_markdown_headers( + risk_state["safe_history"])) + md_content.append("") # Empty line for spacing # Neutral Analyst Analysis if risk_state.get("neutral_history"): @@ -685,6 +732,10 @@ def display_complete_report(final_state): padding=(1, 2), ) ) + md_content.append("### Neutral Analyst") + md_content.append(adjust_markdown_headers( + risk_state["neutral_history"])) + md_content.append("") # Empty line for spacing if risk_reports: console.print( @@ -698,6 +749,11 @@ def display_complete_report(final_state): # V. Portfolio Manager Decision if risk_state.get("judge_decision"): + md_content.append("## V. Portfolio Manager Decision") + md_content.append("### Portfolio Manager") + md_content.append(adjust_markdown_headers( + risk_state["judge_decision"])) + console.print( Panel( Panel( @@ -712,6 +768,12 @@ def display_complete_report(final_state): ) ) + # Write the full markdown report to file + complete_report_filename = f"complete_report_by_{selections.get('shallow_thinker')}__{selections.get('deep_thinker')}.md" + complete_report_path = report_dir / complete_report_filename + with open(complete_report_path, "w") as f: + f.write("\n".join(md_content)) + def update_research_team_status(status): """Update status for all research team members and trader.""" @@ -1102,7 +1164,7 @@ def run_analysis(): message_buffer.update_report_section(section, final_state[section]) # Display the complete final report - display_complete_report(final_state) + display_complete_report(final_state, report_dir, selections) update_display(layout) diff --git a/cli/utils.py b/cli/utils.py index 7b9682a6..8664fcdd 100644 --- a/cli/utils.py +++ b/cli/utils.py @@ -1,6 +1,6 @@ import questionary from typing import List, Optional, Tuple, Dict - +import re from cli.models import AnalystType ANALYST_ORDER = [ @@ -274,3 +274,23 @@ def select_llm_provider() -> tuple[str, str]: print(f"You selected: {display_name}\tURL: {url}") return display_name, url + + +def adjust_markdown_headers(markdown_text: str) -> str: + def replace_header(match): + hashes = match.group(1) + header_text = match.group(2) + header_level = len(hashes) + + if header_level <= 3: + new_hashes = "####" # Force at least h4 + else: + new_hashes = "#" * (header_level + 1) # Increase one # + + return f"{new_hashes} {header_text}" + + # Regex to match markdown headers from level 1 to 6 + adjusted_text = re.sub( + r"^(#{1,6})\s+(.*)", replace_header, markdown_text, flags=re.MULTILINE + ) + return adjusted_text \ No newline at end of file From 8df223b2b6e9e80ccd03311a50b2a0a7e0c09165 Mon Sep 17 00:00:00 2001 From: Taylor Mao Date: Mon, 21 Jul 2025 20:34:58 -0400 Subject: [PATCH 3/4] Fix main local test of tradingagents/agents/utils/memory.py --- tradingagents/agents/utils/memory.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tradingagents/agents/utils/memory.py b/tradingagents/agents/utils/memory.py index 69b8ab8c..c3668161 100644 --- a/tradingagents/agents/utils/memory.py +++ b/tradingagents/agents/utils/memory.py @@ -2,7 +2,6 @@ import chromadb from chromadb.config import Settings from openai import OpenAI - class FinancialSituationMemory: def __init__(self, name, config): if config["backend_url"] == "http://localhost:11434/v1": @@ -69,7 +68,7 @@ class FinancialSituationMemory: if __name__ == "__main__": # Example usage - matcher = FinancialSituationMemory() + matcher = FinancialSituationMemory( name="test", config={"backend_url": "https://api.openai.com/v1",}) # Example data example_data = [ From 4a92c324a56882b4f216c1094e0450ab29ed5459 Mon Sep 17 00:00:00 2001 From: Taylor Mao Date: Mon, 21 Jul 2025 21:40:27 -0400 Subject: [PATCH 4/4] fix: make DEPTH_OPTIONS change debate/risk_discuss round numbers as described in the title --- tradingagents/graph/trading_graph.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tradingagents/graph/trading_graph.py b/tradingagents/graph/trading_graph.py index 80a29e53..bc5e4a5c 100644 --- a/tradingagents/graph/trading_graph.py +++ b/tradingagents/graph/trading_graph.py @@ -83,7 +83,10 @@ class TradingAgentsGraph: self.tool_nodes = self._create_tool_nodes() # Initialize components - self.conditional_logic = ConditionalLogic() + self.conditional_logic = ConditionalLogic( + max_debate_rounds=self.config["max_debate_rounds"], + max_risk_discuss_rounds=self.config["max_risk_discuss_rounds"] + ) self.graph_setup = GraphSetup( self.quick_thinking_llm, self.deep_thinking_llm,