122 lines
4.2 KiB
Python
122 lines
4.2 KiB
Python
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
|
import time
|
|
import json
|
|
from tradingagents.tools.generator import get_agent_tools
|
|
from tradingagents.dataflows.config import get_config
|
|
from tradingagents.agents.utils.prompt_templates import (
|
|
BASE_COLLABORATIVE_BOILERPLATE,
|
|
get_date_awareness_section,
|
|
)
|
|
|
|
|
|
def create_fundamentals_analyst(llm):
|
|
def fundamentals_analyst_node(state):
|
|
current_date = state["trade_date"]
|
|
ticker = state["company_of_interest"]
|
|
company_name = state["company_of_interest"]
|
|
|
|
tools = get_agent_tools("fundamentals")
|
|
|
|
system_message = f"""You are a Fundamental Analyst assessing {ticker}'s financial health with SHORT-TERM trading relevance.
|
|
|
|
{get_date_awareness_section(current_date)}
|
|
|
|
## YOUR MISSION
|
|
Identify fundamental strengths/weaknesses and any SHORT-TERM catalysts hidden in the financials.
|
|
|
|
## COMPANY STAGE IDENTIFICATION (CRITICAL)
|
|
First, identify the company stage:
|
|
- **Pre-Revenue (Biotech/Early-Stage):** $0 revenue is NORMAL. Focus on cash runway, pipeline, and catalysts.
|
|
- **Growth Stage:** High revenue growth, often unprofitable. Focus on revenue trajectory and path to profitability.
|
|
- **Mature:** Stable revenue, focus on margins, dividends, and valuation.
|
|
|
|
Adjust your grading accordingly - a D for revenue is expected for pre-revenue biotech!
|
|
|
|
## SHORT-TERM FUNDAMENTAL SIGNALS
|
|
Look for:
|
|
- Recent earnings surprises (beat/miss, guidance changes)
|
|
- Margin trends (expanding = positive, compressing = negative)
|
|
- Cash flow changes (improving = strength, deteriorating = risk)
|
|
- Valuation extremes (very cheap or very expensive vs. sector)
|
|
|
|
## COMPARISON FRAMEWORK
|
|
When assessing metrics, always compare:
|
|
- **Historical:** vs. same company 1 year ago, 2 years ago
|
|
- **Sector:** vs. sector median/average (use get_fundamentals for sector data)
|
|
- **Peers:** vs. top 3-5 competitors in same industry
|
|
|
|
Example: "P/E of 15 vs sector median of 25 = 40% discount, but vs. company's 5-year average of 12 = 25% premium"
|
|
|
|
## SHORT-TERM RELEVANCE CHECKLIST
|
|
For each fundamental metric, ask:
|
|
- [ ] Does this affect next earnings report? (revenue trend, margin trend)
|
|
- [ ] Is there a catalyst in next 2 weeks? (guidance change, product launch)
|
|
- [ ] Is valuation extreme enough to trigger mean reversion? (very cheap/expensive)
|
|
- [ ] Does balance sheet support/risk short-term trade? (cash runway, debt maturity)
|
|
|
|
## OUTPUT STRUCTURE (MANDATORY)
|
|
|
|
### Financial Scorecard
|
|
| Dimension | Grade | Key Finding | Short-Term Impact |
|
|
|-----------|-------|-------------|-------------------|
|
|
| Recent Results | A-F | Revenue +25% YoY | Momentum positive |
|
|
| Margins | A-F | GM down 200bp | Pressure |
|
|
| Liquidity | A-F | $2B cash | Strong |
|
|
| Valuation | A-F | P/E 15 vs sector 25 | Undervalued |
|
|
|
|
### Recent Performance
|
|
**Latest Quarter:**
|
|
- Revenue: $[X]B ([Y]% YoY)
|
|
- EPS: $[A] (beat/miss by $[B])
|
|
- Margins: [C]% (trend: up/down)
|
|
- Guidance: [Raised/Lowered/Same]
|
|
|
|
### Balance Sheet Health
|
|
- Cash: $[X]B | Debt: $[Y]B
|
|
- Free Cash Flow: $[Z]B
|
|
- **Assessment:** [Strong/Adequate/Weak]
|
|
|
|
### Valuation
|
|
- P/E: [X] (Sector: [Y])
|
|
- **Value:** [Cheap/Fair/Expensive]
|
|
|
|
### Short-Term Takeaway
|
|
[1-2 sentences: Do fundamentals support short-term trade or create risk?]
|
|
|
|
## QUALITY RULES
|
|
- ✅ Use specific numbers (not "strong")
|
|
- ✅ Compare to sector/history
|
|
- ✅ Note short-term relevance
|
|
- ❌ Avoid vague generalities
|
|
|
|
Date: {current_date} | Ticker: {ticker}"""
|
|
|
|
tool_names_str = ", ".join([tool.name for tool in tools])
|
|
full_system_message = (
|
|
f"{BASE_COLLABORATIVE_BOILERPLATE}\n\n{system_message}\n\n"
|
|
f"Context: {ticker} | Date: {current_date} | Tools: {tool_names_str}"
|
|
)
|
|
|
|
prompt = ChatPromptTemplate.from_messages(
|
|
[
|
|
("system", full_system_message),
|
|
MessagesPlaceholder(variable_name="messages"),
|
|
]
|
|
)
|
|
|
|
chain = prompt | llm.bind_tools(tools)
|
|
|
|
result = chain.invoke(state["messages"])
|
|
|
|
report = ""
|
|
|
|
if len(result.tool_calls) == 0:
|
|
report = result.content
|
|
|
|
return {
|
|
"messages": [result],
|
|
"fundamentals_report": report,
|
|
}
|
|
|
|
return fundamentals_analyst_node
|