feat: update graph workflow for Polymarket 3-way debate
This commit is contained in:
parent
26657acab5
commit
7e45020dbb
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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."""
|
||||
|
|
|
|||
Loading…
Reference in New Issue