This commit is contained in:
MarkLo 2025-12-14 21:26:36 +08:00
parent 2143b02541
commit e8b6919179
2 changed files with 155 additions and 25 deletions

View File

@ -29,6 +29,7 @@ from tradingagents.graph.trading_graph import TradingAgentsXGraph
from tradingagents.default_config import DEFAULT_CONFIG
from cli.models import AnalystType
from cli.utils import *
from cli.utils import select_market
# 初始化 rich Console
console = Console()
@ -447,29 +448,37 @@ def get_user_selections():
box_content += f"\n[dim]預設值: {default}[/dim]"
return Panel(box_content, border_style="blue", padding=(1, 2))
# 步驟 1股票代碼
# 步驟 1選擇市場
console.print(
create_question_box(
"步驟 1股票代碼", "輸入要分析的股票代碼", "SPY"
"步驟 1選擇市場", "選擇要分析的股票市場"
)
)
selected_ticker = get_ticker()
selected_market, default_ticker = select_market()
# 步驟 2分析日期
# 步驟 2股票代碼
console.print(
create_question_box(
"步驟 2股票代碼", "輸入要分析的股票代碼", default_ticker
)
)
selected_ticker = get_ticker(default_ticker)
# 步驟 3分析日期
default_date = datetime.datetime.now().strftime("%Y-%m-%d")
console.print(
create_question_box(
"步驟 2分析日期",
"步驟 3:分析日期",
"輸入分析日期 (YYYY-MM-DD)",
default_date,
)
)
analysis_date = get_analysis_date()
# 步驟 3:選擇分析師
# 步驟 4:選擇分析師
console.print(
create_question_box(
"步驟 3:分析師團隊", "為分析選擇您的 LLM 分析師代理"
"步驟 4:分析師團隊", "為分析選擇您的 LLM 分析師代理"
)
)
selected_analysts = select_analysts()
@ -477,59 +486,100 @@ def get_user_selections():
f"[green]已選分析師:[/green] {', '.join(analyst.value for analyst in selected_analysts)}"
)
# 步驟 4:研究深度
# 步驟 5:研究深度
console.print(
create_question_box(
"步驟 4:研究深度", "選擇您的研究深度等級"
"步驟 5:研究深度", "選擇您的研究深度等級"
)
)
selected_research_depth = select_research_depth()
# 步驟 5LLM 供應商
# 步驟 6LLM 供應商
console.print(
create_question_box(
"步驟 5LLM 供應商", "選擇要對話的服務"
"步驟 6LLM 供應商", "選擇要對話的服務"
)
)
selected_llm_provider, backend_url = select_llm_provider()
# 步驟 6:思維代理
# 步驟 7:思維代理
console.print(
create_question_box(
"步驟 6:思維代理", "為分析選擇您的思維代理"
"步驟 7:思維代理", "為分析選擇您的思維代理"
)
)
selected_shallow_thinker = select_shallow_thinking_agent(selected_llm_provider)
selected_deep_thinker = select_deep_thinking_agent(selected_llm_provider)
# 步驟 7:嵌入模型供應商
# 步驟 8:嵌入模型供應商
console.print(
create_question_box(
"步驟 7:嵌入模型供應商", "選擇嵌入模型服務(用於記憶體系統)"
"步驟 8:嵌入模型供應商", "選擇嵌入模型服務(用於記憶體系統)"
)
)
embedding_provider, embedding_url = select_embedding_provider()
# 步驟 8API Keys
# 步驟 9API Keys
console.print(
create_question_box(
"步驟 8API Keys", "輸入 API Keys可留空使用 .env 中的設定)"
"步驟 9API Keys", "輸入 API Keys可留空使用 .env 中的設定)"
)
)
import os
# 從 .env 讀取 API Key
default_openai_key = os.getenv("OPENAI_API_KEY")
# 定義供應商對應的環境變數名稱
PROVIDER_API_KEY_MAP = {
"openai": "OPENAI_API_KEY",
"anthropic": "ANTHROPIC_API_KEY",
"google": "GEMINI_API_KEY",
"grok": "XAI_API_KEY",
"deepseek": "DEEPSEEK_API_KEY",
"qwen": "DASHSCOPE_API_KEY",
"自訂供應商": "OPENAI_API_KEY", # 自訂供應商預設使用 OpenAI 格式
}
# 根據選擇的供應商獲取對應的 API Key 環境變數名稱
def get_provider_api_key(provider_name: str) -> str:
"""根據供應商名稱從 .env 讀取對應的 API Key"""
provider_lower = provider_name.lower()
env_var_name = PROVIDER_API_KEY_MAP.get(provider_lower, "OPENAI_API_KEY")
return os.getenv(env_var_name)
# 從選擇的快速思維模型名稱推斷供應商
def infer_provider_from_model(model_name: str) -> str:
"""根據模型名稱推斷供應商"""
model_lower = model_name.lower()
if "gpt" in model_lower or model_lower.startswith("o4"):
return "openai"
elif "claude" in model_lower:
return "anthropic"
elif "gemini" in model_lower:
return "google"
elif "grok" in model_lower:
return "grok"
elif "deepseek" in model_lower:
return "deepseek"
elif "qwen" in model_lower:
return "qwen"
return "openai" # 預設
# 根據模型推斷供應商並獲取對應的 API Key
quick_think_provider = infer_provider_from_model(selected_shallow_thinker)
deep_think_provider = infer_provider_from_model(selected_deep_thinker)
default_quick_think_key = get_provider_api_key(quick_think_provider)
default_deep_think_key = get_provider_api_key(deep_think_provider)
default_embedding_key = get_provider_api_key(embedding_provider)
# 快速思維模型 API Key
quick_think_api_key = get_api_key("快速思維模型", default_openai_key)
quick_think_api_key = get_api_key("快速思維模型", default_quick_think_key)
# 深度思維模型 API Key
deep_think_api_key = get_api_key("深度思維模型", default_openai_key)
deep_think_api_key = get_api_key("深度思維模型", default_deep_think_key)
# 嵌入模型 API Key
embedding_api_key = get_api_key("嵌入模型", default_openai_key)
embedding_api_key = get_api_key("嵌入模型", default_embedding_key)
# Alpha Vantage API Key必填
alpha_vantage_key = os.getenv("ALPHA_VANTAGE_API_KEY")
@ -548,6 +598,7 @@ def get_user_selections():
"backend_url": backend_url,
"shallow_thinker": selected_shallow_thinker,
"deep_thinker": selected_deep_thinker,
"market_type": selected_market,
"embedding_provider": embedding_provider,
"embedding_url": embedding_url,
"quick_think_api_key": quick_think_api_key,
@ -557,9 +608,13 @@ def get_user_selections():
}
def get_ticker():
"""從使用者輸入中獲取股票代碼。"""
ticker = typer.prompt("", default="SPY")
def get_ticker(default: str = "SPY"):
"""從使用者輸入中獲取股票代碼。
參數:
default (str): 預設的股票代碼美股預設 SPY台股預設 2330
"""
ticker = typer.prompt("", default=default)
# 防呆:將股票代碼轉換為大寫
ticker = ticker.strip().upper()
return ticker
@ -819,10 +874,40 @@ def run_analysis():
config["embedding_api_key"] = selections["embedding_api_key"]
config["embedding_base_url"] = selections["embedding_url"]
# 根據市場類型設定資料供應商
market_type = selections.get("market_type", "us")
if market_type == "tw":
# 台股使用 FinMind API
console.print("[cyan]📊 使用 FinMind API 獲取台股資料[/cyan]")
config["data_vendors"] = {
"core_stock_apis": "finmind", # 使用 FinMind 獲取股價
"technical_indicators": "finmind", # 使用 FinMind 獲取技術指標
"fundamental_data": "finmind", # 使用 FinMind 獲取基本面資料
"news_data": "finmind", # 使用 FinMind 獲取新聞
}
else:
# 美股使用 yfinance 和 Alpha Vantage
console.print("[cyan]📊 使用 yfinance / Alpha Vantage 獲取美股資料[/cyan]")
config["data_vendors"] = {
"core_stock_apis": "yfinance",
"technical_indicators": "yfinance",
"fundamental_data": "alpha_vantage",
"news_data": "openai",
}
# 設置環境變數(某些工具可能需要)
import os
os.environ["OPENAI_API_KEY"] = selections["quick_think_api_key"]
os.environ["ALPHA_VANTAGE_API_KEY"] = selections["alpha_vantage_api_key"]
# 如果是台股,還需要設置 FinMind API Key
if market_type == "tw":
finmind_key = os.getenv("FINMIND_API_KEY", "")
if finmind_key:
os.environ["FINMIND_API_KEY"] = finmind_key
console.print("[green]✓ 已載入 FinMind API Key[/green]")
else:
console.print("[yellow]⚠ 未找到 FINMIND_API_KEY部分功能可能受限[/yellow]")
# 初始化圖
graph = TradingAgentsXGraph(

View File

@ -131,6 +131,51 @@ def select_analysts() -> List[AnalystType]:
return choices
def select_market() -> tuple[str, str]:
"""
使用互動式選單選擇市場類型
返回:
tuple[str, str]: 包含市場類型代碼和預設股票代碼的元組
市場類型: "us" (美股) "tw" (台股)
預設股票: "SPY" (美股) "2330" (台股)
"""
# 定義市場選項
MARKET_OPTIONS = [
("🇺🇸 美股 (US Stocks)", ("us", "SPY")),
("🇹🇼 台股 (Taiwan Stocks)", ("tw", "2330")),
]
choice = questionary.select(
"選擇您要分析的市場:",
# 設定可選項
choices=[
questionary.Choice(display, value=value) for display, value in MARKET_OPTIONS
],
# 提供操作說明
instruction="\n- 使用方向鍵導覽\n- 按下 Enter 鍵選擇",
# 設定提示的樣式
style=questionary.Style(
[
("selected", "fg:cyan noinherit"),
("highlighted", "fg:cyan noinherit"),
("pointer", "fg:cyan noinherit"),
]
),
).ask()
# 如果使用者沒有選擇,則退出程式
if choice is None:
console.print("\n[red]未選擇市場。正在結束程式...[/red]")
exit(1)
market_type, default_ticker = choice
console.print(f"[green]已選擇:{'美股' if market_type == 'us' else '台股'}[/green]")
# 返回市場類型和預設股票代碼
return market_type, default_ticker
def select_research_depth() -> int:
"""
使用互動式選單選擇研究深度