Merge 4a92c324a5 into 13b826a31d
This commit is contained in:
commit
cdf4a5e8ad
97
cli/main.py
97
cli/main.py
|
|
@ -72,6 +72,7 @@ class MessageBuffer:
|
||||||
"fundamentals_report": None,
|
"fundamentals_report": None,
|
||||||
"investment_plan": None,
|
"investment_plan": None,
|
||||||
"trader_investment_plan": None,
|
"trader_investment_plan": None,
|
||||||
|
"risk_debate": None,
|
||||||
"final_trade_decision": None,
|
"final_trade_decision": None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,6 +114,7 @@ class MessageBuffer:
|
||||||
"fundamentals_report": "Fundamentals Analysis",
|
"fundamentals_report": "Fundamentals Analysis",
|
||||||
"investment_plan": "Research Team Decision",
|
"investment_plan": "Research Team Decision",
|
||||||
"trader_investment_plan": "Trading Team Plan",
|
"trader_investment_plan": "Trading Team Plan",
|
||||||
|
"risk_debate": "Risk Management Team Debate",
|
||||||
"final_trade_decision": "Portfolio Management Decision",
|
"final_trade_decision": "Portfolio Management Decision",
|
||||||
}
|
}
|
||||||
self.current_report = (
|
self.current_report = (
|
||||||
|
|
@ -162,6 +164,11 @@ class MessageBuffer:
|
||||||
if self.report_sections["trader_investment_plan"]:
|
if self.report_sections["trader_investment_plan"]:
|
||||||
report_parts.append("## Trading Team Plan")
|
report_parts.append("## Trading Team Plan")
|
||||||
report_parts.append(f"{self.report_sections['trader_investment_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
|
# Portfolio Management Decision
|
||||||
if self.report_sections["final_trade_decision"]:
|
if self.report_sections["final_trade_decision"]:
|
||||||
|
|
@ -520,12 +527,16 @@ def get_analysis_date():
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def display_complete_report(final_state):
|
def display_complete_report(final_state, report_dir, selections):
|
||||||
"""Display the complete analysis report with team-based panels."""
|
"""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")
|
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
|
# I. Analyst Team Reports
|
||||||
analyst_reports = []
|
analyst_reports = []
|
||||||
|
md_content.append("## I. Analyst Team Reports")
|
||||||
|
|
||||||
# Market Analyst Report
|
# Market Analyst Report
|
||||||
if final_state.get("market_report"):
|
if final_state.get("market_report"):
|
||||||
|
|
@ -537,6 +548,10 @@ def display_complete_report(final_state):
|
||||||
padding=(1, 2),
|
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
|
# Social Analyst Report
|
||||||
if final_state.get("sentiment_report"):
|
if final_state.get("sentiment_report"):
|
||||||
|
|
@ -548,6 +563,10 @@ def display_complete_report(final_state):
|
||||||
padding=(1, 2),
|
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
|
# News Analyst Report
|
||||||
if final_state.get("news_report"):
|
if final_state.get("news_report"):
|
||||||
|
|
@ -559,6 +578,9 @@ def display_complete_report(final_state):
|
||||||
padding=(1, 2),
|
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
|
# Fundamentals Analyst Report
|
||||||
if final_state.get("fundamentals_report"):
|
if final_state.get("fundamentals_report"):
|
||||||
|
|
@ -570,6 +592,10 @@ def display_complete_report(final_state):
|
||||||
padding=(1, 2),
|
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:
|
if analyst_reports:
|
||||||
console.print(
|
console.print(
|
||||||
|
|
@ -585,6 +611,7 @@ def display_complete_report(final_state):
|
||||||
if final_state.get("investment_debate_state"):
|
if final_state.get("investment_debate_state"):
|
||||||
research_reports = []
|
research_reports = []
|
||||||
debate_state = final_state["investment_debate_state"]
|
debate_state = final_state["investment_debate_state"]
|
||||||
|
md_content.append("## II. Research Team Decision")
|
||||||
|
|
||||||
# Bull Researcher Analysis
|
# Bull Researcher Analysis
|
||||||
if debate_state.get("bull_history"):
|
if debate_state.get("bull_history"):
|
||||||
|
|
@ -596,6 +623,10 @@ def display_complete_report(final_state):
|
||||||
padding=(1, 2),
|
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
|
# Bear Researcher Analysis
|
||||||
if debate_state.get("bear_history"):
|
if debate_state.get("bear_history"):
|
||||||
|
|
@ -607,6 +638,10 @@ def display_complete_report(final_state):
|
||||||
padding=(1, 2),
|
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
|
# Research Manager Decision
|
||||||
if debate_state.get("judge_decision"):
|
if debate_state.get("judge_decision"):
|
||||||
|
|
@ -618,6 +653,10 @@ def display_complete_report(final_state):
|
||||||
padding=(1, 2),
|
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:
|
if research_reports:
|
||||||
console.print(
|
console.print(
|
||||||
|
|
@ -631,6 +670,12 @@ def display_complete_report(final_state):
|
||||||
|
|
||||||
# III. Trading Team Reports
|
# III. Trading Team Reports
|
||||||
if final_state.get("trader_investment_plan"):
|
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(
|
console.print(
|
||||||
Panel(
|
Panel(
|
||||||
Panel(
|
Panel(
|
||||||
|
|
@ -649,6 +694,7 @@ def display_complete_report(final_state):
|
||||||
if final_state.get("risk_debate_state"):
|
if final_state.get("risk_debate_state"):
|
||||||
risk_reports = []
|
risk_reports = []
|
||||||
risk_state = final_state["risk_debate_state"]
|
risk_state = final_state["risk_debate_state"]
|
||||||
|
md_content.append("## IV. Risk Management Team Decision")
|
||||||
|
|
||||||
# Aggressive (Risky) Analyst Analysis
|
# Aggressive (Risky) Analyst Analysis
|
||||||
if risk_state.get("risky_history"):
|
if risk_state.get("risky_history"):
|
||||||
|
|
@ -660,6 +706,10 @@ def display_complete_report(final_state):
|
||||||
padding=(1, 2),
|
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
|
# Conservative (Safe) Analyst Analysis
|
||||||
if risk_state.get("safe_history"):
|
if risk_state.get("safe_history"):
|
||||||
|
|
@ -671,6 +721,10 @@ def display_complete_report(final_state):
|
||||||
padding=(1, 2),
|
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
|
# Neutral Analyst Analysis
|
||||||
if risk_state.get("neutral_history"):
|
if risk_state.get("neutral_history"):
|
||||||
|
|
@ -682,6 +736,10 @@ def display_complete_report(final_state):
|
||||||
padding=(1, 2),
|
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:
|
if risk_reports:
|
||||||
console.print(
|
console.print(
|
||||||
|
|
@ -695,6 +753,11 @@ def display_complete_report(final_state):
|
||||||
|
|
||||||
# V. Portfolio Manager Decision
|
# V. Portfolio Manager Decision
|
||||||
if risk_state.get("judge_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(
|
console.print(
|
||||||
Panel(
|
Panel(
|
||||||
Panel(
|
Panel(
|
||||||
|
|
@ -709,6 +772,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):
|
def update_research_team_status(status):
|
||||||
"""Update status for all research team members and trader."""
|
"""Update status for all research team members and trader."""
|
||||||
|
|
@ -993,6 +1062,7 @@ def run_analysis():
|
||||||
# Risk Management Team - Handle Risk Debate State
|
# Risk Management Team - Handle Risk Debate State
|
||||||
if "risk_debate_state" in chunk and chunk["risk_debate_state"]:
|
if "risk_debate_state" in chunk and chunk["risk_debate_state"]:
|
||||||
risk_state = chunk["risk_debate_state"]
|
risk_state = chunk["risk_debate_state"]
|
||||||
|
risk_debate_content = ""
|
||||||
|
|
||||||
# Update Risky Analyst status and report
|
# Update Risky Analyst status and report
|
||||||
if (
|
if (
|
||||||
|
|
@ -1006,10 +1076,11 @@ def run_analysis():
|
||||||
"Reasoning",
|
"Reasoning",
|
||||||
f"Risky Analyst: {risk_state['current_risky_response']}",
|
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(
|
message_buffer.update_report_section(
|
||||||
"final_trade_decision",
|
"risk_debate",
|
||||||
f"### Risky Analyst Analysis\n{risk_state['current_risky_response']}",
|
risk_debate_content,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Update Safe Analyst status and report
|
# Update Safe Analyst status and report
|
||||||
|
|
@ -1024,10 +1095,11 @@ def run_analysis():
|
||||||
"Reasoning",
|
"Reasoning",
|
||||||
f"Safe Analyst: {risk_state['current_safe_response']}",
|
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(
|
message_buffer.update_report_section(
|
||||||
"final_trade_decision",
|
"risk_debate",
|
||||||
f"### Safe Analyst Analysis\n{risk_state['current_safe_response']}",
|
risk_debate_content,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Update Neutral Analyst status and report
|
# Update Neutral Analyst status and report
|
||||||
|
|
@ -1042,10 +1114,11 @@ def run_analysis():
|
||||||
"Reasoning",
|
"Reasoning",
|
||||||
f"Neutral Analyst: {risk_state['current_neutral_response']}",
|
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(
|
message_buffer.update_report_section(
|
||||||
"final_trade_decision",
|
"risk_debate",
|
||||||
f"### Neutral Analyst Analysis\n{risk_state['current_neutral_response']}",
|
risk_debate_content,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Update Portfolio Manager status and final decision
|
# Update Portfolio Manager status and final decision
|
||||||
|
|
@ -1095,7 +1168,7 @@ def run_analysis():
|
||||||
message_buffer.update_report_section(section, final_state[section])
|
message_buffer.update_report_section(section, final_state[section])
|
||||||
|
|
||||||
# Display the complete final report
|
# Display the complete final report
|
||||||
display_complete_report(final_state)
|
display_complete_report(final_state, report_dir, selections)
|
||||||
|
|
||||||
update_display(layout)
|
update_display(layout)
|
||||||
|
|
||||||
|
|
|
||||||
22
cli/utils.py
22
cli/utils.py
|
|
@ -1,6 +1,6 @@
|
||||||
import questionary
|
import questionary
|
||||||
from typing import List, Optional, Tuple, Dict
|
from typing import List, Optional, Tuple, Dict
|
||||||
|
import re
|
||||||
from cli.models import AnalystType
|
from cli.models import AnalystType
|
||||||
|
|
||||||
ANALYST_ORDER = [
|
ANALYST_ORDER = [
|
||||||
|
|
@ -274,3 +274,23 @@ def select_llm_provider() -> tuple[str, str]:
|
||||||
print(f"You selected: {display_name}\tURL: {url}")
|
print(f"You selected: {display_name}\tURL: {url}")
|
||||||
|
|
||||||
return display_name, 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
|
||||||
|
|
@ -2,7 +2,6 @@ import chromadb
|
||||||
from chromadb.config import Settings
|
from chromadb.config import Settings
|
||||||
from openai import OpenAI
|
from openai import OpenAI
|
||||||
|
|
||||||
|
|
||||||
class FinancialSituationMemory:
|
class FinancialSituationMemory:
|
||||||
def __init__(self, name, config):
|
def __init__(self, name, config):
|
||||||
if config["backend_url"] == "http://localhost:11434/v1":
|
if config["backend_url"] == "http://localhost:11434/v1":
|
||||||
|
|
@ -69,7 +68,7 @@ class FinancialSituationMemory:
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Example usage
|
# Example usage
|
||||||
matcher = FinancialSituationMemory()
|
matcher = FinancialSituationMemory( name="test", config={"backend_url": "https://api.openai.com/v1",})
|
||||||
|
|
||||||
# Example data
|
# Example data
|
||||||
example_data = [
|
example_data = [
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,10 @@ class TradingAgentsGraph:
|
||||||
self.tool_nodes = self._create_tool_nodes()
|
self.tool_nodes = self._create_tool_nodes()
|
||||||
|
|
||||||
# Initialize components
|
# 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.graph_setup = GraphSetup(
|
||||||
self.quick_thinking_llm,
|
self.quick_thinking_llm,
|
||||||
self.deep_thinking_llm,
|
self.deep_thinking_llm,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue