How to Build a Crypto Trading Bot with a Swap API

Last updated:

TL;DR

A crypto trading bot needs three things: a price signal, swap execution, and safety checks. swapapi handles execution — one GET request returns executable calldata across 46 EVM chains, no API key required. This guide shows how to build a complete trading bot from scratch.

Architecture Overview

A trading bot is a pipeline: data comes in, decisions are made, trades are executed, and results are monitored.

1

Price Feed

Monitor token prices via CoinGecko, on-chain oracles, or DEX prices

2

Strategy Logic

Decide when and what to trade: arbitrage, DCA, rebalancing

4

Execution

Sign and submit the transaction on-chain

5

Monitoring

Track results, handle failures, log P&L

Choose Your Strategy

Your strategy determines everything else — what data you need, how often you trade, and what safety checks matter most.

DCA (Dollar-Cost Averaging)

Difficulty: Low / Frequency: Hourly or Daily

Buy a fixed amount of a token at regular intervals regardless of price. The simplest strategy to implement. Example: buy 0.1 ETH worth of USDC every hour.

Rebalancing

Difficulty: Medium / Frequency: Every 15-60 min

Maintain a target portfolio ratio (e.g., 60% ETH / 40% USDC). When one asset exceeds its target by a threshold, sell the excess to rebalance.

Arbitrage

Difficulty: High / Frequency: Continuous

Buy where price is lower, sell where it is higher. swapapi is single-chain, so this works for cross-DEX arbitrage on the same chain — the aggregator already finds the best route.

Signal-based

Difficulty: Variable / Frequency: Event-driven

Trade based on external signals: technical indicators, social sentiment, oracle price feeds, or on-chain events. Your bot watches for signals and executes when conditions are met.

Get Swap Quotes

A single GET request returns the optimal route, expected output, price impact, and ready-to-execute calldata.

bash — get a swap quote
$ curl "https://api.swapapi.dev/v1/swap/1?\
  tokenIn=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE&\
  tokenOut=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48&\
  amount=100000000000000000&\
  sender=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
  • No API key — No credential management, no key rotation, no secrets to leak. Your bot just makes HTTP requests.
  • Rate limit: 30 req/min — Enough for DCA (1 req/hour), rebalancing (4 req/hour), and most signal-based strategies.
  • Ready-to-execute calldata — The response includes tx.to, tx.data, and tx.value. No additional encoding needed.
  • Built-in RPC URLs — The response includes an rpcUrl field, so you don't need a separate RPC provider.

Safety Checks

Safety checks are what separate a working bot from one that loses money. Never skip these.

  • Check priceImpact — Reject any swap where priceImpact < -0.05 (worse than -5%). Large price impact means you are moving the market against yourself.
  • Set maximum trade size — Cap the amount your bot can swap in a single transaction. Start small and increase as you gain confidence.
  • Simulate with eth_call — Before submitting a transaction, simulate it with eth_call to check if it would revert. This costs no gas.
  • Check wallet balance — Verify your wallet has enough tokens (and gas) before attempting a swap. A failed transaction still costs gas.
  • Never retry in a tight loop — If a swap fails, wait before retrying. Tight retry loops can drain gas on repeated failures.
  • Understand slippage — Read the price impact and slippage guide to set appropriate slippage tolerances.

Execute Trades

Complete working examples in TypeScript and Python. Copy, customize the strategy parameters, and run.

dca-bot.ts — TypeScript DCA Bot
// TypeScript DCA Bot — buys USDC with ETH every hour
// Dependencies: npm install viem

import { createWalletClient, http, parseEther } from "viem";
import { mainnet } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";

const SWAP_API = "https://api.swapapi.dev/v1/swap";
const CHAIN_ID = 1;
const ETH = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
const USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
const AMOUNT = parseEther("0.1").toString(); // 0.1 ETH per trade
const SENDER = "0xYourWalletAddress";
const MAX_PRICE_IMPACT = -0.05;

async function dcaBuy() {
  // 1. Get swap quote
  const url = `${SWAP_API}/${CHAIN_ID}?` + new URLSearchParams({
    tokenIn: ETH,
    tokenOut: USDC,
    amount: AMOUNT,
    sender: SENDER,
  });

  const res = await fetch(url);
  const { success, data } = await res.json();

  if (!success) {
    console.error("API error");
    return;
  }

  if (data.status !== "Successful") {
    console.error(`Status: ${data.status}`);
    return;
  }

  // 2. Safety check
  if (data.priceImpact < MAX_PRICE_IMPACT) {
    console.error(`Price impact too high: ${data.priceImpact}`);
    return;
  }

  // 3. Execute
  const account = privateKeyToAccount("0x...");
  const client = createWalletClient({
    account,
    chain: mainnet,
    transport: http(data.rpcUrl),
  });

  const hash = await client.sendTransaction({
    to: data.tx.to,
    data: data.tx.data,
    value: BigInt(data.tx.value ?? "0"),
  });

  console.log(`DCA buy executed: ${hash}`);
  console.log(`Expected: ${data.expectedAmountOut} USDC (raw)`);
}

// Run every hour
setInterval(dcaBuy, 60 * 60 * 1000);
dcaBuy(); // Run immediately
rebalance-bot.py — Python Rebalancing Bot
# Python Rebalancing Bot — maintains 60/40 ETH/USDC ratio
# Dependencies: pip install requests web3

import requests
from web3 import Web3
import time

SWAP_API = "https://api.swapapi.dev/v1/swap"
CHAIN_ID = 1
ETH = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"
USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
SENDER = "0xYourWalletAddress"
TARGET_ETH_RATIO = 0.6  # 60% ETH, 40% USDC

def get_swap_quote(token_in, token_out, amount):
    """Get swap quote from swapapi — no API key needed."""
    response = requests.get(
        f"{SWAP_API}/{CHAIN_ID}",
        params={
            "tokenIn": token_in,
            "tokenOut": token_out,
            "amount": str(amount),
            "sender": SENDER,
        },
        timeout=15,
    )
    result = response.json()
    if not result["success"]:
        raise Exception(f"API error: {result['error']}")
    return result["data"]

def check_and_rebalance():
    """Check portfolio balance and rebalance if needed."""
    w3 = Web3(Web3.HTTPProvider("https://eth.llamarpc.com"))

    eth_balance = w3.eth.get_balance(SENDER)
    # ... check USDC balance, calculate ratios
    # ... if ratio deviates > 5%, execute rebalance swap

    quote = get_swap_quote(ETH, USDC, amount_to_sell)

    if quote["status"] != "Successful":
        print(f"No route: {quote['status']}")
        return

    if quote["priceImpact"] < -0.05:
        print(f"Price impact too high: {quote['priceImpact']}")
        return

    # Execute the swap
    tx = {
        "from": SENDER,
        "to": Web3.to_checksum_address(quote["tx"]["to"]),
        "data": quote["tx"]["data"],
        "value": int(quote["tx"].get("value", "0")),
    }
    # ... sign and send

# Run every 15 minutes
while True:
    check_and_rebalance()
    time.sleep(900)

Production Considerations

A bot that works in testing can still fail in production. These are the things that matter when real money is on the line.

  • Error handling — Retry UPSTREAM_ERROR (502) with exponential backoff. Don't retry INVALID_PARAMS (400) — those are bugs in your code.
  • Gas management — Use eth_estimateGas plus a 20% buffer. On EIP-1559 chains, let your library (viem, ethers, web3.py) handle gas pricing automatically.
  • Rate limits — swapapi allows approximately 30 requests per minute per IP. Space out your requests instead of bursting. If you need more throughput, use multiple IPs or request a higher limit.
  • Stale calldata — Submit the transaction within 30 seconds of fetching the quote. If your bot has latency, re-fetch the quote before executing.
  • Monitoring — Log every trade with amounts, price impact, gas cost, and transaction hash. Track P&L daily. Alert on failures.
  • Security — Never hardcode private keys. Use environment variables or a secrets manager. Consider using a dedicated trading wallet with limited funds so a compromised key cannot drain your main wallet.
error-handling.ts — retry logic
// Exponential backoff for transient errors
async function fetchWithRetry(url: string, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const res = await fetch(url);
    const json = await res.json();

    if (json.success) return json.data;

    // Don't retry client errors (400) — fix your code
    if (res.status === 400) throw new Error(json.error);

    // Retry server errors (502) with backoff
    if (res.status === 502) {
      const delay = 1000 * Math.pow(2, i); // 1s, 2s, 4s
      await new Promise(r => setTimeout(r, delay));
      continue;
    }

    throw new Error(`Unexpected status: ${res.status}`);
  }
  throw new Error("Max retries exceeded");
}

Keep building

Compare APIs

Choose the right aggregator

Side-by-side comparison of swapapi, 1inch, 0x, Li.Fi, and more. See which fits your bot's needs.

Read comparison →

Price Impact & Slippage Guide

Protect your trades

Understand price impact, slippage tolerance, and how to set safe parameters for automated trading.

Read guide →

Supported Chains

46 EVM chains

Full list of supported chains with chain IDs, native tokens, and key token addresses.

View chains →

AI Agent Integration

Autonomous trading

How to integrate swapapi into AI agents and autonomous systems. No API key, no credentials.

Read guide →