Build a Crypto Trading Bot with Python — Free API, No Exchange Account Needed

Learn how to build a cryptocurrency trading bot using Python and a free REST API that gives you real-time access to 229 perpetual futures markets — prices, orderbooks, OHLCV candles, and funding rates. No exchange API keys, no KYC, no signup.

March 2026 15 min read Intermediate
Contents
  1. Why Build a Crypto Trading Bot?
  2. Bot Architecture & API Overview
  3. Setup & First API Call
  4. Fetching Market Data — Prices, Orderbooks, Candles
  5. Building a Simple Trading Strategy
  6. Funding Rate Arbitrage Scanner
  7. Real-Time Monitoring Dashboard
  8. Next Steps & Going to Production

1 Why Build a Crypto Trading Bot?

Crypto markets trade 24/7 across hundreds of exchanges. No human can monitor 229 markets simultaneously, but a bot can. Here's what a trading bot gives you:

Most tutorials require you to create exchange accounts, deal with KYC, generate API keys, and navigate complex rate limits. This tutorial uses a free, unified REST API that proxies Hyperliquid's market data — so you can start building in 30 seconds with just curl.

2 Bot Architecture & API Overview

Your bot needs three things: data (what's happening in the market), logic (when to act), and execution (placing orders). This tutorial focuses on data and logic. Here's the API:

EndpointWhat It ReturnsUse Case
GET /api/pricesAll 229 mid-prices in one callMarket scanner, portfolio tracker
GET /api/price/:symbolSingle asset priceQuick price check, alerts
GET /api/book/:symbolL2 orderbook (bids + asks)Spread analysis, liquidity detection
GET /api/candles/:symbolOHLCV candles (1m to 1M)Technical analysis, backtesting
GET /api/funding/:symbolFunding rate historyCarry trade, sentiment analysis
GET /api/marketsAll markets with metadataDiscovery, universe selection
GET /api/market/:symbolSingle market detailsMax leverage, symbol info
Free Tier
100 requests per day with no authentication. For more, create an API key (50 free credits included) — each request costs 1 credit. Top up with USDC on Base for unlimited access.

3 Setup & First API Call

No SDK needed. The API returns JSON over plain HTTP. Let's start with curl to verify everything works:

bash
# Get the current BTC price
curl https://agent-gateway-kappa.vercel.app/v1/defi-trading/api/price/BTC
{"symbol":"BTC","price":"67114.5"}

Now let's set up a Python project:

bash
# Create project directory
mkdir crypto-bot && cd crypto-bot

# Install the only dependency
pip install requests

Create a base client that all your bot modules will use:

python — client.py
import requests

BASE_URL = "https://agent-gateway-kappa.vercel.app/v1/defi-trading"

def get(path, params=None):
    """Make a GET request to the DeFi Trading API."""
    resp = requests.get(f"{BASE_URL}{path}", params=params, timeout=10)
    resp.raise_for_status()
    return resp.json()

def get_price(symbol):
    """Get current price for a symbol."""
    return float(get(f"/api/price/{symbol}")["price"])

def get_all_prices():
    """Get all 229 market prices in one call."""
    data = get("/api/prices")
    return {k: float(v) for k, v in data["prices"].items()}

def get_candles(symbol, interval="1h"):
    """Get OHLCV candles for backtesting."""
    return get(f"/api/candles/{symbol}", {"interval": interval})["candles"]

def get_orderbook(symbol, depth=3):
    """Get L2 orderbook."""
    return get(f"/api/book/{symbol}", {"depth": depth})

def get_funding(symbol):
    """Get funding rate history."""
    return get(f"/api/funding/{symbol}")["funding"]

Test it:

python
from client import get_price, get_all_prices

# Single price
btc = get_price("BTC")
print(f"BTC: ${btc:,.2f}")

# All 229 prices in one request
prices = get_all_prices()
print(f"Tracking {len(prices)} markets")
print(f"Top 5: {dict(sorted(prices.items(), key=lambda x: -x[1])[:5])}")
BTC: $67,114.50 Tracking 229 markets Top 5: {'BTC': 67114.5, 'ETH': 3842.1, 'BNB': 612.3, 'SOL': 188.4, 'AVAX': 42.8}

4 Fetching Market Data — Prices, Orderbooks, Candles

Multi-Market Price Scanner

A trading bot needs to monitor multiple markets simultaneously. Here's a scanner that tracks price changes across all 229 markets:

python — scanner.py
import time
from client import get_all_prices

def scan_markets(interval_sec=60):
    """Monitor all markets for significant price moves."""
    prev_prices = get_all_prices()
    print(f"Monitoring {len(prev_prices)} markets...")

    while True:
        time.sleep(interval_sec)
        curr_prices = get_all_prices()

        movers = []
        for symbol, price in curr_prices.items():
            if symbol in prev_prices and prev_prices[symbol] > 0:
                change = (price - prev_prices[symbol]) / prev_prices[symbol] * 100
                if abs(change) >= 1.0:  # 1% move threshold
                    movers.append((symbol, change, price))

        if movers:
            movers.sort(key=lambda x: abs(x[1]), reverse=True)
            print(f"\n--- Movers ({time.strftime('%H:%M:%S')}) ---")
            for sym, chg, px in movers[:10]:
                direction = "+" if chg > 0 else ""
                print(f"  {sym:<10} {direction}{chg:.2f}%  ${px:,.4f}")

        prev_prices = curr_prices

scan_markets()

Orderbook Spread Analysis

The spread between the best bid and best ask tells you about market liquidity. Wide spreads = less liquid, potentially more volatile:

python — spreads.py
from client import get_orderbook, get_all_prices

def analyze_spreads(symbols):
    """Analyze bid-ask spreads for given symbols."""
    for symbol in symbols:
        book = get_orderbook(symbol, depth=3)
        levels = book["levels"]

        # levels[0] = bids, levels[1] = asks
        best_bid = float(levels[0][0]["px"])
        best_ask = float(levels[1][0]["px"])
        mid = (best_bid + best_ask) / 2
        spread_bps = (best_ask - best_bid) / mid * 10000

        bid_depth = sum(float(l["sz"]) for l in levels[0])
        ask_depth = sum(float(l["sz"]) for l in levels[1])
        imbalance = bid_depth / (bid_depth + ask_depth) * 100

        print(f"{symbol:<8} Spread: {spread_bps:.1f}bps  "
              f"Bid depth: {bid_depth:.1f}  Ask depth: {ask_depth:.1f}  "
              f"Imbalance: {imbalance:.0f}% buy")

# Analyze the top markets
analyze_spreads(["BTC", "ETH", "SOL", "DOGE", "ARB"])
BTC Spread: 0.1bps Bid depth: 273.3 Ask depth: 312.9 Imbalance: 47% buy ETH Spread: 0.3bps Bid depth: 1842.1 Ask depth: 2104.8 Imbalance: 47% buy SOL Spread: 0.5bps Bid depth: 8421.0 Ask depth: 9102.3 Imbalance: 48% buy DOGE Spread: 1.2bps Bid depth: 421891.0 Ask depth: 389102.3 Imbalance: 52% buy ARB Spread: 2.8bps Bid depth: 42189.0 Ask depth: 51023.4 Imbalance: 45% buy

OHLCV Candles for Technical Analysis

Candle data is essential for backtesting. The API provides 9 intervals from 1-minute to 1-month:

python — candles.py
from client import get_candles

def compute_sma(candles, period):
    """Simple moving average over closing prices."""
    closes = [float(c["c"]) for c in candles]
    if len(closes) < period:
        return None
    return sum(closes[-period:]) / period

def compute_rsi(candles, period=14):
    """Relative Strength Index."""
    closes = [float(c["c"]) for c in candles]
    if len(closes) < period + 1:
        return None

    gains, losses = [], []
    for i in range(1, len(closes)):
        delta = closes[i] - closes[i-1]
        gains.append(max(delta, 0))
        losses.append(max(-delta, 0))

    avg_gain = sum(gains[-period:]) / period
    avg_loss = sum(losses[-period:]) / period

    if avg_loss == 0:
        return 100
    rs = avg_gain / avg_loss
    return 100 - (100 / (1 + rs))

# Analyze BTC on 1-hour candles
candles = get_candles("BTC", "1h")
sma_20 = compute_sma(candles, 20)
rsi = compute_rsi(candles)
current = float(candles[-1]["c"])

print(f"BTC Current: ${current:,.0f}")
print(f"BTC SMA(20): ${sma_20:,.0f}")
print(f"BTC RSI(14): {rsi:.1f}")
print(f"Signal: {'ABOVE' if current > sma_20 else 'BELOW'} SMA")
print(f"RSI: {'Overbought' if rsi > 70 else 'Oversold' if rsi < 30 else 'Neutral'}")
BTC Current: $67,114 BTC SMA(20): $66,890 BTC RSI(14): 52.3 Signal: ABOVE SMA RSI: Neutral

5 Building a Simple Trading Strategy

Let's build a momentum scanner that finds markets where price just crossed above the 20-period SMA with RSI between 40-60 (not already overbought):

python — strategy.py
from client import get, get_candles

def momentum_scan():
    """Find markets with bullish momentum signals."""
    # Get all available markets
    markets = get("/api/markets")["markets"]
    symbols = [m["symbol"] for m in markets]

    signals = []
    for symbol in symbols[:30]:  # Top 30 by market cap
        try:
            candles = get_candles(symbol, "1h")
            if len(candles) < 21:
                continue

            closes = [float(c["c"]) for c in candles]
            current = closes[-1]
            prev = closes[-2]

            # SMA crossover
            sma_now = sum(closes[-20:]) / 20
            sma_prev = sum(closes[-21:-1]) / 20

            crossed_above = prev < sma_prev and current > sma_now

            # RSI filter
            gains, losses = [], []
            for i in range(1, len(closes)):
                d = closes[i] - closes[i-1]
                gains.append(max(d, 0))
                losses.append(max(-d, 0))
            ag = sum(gains[-14:]) / 14
            al = sum(losses[-14:]) / 14
            rsi = 100 - (100 / (1 + ag/al)) if al > 0 else 100

            if crossed_above and 40 < rsi < 60:
                signals.append({
                    "symbol": symbol,
                    "price": current,
                    "rsi": rsi,
                    "sma": sma_now,
                    "distance_pct": (current - sma_now) / sma_now * 100
                })
        except Exception:
            continue

    if signals:
        print("=== BULLISH SMA CROSSOVER SIGNALS ===")
        for s in signals:
            print(f"  {s['symbol']:<8} ${s['price']:>10,.2f}  "
                  f"RSI: {s['rsi']:.0f}  "
                  f"+{s['distance_pct']:.2f}% above SMA")
    else:
        print("No crossover signals right now.")

    return signals

momentum_scan()
Important
This tutorial builds a market data scanner and signal generator. It does NOT execute trades. To actually trade, you'd connect to an exchange (Hyperliquid, Binance, etc.) using their trading API. Always paper-trade first and never risk more than you can afford to lose.

6 Funding Rate Arbitrage Scanner

Perpetual futures have funding rates — periodic payments between longs and shorts to keep the price anchored to spot. When funding is highly positive, shorts get paid. When negative, longs get paid. This creates arbitrage opportunities:

python — funding_scanner.py
from client import get, get_funding

def scan_funding_rates():
    """Find extreme funding rates for carry trade opportunities."""
    markets = get("/api/markets")["markets"]

    rates = []
    for m in markets[:50]:  # Top 50 markets
        try:
            funding = get_funding(m["symbol"])
            if not funding:
                continue

            # Get last 24 funding payments
            recent = funding[:24]
            rates_list = [float(f["fundingRate"]) for f in recent]
            avg_rate = sum(rates_list) / len(rates_list)
            annualized = avg_rate * 3 * 365 * 100  # 3 payments/day * 365

            rates.append({
                "symbol": m["symbol"],
                "current_rate": float(funding[0]["fundingRate"]),
                "avg_24h": avg_rate,
                "annualized_pct": annualized,
                "leverage": m.get("maxLeverage", "?")
            })
        except Exception:
            continue

    # Sort by absolute annualized rate
    rates.sort(key=lambda x: abs(x["annualized_pct"]), reverse=True)

    print("=== FUNDING RATE SCANNER ===")
    print(f"{'Symbol':<8} {'Current':>10} {'Avg 24h':>10} {'Annual':>10} {'Leverage':>8}")
    print("-" * 52)

    for r in rates[:15]:
        direction = "LONGS PAY" if r["current_rate"] > 0 else "SHORTS PAY"
        print(f"{r['symbol']:<8} {r['current_rate']:>+10.6f} "
              f"{r['avg_24h']:>+10.6f} {r['annualized_pct']:>+9.1f}% "
              f"{r['leverage']:>5}x  {direction}")

scan_funding_rates()
=== FUNDING RATE SCANNER === Symbol Current Avg 24h Annual Leverage ---------------------------------------------------- DOGE +0.000125 +0.000098 +10.7% 20x LONGS PAY PEPE +0.000250 +0.000180 +19.7% 10x LONGS PAY WIF -0.000089 -0.000120 -13.1% 10x SHORTS PAY BTC +0.000013 +0.000010 +1.1% 40x LONGS PAY ETH +0.000025 +0.000015 +1.6% 25x LONGS PAY
What to look for
Markets with annualized funding rates above +20% or below -20% are potential carry trade candidates. You'd go short (to earn funding) on high positive rates, or long on high negative rates, while hedging spot exposure on another exchange.

7 Real-Time Monitoring Dashboard

Combine everything into a terminal dashboard that monitors your watchlist with live prices, RSI, and funding rates:

python — dashboard.py
import time, os
from client import get_price, get_candles, get_funding

WATCHLIST = ["BTC", "ETH", "SOL", "DOGE", "ARB", "AVAX"]

def dashboard():
    while True:
        os.system("clear")
        print(f"  CRYPTO TRADING BOT DASHBOARD  |  {time.strftime('%H:%M:%S UTC')}")
        print("=" * 72)
        print(f"{'Symbol':<8} {'Price':>12} {'RSI':>6} {'SMA20':>12} {'Funding':>10}")
        print("-" * 72)

        for symbol in WATCHLIST:
            try:
                price = get_price(symbol)
                candles = get_candles(symbol, "1h")
                closes = [float(c["c"]) for c in candles]

                # SMA
                sma = sum(closes[-20:]) / 20 if len(closes) >= 20 else 0

                # RSI
                gains = [max(closes[i]-closes[i-1], 0) for i in range(1, len(closes))]
                losses = [max(closes[i-1]-closes[i], 0) for i in range(1, len(closes))]
                ag = sum(gains[-14:])/14
                al = sum(losses[-14:])/14
                rsi = 100-(100/(1+ag/al)) if al > 0 else 100

                # Funding
                funding = get_funding(symbol)
                fr = float(funding[0]["fundingRate"]) if funding else 0

                rsi_label = f"{rsi:.0f}"
                print(f"{symbol:<8} ${price:>11,.2f} {rsi_label:>6} ${sma:>11,.2f} {fr:>+10.6f}")
            except Exception as e:
                print(f"{symbol:<8} {'error':>12}")

        print("\nRefreshing in 60s... (Ctrl+C to exit)")
        time.sleep(60)

dashboard()
CRYPTO TRADING BOT DASHBOARD | 14:30:15 UTC ======================================================================== Symbol Price RSI SMA20 Funding ------------------------------------------------------------------------ BTC $67,114.50 52 $66,890.00 +0.000013 ETH $3,842.10 48 $3,801.50 +0.000025 SOL $188.40 55 $185.20 +0.000040 DOGE $0.18 61 $0.17 +0.000125 ARB $1.24 44 $1.21 -0.000012 AVAX $42.80 50 $42.10 +0.000018 Refreshing in 60s... (Ctrl+C to exit)

8 Next Steps & Going to Production

You now have a complete market data pipeline. Here's how to take it further:

Get an API Key for More Requests

The free tier gives you 100 requests/day. For a real trading bot, create an API key to get 50 free credits (each request = 1 credit):

bash
# Create an API key (50 free credits included)
curl -X POST https://agent-gateway-kappa.vercel.app/v1/defi-trading/api/keys/create

# Use it in requests
curl -H "Authorization: Bearer dt_your_key_here" \
  https://agent-gateway-kappa.vercel.app/v1/defi-trading/api/prices

# Check your balance
curl -H "Authorization: Bearer dt_your_key_here" \
  https://agent-gateway-kappa.vercel.app/v1/defi-trading/api/keys/balance

Need more? Top up with USDC on Base — 500 credits per USDC (min 0.5 USDC). See GET /api/payments/info for details.

Add to Your Python Client

python
# Updated client with API key support
API_KEY = "dt_your_key_here"  # From POST /api/keys/create

def get(path, params=None):
    headers = {}
    if API_KEY:
        headers["Authorization"] = f"Bearer {API_KEY}"
    resp = requests.get(f"{BASE_URL}{path}", params=params,
                        headers=headers, timeout=10)
    # Check remaining credits from response headers
    remaining = resp.headers.get("X-Credits-Remaining")
    if remaining:
        print(f"Credits remaining: {remaining}")
    resp.raise_for_status()
    return resp.json()

Production Checklist

Start Building Your Trading Bot

229 perpetual futures markets. Real-time prices, orderbooks, candles, and funding rates. Free to start.

Explore API Docs

Related APIs