422 lines
10 KiB
Markdown
422 lines
10 KiB
Markdown
# Guide: Adding a New Analyst
|
|
|
|
This guide shows you how to extend TradingAgents with a custom analyst agent.
|
|
|
|
## Overview
|
|
|
|
Creating a new analyst involves:
|
|
1. Creating the analyst class
|
|
2. Defining analysis logic
|
|
3. Integrating data access tools
|
|
4. Registering the analyst
|
|
5. Testing the implementation
|
|
|
|
## Step 1: Create Analyst Class
|
|
|
|
Create a new file in `tradingagents/agents/analysts/`:
|
|
|
|
```python
|
|
# tradingagents/agents/analysts/momentum_analyst.py
|
|
|
|
from typing import List, Dict, Any
|
|
from langchain.schema import HumanMessage
|
|
|
|
class MomentumAnalyst:
|
|
"""Analyzes multi-timeframe momentum and trend strength."""
|
|
|
|
def __init__(self, llm, tools: List):
|
|
"""
|
|
Initialize momentum analyst.
|
|
|
|
Args:
|
|
llm: Language model for analysis
|
|
tools: List of data access tools
|
|
"""
|
|
self.llm = llm
|
|
self.tools = {tool.name: tool for tool in tools}
|
|
self.name = "momentum"
|
|
|
|
def analyze(self, ticker: str, date: str) -> str:
|
|
"""
|
|
Perform momentum analysis.
|
|
|
|
Args:
|
|
ticker: Stock ticker symbol
|
|
date: Analysis date (YYYY-MM-DD)
|
|
|
|
Returns:
|
|
Analysis report as string
|
|
"""
|
|
# Step 1: Gather data
|
|
data = self._gather_data(ticker, date)
|
|
|
|
# Step 2: Create analysis prompt
|
|
prompt = self._create_prompt(ticker, date, data)
|
|
|
|
# Step 3: Generate analysis
|
|
response = self.llm.invoke([HumanMessage(content=prompt)])
|
|
|
|
return response.content
|
|
|
|
def _gather_data(self, ticker: str, date: str) -> Dict[str, Any]:
|
|
"""Gather required data for analysis."""
|
|
# Get stock data for multiple timeframes
|
|
stock_data = self.tools["get_stock_data"](
|
|
ticker,
|
|
start_date=self._get_start_date(date, days=90),
|
|
end_date=date
|
|
)
|
|
|
|
# Get momentum indicators
|
|
indicators = self.tools["get_indicators"](
|
|
ticker,
|
|
indicators=["MACD", "RSI", "ADX"]
|
|
)
|
|
|
|
return {
|
|
"stock_data": stock_data,
|
|
"indicators": indicators
|
|
}
|
|
|
|
def _create_prompt(self, ticker: str, date: str, data: Dict[str, Any]) -> str:
|
|
"""Create analysis prompt for LLM."""
|
|
return f"""
|
|
You are a Momentum Analyst specializing in multi-timeframe trend analysis.
|
|
|
|
Analyze the momentum and trend strength for {ticker} as of {date}.
|
|
|
|
Data provided:
|
|
- Stock prices (90 days): {data['stock_data']}
|
|
- MACD: {data['indicators']['MACD']}
|
|
- RSI: {data['indicators']['RSI']}
|
|
- ADX: {data['indicators']['ADX']}
|
|
|
|
Provide analysis covering:
|
|
1. Short-term momentum (daily/weekly)
|
|
2. Medium-term trend (monthly)
|
|
3. Trend strength assessment
|
|
4. Potential reversal signals
|
|
5. Momentum-based trading recommendation
|
|
|
|
Format your response as a concise report.
|
|
"""
|
|
|
|
def _get_start_date(self, end_date: str, days: int) -> str:
|
|
"""Calculate start date for data retrieval."""
|
|
from datetime import datetime, timedelta
|
|
end = datetime.strptime(end_date, "%Y-%m-%d")
|
|
start = end - timedelta(days=days)
|
|
return start.strftime("%Y-%m-%d")
|
|
```
|
|
|
|
## Step 2: Register Data Tools
|
|
|
|
Ensure your analyst has access to required data tools:
|
|
|
|
```python
|
|
from tradingagents.agents.utils.agent_utils import (
|
|
get_stock_data,
|
|
get_indicators,
|
|
get_fundamentals,
|
|
get_news
|
|
)
|
|
|
|
# Tools will be passed to analyst constructor
|
|
tools = [
|
|
get_stock_data,
|
|
get_indicators,
|
|
# Add other tools as needed
|
|
]
|
|
```
|
|
|
|
## Step 3: Integrate into TradingGraph
|
|
|
|
Modify `tradingagents/graph/trading_graph.py` to include your analyst:
|
|
|
|
```python
|
|
# Import your analyst
|
|
from tradingagents.agents.analysts.momentum_analyst import MomentumAnalyst
|
|
|
|
class TradingAgentsGraph:
|
|
def __init__(self, selected_analysts=None, debug=False, config=None):
|
|
# ... existing initialization ...
|
|
|
|
# Initialize analysts
|
|
self.analysts = {}
|
|
|
|
if "momentum" in selected_analysts:
|
|
self.analysts["momentum"] = MomentumAnalyst(
|
|
llm=self.quick_thinking_llm,
|
|
tools=self.analyst_tools
|
|
)
|
|
|
|
# ... rest of initialization ...
|
|
```
|
|
|
|
## Step 4: Update Analyst Selection
|
|
|
|
Allow users to select your analyst:
|
|
|
|
```python
|
|
# In main.py or CLI
|
|
selected_analysts = ["market", "fundamentals", "momentum"]
|
|
|
|
ta = TradingAgentsGraph(
|
|
selected_analysts=selected_analysts,
|
|
debug=True
|
|
)
|
|
```
|
|
|
|
## Step 5: Test Your Analyst
|
|
|
|
Create a test file `tests/unit/test_momentum_analyst.py`:
|
|
|
|
```python
|
|
import pytest
|
|
from tradingagents.agents.analysts.momentum_analyst import MomentumAnalyst
|
|
from unittest.mock import Mock
|
|
|
|
def test_momentum_analyst_initialization():
|
|
"""Test analyst can be initialized."""
|
|
llm = Mock()
|
|
tools = []
|
|
|
|
analyst = MomentumAnalyst(llm, tools)
|
|
|
|
assert analyst.name == "momentum"
|
|
assert analyst.llm == llm
|
|
|
|
def test_momentum_analyst_analyze():
|
|
"""Test analyst can perform analysis."""
|
|
# Mock LLM
|
|
llm = Mock()
|
|
llm.invoke.return_value = Mock(
|
|
content="Momentum analysis: Strong uptrend..."
|
|
)
|
|
|
|
# Mock tools
|
|
get_stock_data = Mock(return_value={
|
|
"dates": ["2024-01-01", "2024-01-02"],
|
|
"close": [150.0, 152.0]
|
|
})
|
|
get_indicators = Mock(return_value={
|
|
"MACD": {"macd": [0.5], "signal": [0.4]},
|
|
"RSI": {"rsi": [65.0]},
|
|
"ADX": {"adx": [30.0]}
|
|
})
|
|
|
|
get_stock_data.name = "get_stock_data"
|
|
get_indicators.name = "get_indicators"
|
|
|
|
tools = [get_stock_data, get_indicators]
|
|
|
|
# Create analyst
|
|
analyst = MomentumAnalyst(llm, tools)
|
|
|
|
# Run analysis
|
|
report = analyst.analyze("NVDA", "2024-01-02")
|
|
|
|
# Verify
|
|
assert "Momentum analysis" in report
|
|
assert llm.invoke.called
|
|
assert get_stock_data.called
|
|
assert get_indicators.called
|
|
```
|
|
|
|
Run tests:
|
|
```bash
|
|
pytest tests/unit/test_momentum_analyst.py -v
|
|
```
|
|
|
|
## Advanced Features
|
|
|
|
### Multi-Timeframe Analysis
|
|
|
|
```python
|
|
def _gather_multi_timeframe_data(self, ticker: str, date: str):
|
|
"""Get data for multiple timeframes."""
|
|
return {
|
|
"daily": self.tools["get_stock_data"](
|
|
ticker,
|
|
self._get_start_date(date, days=30),
|
|
date
|
|
),
|
|
"weekly": self._aggregate_weekly(
|
|
self.tools["get_stock_data"](
|
|
ticker,
|
|
self._get_start_date(date, days=90),
|
|
date
|
|
)
|
|
),
|
|
"monthly": self._aggregate_monthly(
|
|
self.tools["get_stock_data"](
|
|
ticker,
|
|
self._get_start_date(date, days=365),
|
|
date
|
|
)
|
|
)
|
|
}
|
|
```
|
|
|
|
### Custom Indicators
|
|
|
|
```python
|
|
def _calculate_custom_indicators(self, data):
|
|
"""Calculate custom momentum indicators."""
|
|
import numpy as np
|
|
|
|
prices = np.array(data["close"])
|
|
|
|
# Rate of Change
|
|
roc = (prices[-1] - prices[-20]) / prices[-20] * 100
|
|
|
|
# Momentum
|
|
momentum = prices[-1] - prices[-10]
|
|
|
|
return {
|
|
"roc": roc,
|
|
"momentum": momentum
|
|
}
|
|
```
|
|
|
|
### Caching Analysis
|
|
|
|
```python
|
|
def analyze(self, ticker: str, date: str) -> str:
|
|
"""Analyze with caching."""
|
|
# Check cache
|
|
cache_key = f"momentum_{ticker}_{date}"
|
|
if cached := self._get_from_cache(cache_key):
|
|
return cached
|
|
|
|
# Perform analysis
|
|
result = self._perform_analysis(ticker, date)
|
|
|
|
# Save to cache
|
|
self._save_to_cache(cache_key, result)
|
|
|
|
return result
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
1. **Clear Responsibility**: Each analyst should have a focused domain
|
|
2. **Consistent Interface**: Follow the `analyze(ticker, date)` pattern
|
|
3. **Tool Usage**: Use the unified data interface for vendor independence
|
|
4. **Error Handling**: Handle missing data and API failures gracefully
|
|
5. **Structured Output**: Return well-formatted reports
|
|
6. **Testing**: Write unit tests for your analyst
|
|
7. **Documentation**: Add docstrings to all methods
|
|
8. **Performance**: Cache expensive calculations
|
|
9. **Logging**: Use logging for debugging
|
|
10. **Configuration**: Make analyst behavior configurable
|
|
|
|
## Common Patterns
|
|
|
|
### Comparative Analysis
|
|
|
|
```python
|
|
def compare_to_benchmark(self, ticker: str, benchmark: str, date: str):
|
|
"""Compare ticker performance to benchmark."""
|
|
ticker_data = self.tools["get_stock_data"](ticker, ...)
|
|
benchmark_data = self.tools["get_stock_data"](benchmark, ...)
|
|
|
|
# Calculate relative strength
|
|
relative_strength = self._calculate_relative_strength(
|
|
ticker_data,
|
|
benchmark_data
|
|
)
|
|
|
|
return relative_strength
|
|
```
|
|
|
|
### Sector Analysis
|
|
|
|
```python
|
|
def analyze_sector_context(self, ticker: str, date: str):
|
|
"""Analyze ticker in sector context."""
|
|
sector = self._get_sector(ticker)
|
|
peers = self._get_sector_peers(sector)
|
|
|
|
# Compare to sector average
|
|
sector_analysis = self._compare_to_peers(ticker, peers, date)
|
|
|
|
return sector_analysis
|
|
```
|
|
|
|
### Historical Patterns
|
|
|
|
```python
|
|
def find_historical_patterns(self, ticker: str, date: str):
|
|
"""Find similar historical patterns."""
|
|
current_pattern = self._extract_pattern(ticker, date)
|
|
|
|
# Search memory for similar patterns
|
|
similar = self.memory.search_similar(
|
|
query=f"{ticker} pattern {current_pattern}",
|
|
k=5
|
|
)
|
|
|
|
return similar
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Analyst Not Running
|
|
|
|
**Issue**: Analyst not included in workflow
|
|
|
|
**Solution**: Check `selected_analysts` includes your analyst name
|
|
|
|
```python
|
|
selected_analysts = ["market", "fundamentals", "momentum"]
|
|
```
|
|
|
|
### Data Access Errors
|
|
|
|
**Issue**: Tools not available or returning errors
|
|
|
|
**Solution**: Verify tool registration and vendor configuration
|
|
|
|
```python
|
|
# Check tools are available
|
|
print(self.tools.keys())
|
|
|
|
# Verify vendor config
|
|
from tradingagents.dataflows.config import get_config
|
|
print(get_config()["data_vendors"])
|
|
```
|
|
|
|
### LLM Errors
|
|
|
|
**Issue**: LLM returning unexpected responses
|
|
|
|
**Solution**: Improve prompt clarity and structure
|
|
|
|
```python
|
|
def _create_prompt(self, ticker, date, data):
|
|
"""Create clear, structured prompt."""
|
|
return f"""
|
|
You are a {self.name} analyst.
|
|
|
|
Task: Analyze {ticker} as of {date}
|
|
|
|
Data:
|
|
{self._format_data(data)}
|
|
|
|
Required output format:
|
|
1. Key findings
|
|
2. Specific metrics
|
|
3. Recommendation
|
|
|
|
Be concise and specific.
|
|
"""
|
|
```
|
|
|
|
## See Also
|
|
|
|
- [Multi-Agent System Architecture](../architecture/multi-agent-system.md)
|
|
- [Agents API Reference](../api/agents.md)
|
|
- [Data Flows API](../api/dataflows.md)
|
|
- [Testing Guide](../testing/writing-tests.md)
|