TradingAgents/backend/tradingagents/agents/managers/risk_manager.py

152 lines
6.7 KiB
Python

import time
import json
import logging
logger = logging.getLogger(__name__)
def create_risk_manager(llm, memory):
def risk_manager_node(state) -> dict:
logger.info("🎯 Risk Manager: Starting final decision process")
# Extract basic information
company_name = state["company_of_interest"]
# Get risk debate state
risk_debate_state = state.get("risk_debate_state", {})
history = risk_debate_state.get("history", "")
# Extract all reports with validation
market_research_report = state.get("market_report", "")
news_report = state.get("news_report", "")
fundamentals_report = state.get("fundamentals_report", "") # FIX: was incorrectly assigned to news_report
sentiment_report = state.get("sentiment_report", "")
trader_plan = state.get("investment_plan", "")
# Validate required data
logger.info("🎯 Risk Manager: Validating input data...")
logger.info(f"🎯 Risk Manager: market_report length: {len(market_research_report)}")
logger.info(f"🎯 Risk Manager: news_report length: {len(news_report)}")
logger.info(f"🎯 Risk Manager: fundamentals_report length: {len(fundamentals_report)}")
logger.info(f"🎯 Risk Manager: sentiment_report length: {len(sentiment_report)}")
logger.info(f"🎯 Risk Manager: investment_plan length: {len(trader_plan)}")
logger.info(f"🎯 Risk Manager: risk_debate_history length: {len(history)}")
missing_data = []
if not market_research_report:
missing_data.append("market_report")
if not news_report:
missing_data.append("news_report")
if not fundamentals_report:
missing_data.append("fundamentals_report")
if not sentiment_report:
missing_data.append("sentiment_report")
if not trader_plan:
missing_data.append("investment_plan")
if not history:
missing_data.append("risk_analyst_debate")
if missing_data:
logger.warning(f"🎯 Risk Manager: Missing data: {missing_data}")
# Create a fallback response
fallback_response = f"""**Risk Management Decision: HOLD**
**Reason**: Insufficient data available for comprehensive risk analysis.
**Missing Information**: {', '.join(missing_data)}
**Recommendation**: Wait for complete analysis before making investment decisions. The following data is required:
- Market analysis and technical indicators
- News and world events impact
- Company fundamentals assessment
- Social sentiment analysis
- Risk team debate and perspectives
**Action**: Hold current position until all required analysis is complete."""
logger.info("🎯 Risk Manager: Generated fallback decision due to missing data")
new_risk_debate_state = risk_debate_state.copy()
new_risk_debate_state.update({
"judge_decision": fallback_response,
"latest_speaker": "Judge",
"count": risk_debate_state.get("count", 0) + 1
})
return {
"risk_debate_state": new_risk_debate_state,
"final_trade_decision": fallback_response,
}
# All data is present, proceed with normal analysis
logger.info("🎯 Risk Manager: All required data present, proceeding with analysis")
# Prepare current situation summary
curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}"
# Get past memories
past_memories = memory.get_memories(curr_situation, n_matches=2)
past_memory_str = ""
for i, rec in enumerate(past_memories, 1):
past_memory_str += rec["recommendation"] + "\n\n"
# Original simple prompt
prompt = f"""You are a risk management judge. You need to evaluate the debate between three risk analysts (Risky, Neutral, Safe/Conservative) and decide on the best course of action for the trader.
Company: {company_name}
Trader's original plan: {trader_plan}
Risk analysts debate:
{history}
Market research report: {market_research_report}
News report: {news_report}
Fundamentals report: {fundamentals_report}
Sentiment report: {sentiment_report}
Past lessons learned:
{past_memory_str}
Based on the above information, make a final decision on whether to BUY, SELL, or HOLD the stock. Provide detailed reasoning for your decision."""
logger.info("🎯 Risk Manager: Invoking LLM for final decision...")
logger.info(f"🎯 Risk Manager: Prompt length: {len(prompt)} chars")
logger.info(f"🎯 Risk Manager: Prompt preview: {prompt[:500]}...")
logger.info(f"🎯 Risk Manager: Full prompt sections:")
logger.info(f"🎯 Risk Manager: - Company: {company_name}")
logger.info(f"🎯 Risk Manager: - Trader plan preview: {trader_plan[:100]}...")
logger.info(f"🎯 Risk Manager: - Risk debate preview: {history[:100]}...")
logger.info(f"🎯 Risk Manager: - Market report preview: {market_research_report[:100]}...")
logger.info(f"🎯 Risk Manager: - News report preview: {news_report[:100]}...")
logger.info(f"🎯 Risk Manager: - Fundamentals report preview: {fundamentals_report[:100]}...")
logger.info(f"🎯 Risk Manager: - Sentiment report preview: {sentiment_report[:100]}...")
response = llm.invoke(prompt)
logger.info(f"🎯 Risk Manager: Decision received ({len(response.content)} chars)")
logger.info(f"🎯 Risk Manager: Decision preview: {response.content[:200]}...")
# Update risk debate state
new_risk_debate_state = {
"judge_decision": response.content,
"history": risk_debate_state.get("history", ""),
"risky_history": risk_debate_state.get("risky_history", ""),
"safe_history": risk_debate_state.get("safe_history", ""),
"neutral_history": risk_debate_state.get("neutral_history", ""),
"latest_speaker": "Judge",
"current_risky_response": risk_debate_state.get("current_risky_response", ""),
"current_safe_response": risk_debate_state.get("current_safe_response", ""),
"current_neutral_response": risk_debate_state.get("current_neutral_response", ""),
"count": risk_debate_state.get("count", 0) + 1,
}
logger.info("🎯 Risk Manager: Final decision complete")
return {
"risk_debate_state": new_risk_debate_state,
"final_trade_decision": response.content,
}
return risk_manager_node