145 lines
4.7 KiB
Markdown
145 lines
4.7 KiB
Markdown
# Contributing Custom Agents
|
||
|
||
This guide explains how to create and register third-party trading agents using the generic agent interface.
|
||
|
||
## Interface Overview
|
||
|
||
Every agent implements `BaseAgent.analyze(AgentInput) -> AgentOutput`. This contract ensures agents are interchangeable, composable, and benchmarkable.
|
||
|
||
## Schemas
|
||
|
||
### AgentInput
|
||
|
||
```python
|
||
from tradingagents.agents import AgentInput
|
||
|
||
agent_input = AgentInput(
|
||
ticker="AAPL",
|
||
date="2025-01-15",
|
||
context={
|
||
"market_data": "...",
|
||
"news": "...",
|
||
"fundamentals": "...",
|
||
"sentiment": "...",
|
||
"technical_indicators": "...",
|
||
},
|
||
)
|
||
```
|
||
|
||
| Field | Type | Required | Description |
|
||
|-----------|------------------|----------|--------------------------------------------------|
|
||
| `ticker` | `str` | Yes | Stock ticker symbol |
|
||
| `date` | `str` | Yes | Analysis date |
|
||
| `context` | `dict[str, str]` | No | Optional data keyed by category (see keys above) |
|
||
|
||
### AgentOutput
|
||
|
||
| Field | Type | Required | Description |
|
||
|-----------------|-------------------------------------------------------------|----------|--------------------------------|
|
||
| `rating` | `"BUY" \| "OVERWEIGHT" \| "HOLD" \| "UNDERWEIGHT" \| "SELL"` | Yes | 5-tier recommendation |
|
||
| `confidence` | `float` (0.0–1.0) | Yes | Confidence in the rating |
|
||
| `price_targets` | `PriceTargets \| None` | No | Entry, target, and stop-loss |
|
||
| `thesis` | `str` | Yes | One-paragraph investment thesis|
|
||
| `risk_factors` | `list[str]` | No | Key risks (defaults to `[]`) |
|
||
|
||
### PriceTargets
|
||
|
||
| Field | Type | Description |
|
||
|-------------|---------|-------------------|
|
||
| `entry` | `float` | Entry price |
|
||
| `target` | `float` | Target price |
|
||
| `stop_loss` | `float` | Stop-loss price |
|
||
|
||
## Creating a Custom Agent
|
||
|
||
Subclass `BaseAgent` and implement `analyze`:
|
||
|
||
```python
|
||
from tradingagents.agents import BaseAgent, AgentInput, AgentOutput
|
||
|
||
class MyCustomAgent(BaseAgent):
|
||
name: str = "my_custom_agent"
|
||
|
||
def __init__(self, llm) -> None:
|
||
self.llm = llm
|
||
|
||
def analyze(self, agent_input: AgentInput) -> AgentOutput:
|
||
# Your analysis logic here — call self.llm, fetch data, etc.
|
||
return AgentOutput(
|
||
rating="HOLD",
|
||
confidence=0.75,
|
||
thesis="The stock shows mixed signals...",
|
||
risk_factors=["Sector rotation risk", "Earnings uncertainty"],
|
||
)
|
||
```
|
||
|
||
The `__init__` signature is flexible — the only hard requirement is that `analyze` accepts `AgentInput` and returns `AgentOutput`.
|
||
|
||
## Registering Your Agent
|
||
|
||
Use `AgentRegistry` to make your agent discoverable:
|
||
|
||
```python
|
||
from tradingagents.agents import AgentRegistry
|
||
|
||
registry = AgentRegistry()
|
||
|
||
# Register a class (lazy instantiation with kwargs)
|
||
registry.register("my_custom", MyCustomAgent, llm=my_llm)
|
||
|
||
# Or register a pre-built instance
|
||
agent = MyCustomAgent(llm=my_llm)
|
||
registry.register("my_custom", agent)
|
||
|
||
# Retrieve and use
|
||
agent = registry.get("my_custom")
|
||
output = agent.analyze(agent_input)
|
||
|
||
# List all registered agents
|
||
print(registry.list())
|
||
```
|
||
|
||
## Benchmarking Your Agent
|
||
|
||
Compare your agent across LLM backends:
|
||
|
||
```python
|
||
from tradingagents.agents import (
|
||
AgentInput, LLMBackend, benchmark_agent, benchmark_agents,
|
||
)
|
||
|
||
agent_input = AgentInput(ticker="AAPL", date="2025-01-15")
|
||
|
||
backends = [
|
||
LLMBackend(provider="openai", model="gpt-4o"),
|
||
LLMBackend(provider="anthropic", model="claude-sonnet-4-20250514"),
|
||
LLMBackend(provider="google", model="gemini-2.0-flash"),
|
||
]
|
||
|
||
# Single agent across backends
|
||
report = benchmark_agent(MyCustomAgent, agent_input, backends)
|
||
|
||
# Multiple agents across backends
|
||
report = benchmark_agents(
|
||
[MyCustomAgent, FundamentalsAgent],
|
||
agent_input,
|
||
backends,
|
||
)
|
||
|
||
for row in report.summary():
|
||
print(row)
|
||
```
|
||
|
||
Each `BenchmarkResult` contains: `agent_name`, `provider`, `model`, `output`, `elapsed_seconds`, and `error` (if any).
|
||
|
||
## Checklist
|
||
|
||
Before submitting a PR with a new agent:
|
||
|
||
- [ ] Subclasses `BaseAgent`
|
||
- [ ] Sets a unique `name` class attribute
|
||
- [ ] `analyze()` accepts `AgentInput` and returns `AgentOutput`
|
||
- [ ] `rating` uses one of the 5 valid tiers
|
||
- [ ] `confidence` is between 0.0 and 1.0
|
||
- [ ] Agent is importable and added to `__all__` in `tradingagents/agents/__init__.py`
|