From 20e0c6a2d9cc8d7845d9d7d7961f84972989542d Mon Sep 17 00:00:00 2001 From: MarkLo Date: Thu, 11 Dec 2025 13:46:33 +0800 Subject: [PATCH] --- backend/app/services/trading_service.py | 4 ++ tradingagents/dataflows/interface.py | 3 +- tradingagents/dataflows/y_finance.py | 73 +++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/backend/app/services/trading_service.py b/backend/app/services/trading_service.py index 7f518e30..73fa4283 100644 --- a/backend/app/services/trading_service.py +++ b/backend/app/services/trading_service.py @@ -90,6 +90,10 @@ class TradingService: if alpha_vantage_api_key: os.environ["ALPHA_VANTAGE_API_KEY"] = alpha_vantage_api_key + # Set OpenAI API key for dataflows (openai.py reads from env var) + if openai_api_key: + os.environ["OPENAI_API_KEY"] = openai_api_key + # Create configuration logger.info(f"Initializing TradingAgentsX for {ticker} on {analysis_date}") config = self.create_config(research_depth, deep_think_llm, quick_think_llm) diff --git a/tradingagents/dataflows/interface.py b/tradingagents/dataflows/interface.py index 9b9aeaff..a227b054 100644 --- a/tradingagents/dataflows/interface.py +++ b/tradingagents/dataflows/interface.py @@ -2,7 +2,7 @@ from typing import Annotated # 從特定供應商的模組匯入 from .local import get_YFin_data, get_finnhub_news, get_finnhub_company_insider_sentiment, get_finnhub_company_insider_transactions, get_simfin_balance_sheet, get_simfin_cashflow, get_simfin_income_statements, get_reddit_global_news, get_reddit_company_news -from .y_finance import get_YFin_data_online, get_stock_stats_indicators_window, get_balance_sheet as get_yfinance_balance_sheet, get_cashflow as get_yfinance_cashflow, get_income_statement as get_yfinance_income_statement, get_insider_transactions as get_yfinance_insider_transactions +from .y_finance import get_YFin_data_online, get_stock_stats_indicators_window, get_balance_sheet as get_yfinance_balance_sheet, get_cashflow as get_yfinance_cashflow, get_income_statement as get_yfinance_income_statement, get_insider_transactions as get_yfinance_insider_transactions, get_fundamentals as get_yfinance_fundamentals from .google import get_google_news from .openai import get_stock_news_openai, get_global_news_openai, get_fundamentals_openai from .alpha_vantage import ( @@ -79,6 +79,7 @@ VENDOR_METHODS = { "get_fundamentals": { "alpha_vantage": get_alpha_vantage_fundamentals, "openai": get_fundamentals_openai, + "yfinance": get_yfinance_fundamentals, }, "get_balance_sheet": { "alpha_vantage": get_alpha_vantage_balance_sheet, diff --git a/tradingagents/dataflows/y_finance.py b/tradingagents/dataflows/y_finance.py index 40906043..f8cf8820 100644 --- a/tradingagents/dataflows/y_finance.py +++ b/tradingagents/dataflows/y_finance.py @@ -466,6 +466,79 @@ def get_income_statement( return f"檢索 {ticker} 的損益表時出錯:{str(e)}" +def get_fundamentals( + ticker: Annotated[str, "公司的股票代碼"], + curr_date: Annotated[str, "當前日期 (yfinance 未使用)"] = None +): + """從 yfinance 獲取公司基本面數據。""" + try: + ticker_obj = yf.Ticker(ticker.upper()) + info = ticker_obj.info + + if not info or len(info) == 0: + return f"找不到 '{ticker}' 的基本面數據" + + # 提取關鍵基本面指標(與 alpha_vantage 格式相似) + fundamentals = { + # 基本資訊 + "Symbol": info.get("symbol", ticker.upper()), + "Name": info.get("longName", info.get("shortName", "")), + "Description": (info.get("longBusinessSummary", "") or "")[:300], + "Sector": info.get("sector", ""), + "Industry": info.get("industry", ""), + "MarketCapitalization": info.get("marketCap", ""), + + # 關鍵財務指標 + "EBITDA": info.get("ebitda", ""), + "PERatio": info.get("trailingPE", info.get("forwardPE", "")), + "PEGRatio": info.get("pegRatio", ""), + "BookValue": info.get("bookValue", ""), + "DividendPerShare": info.get("dividendRate", ""), + "DividendYield": info.get("dividendYield", ""), + "EPS": info.get("trailingEps", ""), + "RevenuePerShareTTM": info.get("revenuePerShare", ""), + "ProfitMargin": info.get("profitMargins", ""), + "OperatingMarginTTM": info.get("operatingMargins", ""), + "ReturnOnAssetsTTM": info.get("returnOnAssets", ""), + "ReturnOnEquityTTM": info.get("returnOnEquity", ""), + "RevenueTTM": info.get("totalRevenue", ""), + "GrossProfitTTM": info.get("grossProfits", ""), + + # 交易指標 + "52WeekHigh": info.get("fiftyTwoWeekHigh", ""), + "52WeekLow": info.get("fiftyTwoWeekLow", ""), + "50DayMovingAverage": info.get("fiftyDayAverage", ""), + "200DayMovingAverage": info.get("twoHundredDayAverage", ""), + + # 財務健康指標 + "QuarterlyEarningsGrowthYOY": info.get("earningsQuarterlyGrowth", ""), + "QuarterlyRevenueGrowthYOY": info.get("revenueGrowth", ""), + "AnalystTargetPrice": info.get("targetMeanPrice", ""), + "Beta": info.get("beta", ""), + + # 額外的 yfinance 特有指標 + "CurrentPrice": info.get("currentPrice", info.get("regularMarketPrice", "")), + "DebtToEquity": info.get("debtToEquity", ""), + "CurrentRatio": info.get("currentRatio", ""), + "QuickRatio": info.get("quickRatio", ""), + "FreeCashFlow": info.get("freeCashflow", ""), + } + + # 過濾掉空值和 None + fundamentals = {k: v for k, v in fundamentals.items() if v not in (None, "", "None")} + + import json + + # 新增標頭資訊 + header = f"# {ticker.upper()} 的基本面數據 (來源: yfinance)\n" + header += f"# 數據檢索時間:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n" + + return header + json.dumps(fundamentals, ensure_ascii=False, indent=2) + + except Exception as e: + return f"檢索 {ticker} 的基本面數據時出錯:{str(e)}" + + def get_insider_transactions( ticker: Annotated[str, "公司的股票代碼"] ):