120 lines
4.2 KiB
Python
120 lines
4.2 KiB
Python
from tradingagents.agents.utils.agent_utils import format_memory_context
|
|
from tradingagents.agents.utils.llm_utils import parse_llm_response
|
|
|
|
|
|
def create_risk_manager(llm, memory):
|
|
def risk_manager_node(state) -> dict:
|
|
|
|
company_name = state["company_of_interest"]
|
|
|
|
history = state["risk_debate_state"]["history"]
|
|
risk_debate_state = state["risk_debate_state"]
|
|
market_research_report = state["market_report"]
|
|
news_report = state["news_report"]
|
|
fundamentals_report = state["fundamentals_report"]
|
|
sentiment_report = state["sentiment_report"]
|
|
trader_plan = state.get("trader_investment_plan") or state.get("investment_plan", "")
|
|
|
|
past_memory_str = format_memory_context(memory, state)
|
|
|
|
prompt = (
|
|
f"""You are the Final Trade Decider for {company_name}. Make the definitive SHORT-TERM call (5-14 days) after reviewing the risk debate.
|
|
|
|
## CORE RULES
|
|
- Evaluate this ticker IN ISOLATION (no portfolio sizing or correlation analysis).
|
|
- Base your decision on the provided reports, the Trader's plan, and the risk debate.
|
|
- Use ONLY data from the provided reports — do not invent numbers, events, or metrics.
|
|
- If data is unavailable for a field, write "N/A".
|
|
|
|
## CONVICTION SCORING
|
|
Assess alignment across the debate participants:
|
|
- **Unanimous agreement** (all 3 reviewers + Trader agree on direction) → High conviction
|
|
- **Majority agreement** (3 of 4 agree) → Medium conviction
|
|
- **Split decision** (2 vs 2, or significant disagreement on setup) → Low conviction
|
|
|
|
Then adjust conviction based on data quality:
|
|
- Strong, specific evidence cited → conviction stays or increases
|
|
- Vague or contradictory evidence → conviction decreases one level
|
|
|
|
## OUTPUT STRUCTURE (MANDATORY)
|
|
|
|
### Final Decision
|
|
**DECISION: BUY** or **DECISION: SELL** (choose exactly one)
|
|
**Conviction: High / Medium / Low**
|
|
**Time Horizon: [X] days**
|
|
|
|
### Debate Alignment
|
|
- Trader: [BUY/SELL]
|
|
- Aggressive Reviewer: [BUY/SELL]
|
|
- Conservative Reviewer: [BUY/SELL]
|
|
- Neutral Reviewer: [BUY/SELL]
|
|
- **Alignment:** [Unanimous / Majority / Split]
|
|
|
|
### Execution
|
|
- Entry: [price or condition — adopt the best entry from the debate]
|
|
- Stop: [price] ([%] risk from entry)
|
|
- Target: [price] ([%] reward from entry)
|
|
- Risk/Reward: [ratio]
|
|
- Invalidation: [specific price or event that kills the thesis]
|
|
- Catalyst / Timing: [what should move it in next 1-2 weeks — cite specific dated events]
|
|
|
|
### Rationale (3 bullets max)
|
|
- [Strongest data-backed reason — cite specific numbers from reports]
|
|
- [Second reason]
|
|
- [Third reason]
|
|
|
|
### Key Risks (2 bullets max)
|
|
- [Main way this fails — cite the Conservative Reviewer's best point]
|
|
- [Secondary risk]
|
|
"""
|
|
+ (
|
|
f"""
|
|
## PAST LESSONS — CRITICAL
|
|
Review past mistakes to avoid repeating trade-setup errors:
|
|
{past_memory_str}
|
|
|
|
**Self-check:** Have similar setups failed before? What was the key mistake (timing, catalyst read, or stop placement)?
|
|
"""
|
|
if past_memory_str
|
|
else ""
|
|
)
|
|
+ f"""
|
|
---
|
|
|
|
**TRADER'S PLAN:**
|
|
{trader_plan}
|
|
|
|
**RISK DEBATE:**
|
|
{history}
|
|
|
|
**MARKET DATA:**
|
|
Technical: {market_research_report}
|
|
Sentiment: {sentiment_report}
|
|
News: {news_report}
|
|
Fundamentals: {fundamentals_report}
|
|
"""
|
|
)
|
|
|
|
response = llm.invoke(prompt)
|
|
response_text = parse_llm_response(response.content)
|
|
|
|
new_risk_debate_state = {
|
|
"judge_decision": response_text,
|
|
"history": risk_debate_state["history"],
|
|
"risky_history": risk_debate_state["risky_history"],
|
|
"safe_history": risk_debate_state["safe_history"],
|
|
"neutral_history": risk_debate_state["neutral_history"],
|
|
"latest_speaker": "Judge",
|
|
"current_risky_response": risk_debate_state["current_risky_response"],
|
|
"current_safe_response": risk_debate_state["current_safe_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": response_text,
|
|
}
|
|
|
|
return risk_manager_node
|