mirror of
https://github.com/TauricResearch/TradingAgents.git
synced 2026-09-27 06:56:39 +03:00
docs: drop comments that narrate the next line
- about seventy '# Create/Initialize/Add ...' lines across graph, cli and dataflows, and the file-path headers; comments that give a reason stay
This commit is contained in:
@@ -20,8 +20,6 @@ from tradingagents.graph.analyst_execution import (
|
|||||||
AnalystExecutionPlan,
|
AnalystExecutionPlan,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create a deque to store recent messages with a maximum length
|
|
||||||
|
|
||||||
console = Console()
|
console = Console()
|
||||||
|
|
||||||
|
|
||||||
@@ -72,20 +70,16 @@ class MessageBuffer:
|
|||||||
"""
|
"""
|
||||||
self.selected_analysts = [a.lower() for a in selected_analysts]
|
self.selected_analysts = [a.lower() for a in selected_analysts]
|
||||||
|
|
||||||
# Build agent_status dynamically
|
|
||||||
self.agent_status = {}
|
self.agent_status = {}
|
||||||
|
|
||||||
# Add selected analysts
|
|
||||||
for analyst_key in self.selected_analysts:
|
for analyst_key in self.selected_analysts:
|
||||||
if analyst_key in self.ANALYST_MAPPING:
|
if analyst_key in self.ANALYST_MAPPING:
|
||||||
self.agent_status[self.ANALYST_MAPPING[analyst_key]] = "pending"
|
self.agent_status[self.ANALYST_MAPPING[analyst_key]] = "pending"
|
||||||
|
|
||||||
# Add fixed teams
|
|
||||||
for team_agents in self.FIXED_AGENTS.values():
|
for team_agents in self.FIXED_AGENTS.values():
|
||||||
for agent in team_agents:
|
for agent in team_agents:
|
||||||
self.agent_status[agent] = "pending"
|
self.agent_status[agent] = "pending"
|
||||||
|
|
||||||
# Build report_sections dynamically
|
|
||||||
self.report_sections = {}
|
self.report_sections = {}
|
||||||
for section, (analyst_key, _) in self.REPORT_SECTIONS.items():
|
for section, (analyst_key, _) in self.REPORT_SECTIONS.items():
|
||||||
if analyst_key is None or analyst_key in self.selected_analysts:
|
if analyst_key is None or analyst_key in self.selected_analysts:
|
||||||
@@ -140,14 +134,12 @@ class MessageBuffer:
|
|||||||
latest_section = None
|
latest_section = None
|
||||||
latest_content = None
|
latest_content = None
|
||||||
|
|
||||||
# Find the most recently updated section
|
|
||||||
for section, content in self.report_sections.items():
|
for section, content in self.report_sections.items():
|
||||||
if content is not None:
|
if content is not None:
|
||||||
latest_section = section
|
latest_section = section
|
||||||
latest_content = content
|
latest_content = content
|
||||||
|
|
||||||
if latest_section and latest_content:
|
if latest_section and latest_content:
|
||||||
# Format the current section for display
|
|
||||||
section_titles = {
|
section_titles = {
|
||||||
"market_report": "Market Analysis",
|
"market_report": "Market Analysis",
|
||||||
"sentiment_report": "Social Sentiment",
|
"sentiment_report": "Social Sentiment",
|
||||||
@@ -229,7 +221,6 @@ def update_display(layout, spinner_text=None, stats_handler=None, start_time=Non
|
|||||||
"Portfolio Management": ["Portfolio Manager"],
|
"Portfolio Management": ["Portfolio Manager"],
|
||||||
}
|
}
|
||||||
|
|
||||||
# Filter teams to only include agents that are in agent_status
|
|
||||||
teams = {}
|
teams = {}
|
||||||
for team, agents in all_teams.items():
|
for team, agents in all_teams.items():
|
||||||
active_agents = [a for a in agents if a in message_buffer.agent_status]
|
active_agents = [a for a in agents if a in message_buffer.agent_status]
|
||||||
@@ -237,7 +228,6 @@ def update_display(layout, spinner_text=None, stats_handler=None, start_time=Non
|
|||||||
teams[team] = active_agents
|
teams[team] = active_agents
|
||||||
|
|
||||||
for team, agents in teams.items():
|
for team, agents in teams.items():
|
||||||
# Add first agent with team name
|
|
||||||
first_agent = agents[0]
|
first_agent = agents[0]
|
||||||
status = message_buffer.agent_status.get(first_agent, "pending")
|
status = message_buffer.agent_status.get(first_agent, "pending")
|
||||||
if status == "in_progress":
|
if status == "in_progress":
|
||||||
@@ -254,7 +244,6 @@ def update_display(layout, spinner_text=None, stats_handler=None, start_time=Non
|
|||||||
status_cell = f"[{status_color}]{status}[/{status_color}]"
|
status_cell = f"[{status_color}]{status}[/{status_color}]"
|
||||||
progress_table.add_row(team, first_agent, status_cell)
|
progress_table.add_row(team, first_agent, status_cell)
|
||||||
|
|
||||||
# Add remaining agents in team
|
|
||||||
for agent in agents[1:]:
|
for agent in agents[1:]:
|
||||||
status = message_buffer.agent_status.get(agent, "pending")
|
status = message_buffer.agent_status.get(agent, "pending")
|
||||||
if status == "in_progress":
|
if status == "in_progress":
|
||||||
@@ -271,7 +260,6 @@ def update_display(layout, spinner_text=None, stats_handler=None, start_time=Non
|
|||||||
status_cell = f"[{status_color}]{status}[/{status_color}]"
|
status_cell = f"[{status_color}]{status}[/{status_color}]"
|
||||||
progress_table.add_row("", agent, status_cell)
|
progress_table.add_row("", agent, status_cell)
|
||||||
|
|
||||||
# Add horizontal line after each team
|
|
||||||
progress_table.add_row("─" * 20, "─" * 20, "─" * 20, style="dim")
|
progress_table.add_row("─" * 20, "─" * 20, "─" * 20, style="dim")
|
||||||
|
|
||||||
layout["progress"].update(
|
layout["progress"].update(
|
||||||
@@ -297,12 +285,10 @@ def update_display(layout, spinner_text=None, stats_handler=None, start_time=Non
|
|||||||
# Combine tool calls and messages
|
# Combine tool calls and messages
|
||||||
all_messages = []
|
all_messages = []
|
||||||
|
|
||||||
# Add tool calls
|
|
||||||
for timestamp, tool_name, args in message_buffer.tool_calls:
|
for timestamp, tool_name, args in message_buffer.tool_calls:
|
||||||
formatted_args = format_tool_args(args)
|
formatted_args = format_tool_args(args)
|
||||||
all_messages.append((timestamp, "Tool", f"{tool_name}: {formatted_args}"))
|
all_messages.append((timestamp, "Tool", f"{tool_name}: {formatted_args}"))
|
||||||
|
|
||||||
# Add regular messages
|
|
||||||
for timestamp, msg_type, content in message_buffer.messages:
|
for timestamp, msg_type, content in message_buffer.messages:
|
||||||
content_str = str(content) if content else ""
|
content_str = str(content) if content else ""
|
||||||
if len(content_str) > 200:
|
if len(content_str) > 200:
|
||||||
@@ -312,15 +298,11 @@ def update_display(layout, spinner_text=None, stats_handler=None, start_time=Non
|
|||||||
# Sort by timestamp descending (newest first)
|
# Sort by timestamp descending (newest first)
|
||||||
all_messages.sort(key=lambda x: x[0], reverse=True)
|
all_messages.sort(key=lambda x: x[0], reverse=True)
|
||||||
|
|
||||||
# Calculate how many messages we can show based on available space
|
|
||||||
max_messages = 12
|
max_messages = 12
|
||||||
|
|
||||||
# Get the first N messages (newest ones)
|
|
||||||
recent_messages = all_messages[:max_messages]
|
recent_messages = all_messages[:max_messages]
|
||||||
|
|
||||||
# Add messages to table (already in newest-first order)
|
|
||||||
for timestamp, msg_type, content in recent_messages:
|
for timestamp, msg_type, content in recent_messages:
|
||||||
# Format content with word wrapping
|
|
||||||
wrapped_content = Text(content, overflow="fold")
|
wrapped_content = Text(content, overflow="fold")
|
||||||
messages_table.add_row(timestamp, msg_type, wrapped_content)
|
messages_table.add_row(timestamp, msg_type, wrapped_content)
|
||||||
|
|
||||||
@@ -364,7 +346,6 @@ def update_display(layout, spinner_text=None, stats_handler=None, start_time=Non
|
|||||||
reports_completed = message_buffer.get_completed_reports_count()
|
reports_completed = message_buffer.get_completed_reports_count()
|
||||||
reports_total = len(message_buffer.report_sections)
|
reports_total = len(message_buffer.report_sections)
|
||||||
|
|
||||||
# Build stats parts
|
|
||||||
stats_parts = [f"Agents: {agents_completed}/{agents_total}"]
|
stats_parts = [f"Agents: {agents_completed}/{agents_total}"]
|
||||||
|
|
||||||
# LLM and tool stats from callback handler
|
# LLM and tool stats from callback handler
|
||||||
|
|||||||
@@ -140,7 +140,6 @@ def select_analysts(asset_type: AssetType = AssetType.STOCK, default=None) -> li
|
|||||||
def select_research_depth(default=None) -> int:
|
def select_research_depth(default=None) -> int:
|
||||||
"""Select research depth using an interactive selection."""
|
"""Select research depth using an interactive selection."""
|
||||||
|
|
||||||
# Define research depth options with their corresponding values
|
|
||||||
DEPTH_OPTIONS = [
|
DEPTH_OPTIONS = [
|
||||||
("Shallow - Quick research, few debate and strategy discussion rounds", 1),
|
("Shallow - Quick research, few debate and strategy discussion rounds", 1),
|
||||||
("Medium - Middle ground, moderate debate rounds and strategy discussion", 3),
|
("Medium - Middle ground, moderate debate rounds and strategy discussion", 3),
|
||||||
|
|||||||
-13
@@ -99,7 +99,6 @@ def run_analysis(checkpoint: bool | None = None, portfolio=None):
|
|||||||
|
|
||||||
config = _build_run_config(selections, checkpoint)
|
config = _build_run_config(selections, checkpoint)
|
||||||
|
|
||||||
# Create stats callback handler for tracking LLM/tool calls
|
|
||||||
stats_handler = StatsCallbackHandler()
|
stats_handler = StatsCallbackHandler()
|
||||||
|
|
||||||
# Normalize analyst selection to predefined order (selection is a 'set', order is fixed)
|
# Normalize analyst selection to predefined order (selection is a 'set', order is fixed)
|
||||||
@@ -108,7 +107,6 @@ def run_analysis(checkpoint: bool | None = None, portfolio=None):
|
|||||||
analyst_execution_plan = build_analyst_execution_plan(selected_analyst_keys)
|
analyst_execution_plan = build_analyst_execution_plan(selected_analyst_keys)
|
||||||
analyst_wall_time_tracker = AnalystWallTimeTracker(analyst_execution_plan)
|
analyst_wall_time_tracker = AnalystWallTimeTracker(analyst_execution_plan)
|
||||||
|
|
||||||
# Initialize the graph with callbacks bound to LLMs
|
|
||||||
graph = TradingAgentsGraph(
|
graph = TradingAgentsGraph(
|
||||||
selected_analyst_keys,
|
selected_analyst_keys,
|
||||||
config=config,
|
config=config,
|
||||||
@@ -116,13 +114,11 @@ def run_analysis(checkpoint: bool | None = None, portfolio=None):
|
|||||||
callbacks=[stats_handler],
|
callbacks=[stats_handler],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Initialize message buffer with selected analysts
|
|
||||||
message_buffer.init_for_analysis(selected_analyst_keys)
|
message_buffer.init_for_analysis(selected_analyst_keys)
|
||||||
|
|
||||||
# Track start time for elapsed display
|
# Track start time for elapsed display
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
# Create result directory
|
|
||||||
results_dir = _run_directory(config, selections["ticker"], selections["analysis_date"])
|
results_dir = _run_directory(config, selections["ticker"], selections["analysis_date"])
|
||||||
results_dir.mkdir(parents=True, exist_ok=True)
|
results_dir.mkdir(parents=True, exist_ok=True)
|
||||||
report_dir = results_dir / "reports"
|
report_dir = results_dir / "reports"
|
||||||
@@ -173,7 +169,6 @@ def run_analysis(checkpoint: bool | None = None, portfolio=None):
|
|||||||
message_buffer.add_tool_call = save_tool_call_decorator(message_buffer, "add_tool_call")
|
message_buffer.add_tool_call = save_tool_call_decorator(message_buffer, "add_tool_call")
|
||||||
message_buffer.update_report_section = save_report_section_decorator(message_buffer, "update_report_section")
|
message_buffer.update_report_section = save_report_section_decorator(message_buffer, "update_report_section")
|
||||||
|
|
||||||
# Now start the display layout
|
|
||||||
layout = create_layout()
|
layout = create_layout()
|
||||||
|
|
||||||
# The alternate screen keeps a layout taller than the window from redrawing
|
# The alternate screen keeps a layout taller than the window from redrawing
|
||||||
@@ -182,7 +177,6 @@ def run_analysis(checkpoint: bool | None = None, portfolio=None):
|
|||||||
# Initial display
|
# Initial display
|
||||||
update_display(layout, stats_handler=stats_handler, start_time=start_time)
|
update_display(layout, stats_handler=stats_handler, start_time=start_time)
|
||||||
|
|
||||||
# Add initial messages
|
|
||||||
message_buffer.add_message("System", f"Selected ticker: {selections['ticker']}")
|
message_buffer.add_message("System", f"Selected ticker: {selections['ticker']}")
|
||||||
if selections["asset_type"] != "stock":
|
if selections["asset_type"] != "stock":
|
||||||
message_buffer.add_message("System", f"Detected asset type: {selections['asset_type']}")
|
message_buffer.add_message("System", f"Detected asset type: {selections['asset_type']}")
|
||||||
@@ -195,13 +189,11 @@ def run_analysis(checkpoint: bool | None = None, portfolio=None):
|
|||||||
)
|
)
|
||||||
update_display(layout, stats_handler=stats_handler, start_time=start_time)
|
update_display(layout, stats_handler=stats_handler, start_time=start_time)
|
||||||
|
|
||||||
# Update agent status to in_progress for the first analyst
|
|
||||||
first_analyst = analyst_execution_plan.specs[0].agent_node
|
first_analyst = analyst_execution_plan.specs[0].agent_node
|
||||||
message_buffer.update_agent_status(first_analyst, "in_progress")
|
message_buffer.update_agent_status(first_analyst, "in_progress")
|
||||||
analyst_wall_time_tracker.mark_started(selected_analyst_keys[0])
|
analyst_wall_time_tracker.mark_started(selected_analyst_keys[0])
|
||||||
update_display(layout, stats_handler=stats_handler, start_time=start_time)
|
update_display(layout, stats_handler=stats_handler, start_time=start_time)
|
||||||
|
|
||||||
# Create spinner text
|
|
||||||
spinner_text = (
|
spinner_text = (
|
||||||
f"Analyzing {selections['ticker']} on {selections['analysis_date']}..."
|
f"Analyzing {selections['ticker']} on {selections['analysis_date']}..."
|
||||||
)
|
)
|
||||||
@@ -232,7 +224,6 @@ def run_analysis(checkpoint: bool | None = None, portfolio=None):
|
|||||||
trace = []
|
trace = []
|
||||||
try:
|
try:
|
||||||
for chunk in graph.graph.stream(graph.checkpoint_input(init_agent_state), **args):
|
for chunk in graph.graph.stream(graph.checkpoint_input(init_agent_state), **args):
|
||||||
# Process all messages in chunk, deduplicating by message ID
|
|
||||||
for message in chunk.get("messages", []):
|
for message in chunk.get("messages", []):
|
||||||
msg_id = getattr(message, "id", None)
|
msg_id = getattr(message, "id", None)
|
||||||
if msg_id is not None:
|
if msg_id is not None:
|
||||||
@@ -251,7 +242,6 @@ def run_analysis(checkpoint: bool | None = None, portfolio=None):
|
|||||||
else:
|
else:
|
||||||
message_buffer.add_tool_call(tool_call.name, tool_call.args)
|
message_buffer.add_tool_call(tool_call.name, tool_call.args)
|
||||||
|
|
||||||
# Update analyst statuses based on report state (runs on every chunk)
|
|
||||||
update_analyst_statuses(
|
update_analyst_statuses(
|
||||||
message_buffer,
|
message_buffer,
|
||||||
chunk,
|
chunk,
|
||||||
@@ -328,7 +318,6 @@ def run_analysis(checkpoint: bool | None = None, portfolio=None):
|
|||||||
message_buffer.update_agent_status("Neutral Analyst", "completed")
|
message_buffer.update_agent_status("Neutral Analyst", "completed")
|
||||||
message_buffer.update_agent_status("Portfolio Manager", "completed")
|
message_buffer.update_agent_status("Portfolio Manager", "completed")
|
||||||
|
|
||||||
# Update the display
|
|
||||||
update_display(layout, stats_handler=stats_handler, start_time=start_time)
|
update_display(layout, stats_handler=stats_handler, start_time=start_time)
|
||||||
|
|
||||||
trace.append(chunk)
|
trace.append(chunk)
|
||||||
@@ -350,7 +339,6 @@ def run_analysis(checkpoint: bool | None = None, portfolio=None):
|
|||||||
# Always restore the plain uncheckpointed graph, even on failure.
|
# Always restore the plain uncheckpointed graph, even on failure.
|
||||||
graph.end_checkpoint()
|
graph.end_checkpoint()
|
||||||
|
|
||||||
# Update all agent statuses to completed
|
|
||||||
for agent in message_buffer.agent_status:
|
for agent in message_buffer.agent_status:
|
||||||
message_buffer.update_agent_status(agent, "completed")
|
message_buffer.update_agent_status(agent, "completed")
|
||||||
|
|
||||||
@@ -359,7 +347,6 @@ def run_analysis(checkpoint: bool | None = None, portfolio=None):
|
|||||||
)
|
)
|
||||||
message_buffer.add_message("System", analyst_wall_time_tracker.format_summary())
|
message_buffer.add_message("System", analyst_wall_time_tracker.format_summary())
|
||||||
|
|
||||||
# Update final report sections
|
|
||||||
for section in message_buffer.report_sections:
|
for section in message_buffer.report_sections:
|
||||||
if section in final_state:
|
if section in final_state:
|
||||||
message_buffer.update_report_section(section, final_state[section])
|
message_buffer.update_report_section(section, final_state[section])
|
||||||
|
|||||||
@@ -45,11 +45,9 @@ def get_user_selections():
|
|||||||
|
|
||||||
def _prompt_selections(prefs):
|
def _prompt_selections(prefs):
|
||||||
"""Walk the selection steps. ``prefs`` prefills, the environment skips."""
|
"""Walk the selection steps. ``prefs`` prefills, the environment skips."""
|
||||||
# Display ASCII art welcome message
|
|
||||||
with open(Path(__file__).parent / "static" / "welcome.txt", encoding="utf-8") as f:
|
with open(Path(__file__).parent / "static" / "welcome.txt", encoding="utf-8") as f:
|
||||||
welcome_ascii = f.read()
|
welcome_ascii = f.read()
|
||||||
|
|
||||||
# Create welcome box content
|
|
||||||
welcome_content = f"{welcome_ascii}\n"
|
welcome_content = f"{welcome_ascii}\n"
|
||||||
welcome_content += "[bold green]TradingAgents: Multi-Agents LLM Financial Trading Framework - CLI[/bold green]\n\n"
|
welcome_content += "[bold green]TradingAgents: Multi-Agents LLM Financial Trading Framework - CLI[/bold green]\n\n"
|
||||||
welcome_content += "[bold]Workflow Steps:[/bold]\n"
|
welcome_content += "[bold]Workflow Steps:[/bold]\n"
|
||||||
@@ -58,7 +56,6 @@ def _prompt_selections(prefs):
|
|||||||
"[dim]Built by [Tauric Research](https://github.com/TauricResearch)[/dim]"
|
"[dim]Built by [Tauric Research](https://github.com/TauricResearch)[/dim]"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create and center the welcome box
|
|
||||||
welcome_box = Panel(
|
welcome_box = Panel(
|
||||||
welcome_content,
|
welcome_content,
|
||||||
border_style="green",
|
border_style="green",
|
||||||
@@ -74,7 +71,6 @@ def _prompt_selections(prefs):
|
|||||||
announcements = fetch_announcements()
|
announcements = fetch_announcements()
|
||||||
display_announcements(console, announcements)
|
display_announcements(console, announcements)
|
||||||
|
|
||||||
# Create a boxed questionnaire for each step
|
|
||||||
def create_question_box(title, prompt, default=None):
|
def create_question_box(title, prompt, default=None):
|
||||||
box_content = f"[bold]{title}[/bold]\n"
|
box_content = f"[bold]{title}[/bold]\n"
|
||||||
box_content += f"[dim]{prompt}[/dim]"
|
box_content += f"[dim]{prompt}[/dim]"
|
||||||
|
|||||||
@@ -61,5 +61,4 @@ def get_config() -> dict:
|
|||||||
return deepcopy(_config)
|
return deepcopy(_config)
|
||||||
|
|
||||||
|
|
||||||
# Initialize with default config
|
|
||||||
initialize_config()
|
initialize_config()
|
||||||
|
|||||||
@@ -83,7 +83,6 @@ def get_indicator(
|
|||||||
series_type = required_series_type
|
series_type = required_series_type
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Get indicator data for the period
|
|
||||||
if indicator == "close_50_sma":
|
if indicator == "close_50_sma":
|
||||||
data = _make_api_request("SMA", {
|
data = _make_api_request("SMA", {
|
||||||
"symbol": symbol,
|
"symbol": symbol,
|
||||||
@@ -146,12 +145,10 @@ def get_indicator(
|
|||||||
symbol, symbol, f"Alpha Vantage does not serve the {indicator} indicator"
|
symbol, symbol, f"Alpha Vantage does not serve the {indicator} indicator"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Parse CSV data and extract values for the date range
|
|
||||||
lines = data.strip().split('\n')
|
lines = data.strip().split('\n')
|
||||||
if len(lines) < 2:
|
if len(lines) < 2:
|
||||||
return f"Error: No data returned for {indicator}"
|
return f"Error: No data returned for {indicator}"
|
||||||
|
|
||||||
# Parse header and data
|
|
||||||
header = [col.strip() for col in lines[0].split(',')]
|
header = [col.strip() for col in lines[0].split(',')]
|
||||||
try:
|
try:
|
||||||
date_col_idx = header.index('time')
|
date_col_idx = header.index('time')
|
||||||
@@ -185,10 +182,8 @@ def get_indicator(
|
|||||||
if len(values) > value_col_idx:
|
if len(values) > value_col_idx:
|
||||||
try:
|
try:
|
||||||
date_str = values[date_col_idx].strip()
|
date_str = values[date_col_idx].strip()
|
||||||
# Parse the date
|
|
||||||
date_dt = datetime.strptime(date_str, "%Y-%m-%d")
|
date_dt = datetime.strptime(date_str, "%Y-%m-%d")
|
||||||
|
|
||||||
# Check if date is in our range
|
|
||||||
if before <= date_dt <= curr_date_dt:
|
if before <= date_dt <= curr_date_dt:
|
||||||
value = values[value_col_idx].strip()
|
value = values[value_col_idx].strip()
|
||||||
result_data.append((date_dt, value))
|
result_data.append((date_dt, value))
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ def get_stock(
|
|||||||
Returns:
|
Returns:
|
||||||
CSV string containing the daily adjusted time series data filtered to the date range.
|
CSV string containing the daily adjusted time series data filtered to the date range.
|
||||||
"""
|
"""
|
||||||
# Parse dates to determine the range
|
|
||||||
start_dt = datetime.strptime(start_date, "%Y-%m-%d")
|
start_dt = datetime.strptime(start_date, "%Y-%m-%d")
|
||||||
today = datetime.now()
|
today = datetime.now()
|
||||||
|
|
||||||
|
|||||||
@@ -180,7 +180,6 @@ def get_stock_stats_indicators_window(
|
|||||||
date_values.append((date_str, indicator_value))
|
date_values.append((date_str, indicator_value))
|
||||||
current_dt = current_dt - relativedelta(days=1)
|
current_dt = current_dt - relativedelta(days=1)
|
||||||
|
|
||||||
# Build the result string
|
|
||||||
ind_string = ""
|
ind_string = ""
|
||||||
for date_str, value in date_values:
|
for date_str, value in date_values:
|
||||||
ind_string += f"{date_str}: {value}\n"
|
ind_string += f"{date_str}: {value}\n"
|
||||||
@@ -225,16 +224,13 @@ def _get_stock_stats_bulk(
|
|||||||
df = wrap(data)
|
df = wrap(data)
|
||||||
df["Date"] = df["Date"].dt.strftime("%Y-%m-%d")
|
df["Date"] = df["Date"].dt.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
# Calculate the indicator for all rows at once
|
|
||||||
df[indicator] # This triggers stockstats to calculate the indicator
|
df[indicator] # This triggers stockstats to calculate the indicator
|
||||||
|
|
||||||
# Create a dictionary mapping date strings to indicator values
|
|
||||||
result_dict = {}
|
result_dict = {}
|
||||||
for _, row in df.iterrows():
|
for _, row in df.iterrows():
|
||||||
date_str = row["Date"]
|
date_str = row["Date"]
|
||||||
indicator_value = row[indicator]
|
indicator_value = row[indicator]
|
||||||
|
|
||||||
# Handle NaN/None values
|
|
||||||
if pd.isna(indicator_value):
|
if pd.isna(indicator_value):
|
||||||
result_dict[date_str] = "N/A"
|
result_dict[date_str] = "N/A"
|
||||||
else:
|
else:
|
||||||
@@ -274,7 +270,6 @@ def get_stockstats_indicator(
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_closes(symbol: str, start_date: str, end_date: str) -> pd.Series:
|
def get_closes(symbol: str, start_date: str, end_date: str) -> pd.Series:
|
||||||
"""Daily closes from ``start_date`` up to, not including, ``end_date``."""
|
"""Daily closes from ``start_date`` up to, not including, ``end_date``."""
|
||||||
canonical = normalize_symbol(symbol)
|
canonical = normalize_symbol(symbol)
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ from tradingagents.dataflows.vendors.yahoo.ohlcv import yf_retry
|
|||||||
|
|
||||||
def _extract_article_data(article: dict) -> dict:
|
def _extract_article_data(article: dict) -> dict:
|
||||||
"""Extract article data from yfinance news format (handles nested 'content' structure)."""
|
"""Extract article data from yfinance news format (handles nested 'content' structure)."""
|
||||||
# Handle nested content structure
|
|
||||||
if "content" in article:
|
if "content" in article:
|
||||||
content = article["content"]
|
content = article["content"]
|
||||||
title = content.get("title", "No title")
|
title = content.get("title", "No title")
|
||||||
@@ -23,11 +22,9 @@ def _extract_article_data(article: dict) -> dict:
|
|||||||
provider = content.get("provider", {})
|
provider = content.get("provider", {})
|
||||||
publisher = provider.get("displayName", "Unknown")
|
publisher = provider.get("displayName", "Unknown")
|
||||||
|
|
||||||
# Get URL from canonicalUrl or clickThroughUrl
|
|
||||||
url_obj = content.get("canonicalUrl") or content.get("clickThroughUrl") or {}
|
url_obj = content.get("canonicalUrl") or content.get("clickThroughUrl") or {}
|
||||||
link = url_obj.get("url", "")
|
link = url_obj.get("url", "")
|
||||||
|
|
||||||
# Get publish date
|
|
||||||
pub_date_str = content.get("pubDate", "")
|
pub_date_str = content.get("pubDate", "")
|
||||||
pub_date = None
|
pub_date = None
|
||||||
if pub_date_str:
|
if pub_date_str:
|
||||||
@@ -87,7 +84,6 @@ def get_news_yfinance(
|
|||||||
stock = yf.Ticker(canonical)
|
stock = yf.Ticker(canonical)
|
||||||
news = yf_retry(lambda: stock.get_news(count=article_limit)) or []
|
news = yf_retry(lambda: stock.get_news(count=article_limit)) or []
|
||||||
|
|
||||||
# Parse date range for filtering
|
|
||||||
start_dt = datetime.strptime(start_date, "%Y-%m-%d")
|
start_dt = datetime.strptime(start_date, "%Y-%m-%d")
|
||||||
end_dt = datetime.strptime(end_date, "%Y-%m-%d")
|
end_dt = datetime.strptime(end_date, "%Y-%m-%d")
|
||||||
|
|
||||||
|
|||||||
@@ -154,7 +154,6 @@ class TradingMemoryLog:
|
|||||||
and tag_line.startswith(pending_prefix)
|
and tag_line.startswith(pending_prefix)
|
||||||
and tag_line.endswith("| pending]")
|
and tag_line.endswith("| pending]")
|
||||||
):
|
):
|
||||||
# Parse rating from the existing pending tag
|
|
||||||
fields = [f.strip() for f in tag_line[1:-1].split("|")]
|
fields = [f.strip() for f in tag_line[1:-1].split("|")]
|
||||||
rating = fields[2]
|
rating = fields[2]
|
||||||
new_tag = self._resolved_tag(
|
new_tag = self._resolved_tag(
|
||||||
@@ -189,7 +188,6 @@ class TradingMemoryLog:
|
|||||||
text = self._log_path.read_text(encoding="utf-8")
|
text = self._log_path.read_text(encoding="utf-8")
|
||||||
blocks = text.split(self._SEPARATOR)
|
blocks = text.split(self._SEPARATOR)
|
||||||
|
|
||||||
# Build lookup keyed by (trade_date, ticker) for O(1) dispatch
|
|
||||||
update_map = {(u["trade_date"], u["ticker"]): u for u in updates}
|
update_map = {(u["trade_date"], u["ticker"]): u for u in updates}
|
||||||
|
|
||||||
new_blocks = []
|
new_blocks = []
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# TradingAgents/graph/__init__.py
|
|
||||||
|
|
||||||
from .conditional_logic import ConditionalLogic
|
from .conditional_logic import ConditionalLogic
|
||||||
from .propagation import Propagator
|
from .propagation import Propagator
|
||||||
from .reflection import Reflector
|
from .reflection import Reflector
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# TradingAgents/graph/conditional_logic.py
|
|
||||||
|
|
||||||
from tradingagents.agents.state import AgentState
|
from tradingagents.agents.state import AgentState
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# TradingAgents/graph/propagation.py
|
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from tradingagents.agents.state import InvestDebateState, RiskDebateState
|
from tradingagents.agents.state import InvestDebateState, RiskDebateState
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# TradingAgents/graph/reflection.py
|
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# TradingAgents/graph/setup.py
|
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from langgraph.graph import END, START, StateGraph
|
from langgraph.graph import END, START, StateGraph
|
||||||
@@ -84,29 +82,24 @@ class GraphSetup:
|
|||||||
"fundamentals": lambda: create_fundamentals_analyst(self.quick_thinking_llm),
|
"fundamentals": lambda: create_fundamentals_analyst(self.quick_thinking_llm),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Create researcher and manager nodes
|
|
||||||
bull_researcher_node = create_bull_researcher(self.quick_thinking_llm)
|
bull_researcher_node = create_bull_researcher(self.quick_thinking_llm)
|
||||||
bear_researcher_node = create_bear_researcher(self.quick_thinking_llm)
|
bear_researcher_node = create_bear_researcher(self.quick_thinking_llm)
|
||||||
research_manager_node = create_research_manager(self.deep_thinking_llm)
|
research_manager_node = create_research_manager(self.deep_thinking_llm)
|
||||||
trader_node = create_trader(self.quick_thinking_llm)
|
trader_node = create_trader(self.quick_thinking_llm)
|
||||||
|
|
||||||
# Create risk analysis nodes
|
|
||||||
aggressive_analyst = create_aggressive_debator(self.quick_thinking_llm)
|
aggressive_analyst = create_aggressive_debator(self.quick_thinking_llm)
|
||||||
neutral_analyst = create_neutral_debator(self.quick_thinking_llm)
|
neutral_analyst = create_neutral_debator(self.quick_thinking_llm)
|
||||||
conservative_analyst = create_conservative_debator(self.quick_thinking_llm)
|
conservative_analyst = create_conservative_debator(self.quick_thinking_llm)
|
||||||
portfolio_manager_node = create_portfolio_manager(self.deep_thinking_llm)
|
portfolio_manager_node = create_portfolio_manager(self.deep_thinking_llm)
|
||||||
|
|
||||||
# Create workflow
|
|
||||||
workflow = StateGraph(AgentState)
|
workflow = StateGraph(AgentState)
|
||||||
|
|
||||||
# Add analyst nodes to the graph
|
|
||||||
for spec in plan.specs:
|
for spec in plan.specs:
|
||||||
workflow.add_node(spec.agent_node, analyst_factories[spec.key]())
|
workflow.add_node(spec.agent_node, analyst_factories[spec.key]())
|
||||||
workflow.add_node(spec.clear_node, create_msg_delete())
|
workflow.add_node(spec.clear_node, create_msg_delete())
|
||||||
if spec.tools:
|
if spec.tools:
|
||||||
workflow.add_node(spec.tool_node, ToolNode(list(spec.tools)))
|
workflow.add_node(spec.tool_node, ToolNode(list(spec.tools)))
|
||||||
|
|
||||||
# Add other nodes
|
|
||||||
workflow.add_node("Bull Researcher", bull_researcher_node)
|
workflow.add_node("Bull Researcher", bull_researcher_node)
|
||||||
workflow.add_node("Bear Researcher", bear_researcher_node)
|
workflow.add_node("Bear Researcher", bear_researcher_node)
|
||||||
workflow.add_node("Research Manager", research_manager_node)
|
workflow.add_node("Research Manager", research_manager_node)
|
||||||
@@ -116,11 +109,8 @@ class GraphSetup:
|
|||||||
workflow.add_node("Conservative Analyst", conservative_analyst)
|
workflow.add_node("Conservative Analyst", conservative_analyst)
|
||||||
workflow.add_node("Portfolio Manager", portfolio_manager_node)
|
workflow.add_node("Portfolio Manager", portfolio_manager_node)
|
||||||
|
|
||||||
# Define edges
|
|
||||||
# Start with the first analyst
|
|
||||||
workflow.add_edge(START, plan.specs[0].agent_node)
|
workflow.add_edge(START, plan.specs[0].agent_node)
|
||||||
|
|
||||||
# Connect analysts in sequence
|
|
||||||
for i, spec in enumerate(plan.specs):
|
for i, spec in enumerate(plan.specs):
|
||||||
if spec.tools:
|
if spec.tools:
|
||||||
workflow.add_conditional_edges(
|
workflow.add_conditional_edges(
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# TradingAgents/graph/trading_graph.py
|
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
@@ -64,17 +62,13 @@ class TradingAgentsGraph:
|
|||||||
self.config = config or DEFAULT_CONFIG
|
self.config = config or DEFAULT_CONFIG
|
||||||
self.callbacks = callbacks or []
|
self.callbacks = callbacks or []
|
||||||
|
|
||||||
# Update the interface's config
|
|
||||||
set_config(self.config)
|
set_config(self.config)
|
||||||
|
|
||||||
# Create necessary directories
|
|
||||||
os.makedirs(self.config["data_cache_dir"], exist_ok=True)
|
os.makedirs(self.config["data_cache_dir"], exist_ok=True)
|
||||||
os.makedirs(self.config["results_dir"], exist_ok=True)
|
os.makedirs(self.config["results_dir"], exist_ok=True)
|
||||||
|
|
||||||
# Initialize LLMs with provider-specific thinking configuration
|
|
||||||
llm_kwargs = build_llm_kwargs(self.config)
|
llm_kwargs = build_llm_kwargs(self.config)
|
||||||
|
|
||||||
# Add callbacks to kwargs if provided (passed to LLM constructor)
|
|
||||||
if self.callbacks:
|
if self.callbacks:
|
||||||
llm_kwargs["callbacks"] = self.callbacks
|
llm_kwargs["callbacks"] = self.callbacks
|
||||||
|
|
||||||
@@ -96,7 +90,6 @@ class TradingAgentsGraph:
|
|||||||
|
|
||||||
self.memory_log = TradingMemoryLog(self.config)
|
self.memory_log = TradingMemoryLog(self.config)
|
||||||
|
|
||||||
# Initialize components
|
|
||||||
self.conditional_logic = ConditionalLogic(
|
self.conditional_logic = ConditionalLogic(
|
||||||
max_debate_rounds=self.config["max_debate_rounds"],
|
max_debate_rounds=self.config["max_debate_rounds"],
|
||||||
max_risk_discuss_rounds=self.config["max_risk_discuss_rounds"],
|
max_risk_discuss_rounds=self.config["max_risk_discuss_rounds"],
|
||||||
|
|||||||
Reference in New Issue
Block a user