refactor: standardize portfolio manager, five-tier rating scale, fix analyst status tracking
This commit is contained in:
parent
318adda0c6
commit
b8b2825783
13
cli/main.py
13
cli/main.py
|
|
@ -800,9 +800,11 @@ ANALYST_REPORT_MAP = {
|
|||
|
||||
|
||||
def update_analyst_statuses(message_buffer, chunk):
|
||||
"""Update all analyst statuses based on current report state.
|
||||
"""Update analyst statuses based on accumulated report state.
|
||||
|
||||
Logic:
|
||||
- Store new report content from the current chunk if present
|
||||
- Check accumulated report_sections (not just current chunk) for status
|
||||
- Analysts with reports = completed
|
||||
- First analyst without report = in_progress
|
||||
- Remaining analysts without reports = pending
|
||||
|
|
@ -817,11 +819,16 @@ def update_analyst_statuses(message_buffer, chunk):
|
|||
|
||||
agent_name = ANALYST_AGENT_NAMES[analyst_key]
|
||||
report_key = ANALYST_REPORT_MAP[analyst_key]
|
||||
has_report = bool(chunk.get(report_key))
|
||||
|
||||
# Capture new report content from current chunk
|
||||
if chunk.get(report_key):
|
||||
message_buffer.update_report_section(report_key, chunk[report_key])
|
||||
|
||||
# Determine status from accumulated sections, not just current chunk
|
||||
has_report = bool(message_buffer.report_sections.get(report_key))
|
||||
|
||||
if has_report:
|
||||
message_buffer.update_agent_status(agent_name, "completed")
|
||||
message_buffer.update_report_section(report_key, chunk[report_key])
|
||||
elif not found_active:
|
||||
message_buffer.update_agent_status(agent_name, "in_progress")
|
||||
found_active = True
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ from .risk_mgmt.conservative_debator import create_conservative_debator
|
|||
from .risk_mgmt.neutral_debator import create_neutral_debator
|
||||
|
||||
from .managers.research_manager import create_research_manager
|
||||
from .managers.risk_manager import create_risk_manager
|
||||
from .managers.portfolio_manager import create_portfolio_manager
|
||||
|
||||
from .trader.trader import create_trader
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ __all__ = [
|
|||
"create_neutral_debator",
|
||||
"create_news_analyst",
|
||||
"create_aggressive_debator",
|
||||
"create_risk_manager",
|
||||
"create_portfolio_manager",
|
||||
"create_conservative_debator",
|
||||
"create_social_media_analyst",
|
||||
"create_trader",
|
||||
|
|
|
|||
|
|
@ -1,11 +1,8 @@
|
|||
import time
|
||||
import json
|
||||
|
||||
from tradingagents.agents.utils.agent_utils import build_instrument_context
|
||||
|
||||
|
||||
def create_risk_manager(llm, memory):
|
||||
def risk_manager_node(state) -> dict:
|
||||
def create_portfolio_manager(llm, memory):
|
||||
def portfolio_manager_node(state) -> dict:
|
||||
|
||||
instrument_context = build_instrument_context(state["company_of_interest"])
|
||||
|
||||
|
|
@ -24,7 +21,7 @@ def create_risk_manager(llm, memory):
|
|||
for i, rec in enumerate(past_memories, 1):
|
||||
past_memory_str += rec["recommendation"] + "\n\n"
|
||||
|
||||
prompt = f"""As the Risk Management Judge, evaluate the debate between the Aggressive, Neutral, and Conservative analysts and deliver a final trading decision.
|
||||
prompt = f"""As the Portfolio Manager, synthesize the risk analysts' debate and deliver the final trading decision.
|
||||
|
||||
{instrument_context}
|
||||
|
||||
|
|
@ -37,19 +34,18 @@ def create_risk_manager(llm, memory):
|
|||
- **Underweight**: Reduce exposure, take partial profits
|
||||
- **Sell**: Exit position or avoid entry
|
||||
|
||||
**Guidelines:**
|
||||
1. Extract the strongest points from each analyst, focusing on relevance to the current context.
|
||||
2. Start with the trader's original plan: **{trader_plan}**, and refine it based on the analysts' insights.
|
||||
3. Apply lessons from past decisions to strengthen this analysis: **{past_memory_str}**
|
||||
**Context:**
|
||||
- Trader's proposed plan: **{trader_plan}**
|
||||
- Lessons from past decisions: **{past_memory_str}**
|
||||
|
||||
**Required Output Structure:**
|
||||
1. **Rating**: State one of Buy / Overweight / Hold / Underweight / Sell.
|
||||
2. **Executive Summary**: A concise action plan covering entry strategy, position sizing, key risk levels, and time horizon. Keep this brief and actionable.
|
||||
3. **Investment Thesis**: Detailed reasoning anchored in the debate and past reflections.
|
||||
2. **Executive Summary**: A concise action plan covering entry strategy, position sizing, key risk levels, and time horizon.
|
||||
3. **Investment Thesis**: Detailed reasoning anchored in the analysts' debate and past reflections.
|
||||
|
||||
---
|
||||
|
||||
**Analysts Debate History:**
|
||||
**Risk Analysts Debate History:**
|
||||
{history}
|
||||
|
||||
---
|
||||
|
|
@ -76,4 +72,4 @@ Be decisive and ground every conclusion in specific evidence from the analysts."
|
|||
"final_trade_decision": response.content,
|
||||
}
|
||||
|
||||
return risk_manager_node
|
||||
return portfolio_manager_node
|
||||
|
|
@ -59,7 +59,7 @@ class ConditionalLogic:
|
|||
if (
|
||||
state["risk_debate_state"]["count"] >= 3 * self.max_risk_discuss_rounds
|
||||
): # 3 rounds of back-and-forth between 3 agents
|
||||
return "Risk Judge"
|
||||
return "Portfolio Manager"
|
||||
if state["risk_debate_state"]["latest_speaker"].startswith("Aggressive"):
|
||||
return "Conservative Analyst"
|
||||
if state["risk_debate_state"]["latest_speaker"].startswith("Conservative"):
|
||||
|
|
|
|||
|
|
@ -110,12 +110,12 @@ Adhere strictly to these instructions, and ensure your output is detailed, accur
|
|||
)
|
||||
invest_judge_memory.add_situations([(situation, result)])
|
||||
|
||||
def reflect_risk_manager(self, current_state, returns_losses, risk_manager_memory):
|
||||
"""Reflect on risk manager's decision and update memory."""
|
||||
def reflect_portfolio_manager(self, current_state, returns_losses, portfolio_manager_memory):
|
||||
"""Reflect on portfolio manager's decision and update memory."""
|
||||
situation = self._extract_current_situation(current_state)
|
||||
judge_decision = current_state["risk_debate_state"]["judge_decision"]
|
||||
|
||||
result = self._reflect_on_component(
|
||||
"RISK JUDGE", judge_decision, situation, returns_losses
|
||||
"PORTFOLIO MANAGER", judge_decision, situation, returns_losses
|
||||
)
|
||||
risk_manager_memory.add_situations([(situation, result)])
|
||||
portfolio_manager_memory.add_situations([(situation, result)])
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class GraphSetup:
|
|||
bear_memory,
|
||||
trader_memory,
|
||||
invest_judge_memory,
|
||||
risk_manager_memory,
|
||||
portfolio_manager_memory,
|
||||
conditional_logic: ConditionalLogic,
|
||||
):
|
||||
"""Initialize with required components."""
|
||||
|
|
@ -34,7 +34,7 @@ class GraphSetup:
|
|||
self.bear_memory = bear_memory
|
||||
self.trader_memory = trader_memory
|
||||
self.invest_judge_memory = invest_judge_memory
|
||||
self.risk_manager_memory = risk_manager_memory
|
||||
self.portfolio_manager_memory = portfolio_manager_memory
|
||||
self.conditional_logic = conditional_logic
|
||||
|
||||
def setup_graph(
|
||||
|
|
@ -101,8 +101,8 @@ class GraphSetup:
|
|||
aggressive_analyst = create_aggressive_debator(self.quick_thinking_llm)
|
||||
neutral_analyst = create_neutral_debator(self.quick_thinking_llm)
|
||||
conservative_analyst = create_conservative_debator(self.quick_thinking_llm)
|
||||
risk_manager_node = create_risk_manager(
|
||||
self.deep_thinking_llm, self.risk_manager_memory
|
||||
portfolio_manager_node = create_portfolio_manager(
|
||||
self.deep_thinking_llm, self.portfolio_manager_memory
|
||||
)
|
||||
|
||||
# Create workflow
|
||||
|
|
@ -124,7 +124,7 @@ class GraphSetup:
|
|||
workflow.add_node("Aggressive Analyst", aggressive_analyst)
|
||||
workflow.add_node("Neutral Analyst", neutral_analyst)
|
||||
workflow.add_node("Conservative Analyst", conservative_analyst)
|
||||
workflow.add_node("Risk Judge", risk_manager_node)
|
||||
workflow.add_node("Portfolio Manager", portfolio_manager_node)
|
||||
|
||||
# Define edges
|
||||
# Start with the first analyst
|
||||
|
|
@ -176,7 +176,7 @@ class GraphSetup:
|
|||
self.conditional_logic.should_continue_risk_analysis,
|
||||
{
|
||||
"Conservative Analyst": "Conservative Analyst",
|
||||
"Risk Judge": "Risk Judge",
|
||||
"Portfolio Manager": "Portfolio Manager",
|
||||
},
|
||||
)
|
||||
workflow.add_conditional_edges(
|
||||
|
|
@ -184,7 +184,7 @@ class GraphSetup:
|
|||
self.conditional_logic.should_continue_risk_analysis,
|
||||
{
|
||||
"Neutral Analyst": "Neutral Analyst",
|
||||
"Risk Judge": "Risk Judge",
|
||||
"Portfolio Manager": "Portfolio Manager",
|
||||
},
|
||||
)
|
||||
workflow.add_conditional_edges(
|
||||
|
|
@ -192,11 +192,11 @@ class GraphSetup:
|
|||
self.conditional_logic.should_continue_risk_analysis,
|
||||
{
|
||||
"Aggressive Analyst": "Aggressive Analyst",
|
||||
"Risk Judge": "Risk Judge",
|
||||
"Portfolio Manager": "Portfolio Manager",
|
||||
},
|
||||
)
|
||||
|
||||
workflow.add_edge("Risk Judge", END)
|
||||
workflow.add_edge("Portfolio Manager", END)
|
||||
|
||||
# Compile and return
|
||||
return workflow.compile()
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ class TradingAgentsGraph:
|
|||
self.bear_memory = FinancialSituationMemory("bear_memory", self.config)
|
||||
self.trader_memory = FinancialSituationMemory("trader_memory", self.config)
|
||||
self.invest_judge_memory = FinancialSituationMemory("invest_judge_memory", self.config)
|
||||
self.risk_manager_memory = FinancialSituationMemory("risk_manager_memory", self.config)
|
||||
self.portfolio_manager_memory = FinancialSituationMemory("portfolio_manager_memory", self.config)
|
||||
|
||||
# Create tool nodes
|
||||
self.tool_nodes = self._create_tool_nodes()
|
||||
|
|
@ -117,7 +117,7 @@ class TradingAgentsGraph:
|
|||
self.bear_memory,
|
||||
self.trader_memory,
|
||||
self.invest_judge_memory,
|
||||
self.risk_manager_memory,
|
||||
self.portfolio_manager_memory,
|
||||
self.conditional_logic,
|
||||
)
|
||||
|
||||
|
|
@ -283,8 +283,8 @@ class TradingAgentsGraph:
|
|||
self.reflector.reflect_invest_judge(
|
||||
self.curr_state, returns_losses, self.invest_judge_memory
|
||||
)
|
||||
self.reflector.reflect_risk_manager(
|
||||
self.curr_state, returns_losses, self.risk_manager_memory
|
||||
self.reflector.reflect_portfolio_manager(
|
||||
self.curr_state, returns_losses, self.portfolio_manager_memory
|
||||
)
|
||||
|
||||
def process_signal(self, full_signal):
|
||||
|
|
|
|||
Loading…
Reference in New Issue