TradingAgents/tradingagents/agents/managers/portfolio_manager.py

112 lines
4.7 KiB
Python

from tradingagents.agents.utils.agent_utils import (
build_debate_brief,
build_instrument_context,
extract_feedback_snapshot,
get_language_instruction,
get_localized_final_proposal_instruction,
get_localized_rating_scale,
get_snapshot_template,
get_snapshot_writing_instruction,
localize_label,
localize_rating_term,
localize_role_name,
truncate_for_prompt,
)
def create_portfolio_manager(llm, memory):
def portfolio_manager_node(state) -> dict:
instrument_context = build_instrument_context(state["company_of_interest"])
risk_debate_state = state["risk_debate_state"]
market_research_report = truncate_for_prompt(state["market_report"])
news_report = truncate_for_prompt(state["news_report"])
fundamentals_report = truncate_for_prompt(state["fundamentals_report"])
sentiment_report = truncate_for_prompt(state["sentiment_report"])
trader_plan = truncate_for_prompt(state["investment_plan"])
aggressive_snapshot = risk_debate_state.get("aggressive_snapshot", "")
conservative_snapshot = risk_debate_state.get("conservative_snapshot", "")
neutral_snapshot = risk_debate_state.get("neutral_snapshot", "")
debate_brief = risk_debate_state.get("debate_brief", "")
curr_situation = f"{market_research_report}\n\n{sentiment_report}\n\n{news_report}\n\n{fundamentals_report}"
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"
prompt = f"""As the Portfolio Manager, synthesize the risk analysts' debate and deliver the final trading decision.
{instrument_context}
---
{get_localized_rating_scale()}
**Context:**
- Trader's proposed plan: **{trader_plan}**
- Lessons from past decisions: **{past_memory_str}**
**Required Output Structure:**
1. **{localize_label("Rating", "评级")}**: State one of {localize_rating_term("Buy")} / {localize_rating_term("Overweight")} / {localize_rating_term("Hold")} / {localize_rating_term("Underweight")} / {localize_rating_term("Sell")}.
2. **{localize_label("Executive Summary", "执行摘要")}**: A concise action plan covering entry strategy, position sizing, key risk levels, and time horizon.
3. **{localize_label("Investment Thesis", "投资逻辑")}**: Detailed reasoning anchored in the analysts' debate and past reflections.
---
**{localize_label("Rolling Risk Debate Brief", "滚动风险辩论摘要")}:**
{debate_brief}
**{localize_label("Aggressive Snapshot", f"{localize_role_name('Aggressive Analyst')} 最新快照")}:**
{aggressive_snapshot}
**{localize_label("Conservative Snapshot", f"{localize_role_name('Conservative Analyst')} 最新快照")}:**
{conservative_snapshot}
**{localize_label("Neutral Snapshot", f"{localize_role_name('Neutral Analyst')} 最新快照")}:**
{neutral_snapshot}
---
Be decisive and ground every conclusion in specific evidence from the analysts. {get_localized_final_proposal_instruction()}
Append a feedback block in this exact format:
{get_snapshot_template()}
{get_snapshot_writing_instruction()}{get_language_instruction()}"""
response = llm.invoke(prompt)
judge_snapshot = extract_feedback_snapshot(response.content)
updated_brief = build_debate_brief(
{
"Aggressive Analyst": aggressive_snapshot,
"Conservative Analyst": conservative_snapshot,
"Neutral Analyst": neutral_snapshot,
"Portfolio Manager": judge_snapshot,
},
latest_speaker="Portfolio Manager",
)
new_risk_debate_state = {
"judge_decision": response.content,
"history": risk_debate_state["history"],
"aggressive_history": risk_debate_state["aggressive_history"],
"conservative_history": risk_debate_state["conservative_history"],
"neutral_history": risk_debate_state["neutral_history"],
"debate_brief": updated_brief,
"latest_speaker": "Judge",
"current_aggressive_response": risk_debate_state["current_aggressive_response"],
"current_conservative_response": risk_debate_state["current_conservative_response"],
"current_neutral_response": risk_debate_state["current_neutral_response"],
"aggressive_snapshot": aggressive_snapshot,
"conservative_snapshot": conservative_snapshot,
"neutral_snapshot": neutral_snapshot,
"count": risk_debate_state["count"],
}
return {
"risk_debate_state": new_risk_debate_state,
"final_trade_decision": response.content,
}
return portfolio_manager_node