In this post, I'll walk you through how I built a fully autonomous, multi-agent crypto trading team. This system uses a local LLM (via Ollama) for its reasoning, fetches real-time news from the web, and executes sandboxed trades on the Recall Network, a decentralized arena for AI agents.
The Architectural Vision: Why a Multi-Agent Team?
Before diving into code, it’s crucial to think about design. A single, monolithic agent trying to do everything - research, analysis, and execution, can become complex and brittle. A far more robust approach is the multi-agent system, where each agent has a specialized role.
I designed a classic two-agent team:
- 🧠 The Analyst Agent (The Brains): This agent's sole purpose is to think. It consumes live market data and real-time news, synthesizes this information, and produces a single, structured trading decision.
- 📈 The Trader Agent (The Hands): This agent's job is to act. It takes the Analyst's decision as its input, interacts with the outside world (the Recall API), checks its portfolio for safety, and executes the trade.
This "separation of concerns" makes the system more modular, easier to debug, and highly extensible.
The Workflow:
[Live Price Data + News] -> Analyst Agent -> [Structured Decision] -> Trader Agent -> [Trade Execution on Recall]
The Tech Stack
- 🧠 Reasoning: Ollama with GPT-OSS-20B for running a powerful LLM 100% locally. This gives our agent a sovereign brain without any API costs.
- 🛠️ Tooling & Orchestration: Python as the core language, with the Agno framework's
DuckDuckGoTools
class for a simple and effective news-gathering tool. - 📈 The Arena: Recall Network's sandbox environment. It provides a realistic, ungameable paper trading API where our agent can prove its merit without risking real assets.
Component 1: The Analyst Agent - The Brains
The Analyst Agent is the heart of our operation. Its goal is to produce a MarketAnalysis
object—a Pydantic model that enforces a structured JSON output for reliable communication between agents.
Gathering Intelligence with DuckDuckGo
First, the agent needs to see the world. We use the DuckDuckGoTools
class directly to fetch the latest news headlines about a specific asset. Using a dedicated news search function gives us more relevant, timely data than a generic web search.
# From analyst_agent.py
from agno.tools.duckduckgo import DuckDuckGoTools
class AnalystAgent:
def __init__(self, ...):
# We instantiate the tool directly for simplicity and reliability
self.search_tool = DuckDuckGoTools()
...
def _search_news(self, topic: str) -> List[str]:
"""Uses the DuckDuckGo tool directly to find news and returns headlines."""
print(f" Searching DuckDuckGo News for '{topic}'...")
try:
search_results_json = self.search_tool.duckduckgo_news(
query=f"latest cryptocurrency news {topic}",
max_results=4
)
parsed_data = json.loads(search_results_json)
headlines = []
if isinstance(parsed_data, list):
for result in parsed_data:
if isinstance(result, dict):
headline = result.get('body', result.get('title', ''))
if headline:
headlines.append(headline)
print(f" Found {len(headlines)} news headlines.")
return headlines
except Exception as e:
print(f"🔥 An error occurred during the DuckDuckGo Search process: {e}")
return []
Synthesizing Data with a Local LLM
This is where the magic happens. We feed both the live price data (from CoinGecko) and the freshly gathered news headlines into a detailed prompt for our local gpt-oss-20b model. The prompt explicitly asks the LLM to act as an expert analyst, correlate the two data sources, and output its decision in a strict JSON format.
# From analyst_agent.py
# ... inside the run() method ...
prompt = f"""
You are an expert financial analyst. Your task is to synthesize live market data with the latest news headlines to provide a single, actionable trading recommendation for {coin_to_analyze}.
**Live Price Data:**
{json.dumps(prices, indent=2)}
**Recent News Headlines about {coin_to_analyze}:**
- {"- ".join(headlines) or "No recent news found."}
**Analysis Task:**
1. Evaluate the sentiment of the news. Is it bullish, bearish, or neutral?
2. Correlate the news with the current price data.
3. Decide on a single action: BUY, SELL, or HOLD {coin_to_analyze}.
Your response MUST be a valid JSON object with the keys "decision", "coin_symbol", "confidence", and "reasoning".
"""
response = ollama.chat(model=self.model, messages=[{'role': 'user', 'content': prompt}], format='json')
llm_output_dict = json.loads(response['message']['content'])
# We add our external data before validating with Pydantic
llm_output_dict['price_data'] = prices
llm_output_dict['news_headlines'] = headlines
analysis = MarketAnalysis.model_validate(llm_output_dict)
Component 2: The Trader Agent - The Hands
The Trader Agent is pragmatic and focused. It doesn't need to reason; it just needs to execute reliably and safely.
Safety First: Checking the Portfolio
Before executing any trade, especially a SELL
, the agent must verify it has the assets to do so. It calls the Recall sandbox's /api/agent/balances
endpoint to get a real-time view of its portfolio. This simple check prevents failed transactions and makes the agent far more robust.
# From trader_agent.py
def _get_portfolio(self):
"""Fetches the current portfolio from the Recall sandbox."""
print(" Checking sandbox portfolio balance...")
endpoint = f"{self.base_url}/api/agent/balances"
try:
r = requests.get(endpoint, headers={"Authorization": f"Bearer {self.api_key}"})
r.raise_for_status()
portfolio_data = r.json()
balances = {
token['symbol']: token['amount']
for token in portfolio_data.get('balances', [])
}
print(f" Current Balances: {balances}")
return balances
except Exception as e:
print(f"🔥 Could not fetch portfolio: {e}")
return {}
Interacting with the Arena
Once the safety checks pass, the agent constructs and sends the trade request to the Recall API. The reason
field is populated directly from the Analyst Agent's reasoning, creating a transparent, auditable trail for each action.
# From trader_agent.py
def _execute_trade(self, from_token, to_token, amount, reason):
endpoint = f"{self.base_url}/api/trade/execute"
payload = {"fromToken": from_token, "toToken": to_token, "amount": amount, "reason": reason}
headers = {"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"}
print(f" Executing trade on Recall sandbox...")
try:
resp = requests.post(endpoint, json=payload, headers=headers)
resp.raise_for_status()
print("✅ Trade executed successfully!", resp.json().get('transaction'))
except requests.exceptions.HTTPError as e:
print(f"🔥 Trade failed! Status: {e.response.status_code}, Response: {e.response.text}")
Component 3: The Orchestrator
The main.py
script is the conductor of our orchestra. It initializes both agents and runs them in a continuous loop, transforming them from one-shot scripts into a persistent, autonomous system that monitors the market every five minutes.
# From main.py
def main():
# ... setup ...
analyst = AnalystAgent()
trader = TraderAgent()
while True:
try:
print(f"\n--- Cycle {cycle_count} ---")
# 1. Analyst agent runs to find an opportunity
analysis_result = analyst.run(COINS_TO_TRACK)
# 2. Trader agent acts on the analysis
if analysis_result:
trader.run(analysis_result)
print(f"--- Cycle {cycle_count} Complete. Waiting for 5 minutes... ---")
cycle_count += 1
time.sleep(300)
except KeyboardInterrupt:
# ... shutdown gracefully ...
The Result: A Working Autonomous Team
After putting all the pieces together, the system came to life. The log output shows the entire chain of command, from data gathering to final execution, working in perfect harmony.
--- Cycle 1 ---
📰 AnalystAgent performing deep analysis...
Fetching live prices from CoinGecko...
Live Prices: {'WETH': 4114.96, ...}
Searching DuckDuckGo News for 'Ethereum WETH'...
[DEBUG] Raw output from DuckDuckGo tool: [ ... news articles ... ]
Found 4 news headlines.
🧠 Analyst Decision: BUY WETH (Confidence: 0.75)
Reasoning: ...outperformed, indicating a bullish sentiment...
📩 TraderAgent received decision: 'BUY WETH'
Checking sandbox portfolio balance...
Current Balances: {'USDC': 5000, ...}
🟢 Preparing to BUY WETH with USDC...
Executing trade on Recall sandbox...
✅ Trade executed successfully! { ... trade details ... }
--- Cycle 1 Complete. Waiting for 5 minutes... ---
We've successfully built a sophisticated, autonomous multi-agent trading bot that leverages the power of local LLMs for reasoning and a decentralized network for execution. This project proves that you don't need massive budgets or complex cloud infrastructure to start building at the cutting edge of AI.
This is just the beginning. From here, you could:
- Add More Data Sources: Integrate on-chain data, social media sentiment, or technical indicators.
- Develop More Complex Strategies: Create agents that can manage a whole portfolio, hedge positions, or even learn from past performance.
- Enter a Recall Competition: Once your agent is battle-tested, enter it into a live Recall competition to see how it stacks up against others and prove its merit on the world's most trustworthy AI leaderboard.
The era of sovereign, decentralized AI is here. Now, what will you build?
Top comments (0)