mirror of
https://github.com/TauricResearch/TradingAgents.git
synced 2026-07-04 13:44:23 +03:00
Agents had no ground-truth ticker→company mapping, so the market analyst could pattern-match a price chart to the wrong company (e.g. TOTDY read as "TotalEnergies"), and every downstream agent inherited the bad framing. Resolve identity once at run start via a cached, fail-open yfinance lookup and inject company/sector/exchange into the shared instrument context that all twelve agents consume, with an explicit do-not-substitute instruction. Resolution runs on both the propagate() and CLI entry points. Also replaces the bare "Continue" message-clear placeholder, which some OpenAI-compatible providers interpreted as the user task, with a context-anchored placeholder carrying the resolved identity and date. #814 #888
93 lines
3.3 KiB
Python
93 lines
3.3 KiB
Python
"""Portfolio Manager: synthesises the risk-analyst debate into the final decision.
|
|
|
|
Uses LangChain's ``with_structured_output`` so the LLM produces a typed
|
|
``PortfolioDecision`` directly, in a single call. The result is rendered
|
|
back to markdown for storage in ``final_trade_decision`` so memory log,
|
|
CLI display, and saved reports continue to consume the same shape they do
|
|
today. When a provider does not expose structured output, the agent falls
|
|
back gracefully to free-text generation.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from tradingagents.agents.schemas import PortfolioDecision, render_pm_decision
|
|
from tradingagents.agents.utils.agent_utils import (
|
|
get_instrument_context_from_state,
|
|
get_language_instruction,
|
|
)
|
|
from tradingagents.agents.utils.structured import (
|
|
bind_structured,
|
|
invoke_structured_or_freetext,
|
|
)
|
|
|
|
|
|
def create_portfolio_manager(llm):
|
|
structured_llm = bind_structured(llm, PortfolioDecision, "Portfolio Manager")
|
|
|
|
def portfolio_manager_node(state) -> dict:
|
|
instrument_context = get_instrument_context_from_state(state)
|
|
|
|
history = state["risk_debate_state"]["history"]
|
|
risk_debate_state = state["risk_debate_state"]
|
|
research_plan = state["investment_plan"]
|
|
trader_plan = state["trader_investment_plan"]
|
|
|
|
past_context = state.get("past_context", "")
|
|
lessons_line = (
|
|
f"- Lessons from prior decisions and outcomes:\n{past_context}\n"
|
|
if past_context
|
|
else ""
|
|
)
|
|
|
|
prompt = f"""As the Portfolio Manager, synthesize the risk analysts' debate and deliver the final trading decision.
|
|
|
|
{instrument_context}
|
|
|
|
---
|
|
|
|
**Rating Scale** (use exactly one):
|
|
- **Buy**: Strong conviction to enter or add to position
|
|
- **Overweight**: Favorable outlook, gradually increase exposure
|
|
- **Hold**: Maintain current position, no action needed
|
|
- **Underweight**: Reduce exposure, take partial profits
|
|
- **Sell**: Exit position or avoid entry
|
|
|
|
**Context:**
|
|
- Research Manager's investment plan: **{research_plan}**
|
|
- Trader's transaction proposal: **{trader_plan}**
|
|
{lessons_line}
|
|
**Risk Analysts Debate History:**
|
|
{history}
|
|
|
|
---
|
|
|
|
Be decisive and ground every conclusion in specific evidence from the analysts.{get_language_instruction()}"""
|
|
|
|
final_trade_decision = invoke_structured_or_freetext(
|
|
structured_llm,
|
|
llm,
|
|
prompt,
|
|
render_pm_decision,
|
|
"Portfolio Manager",
|
|
)
|
|
|
|
new_risk_debate_state = {
|
|
"judge_decision": final_trade_decision,
|
|
"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"],
|
|
"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"],
|
|
"count": risk_debate_state["count"],
|
|
}
|
|
|
|
return {
|
|
"risk_debate_state": new_risk_debate_state,
|
|
"final_trade_decision": final_trade_decision,
|
|
}
|
|
|
|
return portfolio_manager_node
|