Compare commits

...

3 Commits

Author SHA1 Message Date
Alex Korbonits d751fa3d4b fix: narrow E501 ignores and add ruff/pytest dev dependencies
- Replace broad tradingagents/**/*.py E501 ignore with targeted
  per-file ignores for agent files (LLM prompts), alpha_vantage_indicator,
  y_finance (description strings), and reflection (prompt constant)
- Fix the two genuine logic-code E501 violations: break long log message
  in stockstats_utils.py and ternary in yfinance_news.py
- Correct pytest version bound to >=8.3.0 (stable floor)
- Add ruff>=0.9.0 as dev dependency for local linter execution

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 22:56:46 -07:00
Alex Korbonits f0d7e6824f fix: address Gemini re-review feedback
- Reorganise cli/main.py imports: move load_dotenv() after all imports
  so isort can sort cleanly; removes need for global E402 ignore
- Remove dead graph.process_signal() call (discarded LLM result)
- Drop E501 and E402 from global ruff ignore; fix resulting violations
  in cli/main.py and cli/utils.py; add per-file E501 ignore for
  tradingagents/** where LLM system prompt strings are intentionally long
- Remove # noqa: I001 from alpha_vantage.py; let isort sort alphabetically

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 22:28:18 -07:00
Alex Korbonits 264e792295 fix: restore facade imports and address PR review feedback
- Restore alpha_vantage.py facade with explicit re-exports and __all__
- Restore agent_utils.py tool facade imports and expand __all__ to cover
  all public names (prevents auto-fixer stripping re-exports in future)
- Consolidate fragmented per-function import blocks in interface.py into
  single blocks; add combine-as-imports = true to ruff isort config
- Enable F403, F405, F841 in Ruff (remove from ignore list) and fix all
  resulting violations: replace star imports in cli/main.py, setup.py,
  and trading_graph.py with explicit imports; drop unused live/decision
  assignments

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 20:47:47 -07:00
11 changed files with 452 additions and 1567 deletions

View File

@ -1,18 +1,14 @@
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
@ -24,10 +20,23 @@ from rich.text import Text
from cli.announcements import display_announcements, fetch_announcements
from cli.stats_handler import StatsCallbackHandler
from cli.utils import *
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 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(
@ -467,7 +476,9 @@ 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]"
)
@ -500,7 +511,8 @@ 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",
)
)
@ -718,7 +730,8 @@ 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
header = f"# Trading Analysis Report: {ticker}\n\nGenerated: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n"
generated = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
header = f"# Trading Analysis Report: {ticker}\n\nGenerated: {generated}\n\n"
(save_path / "complete_report.md").write_text(header + "\n\n".join(sections))
return save_path / "complete_report.md"
@ -761,7 +774,10 @@ 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"):
@ -781,7 +797,10 @@ 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):
@ -1013,7 +1032,7 @@ def run_analysis():
# Now start the display layout
layout = create_layout()
with Live(layout, refresh_per_second=4) as live:
with Live(layout, refresh_per_second=4):
# Initial display
update_display(layout, stats_handler=stats_handler, start_time=start_time)
@ -1152,9 +1171,7 @@ 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,7 +83,11 @@ 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,10 +46,26 @@ line-length = 120
[tool.ruff.lint]
select = ["E", "F", "I"]
ignore = ["E501", "E402", "E731", "F403", "F405", "F841"]
ignore = ["E731"]
[tool.ruff.lint.isort]
combine-as-imports = true
[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,6 +1,34 @@
from langchain_core.messages import HumanMessage, RemoveMessage
# Import tools from separate utility files
# 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",
]
def get_language_instruction() -> str:

View File

@ -1 +1,26 @@
# 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,29 +2,13 @@
# 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
@ -33,20 +17,10 @@ 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,7 +26,10 @@ 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 (attempt {attempt + 1}/{max_retries})")
logger.warning(
f"Yahoo Finance rate limited, retrying in {delay:.0f}s"
f" (attempt {attempt + 1}/{max_retries})"
)
time.sleep(delay)
else:
raise

View File

@ -172,7 +172,11 @@ 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,7 +5,21 @@ from typing import Any, Dict
from langgraph.graph import END, START, StateGraph
from langgraph.prebuilt import ToolNode
from tradingagents.agents import *
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.utils.agent_states import AgentState
from .conditional_logic import ConditionalLogic

View File

@ -7,8 +7,6 @@ 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,

1836
uv.lock

File diff suppressed because it is too large Load Diff