Skip to content

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 → Confirm

The 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)

js
// 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)

js
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.

js
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:

js
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:

js
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:

js
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:

js
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:

js
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

ConcernWithout VenumWith Venum
DEX integrationBuild 12+ integrations1 API
Price feedsPoll RPC or build WebSocket infraSSE streams
Route optimizationBuild your own router/v1/quote
TX buildingManage compute budgets, blockhash, instructions/v1/swap/build
MEV protectionBuild Jito integrationBuilt-in
ConfirmationPoll RPC for statusShredStream SSE

Next Steps