Building a Trading Bot
This guide walks through building an automated trading bot from scratch. By the end, you will have a runnable script that registers an agent, creates a managed wallet, monitors token prices, and executes swaps when conditions are met.
What the Bot Does
1. Registers with the Suwappu API and saves the API key
2. Creates a managed wallet for server-side swap execution
3. Polls token prices in a loop
4. Executes a swap when a price target is hit
5. Tracks the swap status until completion
6. Handles errors and rate limits gracefully
Python Version
class=class="hl-str">"hl-comment">#!/usr/bin/env python3
class="hl-str">""class="hl-str">"
Suwappu Trading Bot — Python
Monitors ETH/USDC price on Base and buys when price drops below target.
"class="hl-str">""
import os
import sys
import time
import requests
BASE_URL = class="hl-str">"https:class="hl-commentclass="hl-str">">//api.suwappu.bot/v1/agent"
class=class="hl-str">"hl-comment"># Configuration
CHAIN = class="hl-str">"base"
FROM_TOKEN = class="hl-str">"USDC"
TO_TOKEN = class="hl-str">"ETH"
BUY_AMOUNT = class="hl-str">"100" class=class="hl-str">"hl-comment"># Buy 100 USDC worth of ETH
PRICE_TARGET = 2000.0 class=class="hl-str">"hl-comment"># Buy when ETH drops below $2000
POLL_INTERVAL = 30 class=class="hl-str">"hl-comment"># Check price every 30 seconds
MAX_RETRIES = 3 class=class="hl-str">"hl-comment"># Retry failed requests up to 3 times
def register_agent():
class="hl-str">""class="hl-str">"Register a new agent and return the API key."class="hl-str">""
response = requests.post(
fclass="hl-str">"{BASE_URL}/register",
json={class="hl-str">"name": fclass="hl-str">"trading-bot-{int(time.time())}"},
)
response.raise_for_status()
data = response.json()
api_key = data[class="hl-str">"agent"][class="hl-str">"api_key"]
print(fclass="hl-str">"Registered agent: {data[class="hl-str">'agent'][class="hl-str">'name']}")
print(fclass="hl-str">"API key: {api_key[:20]}...")
return api_key
def create_wallet(headers):
class="hl-str">""class="hl-str">"Create a managed wallet for swap execution."class="hl-str">""
response = requests.post(fclass="hl-str">"{BASE_URL}/wallets", headers=headers)
response.raise_for_status()
wallet = response.json()[class="hl-str">"wallet"]
print(fclass="hl-str">"Wallet created: {wallet[class="hl-str">'address']}")
print(fclass="hl-str">"Chain type: {wallet[class="hl-str">'chain_type']}")
print(fclass="hl-str">"Fund this wallet with {FROM_TOKEN} on {CHAIN} to start trading.")
return wallet[class="hl-str">"address"]
def get_price(headers, token, chain):
class="hl-str">""class="hl-str">"Fetch the current USD price for a token."class="hl-str">""
response = requests.get(
fclass="hl-str">"{BASE_URL}/prices",
headers=headers,
params={class="hl-str">"token": token, class="hl-str">"chain": chain},
)
response.raise_for_status()
return float(response.json()[class="hl-str">"price_usd"])
def execute_swap(headers, from_token, to_token, amount, chain):
class="hl-str">""class="hl-str">"Get a quote and execute a swap. Returns the swap ID."class="hl-str">""
class=class="hl-str">"hl-comment"># Step 1: Get a quote
quote_response = requests.post(
fclass="hl-str">"{BASE_URL}/quote",
headers=headers,
json={
class="hl-str">"from_token": from_token,
class="hl-str">"to_token": to_token,
class="hl-str">"amount": amount,
class="hl-str">"chain": chain,
},
)
quote_response.raise_for_status()
quote = quote_response.json()
print(fclass="hl-str">"Quote: {amount} {from_token} -> {quote[class="hl-str">'expected_output']} {to_token}")
class=class="hl-str">"hl-comment"># Step 2: Execute
swap_response = requests.post(
fclass="hl-str">"{BASE_URL}/swap/execute",
headers=headers,
json={class="hl-str">"quote_id": quote[class="hl-str">"quote_id"]},
)
swap_response.raise_for_status()
swap = swap_response.json()
print(fclass="hl-str">"Swap submitted: ID {swap[class="hl-str">'swap_id']}, tx: {swap.get(class="hl-str">'tx_hash', class="hl-str">'pending')}")
return swap[class="hl-str">"swap_id"]
def wait_for_completion(headers, swap_id):
class="hl-str">""class="hl-str">"Poll swap status until it completes or fails."class="hl-str">""
while True:
response = requests.get(
fclass="hl-str">"{BASE_URL}/swap/status/{swap_id}",
headers=headers,
)
response.raise_for_status()
status = response.json()
print(fclass="hl-str">" Swap {swap_id}: {status[class="hl-str">'status']}")
if status[class="hl-str">"status"] == class="hl-str">"completed":
print(fclass="hl-str">" Completed! TX: {status[class="hl-str">'tx_hash']}")
return True
elif status[class="hl-str">"status"] == class="hl-str">"failed":
print(fclass="hl-str">" Failed.")
return False
time.sleep(5)
def main():
class=class="hl-str">"hl-comment"># Use existing API key or register a new agent
api_key = os.environ.get(class="hl-str">"SUWAPPU_API_KEY")
if not api_key:
print(class="hl-str">"No SUWAPPU_API_KEY found. Registering new agent...")
api_key = register_agent()
print(fclass="hl-str">"\nSet this for future runs:")
print(fclass="hl-str">" export SUWAPPU_API_KEY={api_key}\n")
headers = {class="hl-str">"Authorization": fclass="hl-str">"Bearer {api_key}"}
class=class="hl-str">"hl-comment"># Check for existing wallets or create one
wallets = requests.get(fclass="hl-str">"{BASE_URL}/wallets", headers=headers).json()
if not wallets.get(class="hl-str">"wallets"):
print(class="hl-str">"No wallets found. Creating one...")
address = create_wallet(headers)
print(fclass="hl-str">"\nFund {address} with {FROM_TOKEN} on {CHAIN}, then restart.\n")
sys.exit(0)
else:
address = wallets[class="hl-str">"wallets"][0][class="hl-str">"address"]
print(fclass="hl-str">"Using wallet: {address}")
class=class="hl-str">"hl-comment"># Price monitoring loop
print(fclass="hl-str">"\nMonitoring {TO_TOKEN} price on {CHAIN}...")
print(fclass="hl-str">"Will buy {BUY_AMOUNT} {FROM_TOKEN} worth of {TO_TOKEN} when price < ${PRICE_TARGET}")
print(fclass="hl-str">"Checking every {POLL_INTERVAL}s. Press Ctrl+C to stop.\n")
retries = 0
while True:
try:
price = get_price(headers, TO_TOKEN, CHAIN)
print(fclass="hl-str">"{TO_TOKEN}: ${price:.2f}", end=class="hl-str">"")
if price < PRICE_TARGET:
print(fclass="hl-str">" < ${PRICE_TARGET} -- BUYING!")
swap_id = execute_swap(
headers, FROM_TOKEN, TO_TOKEN, BUY_AMOUNT, CHAIN
)
success = wait_for_completion(headers, swap_id)
if success:
print(class="hl-str">"Trade executed successfully.")
else:
print(class="hl-str">"Trade failed. Will retry on next signal.")
else:
print(fclass="hl-str">" (target: < ${PRICE_TARGET})")
retries = 0 class=class="hl-str">"hl-comment"># Reset retries on success
except requests.exceptions.HTTPError as e:
if e.response.status_code == 429:
retries += 1
wait = min(60, POLL_INTERVAL * retries)
print(fclass="hl-str">"Rate limited. Waiting {wait}s... (retry {retries}/{MAX_RETRIES})")
time.sleep(wait)
if retries >= MAX_RETRIES:
print(class="hl-str">"Max retries reached. Exiting.")
sys.exit(1)
continue
else:
print(fclass="hl-str">"HTTP error: {e}")
retries += 1
if retries >= MAX_RETRIES:
print(class="hl-str">"Max retries reached. Exiting.")
sys.exit(1)
except KeyboardInterrupt:
print(class="hl-str">"\nStopped.")
sys.exit(0)
except Exception as e:
print(fclass="hl-str">"Error: {e}")
retries += 1
if retries >= MAX_RETRIES:
print(class="hl-str">"Max retries reached. Exiting.")
sys.exit(1)
time.sleep(POLL_INTERVAL)
if __name__ == class="hl-str">"__main__":
main()
Running the Python Bot
-str">"hl-comment"># Install dependencies
-kw">pip install requests
-str">"hl-comment"># First run: registers agent and creates wallet
python trading_bot.py
-str">"hl-comment"># Set the API key for future runs
-kw">export SUWAPPU_API_KEY=suwappu_sk_your_api_key
-str">"hl-comment"># Fund the wallet address printed above, then run again
python trading_bot.py
---
TypeScript Version
class=class="hl-str">"hl-comment">#!/usr/bin/env npx tsx
/**
* Suwappu Trading Bot — TypeScript
* Monitors ETH/USDC price on Base and buys when price drops below target.
*/
const BASE_URL = class="hl-str">"https:class="hl-commentclass="hl-str">">//api.suwappu.bot/v1/agent";
class=class="hl-str">"hl-comment">// Configuration
const CHAIN = class="hl-str">"base";
const FROM_TOKEN = class="hl-str">"USDC";
const TO_TOKEN = class="hl-str">"ETH";
const BUY_AMOUNT = class="hl-str">"100";
const PRICE_TARGET = 2000.0;
const POLL_INTERVAL = 30_000; class=class="hl-str">"hl-comment">// 30 seconds
const MAX_RETRIES = 3;
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
async function api(
path: string,
options: RequestInit & { params?: Record<string, string> } = {},
apiKey?: string
) {
const { params, ...fetchOptions } = options;
let url = ${BASE_URL}${path};
if (params) url += ?${new URLSearchParams(params)};
const headers: Record<string, string> = {
class="hl-str">"Content-Type": class="hl-str">"application/json",
...(options.headers as Record<string, string>),
};
if (apiKey) headers.Authorization = Bearer ${apiKey};
const response = await fetch(url, { ...fetchOptions, headers });
if (!response.ok) {
const text = await response.text();
throw new Error(HTTP ${response.status}: ${text});
}
if (response.status === 204) return {};
return response.json();
}
async function registerAgent(): Promise<string> {
const data = await api(class="hl-str">"/register", {
method: class="hl-str">"POST",
body: JSON.stringify({ name: trading-bot-${Date.now()} }),
});
const apiKey = data.agent.api_key;
console.log(Registered agent: ${data.agent.name});
console.log(API key: ${apiKey.slice(0, 20)}...);
return apiKey;
}
async function createWallet(apiKey: string): Promise<string> {
const data = await api(class="hl-str">"/wallets", { method: class="hl-str">"POST" }, apiKey);
const wallet = data.wallet;
console.log(Wallet created: ${wallet.address});
console.log(Chain type: ${wallet.chain_type});
console.log(Fund this wallet with ${FROM_TOKEN} on ${CHAIN} to start trading.);
return wallet.address;
}
async function getPrice(apiKey: string, token: string, chain: string): Promise<number> {
const data = await api(class="hl-str">"/prices", { params: { token, chain } }, apiKey);
return parseFloat(data.price_usd);
}
async function executeSwap(
apiKey: string,
fromToken: string,
toToken: string,
amount: string,
chain: string
): Promise<number> {
class=class="hl-str">"hl-comment">// Get a quote
const quote = await api(
class="hl-str">"/quote",
{
method: class="hl-str">"POST",
body: JSON.stringify({
from_token: fromToken,
to_token: toToken,
amount,
chain,
}),
},
apiKey
);
console.log(Quote: ${amount} ${fromToken} -> ${quote.expected_output} ${toToken});
class=class="hl-str">"hl-comment">// Execute
const swap = await api(
class="hl-str">"/swap/execute",
{
method: class="hl-str">"POST",
body: JSON.stringify({ quote_id: quote.quote_id }),
},
apiKey
);
console.log(Swap submitted: ID ${swap.swap_id}, tx: ${swap.tx_hash ?? class="hl-str">"pending"});
return swap.swap_id;
}
async function waitForCompletion(apiKey: string, swapId: number): Promise<boolean> {
while (true) {
const status = await api(/swap/status/${swapId}, {}, apiKey);
console.log( Swap ${swapId}: ${status.status});
if (status.status === class="hl-str">"completed") {
console.log( Completed! TX: ${status.tx_hash});
return true;
}
if (status.status === class="hl-str">"failed") {
console.log( Failed.);
return false;
}
await sleep(5000);
}
}
async function main() {
class=class="hl-str">"hl-comment">// Use existing API key or register a new agent
let apiKey = process.env.SUWAPPU_API_KEY;
if (!apiKey) {
console.log(class="hl-str">"No SUWAPPU_API_KEY found. Registering new agent...");
apiKey = await registerAgent();
console.log(\nSet this for future runs:);
console.log( export SUWAPPU_API_KEY=${apiKey}\n);
}
class=class="hl-str">"hl-comment">// Check for existing wallets or create one
const walletData = await api(class="hl-str">"/wallets", {}, apiKey);
if (!walletData.wallets?.length) {
console.log(class="hl-str">"No wallets found. Creating one...");
const address = await createWallet(apiKey);
console.log(\nFund ${address} with ${FROM_TOKEN} on ${CHAIN}, then restart.\n);
process.exit(0);
}
const address = walletData.wallets[0].address;
console.log(Using wallet: ${address});
class=class="hl-str">"hl-comment">// Price monitoring loop
console.log(\nMonitoring ${TO_TOKEN} price on ${CHAIN}...);
console.log(
Will buy ${BUY_AMOUNT} ${FROM_TOKEN} worth of ${TO_TOKEN} when price < $${PRICE_TARGET}
);
console.log(Checking every ${POLL_INTERVAL / 1000}s. Press Ctrl+C to stop.\n);
let retries = 0;
while (true) {
try {
const price = await getPrice(apiKey, TO_TOKEN, CHAIN);
process.stdout.write(${TO_TOKEN}: $${price.toFixed(2)});
if (price < PRICE_TARGET) {
console.log( < $${PRICE_TARGET} -- BUYING!);
const swapId = await executeSwap(apiKey, FROM_TOKEN, TO_TOKEN, BUY_AMOUNT, CHAIN);
const success = await waitForCompletion(apiKey, swapId);
console.log(success ? class="hl-str">"Trade executed successfully." : class="hl-str">"Trade failed. Will retry.");
} else {
console.log( (target: < $${PRICE_TARGET}));
}
retries = 0;
} catch (error: unknown) {
const message = error instanceof Error ? error.message : String(error);
if (message.includes(class="hl-str">"429")) {
retries++;
const wait = Math.min(60_000, POLL_INTERVAL * retries);
console.log(Rate limited. Waiting ${wait / 1000}s... (retry ${retries}/${MAX_RETRIES}));
await sleep(wait);
if (retries >= MAX_RETRIES) {
console.log(class="hl-str">"Max retries reached. Exiting.");
process.exit(1);
}
continue;
}
console.error(Error: ${message});
retries++;
if (retries >= MAX_RETRIES) {
console.log(class="hl-str">"Max retries reached. Exiting.");
process.exit(1);
}
}
await sleep(POLL_INTERVAL);
}
}
main().catch(console.error);
Running the TypeScript Bot
-str">"hl-comment"># Install tsx for running TypeScript directly
-kw">npm install -g tsx
-str">"hl-comment"># First run: registers agent and creates wallet
npx tsx trading_bot.ts
-str">"hl-comment"># Set the API key for future runs
-kw">export SUWAPPU_API_KEY=suwappu_sk_your_api_key
-str">"hl-comment"># Fund the wallet address printed above, then run again
npx tsx trading_bot.ts
---
Customizing the Bot
Different Trading Strategies
The bot above uses a simple "buy below target price" strategy. Here are ideas for modifications:
Dollar-cost averaging (DCA): Remove the price check and buy a fixed amount at regular intervals.class=class="hl-str">"hl-comment"># Replace the price check with a simple timer
while True:
swap_id = execute_swap(headers, FROM_TOKEN, TO_TOKEN, BUY_AMOUNT, CHAIN)
wait_for_completion(headers, swap_id)
time.sleep(3600) class=class="hl-str">"hl-comment"># Buy every hour
Sell above target: Reverse the token pair and condition.
FROM_TOKEN = class="hl-str">"ETH"
TO_TOKEN = class="hl-str">"USDC"
BUY_AMOUNT = class="hl-str">"0.05"
PRICE_TARGET = 2500.0 class=class="hl-str">"hl-comment"># Sell when ETH is above $2500
class=class="hl-str">"hl-comment"># In the loop:
if price > PRICE_TARGET:
execute_swap(...)
Multi-chain monitoring: Check prices across different chains and swap where the best rate is.
Error Handling Tips
- Rate limits: The bot handles 429 responses with exponential backoff. The standard tier allows 60 requests per minute.
- Quote expiration: Quotes expire after a few minutes. The bot gets a fresh quote before each swap.
- Network errors: Transient failures (timeouts, 500s) are retried up to
MAX_RETRIEStimes before exiting. - Insufficient balance: If your wallet does not have enough tokens, the swap execution will fail. Check your wallet balance before trading.