TradingAgents/tradingagents/agents/risk_mgmt/neutral_debator.py

108 lines
4.0 KiB
Python

import time
import json
from langchain_core.messages import SystemMessage, HumanMessage
from tradingagents.log_utils import add_log, step_timer, symbol_progress
def create_neutral_debator(llm):
def neutral_node(state) -> dict:
risk_debate_state = state["risk_debate_state"]
history = risk_debate_state.get("history", "")
neutral_history = risk_debate_state.get("neutral_history", "")
current_risky_response = risk_debate_state.get("current_risky_response", "")
current_safe_response = risk_debate_state.get("current_safe_response", "")
market_research_report = state["market_report"]
sentiment_report = state["sentiment_report"]
news_report = state["news_report"]
fundamentals_report = state["fundamentals_report"]
trader_decision = state["trader_investment_plan"]
system_prompt = """You are a Neutral Risk Analyst at a financial advisory firm. You MUST stay in character as a financial analyst at all times.
CRITICAL RULES:
- NEVER mention that you are an AI, Claude, a language model, or an assistant
- NEVER offer to help with code, software, or implementation tasks
- NEVER say "I don't have access to" or "I can't see the data" — analyze whatever data is provided below
- If data sections are empty, state that data is unavailable and focus your analysis on the data that IS available
Your role: Provide a balanced perspective, weighing both potential benefits and risks objectively.
Focus on: balanced risk/reward assessment, moderate strategies, where both aggressive and conservative views may be flawed.
RESPONSE FORMAT:
- Maximum 2000 characters. Focus on 3-5 key balanced observations.
- Complete your ENTIRE argument in a SINGLE response.
Respond only with your balanced financial analysis. No disclaimers or meta-commentary."""
user_prompt = f"""Provide the balanced/neutral perspective on this investment:
TRADER'S DECISION:
{trader_decision}
MARKET DATA:
{market_research_report}
SENTIMENT:
{sentiment_report}
NEWS:
{news_report}
FUNDAMENTALS:
{fundamentals_report}
DEBATE HISTORY:
{history}
AGGRESSIVE ANALYST'S ARGUMENT:
{current_risky_response if current_risky_response else "None yet"}
CONSERVATIVE ANALYST'S ARGUMENT:
{current_safe_response if current_safe_response else "None yet"}
Present your balanced/neutral case."""
messages = [
SystemMessage(content=system_prompt),
HumanMessage(content=user_prompt)
]
step_timer.start_step("neutral_analyst")
add_log("agent", "neutral", f"⚖️ Neutral Analyst calling LLM...")
t0 = time.time()
response = llm.invoke(messages)
elapsed = time.time() - t0
add_log("llm", "neutral", f"LLM responded in {elapsed:.1f}s ({len(response.content)} chars)")
add_log("agent", "neutral", f"✅ Neutral argument ready: {response.content[:300]}...")
step_timer.end_step("neutral_analyst", "completed", response.content[:200])
symbol_progress.step_done(state["company_of_interest"], "neutral_analyst")
step_timer.set_details("neutral_analyst", {
"system_prompt": system_prompt,
"user_prompt": user_prompt[:3000],
"response": response.content[:3000],
"tool_calls": [],
})
argument = f"Neutral Analyst: {response.content}"
new_risk_debate_state = {
"history": history + "\n" + argument,
"risky_history": risk_debate_state.get("risky_history", ""),
"safe_history": risk_debate_state.get("safe_history", ""),
"neutral_history": neutral_history + "\n" + argument,
"latest_speaker": "Neutral",
"current_risky_response": risk_debate_state.get(
"current_risky_response", ""
),
"current_safe_response": risk_debate_state.get("current_safe_response", ""),
"current_neutral_response": argument,
"count": risk_debate_state["count"] + 1,
}
return {"risk_debate_state": new_risk_debate_state}
return neutral_node