How to Build a Solana Trading Bot
This guide covers the general architecture of a Solana trading bot — from price monitoring to swap execution. No specific strategy, just the infrastructure patterns that every bot needs.
Architecture Overview
Every Solana trading bot has the same core loop:
Monitor prices → Detect opportunity → Build transaction → Submit → ConfirmThe difference between a profitable bot and a money-losing one is usually not the strategy — it's the infrastructure. Latency, reliability, and cost efficiency determine whether your edge survives.
Step 1: Price Monitoring
Your bot needs to know current token prices. There are three approaches:
Polling RPC (Slow, Expensive)
// Don't do this — it's slow and expensive
while (true) {
const account = await connection.getAccountInfo(poolAddress);
const price = decodePoolPrice(account);
await sleep(1000);
}Every iteration costs an RPC call. At 1-second intervals across 20 tokens, that's 1.2M RPC calls per day.
WebSocket Subscriptions (Better)
connection.onAccountChange(poolAddress, (account) => {
const price = decodePoolPrice(account);
});Better than polling — you only get updates when the account changes. But WebSocket connections drop, and you need to handle reconnection, missed updates, and parse raw account data yourself.
SSE Price Streams (Recommended)
const source = new EventSource(
'https://api.venum.dev/v1/stream/prices?tokens=SOL,BONK,JUP',
{ headers: { 'X-API-Key': API_KEY } }
);
source.addEventListener('price', (e) => {
const { token, priceUsd } = JSON.parse(e.data);
// React to price change
});One HTTP connection, sub-second updates, pre-computed USD prices. Reconnection is handled by the EventSource API. No RPC costs.
Step 2: Opportunity Detection
This is where your strategy lives. Common patterns (not exhaustive):
- Threshold-based: Buy when price drops X% below a moving average
- Cross-DEX spread: When the same token is priced differently on two DEXes
- New pool sniping: Act on newly created pools before they're widely traded
- Liquidation: Monitor lending protocol positions nearing liquidation thresholds
Whatever your strategy, keep the detection logic fast and stateless. You don't want to be mid-calculation when a price update arrives.
New Pool Detection
Venum streams new pool creation events in real-time:
const source = new EventSource(
'https://api.venum.dev/v1/stream/pools',
{ headers: { 'X-API-Key': API_KEY } }
);
source.addEventListener('pool', (e) => {
const { poolAddress, dex, tokenA, tokenB } = JSON.parse(e.data);
// New pool detected — evaluate and act
});Step 3: Quoting
Once you've detected an opportunity, get a real-time quote:
const quote = await fetch('https://api.venum.dev/v1/quote', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-API-Key': API_KEY },
body: JSON.stringify({
inputMint: 'So11111111111111111111111111111111111111112',
outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
amount: '1000000000', // 1 SOL in lamports
slippageBps: 50,
}),
}).then(r => r.json());
// quote.routes[0] has the best route
const bestRoute = quote.routes[0];
console.log(`Best: ${bestRoute.dex} — ${bestRoute.outAmount} USDC`);Quotes compute locally from streaming pool state — typical latency is under 10ms.
Step 4: Transaction Building
Build the swap transaction:
const build = await fetch('https://api.venum.dev/v1/swap/build', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-API-Key': API_KEY },
body: JSON.stringify({
inputMint: 'So11111111111111111111111111111111111111112',
outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
amount: '1000000000',
slippageBps: 50,
userPublicKey: wallet.publicKey.toBase58(),
}),
}).then(r => r.json());The returned transaction is unsigned — you can inspect it, add custom instructions, or modify compute budgets before signing.
Step 5: Submission
Sign and submit via Jito bundles:
const tx = VersionedTransaction.deserialize(
Buffer.from(build.transaction, 'base64')
);
tx.sign([wallet]);
const result = await fetch('https://api.venum.dev/v1/swap', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-API-Key': API_KEY },
body: JSON.stringify({
transaction: Buffer.from(tx.serialize()).toString('base64'),
quoteId: build.quoteId,
}),
}).then(r => r.json());
console.log(`Submitted: ${result.signature}`);Venum submits to 5 regional Jito block engines simultaneously (~6ms submission latency). Every transaction is sandwich-protected by default.
Step 6: Confirmation
Track transaction status via SSE:
const source = new EventSource(
`https://api.venum.dev/v1/stream/tx?signatures=${result.signature}`,
{ headers: { 'X-API-Key': API_KEY } }
);
source.addEventListener('status', (e) => {
const { signature, status } = JSON.parse(e.data);
if (status === 'confirmed') {
console.log('Landed!');
source.close();
}
});ShredStream confirmation typically arrives ~200ms after the transaction lands — significantly faster than polling RPC for confirmation.
Best Practices
Error Handling
- Quote expired: Quotes are valid for a few seconds. If your build request fails with a stale quote, re-quote and try again.
- Transaction failed on-chain: Check the error. Common causes: slippage exceeded, insufficient balance, pool state changed between quote and execution.
- Rate limited: Respect rate limits. The free tier allows 10 quotes/min and 2 swaps/min. Upgrade if you need more.
Latency Tips
- Keep connections warm — SSE streams should stay open permanently, not reconnect per trade
- Pre-compute decisions — don't do heavy computation between detecting an opportunity and submitting
- Use the right tier — if you're rate-limited, you're leaving money on the table
Cost Management
- Use SSE streams for price data instead of polling RPC
- Cache token metadata — mint addresses, decimals, etc. don't change
- Batch where possible — one quote request returns routes from all DEXes
Security
- Never expose your API key client-side. Keep it on your server.
- Never log private keys or seed phrases
- Set slippage appropriately — too high and you lose on execution, too low and transactions fail
- Monitor your bot — check on-chain results, not just log output. A "submitted" transaction may have failed.
What Venum Handles for You
| Concern | Without Venum | With Venum |
|---|---|---|
| DEX integration | Build 12+ integrations | 1 API |
| Price feeds | Poll RPC or build WebSocket infra | SSE streams |
| Route optimization | Build your own router | /v1/quote |
| TX building | Manage compute budgets, blockhash, instructions | /v1/swap/build |
| MEV protection | Build Jito integration | Built-in |
| Confirmation | Poll RPC for status | ShredStream SSE |
Next Steps
- Get a free API key
- Quick Start guide — first swap in 2 minutes
- SSE Streams reference — real-time data feeds
- Composable Instructions — extend transactions with custom logic
