""" Report Formatter for TradingAgents Analysis This module formats and structures analysis results for PDF generation, matching the exact terminal output structure. """ from typing import Dict, Any, List, Optional from datetime import datetime import json class ReportFormatter: """Formats trading analysis results into structured sections for PDF generation.""" def __init__(self): self.sections = {} def format_complete_report(self, analysis_data: Dict[str, Any], ticker: str, date: str) -> str: """ Format complete analysis report into structured HTML matching the terminal output. Args: analysis_data: Complete analysis results including final_state ticker: Stock ticker symbol date: Analysis date Returns: Formatted HTML content matching terminal structure """ html_sections = [] # Cover page html_sections.append(self._create_cover_page(ticker, date)) # Get final_state for structured data final_state = analysis_data.get('final_state', {}) # Complete Analysis Report Header html_sections.append('

Complete Analysis Report

') # I. Analyst Team Reports analyst_section = self._format_analyst_team_reports(final_state) if analyst_section: html_sections.append(analyst_section) # II. Research Team Decision research_section = self._format_research_team_decision(final_state) if research_section: html_sections.append(research_section) # III. Trading Team Plan trading_section = self._format_trading_team_plan(final_state) if trading_section: html_sections.append(trading_section) # IV. Risk Management Team Decision risk_section = self._format_risk_management_team_decision(final_state) if risk_section: html_sections.append(risk_section) # V. Portfolio Manager Decision portfolio_section = self._format_portfolio_manager_decision(final_state) if portfolio_section: html_sections.append(portfolio_section) return '\n'.join(html_sections) def _create_cover_page(self, ticker: str, date: str) -> str: """Create report cover page.""" return f"""

TradingAgents Analysis Report

{ticker}

Analysis Date: {date}

Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}

Multi-Agents LLM Financial Trading Framework

Workflow: Analyst Team → Research Team → Trader → Risk Management → Portfolio Management

""" def _format_analyst_team_reports(self, final_state: Dict[str, Any]) -> str: """Format I. Analyst Team Reports section.""" analysts = [] # Market Analyst Report if final_state.get("market_report"): analysts.append(self._create_analyst_panel("Market Analyst", final_state["market_report"])) # Social Analyst Report if final_state.get("sentiment_report"): analysts.append(self._create_analyst_panel("Social Analyst", final_state["sentiment_report"])) # News Analyst Report if final_state.get("news_report"): analysts.append(self._create_analyst_panel("News Analyst", final_state["news_report"])) # Fundamentals Analyst Report if final_state.get("fundamentals_report"): analysts.append(self._create_analyst_panel("Fundamentals Analyst", final_state["fundamentals_report"])) if not analysts: return "" return f"""

I. Analyst Team Reports

{''.join(analysts)}
""" def _format_research_team_decision(self, final_state: Dict[str, Any]) -> str: """Format II. Research Team Decision section.""" if not final_state.get("investment_debate_state"): return "" debate_state = final_state["investment_debate_state"] researchers = [] # Bull Researcher Analysis if debate_state.get("bull_history"): researchers.append(self._create_analyst_panel("Bull Researcher", debate_state["bull_history"])) # Bear Researcher Analysis if debate_state.get("bear_history"): researchers.append(self._create_analyst_panel("Bear Researcher", debate_state["bear_history"])) # Research Manager Decision if debate_state.get("judge_decision"): researchers.append(self._create_analyst_panel("Research Manager", debate_state["judge_decision"])) if not researchers: return "" return f"""

II. Research Team Decision

{''.join(researchers)}
""" def _format_trading_team_plan(self, final_state: Dict[str, Any]) -> str: """Format III. Trading Team Plan section.""" if not final_state.get("trader_investment_plan"): return "" return f"""

III. Trading Team Plan

{self._create_analyst_panel("Trader", final_state["trader_investment_plan"])}
""" def _format_risk_management_team_decision(self, final_state: Dict[str, Any]) -> str: """Format IV. Risk Management Team Decision section.""" if not final_state.get("risk_debate_state"): return "" risk_state = final_state["risk_debate_state"] risk_analysts = [] # Aggressive (Risky) Analyst Analysis if risk_state.get("risky_history"): risk_analysts.append(self._create_analyst_panel("Aggressive Analyst", risk_state["risky_history"])) # Conservative (Safe) Analyst Analysis if risk_state.get("safe_history"): risk_analysts.append(self._create_analyst_panel("Conservative Analyst", risk_state["safe_history"])) # Neutral Analyst Analysis if risk_state.get("neutral_history"): risk_analysts.append(self._create_analyst_panel("Neutral Analyst", risk_state["neutral_history"])) if not risk_analysts: return "" return f"""

IV. Risk Management Team Decision

{''.join(risk_analysts)}
""" def _format_portfolio_manager_decision(self, final_state: Dict[str, Any]) -> str: """Format V. Portfolio Manager Decision section.""" if not final_state.get("risk_debate_state") or not final_state["risk_debate_state"].get("judge_decision"): return "" decision = final_state["risk_debate_state"]["judge_decision"] return f"""

V. Portfolio Manager Decision

{self._create_analyst_panel("Portfolio Manager", decision)}
""" def _create_analyst_panel(self, title: str, content: str) -> str: """Create a styled panel for an analyst's report.""" # Convert markdown-style content to HTML if needed formatted_content = self._format_markdown_content(content) return f"""

{title}

{formatted_content}
""" def _format_markdown_content(self, content: str) -> str: """Convert basic markdown formatting to HTML.""" if not content: return "" # Replace markdown headers content = content.replace('### ', '

').replace('\n### ', '

\n

') content = content.replace('## ', '

').replace('\n## ', '

\n

') content = content.replace('# ', '

').replace('\n# ', '

\n

') # Replace bold text import re content = re.sub(r'\*\*(.*?)\*\*', r'\1', content) # Replace bullet points content = re.sub(r'\n\s*•\s+', '\n
  • ', content) content = re.sub(r'\n\s*\*\s+', '\n
  • ', content) content = re.sub(r'\n\s*-\s+', '\n
  • ', content) # Wrap consecutive list items in
  • ', '')): content += '' return content def _combine_sections(self, sections: List[str]) -> str: """Combine all sections into final HTML.""" return '\n'.join(sections)