Compare commits

..

No commits in common. "d751fa3d4b9e7ace03acabd5a9c689a0b90ee110" and "b30e3f14a71fe20ba89db9ba5c1dcb738ee43d35" have entirely different histories.

11 changed files with 1573 additions and 458 deletions

View File

@ -1,14 +1,18 @@
import datetime
import time
from collections import deque
from functools import wraps
from pathlib import Path
import typer
from dotenv import load_dotenv
from rich.console import Console
# Load environment variables from .env file
load_dotenv()
import time
from collections import deque
from rich import box
from rich.align import Align
from rich.console import Console
from rich.layout import Layout
from rich.live import Live
from rich.markdown import Markdown
@ -20,23 +24,10 @@ from rich.text import Text
from cli.announcements import display_announcements, fetch_announcements
from cli.stats_handler import StatsCallbackHandler
from cli.utils import (
ask_anthropic_effort,
ask_gemini_thinking_config,
ask_openai_reasoning_effort,
ask_output_language,
select_analysts,
select_deep_thinking_agent,
select_llm_provider,
select_research_depth,
select_shallow_thinking_agent,
)
from cli.utils import *
from tradingagents.default_config import DEFAULT_CONFIG
from tradingagents.graph.trading_graph import TradingAgentsGraph
# Load environment variables from .env file
load_dotenv()
console = Console()
app = typer.Typer(
@ -476,9 +467,7 @@ def get_user_selections():
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]Workflow Steps:[/bold]\n"
welcome_content += (
"I. Analyst Team → II. Research Team → III. Trader → IV. Risk Management → V. Portfolio Management\n\n"
)
welcome_content += "I. Analyst Team → II. Research Team → III. Trader → IV. Risk Management → V. Portfolio Management\n\n"
welcome_content += (
"[dim]Built by [Tauric Research](https://github.com/TauricResearch)[/dim]"
)
@ -511,8 +500,7 @@ def get_user_selections():
console.print(
create_question_box(
"Step 1: Ticker Symbol",
"Enter the exact ticker symbol to analyze, including exchange suffix when needed"
" (examples: SPY, CNC.TO, 7203.T, 0700.HK)",
"Enter the exact ticker symbol to analyze, including exchange suffix when needed (examples: SPY, CNC.TO, 7203.T, 0700.HK)",
"SPY",
)
)
@ -730,8 +718,7 @@ def save_report_to_disk(final_state, ticker: str, save_path: Path):
sections.append(f"## V. Portfolio Manager Decision\n\n### Portfolio Manager\n{risk['judge_decision']}")
# Write consolidated report
generated = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
header = f"# Trading Analysis Report: {ticker}\n\nGenerated: {generated}\n\n"
header = f"# Trading Analysis Report: {ticker}\n\nGenerated: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
(save_path / "complete_report.md").write_text(header + "\n\n".join(sections))
return save_path / "complete_report.md"
@ -774,10 +761,7 @@ def display_complete_report(final_state):
# III. Trading Team
if final_state.get("trader_investment_plan"):
console.print(Panel("[bold]III. Trading Team Plan[/bold]", border_style="yellow"))
console.print(Panel(
Markdown(final_state["trader_investment_plan"]),
title="Trader", border_style="blue", padding=(1, 2),
))
console.print(Panel(Markdown(final_state["trader_investment_plan"]), title="Trader", border_style="blue", padding=(1, 2)))
# IV. Risk Management Team
if final_state.get("risk_debate_state"):
@ -797,10 +781,7 @@ def display_complete_report(final_state):
# V. Portfolio Manager Decision
if risk.get("judge_decision"):
console.print(Panel("[bold]V. Portfolio Manager Decision[/bold]", border_style="green"))
console.print(Panel(
Markdown(risk["judge_decision"]),
title="Portfolio Manager", border_style="blue", padding=(1, 2),
))
console.print(Panel(Markdown(risk["judge_decision"]), title="Portfolio Manager", border_style="blue", padding=(1, 2)))
def update_research_team_status(status):
@ -1032,7 +1013,7 @@ def run_analysis():
# Now start the display layout
layout = create_layout()
with Live(layout, refresh_per_second=4):
with Live(layout, refresh_per_second=4) as live:
# Initial display
update_display(layout, stats_handler=stats_handler, start_time=start_time)
@ -1171,7 +1152,9 @@ def run_analysis():
trace.append(chunk)
# Get final state and decision
final_state = trace[-1]
decision = graph.process_signal(final_state["final_trade_decision"])
# Update all agent statuses to completed
for agent in message_buffer.agent_status:

View File

@ -83,11 +83,7 @@ def select_analysts() -> List[AnalystType]:
choices=[
questionary.Choice(display, value=value) for display, value in ANALYST_ORDER
],
instruction=(
"\n- Press Space to select/unselect analysts"
"\n- Press 'a' to select/unselect all"
"\n- Press Enter when done"
),
instruction="\n- Press Space to select/unselect analysts\n- Press 'a' to select/unselect all\n- Press Enter when done",
validate=lambda x: len(x) > 0 or "You must select at least one analyst.",
style=questionary.Style(
[

View File

@ -46,26 +46,10 @@ line-length = 120
[tool.ruff.lint]
select = ["E", "F", "I"]
ignore = ["E731"]
[tool.ruff.lint.isort]
combine-as-imports = true
ignore = ["E501", "E402", "E731", "F403", "F405", "F841"]
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]
# Agent files contain LLM system prompt strings that are intentionally long.
"tradingagents/agents/**/*.py" = ["E501"]
# These dataflow files contain long indicator/tool description strings, not logic code.
"tradingagents/dataflows/alpha_vantage_indicator.py" = ["E501"]
"tradingagents/dataflows/y_finance.py" = ["E501"]
# Reflection module contains a multi-line LLM prompt defined as a string constant.
"tradingagents/graph/reflection.py" = ["E501"]
[tool.uv]
[dependency-groups]
dev = [
"pytest>=8.3.0",
"ruff>=0.9.0",
]
# Install with: uv sync

View File

@ -1,34 +1,6 @@
from langchain_core.messages import HumanMessage, RemoveMessage
# Re-export tool functions so agent modules can import from a single location.
from tradingagents.agents.utils.core_stock_tools import get_stock_data
from tradingagents.agents.utils.fundamental_data_tools import (
get_balance_sheet,
get_cashflow,
get_fundamentals,
get_income_statement,
)
from tradingagents.agents.utils.news_data_tools import (
get_global_news,
get_insider_transactions,
get_news,
)
from tradingagents.agents.utils.technical_indicators_tools import get_indicators
__all__ = [
"get_stock_data",
"get_indicators",
"get_fundamentals",
"get_balance_sheet",
"get_cashflow",
"get_income_statement",
"get_news",
"get_insider_transactions",
"get_global_news",
"get_language_instruction",
"build_instrument_context",
"create_msg_delete",
]
# Import tools from separate utility files
def get_language_instruction() -> str:

View File

@ -1,26 +1 @@
# Import functions from specialized modules
from .alpha_vantage_fundamentals import (
get_balance_sheet,
get_cashflow,
get_fundamentals,
get_income_statement,
)
from .alpha_vantage_indicator import get_indicator
from .alpha_vantage_news import (
get_global_news,
get_insider_transactions,
get_news,
)
from .alpha_vantage_stock import get_stock
__all__ = [
"get_stock",
"get_indicator",
"get_fundamentals",
"get_balance_sheet",
"get_cashflow",
"get_income_statement",
"get_news",
"get_global_news",
"get_insider_transactions",
]

View File

@ -2,13 +2,29 @@
# Import from vendor-specific modules
from .alpha_vantage import (
get_balance_sheet as get_alpha_vantage_balance_sheet,
)
from .alpha_vantage import (
get_cashflow as get_alpha_vantage_cashflow,
)
from .alpha_vantage import (
get_fundamentals as get_alpha_vantage_fundamentals,
)
from .alpha_vantage import (
get_global_news as get_alpha_vantage_global_news,
)
from .alpha_vantage import (
get_income_statement as get_alpha_vantage_income_statement,
)
from .alpha_vantage import (
get_indicator as get_alpha_vantage_indicator,
)
from .alpha_vantage import (
get_insider_transactions as get_alpha_vantage_insider_transactions,
)
from .alpha_vantage import (
get_news as get_alpha_vantage_news,
)
from .alpha_vantage import (
get_stock as get_alpha_vantage_stock,
)
from .alpha_vantage_common import AlphaVantageRateLimitError
@ -17,10 +33,20 @@ from .alpha_vantage_common import AlphaVantageRateLimitError
from .config import get_config
from .y_finance import (
get_balance_sheet as get_yfinance_balance_sheet,
)
from .y_finance import (
get_cashflow as get_yfinance_cashflow,
)
from .y_finance import (
get_fundamentals as get_yfinance_fundamentals,
)
from .y_finance import (
get_income_statement as get_yfinance_income_statement,
)
from .y_finance import (
get_insider_transactions as get_yfinance_insider_transactions,
)
from .y_finance import (
get_stock_stats_indicators_window,
get_YFin_data_online,
)

View File

@ -26,10 +26,7 @@ def yf_retry(func, max_retries=3, base_delay=2.0):
except YFRateLimitError:
if attempt < max_retries:
delay = base_delay * (2 ** attempt)
logger.warning(
f"Yahoo Finance rate limited, retrying in {delay:.0f}s"
f" (attempt {attempt + 1}/{max_retries})"
)
logger.warning(f"Yahoo Finance rate limited, retrying in {delay:.0f}s (attempt {attempt + 1}/{max_retries})")
time.sleep(delay)
else:
raise

View File

@ -172,11 +172,7 @@ def get_global_news_yfinance(
data = _extract_article_data(article)
# Skip articles published after curr_date (look-ahead guard)
if data.get("pub_date"):
pub_naive = (
data["pub_date"].replace(tzinfo=None)
if hasattr(data["pub_date"], "replace")
else data["pub_date"]
)
pub_naive = data["pub_date"].replace(tzinfo=None) if hasattr(data["pub_date"], "replace") else data["pub_date"]
if pub_naive > curr_dt + relativedelta(days=1):
continue
title = data["title"]

View File

@ -5,21 +5,7 @@ from typing import Any, Dict
from langgraph.graph import END, START, StateGraph
from langgraph.prebuilt import ToolNode
from tradingagents.agents import (
create_aggressive_debator,
create_bear_researcher,
create_bull_researcher,
create_conservative_debator,
create_fundamentals_analyst,
create_market_analyst,
create_msg_delete,
create_neutral_debator,
create_news_analyst,
create_portfolio_manager,
create_research_manager,
create_social_media_analyst,
create_trader,
)
from tradingagents.agents import *
from tradingagents.agents.utils.agent_states import AgentState
from .conditional_logic import ConditionalLogic

View File

@ -7,6 +7,8 @@ from typing import Any, Dict, List, Optional
from langgraph.prebuilt import ToolNode
from tradingagents.agents import *
# Import the new abstract tool methods from agent_utils
from tradingagents.agents.utils.agent_utils import (
get_balance_sheet,

1848
uv.lock

File diff suppressed because it is too large Load Diff