Compare commits
3 Commits
b30e3f14a7
...
d751fa3d4b
| Author | SHA1 | Date |
|---|---|---|
|
|
d751fa3d4b | |
|
|
f0d7e6824f | |
|
|
264e792295 |
49
cli/main.py
49
cli/main.py
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
[
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue