Guide 13 min read

Building Autonomous Trading Agents with LLMs

A practical guide to building AI agents that autonomously monitor markets, analyze opportunities, and generate trading signals using LLMs and the TickAtlas API.

9Sections
6Code samples
13Min read
GuideCategory

What Makes an Agent Different from a Chatbot?

A chatbot responds to questions. An agent acts on its own. A trading agent runs in a loop, decides when to check the market, determines which instruments need attention, fetches the relevant data, analyzes it, and takes action — all without human prompting.

The key ingredients are: a planning loop, tool access (the TickAtlas API for market data), memory (to track what it has already analyzed), and guardrails (to prevent it from doing something catastrophic).

Agent Architecture

Shell Agent Architecture
                     +------------------+
                     |   Agent Loop     |
                     |  (runs every N   |
                     |   minutes)       |
                     +--------+---------+
                              |
              +---------------+---------------+
              |               |               |
     +--------v---+   +------v------+  +------v------+
     |  Observe   |   |   Think     |  |    Act      |
     | (fetch     |   | (LLM       |  | (send alert,|
     |  market    |   |  analyzes   |  |  log trade, |
     |  data)     |   |  data)      |  |  update     |
     +------------+   +-------------+  |  memory)    |
                                       +-------------+

Step 1: The Agent Loop

Python Step 1: The Agent Loop
import time
import json
from datetime import datetime

class TradingAgent:
    def __init__(self, api_key: str, llm_client, symbols: list[str]):
        self.api_key = api_key
        self.llm = llm_client
        self.symbols = symbols
        self.memory = []  # Track past observations and decisions
        self.check_interval = 300  # 5 minutes

    def run(self):
        """Main agent loop — runs indefinitely."""
        print(f"[{datetime.utcnow()}] Agent started. Watching {self.symbols}")

        while True:
            try:
                observations = self.observe()
                analysis = self.think(observations)
                self.act(analysis)
            except Exception as e:
                print(f"Agent error: {e}")

            time.sleep(self.check_interval)

Step 2: Observe — Fetch Market Data

Python Step 2: Observe — Fetch Market Data
import requests

CLAW_BASE = "https://tickatlas.com/v1"

def observe(self) -> list[dict]:
    """Fetch indicators for all watched symbols."""
    observations = []
    headers = {"X-API-Key": self.api_key}

    for symbol in self.symbols:
        resp = requests.get(f"{CLAW_BASE}/indicators", params={
            "symbol": symbol,
            "timeframe": "H1",
        }, headers=headers)

        if resp.status_code == 200:
            data = resp.json()["data"]
            observations.append({
                "symbol": symbol,
                "indicators": data["indicators"],
                "ohlcv": data.get("ohlcv", {}),
                "updated_at": data["updated_at"]
            })

    return observations

Step 3: Think — LLM Analysis

This is where the LLM earns its keep. It receives the raw indicator data plus the agent's memory of recent observations and produces a structured analysis.

Python Step 3: Think — LLM Analysis
def think(self, observations: list[dict]) -> dict:
    """Use LLM to analyze observations and decide on actions."""
    # Build context from memory
    recent_memory = self.memory[-10:]  # Last 10 observations

    prompt = f"""You are an autonomous trading analyst agent.

Current observations:
{json.dumps(observations, indent=2)}

Recent memory (previous analyses):
{json.dumps(recent_memory, indent=2)}

Analyze each symbol and return a JSON object with this structure:
{{
  "signals": [
    {{
      "symbol": "EURUSD",
      "action": "ALERT_BUY" | "ALERT_SELL" | "WATCH" | "NO_ACTION",
      "confidence": 0.0-1.0,
      "reasoning": "brief explanation",
      "key_levels": {{"support": 1.0820, "resistance": 1.0890}}
    }}
  ],
  "market_summary": "One paragraph overview of current conditions"
}}

Rules:
- Only signal ALERT_BUY/ALERT_SELL when confidence > 0.7
- Consider what has changed since the last observation
- Flag any divergences between indicators
- Note when ADX < 20 (no trend) — avoid trend signals in ranging markets"""

    response = self.llm.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=2000,
        messages=[{"role": "user", "content": prompt}]
    )

    # Parse the structured response
    text = response.content[0].text
    analysis = json.loads(text)

    # Save to memory
    self.memory.append({
        "timestamp": datetime.utcnow().isoformat(),
        "observations": observations,
        "analysis": analysis
    })

    return analysis

Step 4: Act — Execute Decisions

Python Step 4: Act — Execute Decisions
def act(self, analysis: dict):
    """Execute the agent's decisions."""
    for signal in analysis.get("signals", []):
        if signal["action"] in ("ALERT_BUY", "ALERT_SELL"):
            self.send_alert(signal)

        elif signal["action"] == "WATCH":
            print(f"[WATCH] {signal['symbol']}: {signal['reasoning']}")

def send_alert(self, signal: dict):
    """Send alert via Telegram, email, or webhook."""
    msg = (
        f"{'BUY' if 'BUY' in signal['action'] else 'SELL'} Alert: "
        f"{signal['symbol']}\n"
        f"Confidence: {signal['confidence']:.0%}\n"
        f"Reason: {signal['reasoning']}\n"
        f"Support: {signal['key_levels']['support']}\n"
        f"Resistance: {signal['key_levels']['resistance']}"
    )
    print(f"[ALERT] {msg}")
    # Send to Telegram, Slack, email, etc.

Safety Guardrails

Never Auto-Execute Trades

Agents should generate alerts and analysis, not place orders. Keep a human in the loop for execution decisions.

Rate Limit LLM Calls

At $3-15 per million tokens, an agent checking 10 symbols every 5 minutes can get expensive. Use the LLM for analysis, not for every data fetch.

Bounded Memory

Cap the memory buffer. An agent with unlimited memory will eventually exceed the LLM's context window and degrade in quality.

Confidence Thresholds

Only act on high-confidence signals. The agent's structured output includes a confidence score — filter aggressively.

Running the Agent

Python Running the Agent
import anthropic
import os

if __name__ == "__main__":
    llm = anthropic.Anthropic()
    agent = TradingAgent(
        api_key=os.environ["CLAW_API_KEY"],
        llm_client=llm,
        symbols=["EURUSD", "GBPUSD", "XAUUSD", "BTCUSD"]
    )
    agent.run()

Further Reading

Run this against live data.

Every account starts pay-as-you-go with $2.50 of credit and no card. Paste the key into the samples above and the requests work unchanged.

Prefer the API to the article

Build it instead of reading about it.

Create a key, run the first request, then extend one layer at a time. Every account starts pay-as-you-go with $2.50 of credit — no card required.