diff --git a/tradingagents/graph/propagation.py b/tradingagents/graph/propagation.py index 0fd10c0c..3da63539 100644 --- a/tradingagents/graph/propagation.py +++ b/tradingagents/graph/propagation.py @@ -1,6 +1,5 @@ -# TradingAgents/graph/propagation.py - from typing import Dict, Any, List, Optional + from tradingagents.agents.utils.agent_states import ( AgentState, InvestDebateState, @@ -9,57 +8,54 @@ from tradingagents.agents.utils.agent_states import ( class Propagator: - """Handles state initialization and propagation through the graph.""" + """Handles state initialization and graph argument configuration.""" def __init__(self, max_recur_limit=100): - """Initialize with configuration parameters.""" self.max_recur_limit = max_recur_limit - def create_initial_state( - self, company_name: str, trade_date: str - ) -> Dict[str, Any]: - """Create the initial state for the agent graph.""" + def create_initial_state(self, event_id, event_question, trade_date): + """Create the initial agent state for a Polymarket event analysis.""" return { - "messages": [("human", company_name)], - "company_of_interest": company_name, + "messages": [("human", event_question)], + "event_id": event_id, + "event_question": event_question, "trade_date": str(trade_date), - "investment_debate_state": InvestDebateState( - { - "bull_history": "", - "bear_history": "", - "history": "", - "current_response": "", - "judge_decision": "", - "count": 0, - } - ), - "risk_debate_state": RiskDebateState( - { - "aggressive_history": "", - "conservative_history": "", - "neutral_history": "", - "history": "", - "latest_speaker": "", - "current_aggressive_response": "", - "current_conservative_response": "", - "current_neutral_response": "", - "judge_decision": "", - "count": 0, - } - ), - "market_report": "", - "fundamentals_report": "", + "sender": "", + "odds_report": "", "sentiment_report": "", "news_report": "", + "event_report": "", + "investment_debate_state": { + "yes_history": "", + "no_history": "", + "timing_history": "", + "history": "", + "current_yes_response": "", + "current_no_response": "", + "current_timing_response": "", + "latest_speaker": "", + "judge_decision": "", + "count": 0, + }, + "investment_plan": "", + "trader_plan": "", + "risk_debate_state": { + "aggressive_history": "", + "conservative_history": "", + "neutral_history": "", + "history": "", + "latest_speaker": "", + "current_aggressive_response": "", + "current_conservative_response": "", + "current_neutral_response": "", + "judge_decision": "", + "count": 0, + }, + "final_decision": "", } - def get_graph_args(self, callbacks: Optional[List] = None) -> Dict[str, Any]: - """Get arguments for the graph invocation. - - Args: - callbacks: Optional list of callback handlers for tool execution tracking. - Note: LLM callbacks are handled separately via LLM constructor. - """ + def get_graph_args(self, callbacks=None): + """Get the arguments for graph invocation.""" config = {"recursion_limit": self.max_recur_limit} if callbacks: config["callbacks"] = callbacks diff --git a/tradingagents/graph/reflection.py b/tradingagents/graph/reflection.py index 33303231..99cf2ddc 100644 --- a/tradingagents/graph/reflection.py +++ b/tradingagents/graph/reflection.py @@ -15,45 +15,42 @@ class Reflector: def _get_reflection_prompt(self) -> str: """Get the system prompt for reflection.""" return """ -You are an expert financial analyst tasked with reviewing trading decisions/analysis and providing a comprehensive, step-by-step analysis. -Your goal is to deliver detailed insights into investment decisions and highlight opportunities for improvement, adhering strictly to the following guidelines: +You are an expert prediction market analyst tasked with reviewing trading decisions/analysis and providing a comprehensive, step-by-step analysis. +Your goal is to deliver detailed insights into prediction market decisions and highlight opportunities for improvement, adhering strictly to the following guidelines: 1. Reasoning: - - For each trading decision, determine whether it was correct or incorrect. A correct decision results in an increase in returns, while an incorrect decision does the opposite. + - For each prediction decision, determine whether it was correct or incorrect. A correct decision results in a positive return, while an incorrect decision does the opposite. - Analyze the contributing factors to each success or mistake. Consider: - - Market intelligence. - - Technical indicators. - - Technical signals. - - Price movement analysis. - - Overall market data analysis - - News analysis. + - Market odds and price movements. + - Order book depth and whale activity. + - News and event analysis. - Social media and sentiment analysis. - - Fundamental data analysis. + - Timing and event resolution timeline. - Weight the importance of each factor in the decision-making process. 2. Improvement: - For any incorrect decisions, propose revisions to maximize returns. - - Provide a detailed list of corrective actions or improvements, including specific recommendations (e.g., changing a decision from HOLD to BUY on a particular date). + - Provide a detailed list of corrective actions or improvements, including specific recommendations (e.g., changing a decision from SKIP to YES on a particular event). 3. Summary: - Summarize the lessons learned from the successes and mistakes. - - Highlight how these lessons can be adapted for future trading scenarios and draw connections between similar situations to apply the knowledge gained. + - Highlight how these lessons can be adapted for future prediction market scenarios and draw connections between similar situations to apply the knowledge gained. 4. Query: - Extract key insights from the summary into a concise sentence of no more than 1000 tokens. - Ensure the condensed sentence captures the essence of the lessons and reasoning for easy reference. -Adhere strictly to these instructions, and ensure your output is detailed, accurate, and actionable. You will also be given objective descriptions of the market from a price movements, technical indicator, news, and sentiment perspective to provide more context for your analysis. +Adhere strictly to these instructions, and ensure your output is detailed, accurate, and actionable. You will also be given objective descriptions of the market from an odds, news, and sentiment perspective to provide more context for your analysis. """ def _extract_current_situation(self, current_state: Dict[str, Any]) -> str: """Extract the current market situation from the state.""" - curr_market_report = current_state["market_report"] + curr_odds_report = current_state["odds_report"] curr_sentiment_report = current_state["sentiment_report"] curr_news_report = current_state["news_report"] - curr_fundamentals_report = current_state["fundamentals_report"] + curr_event_report = current_state["event_report"] - return f"{curr_market_report}\n\n{curr_sentiment_report}\n\n{curr_news_report}\n\n{curr_fundamentals_report}" + return f"{curr_odds_report}\n\n{curr_sentiment_report}\n\n{curr_news_report}\n\n{curr_event_report}" def _reflect_on_component( self, component_type: str, report: str, situation: str, returns_losses @@ -70,30 +67,40 @@ Adhere strictly to these instructions, and ensure your output is detailed, accur result = self.quick_thinking_llm.invoke(messages).content return result - def reflect_bull_researcher(self, current_state, returns_losses, bull_memory): - """Reflect on bull researcher's analysis and update memory.""" + def reflect_yes_advocate(self, current_state, returns_losses, yes_memory): + """Reflect on YES advocate's analysis and update memory.""" situation = self._extract_current_situation(current_state) - bull_debate_history = current_state["investment_debate_state"]["bull_history"] + yes_debate_history = current_state["investment_debate_state"]["yes_history"] result = self._reflect_on_component( - "BULL", bull_debate_history, situation, returns_losses + "YES", yes_debate_history, situation, returns_losses ) - bull_memory.add_situations([(situation, result)]) + yes_memory.add_situations([(situation, result)]) - def reflect_bear_researcher(self, current_state, returns_losses, bear_memory): - """Reflect on bear researcher's analysis and update memory.""" + def reflect_no_advocate(self, current_state, returns_losses, no_memory): + """Reflect on NO advocate's analysis and update memory.""" situation = self._extract_current_situation(current_state) - bear_debate_history = current_state["investment_debate_state"]["bear_history"] + no_debate_history = current_state["investment_debate_state"]["no_history"] result = self._reflect_on_component( - "BEAR", bear_debate_history, situation, returns_losses + "NO", no_debate_history, situation, returns_losses ) - bear_memory.add_situations([(situation, result)]) + no_memory.add_situations([(situation, result)]) + + def reflect_timing_advocate(self, current_state, returns_losses, timing_memory): + """Reflect on timing advocate's analysis and update memory.""" + situation = self._extract_current_situation(current_state) + timing_debate_history = current_state["investment_debate_state"]["timing_history"] + + result = self._reflect_on_component( + "TIMING", timing_debate_history, situation, returns_losses + ) + timing_memory.add_situations([(situation, result)]) def reflect_trader(self, current_state, returns_losses, trader_memory): """Reflect on trader's decision and update memory.""" situation = self._extract_current_situation(current_state) - trader_decision = current_state["trader_investment_plan"] + trader_decision = current_state["trader_plan"] result = self._reflect_on_component( "TRADER", trader_decision, situation, returns_losses diff --git a/tradingagents/graph/setup.py b/tradingagents/graph/setup.py index 772efe7f..2d1ac3d0 100644 --- a/tradingagents/graph/setup.py +++ b/tradingagents/graph/setup.py @@ -10,6 +10,14 @@ from tradingagents.agents.utils.agent_states import AgentState from .conditional_logic import ConditionalLogic +# Map analyst key to (display name, factory function, clear name) +_ANALYST_MAP = { + "odds": ("Odds Analyst", create_odds_analyst, "Msg Clear Odds"), + "social": ("Social Analyst", create_social_media_analyst, "Msg Clear Social"), + "news": ("News Analyst", create_news_analyst, "Msg Clear News"), + "event": ("Event Analyst", create_event_analyst, "Msg Clear Event"), +} + class GraphSetup: """Handles the setup and configuration of the agent graph.""" @@ -21,6 +29,7 @@ class GraphSetup: tool_nodes: Dict[str, ToolNode], bull_memory, bear_memory, + timing_memory, trader_memory, invest_judge_memory, risk_manager_memory, @@ -32,66 +41,55 @@ class GraphSetup: self.tool_nodes = tool_nodes self.bull_memory = bull_memory self.bear_memory = bear_memory + self.timing_memory = timing_memory self.trader_memory = trader_memory self.invest_judge_memory = invest_judge_memory self.risk_manager_memory = risk_manager_memory self.conditional_logic = conditional_logic def setup_graph( - self, selected_analysts=["market", "social", "news", "fundamentals"] + self, selected_analysts=["odds", "social", "news", "event"] ): """Set up and compile the agent workflow graph. Args: selected_analysts (list): List of analyst types to include. Options are: - - "market": Market analyst + - "odds": Odds analyst - "social": Social media analyst - "news": News analyst - - "fundamentals": Fundamentals analyst + - "event": Event analyst """ if len(selected_analysts) == 0: raise ValueError("Trading Agents Graph Setup Error: no analysts selected!") + # Validate analyst keys + for key in selected_analysts: + if key not in _ANALYST_MAP: + raise ValueError( + f"Unknown analyst type '{key}'. Valid options: {list(_ANALYST_MAP.keys())}" + ) + # Create analyst nodes analyst_nodes = {} delete_nodes = {} tool_nodes = {} - if "market" in selected_analysts: - analyst_nodes["market"] = create_market_analyst( - self.quick_thinking_llm - ) - delete_nodes["market"] = create_msg_delete() - tool_nodes["market"] = self.tool_nodes["market"] - - if "social" in selected_analysts: - analyst_nodes["social"] = create_social_media_analyst( - self.quick_thinking_llm - ) - delete_nodes["social"] = create_msg_delete() - tool_nodes["social"] = self.tool_nodes["social"] - - if "news" in selected_analysts: - analyst_nodes["news"] = create_news_analyst( - self.quick_thinking_llm - ) - delete_nodes["news"] = create_msg_delete() - tool_nodes["news"] = self.tool_nodes["news"] - - if "fundamentals" in selected_analysts: - analyst_nodes["fundamentals"] = create_fundamentals_analyst( - self.quick_thinking_llm - ) - delete_nodes["fundamentals"] = create_msg_delete() - tool_nodes["fundamentals"] = self.tool_nodes["fundamentals"] + for key in selected_analysts: + display_name, factory, clear_name = _ANALYST_MAP[key] + analyst_nodes[key] = factory(self.quick_thinking_llm) + delete_nodes[key] = create_msg_delete() + tool_nodes[key] = self.tool_nodes[key] # Create researcher and manager nodes - bull_researcher_node = create_bull_researcher( + yes_advocate_node = create_yes_advocate( self.quick_thinking_llm, self.bull_memory ) - bear_researcher_node = create_bear_researcher( + no_advocate_node = create_no_advocate( self.quick_thinking_llm, self.bear_memory ) + timing_advocate_node = create_timing_advocate( + self.quick_thinking_llm, self.timing_memory + ) research_manager_node = create_research_manager( self.deep_thinking_llm, self.invest_judge_memory ) @@ -109,16 +107,16 @@ class GraphSetup: workflow = StateGraph(AgentState) # Add analyst nodes to the graph - for analyst_type, node in analyst_nodes.items(): - workflow.add_node(f"{analyst_type.capitalize()} Analyst", node) - workflow.add_node( - f"Msg Clear {analyst_type.capitalize()}", delete_nodes[analyst_type] - ) - workflow.add_node(f"tools_{analyst_type}", tool_nodes[analyst_type]) + for key in selected_analysts: + display_name, _, clear_name = _ANALYST_MAP[key] + workflow.add_node(display_name, analyst_nodes[key]) + workflow.add_node(clear_name, delete_nodes[key]) + workflow.add_node(f"tools_{key}", tool_nodes[key]) - # Add other nodes - workflow.add_node("Bull Researcher", bull_researcher_node) - workflow.add_node("Bear Researcher", bear_researcher_node) + # Add researcher, manager, trader, and risk nodes + workflow.add_node("YES Advocate", yes_advocate_node) + workflow.add_node("NO Advocate", no_advocate_node) + workflow.add_node("Timing Advocate", timing_advocate_node) workflow.add_node("Research Manager", research_manager_node) workflow.add_node("Trader", trader_node) workflow.add_node("Aggressive Analyst", aggressive_analyst) @@ -128,49 +126,60 @@ class GraphSetup: # Define edges # Start with the first analyst - first_analyst = selected_analysts[0] - workflow.add_edge(START, f"{first_analyst.capitalize()} Analyst") + first_key = selected_analysts[0] + first_display_name = _ANALYST_MAP[first_key][0] + workflow.add_edge(START, first_display_name) - # Connect analysts in sequence - for i, analyst_type in enumerate(selected_analysts): - current_analyst = f"{analyst_type.capitalize()} Analyst" - current_tools = f"tools_{analyst_type}" - current_clear = f"Msg Clear {analyst_type.capitalize()}" + # Connect analysts in sequence using conditional logic + for i, key in enumerate(selected_analysts): + display_name, _, clear_name = _ANALYST_MAP[key] + tools_node = f"tools_{key}" + cond_fn = getattr(self.conditional_logic, f"should_continue_{key}") - # Add conditional edges for current analyst workflow.add_conditional_edges( - current_analyst, - getattr(self.conditional_logic, f"should_continue_{analyst_type}"), - [current_tools, current_clear], + display_name, + cond_fn, + [tools_node, clear_name], ) - workflow.add_edge(current_tools, current_analyst) + workflow.add_edge(tools_node, display_name) - # Connect to next analyst or to Bull Researcher if this is the last analyst + # Connect clear node to next analyst or to YES Advocate if i < len(selected_analysts) - 1: - next_analyst = f"{selected_analysts[i+1].capitalize()} Analyst" - workflow.add_edge(current_clear, next_analyst) + next_display_name = _ANALYST_MAP[selected_analysts[i + 1]][0] + workflow.add_edge(clear_name, next_display_name) else: - workflow.add_edge(current_clear, "Bull Researcher") + workflow.add_edge(clear_name, "YES Advocate") - # Add remaining edges + # 3-way investment debate: YES → NO → Timing → YES (cycle until done) workflow.add_conditional_edges( - "Bull Researcher", + "YES Advocate", self.conditional_logic.should_continue_debate, { - "Bear Researcher": "Bear Researcher", + "NO Advocate": "NO Advocate", "Research Manager": "Research Manager", }, ) workflow.add_conditional_edges( - "Bear Researcher", + "NO Advocate", self.conditional_logic.should_continue_debate, { - "Bull Researcher": "Bull Researcher", + "Timing Advocate": "Timing Advocate", "Research Manager": "Research Manager", }, ) + workflow.add_conditional_edges( + "Timing Advocate", + self.conditional_logic.should_continue_debate, + { + "YES Advocate": "YES Advocate", + "Research Manager": "Research Manager", + }, + ) + workflow.add_edge("Research Manager", "Trader") workflow.add_edge("Trader", "Aggressive Analyst") + + # 3-way risk debate workflow.add_conditional_edges( "Aggressive Analyst", self.conditional_logic.should_continue_risk_analysis, diff --git a/tradingagents/graph/signal_processing.py b/tradingagents/graph/signal_processing.py index 903e8529..a97e9f27 100644 --- a/tradingagents/graph/signal_processing.py +++ b/tradingagents/graph/signal_processing.py @@ -1,31 +1,59 @@ -# TradingAgents/graph/signal_processing.py +"""Signal processing for extracting structured prediction decisions.""" -from langchain_openai import ChatOpenAI +import json +import re class SignalProcessor: - """Processes trading signals to extract actionable decisions.""" + """Processes raw LLM output into structured prediction decisions.""" - def __init__(self, quick_thinking_llm: ChatOpenAI): - """Initialize with an LLM for processing.""" - self.quick_thinking_llm = quick_thinking_llm + def __init__(self, quick_thinking_llm): + self.llm = quick_thinking_llm def process_signal(self, full_signal: str) -> str: - """ - Process a full trading signal to extract the core decision. + """Extract structured JSON decision from the final decision text.""" + prompt = f"""Extract the final prediction decision from the following analysis. +Return ONLY a valid JSON object with these exact fields: +- "action": one of "YES", "NO", or "SKIP" +- "confidence": a float between 0.0 and 1.0 +- "edge": estimated probability minus market price (float, can be negative) +- "position_size": recommended bet size as fraction of bankroll (float 0.0-1.0) +- "reasoning": one sentence summary +- "time_horizon": time until event resolution - Args: - full_signal: Complete trading signal text +Analysis: +{full_signal} - Returns: - Extracted decision (BUY, SELL, or HOLD) - """ - messages = [ - ( - "system", - "You are an efficient assistant designed to analyze paragraphs or financial reports provided by a group of analysts. Your task is to extract the investment decision: SELL, BUY, or HOLD. Provide only the extracted decision (SELL, BUY, or HOLD) as your output, without adding any additional text or information.", - ), - ("human", full_signal), - ] +Return ONLY the JSON object, no other text.""" - return self.quick_thinking_llm.invoke(messages).content + response = self.llm.invoke(prompt) + content = response.content if hasattr(response, "content") else str(response) + + try: + json_match = re.search(r'\{[^\{\}]*\}', content, re.DOTALL) + if json_match: + parsed = json.loads(json_match.group()) + required = ["action", "confidence", "edge", "position_size", "reasoning", "time_horizon"] + if all(k in parsed for k in required): + parsed["action"] = parsed["action"].upper().strip() + if parsed["action"] not in ("YES", "NO", "SKIP"): + parsed["action"] = "SKIP" + return json.dumps(parsed) + except (json.JSONDecodeError, AttributeError): + pass + + action = "SKIP" + text_upper = content.upper() + if "YES" in text_upper and "NO" not in text_upper: + action = "YES" + elif "NO" in text_upper and "YES" not in text_upper: + action = "NO" + + return json.dumps({ + "action": action, + "confidence": 0.5, + "edge": 0.0, + "position_size": 0.0, + "reasoning": "Could not parse structured output from LLM response.", + "time_horizon": "unknown", + }) diff --git a/tradingagents/graph/trading_graph.py b/tradingagents/graph/trading_graph.py index c7ef0f98..1ced1477 100644 --- a/tradingagents/graph/trading_graph.py +++ b/tradingagents/graph/trading_graph.py @@ -20,17 +20,18 @@ from tradingagents.agents.utils.agent_states import ( ) from tradingagents.dataflows.config import set_config -# Import the new abstract tool methods from agent_utils +# Import Polymarket tools from agent_utils from tradingagents.agents.utils.agent_utils import ( - get_stock_data, - get_indicators, - get_fundamentals, - get_balance_sheet, - get_cashflow, - get_income_statement, - get_news, - get_insider_transactions, - get_global_news + get_market_data, + get_price_history, + get_event_news, + get_global_news, + get_whale_activity, + get_event_details, + get_orderbook, + get_market_stats, + get_leaderboard_signals, + get_social_sentiment, ) from .conditional_logic import ConditionalLogic @@ -45,7 +46,7 @@ class TradingAgentsGraph: def __init__( self, - selected_analysts=["market", "social", "news", "fundamentals"], + selected_analysts=["odds", "social", "news", "event"], debug=False, config: Dict[str, Any] = None, callbacks: Optional[List] = None, @@ -93,10 +94,11 @@ class TradingAgentsGraph: self.deep_thinking_llm = deep_client.get_llm() self.quick_thinking_llm = quick_client.get_llm() - + # Initialize memories self.bull_memory = FinancialSituationMemory("bull_memory", self.config) self.bear_memory = FinancialSituationMemory("bear_memory", self.config) + self.timing_memory = FinancialSituationMemory("timing_memory", self.config) self.trader_memory = FinancialSituationMemory("trader_memory", self.config) self.invest_judge_memory = FinancialSituationMemory("invest_judge_memory", self.config) self.risk_manager_memory = FinancialSituationMemory("risk_manager_memory", self.config) @@ -115,6 +117,7 @@ class TradingAgentsGraph: self.tool_nodes, self.bull_memory, self.bear_memory, + self.timing_memory, self.trader_memory, self.invest_judge_memory, self.risk_manager_memory, @@ -127,7 +130,7 @@ class TradingAgentsGraph: # State tracking self.curr_state = None - self.ticker = None + self.event_id = None self.log_states_dict = {} # date to full state dict # Set up the graph @@ -151,49 +154,22 @@ class TradingAgentsGraph: return kwargs def _create_tool_nodes(self) -> Dict[str, ToolNode]: - """Create tool nodes for different data sources using abstract methods.""" + """Create tool nodes for different data sources using Polymarket tools.""" return { - "market": ToolNode( - [ - # Core stock data tools - get_stock_data, - # Technical indicators - get_indicators, - ] - ), - "social": ToolNode( - [ - # News tools for social media analysis - get_news, - ] - ), - "news": ToolNode( - [ - # News and insider information - get_news, - get_global_news, - get_insider_transactions, - ] - ), - "fundamentals": ToolNode( - [ - # Fundamental analysis tools - get_fundamentals, - get_balance_sheet, - get_cashflow, - get_income_statement, - ] - ), + "odds": ToolNode([get_market_data, get_price_history, get_orderbook]), + "social": ToolNode([get_social_sentiment, get_whale_activity]), + "news": ToolNode([get_event_news, get_global_news]), + "event": ToolNode([get_event_details, get_market_stats, get_leaderboard_signals]), } - def propagate(self, company_name, trade_date): - """Run the trading agents graph for a company on a specific date.""" + def propagate(self, event_id, event_question, trade_date): + """Run the trading agents graph for a Polymarket event on a specific date.""" - self.ticker = company_name + self.event_id = event_id # Initialize state init_agent_state = self.propagator.create_initial_state( - company_name, trade_date + event_id, event_question, trade_date ) args = self.propagator.get_graph_args() @@ -219,29 +195,27 @@ class TradingAgentsGraph: self._log_state(trade_date, final_state) # Return decision and processed signal - return final_state, self.process_signal(final_state["final_trade_decision"]) + return final_state, self.process_signal(final_state["final_decision"]) def _log_state(self, trade_date, final_state): """Log the final state to a JSON file.""" self.log_states_dict[str(trade_date)] = { - "company_of_interest": final_state["company_of_interest"], + "event_id": final_state["event_id"], + "event_question": final_state["event_question"], "trade_date": final_state["trade_date"], - "market_report": final_state["market_report"], + "odds_report": final_state["odds_report"], "sentiment_report": final_state["sentiment_report"], "news_report": final_state["news_report"], - "fundamentals_report": final_state["fundamentals_report"], + "event_report": final_state["event_report"], "investment_debate_state": { - "bull_history": final_state["investment_debate_state"]["bull_history"], - "bear_history": final_state["investment_debate_state"]["bear_history"], + "yes_history": final_state["investment_debate_state"]["yes_history"], + "no_history": final_state["investment_debate_state"]["no_history"], + "timing_history": final_state["investment_debate_state"]["timing_history"], "history": final_state["investment_debate_state"]["history"], - "current_response": final_state["investment_debate_state"][ - "current_response" - ], - "judge_decision": final_state["investment_debate_state"][ - "judge_decision" - ], + "judge_decision": final_state["investment_debate_state"]["judge_decision"], }, - "trader_investment_decision": final_state["trader_investment_plan"], + "investment_plan": final_state["investment_plan"], + "trader_plan": final_state["trader_plan"], "risk_debate_state": { "aggressive_history": final_state["risk_debate_state"]["aggressive_history"], "conservative_history": final_state["risk_debate_state"]["conservative_history"], @@ -249,38 +223,28 @@ class TradingAgentsGraph: "history": final_state["risk_debate_state"]["history"], "judge_decision": final_state["risk_debate_state"]["judge_decision"], }, - "investment_plan": final_state["investment_plan"], - "final_trade_decision": final_state["final_trade_decision"], + "final_decision": final_state["final_decision"], } # Save to file - directory = Path(f"eval_results/{self.ticker}/TradingAgentsStrategy_logs/") + safe_id = str(self.event_id).replace("/", "_") + directory = Path(f"eval_results/{safe_id}/TradingAgentsStrategy_logs/") directory.mkdir(parents=True, exist_ok=True) with open( - f"eval_results/{self.ticker}/TradingAgentsStrategy_logs/full_states_log_{trade_date}.json", + f"eval_results/{safe_id}/TradingAgentsStrategy_logs/full_states_log_{trade_date}.json", "w", encoding="utf-8", ) as f: json.dump(self.log_states_dict, f, indent=4) 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_risk_manager( - self.curr_state, returns_losses, self.risk_manager_memory - ) + """Reflect on decisions and update memory based on outcomes. + + Phase 1 no-op: reflection is deferred until Phase 2 when outcome data + is available from resolved Polymarket events. + """ + pass def process_signal(self, full_signal): """Process a signal to extract the core decision."""