Merge dazzling-leakey into main: GraphRecursionError fix and stock data validation
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
commit
3545e1574d
|
|
@ -205,7 +205,16 @@ class TradingService:
|
|||
"investment_debate_state": final_state.get("investment_debate_state"),
|
||||
"risk_debate_state": final_state.get("risk_debate_state"),
|
||||
}
|
||||
|
||||
|
||||
# Log report completeness for debugging
|
||||
for key, value in reports.items():
|
||||
if isinstance(value, dict):
|
||||
sub_filled = [k for k, v in value.items() if v and k not in ("count", "latest_speaker")]
|
||||
logger.info(f"📊 Report '{key}': filled fields = {sub_filled}")
|
||||
else:
|
||||
status_icon = "✅" if value else "❌"
|
||||
logger.info(f"📊 Report '{key}': {status_icon} {'populated' if value else 'EMPTY'}")
|
||||
|
||||
# Load price data
|
||||
from backend.app.services.price_service import PriceService
|
||||
price_data = None
|
||||
|
|
|
|||
|
|
@ -54,6 +54,22 @@ export default function AnalysisResultsPage() {
|
|||
const [saveError, setSaveError] = useState<string | null>(null);
|
||||
const [savedToCloud, setSavedToCloud] = useState(false);
|
||||
|
||||
// Debug: log received analysis data structure
|
||||
useEffect(() => {
|
||||
if (analysisResult) {
|
||||
console.log("[Results] analysisResult.reports keys:", Object.keys(analysisResult.reports || {}));
|
||||
const ids = analysisResult.reports?.investment_debate_state;
|
||||
const rds = analysisResult.reports?.risk_debate_state;
|
||||
if (ids) console.log("[Results] investment_debate_state keys:", Object.keys(ids));
|
||||
if (rds) console.log("[Results] risk_debate_state keys:", Object.keys(rds));
|
||||
// Log which reports are populated
|
||||
ANALYST_KEYS.forEach(a => {
|
||||
const val = getNestedValue(analysisResult.reports, a.reportKey);
|
||||
console.log(`[Results] ${a.key} (${a.reportKey}):`, val ? "populated" : "EMPTY/MISSING");
|
||||
});
|
||||
}
|
||||
}, [analysisResult]);
|
||||
|
||||
// Build analysts array with translations
|
||||
const ANALYSTS = useMemo(() => ANALYST_KEYS.map(analyst => ({
|
||||
key: analyst.key,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from langchain_core.tools import tool
|
||||
from typing import Annotated
|
||||
from datetime import datetime, timedelta
|
||||
from tradingagents.dataflows.interface import route_to_vendor
|
||||
|
||||
|
||||
|
|
@ -19,4 +20,14 @@ def get_stock_data(
|
|||
Returns:
|
||||
str: 一個格式化的數據框,包含指定股票代碼在指定日期範圍內的股價數據。
|
||||
"""
|
||||
# 強制至少 365 天的資料範圍,確保分析品質一致
|
||||
try:
|
||||
start_dt = datetime.strptime(start_date, "%Y-%m-%d")
|
||||
end_dt = datetime.strptime(end_date, "%Y-%m-%d")
|
||||
if (end_dt - start_dt).days < 365:
|
||||
start_dt = end_dt - timedelta(days=365)
|
||||
start_date = start_dt.strftime("%Y-%m-%d")
|
||||
print(f"[get_stock_data] 日期範圍不足 1 年,已自動調整 start_date 為 {start_date}")
|
||||
except ValueError:
|
||||
pass # 日期格式錯誤時使用原始值
|
||||
return route_to_vendor("get_stock_data", symbol, start_date, end_date)
|
||||
|
|
@ -87,7 +87,7 @@ You are a senior technical analyst responsible for providing precise market tech
|
|||
4. **Trading Recommendations**: Provide entry/exit positions, risk control parameters
|
||||
|
||||
【Technical Operations】
|
||||
• Use get_stock_data to obtain historical price data
|
||||
• Use get_stock_data to obtain historical price data — always request at least 1 year of data (start_date = trade_date minus 365 days)
|
||||
• Use get_indicators to calculate technical indicators (set look_back_days to 50 or 200 for moving averages)
|
||||
• Integrate data to provide professional insights
|
||||
|
||||
|
|
@ -118,7 +118,7 @@ Please provide a professional, precise, and actionable technical analysis report
|
|||
4. **操作建議**:提供進出場位置、風險控制參數
|
||||
|
||||
【技術操作】
|
||||
• 使用 get_stock_data 取得歷史價格資料
|
||||
• 使用 get_stock_data 取得歷史價格資料 — 務必取得至少 1 年的資料(start_date = 交易日期減 365 天)
|
||||
• 使用 get_indicators 計算技術指標(均線請設定 look_back_days 為 50 或 200)
|
||||
• 整合數據後提出專業見解
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ DEFAULT_CONFIG = {
|
|||
# 辯論與討論設定
|
||||
"max_debate_rounds": 1,
|
||||
"max_risk_discuss_rounds": 1,
|
||||
"max_recur_limit": 100,
|
||||
"max_recur_limit": 200,
|
||||
# 資料供應商設定
|
||||
# 類別層級設定 (該類別所有工具的預設值)
|
||||
# 可用供應商:
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class Propagator:
|
|||
這個類別負責建立圖執行的初始狀態,並提供圖呼叫所需的參數。
|
||||
"""
|
||||
|
||||
def __init__(self, max_recur_limit=100):
|
||||
def __init__(self, max_recur_limit=200):
|
||||
"""
|
||||
使用設定參數進行初始化。
|
||||
|
||||
|
|
@ -68,14 +68,26 @@ class Propagator:
|
|||
"company_name": actual_company_name, # 真實公司全名
|
||||
"trade_date": str(trade_date), # 交易日期
|
||||
"investment_debate_state": InvestDebateState(
|
||||
{"history": "", "current_response": "", "count": 0}
|
||||
{
|
||||
"bull_history": "",
|
||||
"bear_history": "",
|
||||
"history": "",
|
||||
"current_response": "",
|
||||
"judge_decision": "",
|
||||
"count": 0,
|
||||
}
|
||||
), # 投資辯論的初始狀態
|
||||
"risk_debate_state": RiskDebateState(
|
||||
{
|
||||
"risky_history": "",
|
||||
"safe_history": "",
|
||||
"neutral_history": "",
|
||||
"history": "",
|
||||
"latest_speaker": "",
|
||||
"current_risky_response": "",
|
||||
"current_safe_response": "",
|
||||
"current_neutral_response": "",
|
||||
"judge_decision": "",
|
||||
"count": 0,
|
||||
}
|
||||
), # 風險辯論的初始狀態
|
||||
|
|
|
|||
|
|
@ -146,8 +146,11 @@ class TradingAgentsXGraph:
|
|||
# Extract language from config (default: zh-TW for backward compatibility)
|
||||
self.language = self.config.get("language", "zh-TW")
|
||||
|
||||
# 初始化組件
|
||||
self.conditional_logic = ConditionalLogic()
|
||||
# 初始化組件(從 config 傳入辯論回合數)
|
||||
self.conditional_logic = ConditionalLogic(
|
||||
max_debate_rounds=self.config.get("max_debate_rounds", 1),
|
||||
max_risk_discuss_rounds=self.config.get("max_risk_discuss_rounds", 1),
|
||||
)
|
||||
self.graph_setup = GraphSetup(
|
||||
self.quick_thinking_llm,
|
||||
self.deep_thinking_llm,
|
||||
|
|
@ -161,7 +164,9 @@ class TradingAgentsXGraph:
|
|||
self.language, # Pass language for agent reports
|
||||
)
|
||||
|
||||
self.propagator = Propagator()
|
||||
self.propagator = Propagator(
|
||||
max_recur_limit=self.config.get("max_recur_limit", 200),
|
||||
)
|
||||
self.reflector = Reflector(self.quick_thinking_llm)
|
||||
self.signal_processor = SignalProcessor(self.quick_thinking_llm)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue