Building a Robinhood Chain trading bot with WebSocket streams
Architecture and working code for a Robinhood Chain trading bot: stream new launches and trades, filter with security and holder checks, track prices in real time and handle reconnects and reorgs.
Crius 4 min read
A trading bot lives or dies on two things: seeing events early and filtering out the bad ones before it acts. This guide builds the data side of a Robinhood Chain bot with the Crius API: a WebSocket stream for events, REST calls for checks, and the reconnect and reorg handling that keeps it honest. Execution (signing and sending swaps) is up to you; we only cover the data.
Architecture
WebSocket stream ──► event queue ──► filters (REST checks) ──► strategy ──► your executor launches:all /security graduations:all /bundles price:<token> /dev/{address} trades:<token>- Stream for anything time-sensitive: new launches, graduations, prices of tokens you hold.
- REST for one-off checks on a candidate token: tax, snipers, the creator’s history.
- A queue between them, so a slow check never blocks the stream.
You need a key with the stream scope. The Free plan includes one stream connection with 10 subscriptions; Starter gives 3 connections and 100 subscriptions.
Step 1: listen for candidates
const KEY = process.env.CRIUS_API_KEY;const queue = [];const held = new Set(); // tokens we hold, watched by price
function connect() { const ws = new WebSocket(`wss://api.crius.sh/v1/robinhood/stream?api_key=${KEY}`); ws.onopen = () => ws.send(JSON.stringify({ op: "subscribe", channels: ["graduations:all", ...[...held].map((t) => `price:${t}`)], })); ws.onmessage = (e) => { const m = JSON.parse(e.data); if (m.data?.removed) return onRemoved(m); // reorged: see step 4 if (m.ch.startsWith("graduations:")) queue.push({ token: m.data.token, pool: m.data.pool, block: m.block }); if (m.ch.startsWith("price:")) onPrice(m.ch.slice(6), m.data.usd); }; ws.onclose = () => setTimeout(connect, 2000);}connect();This bot watches graduations rather than raw launches: a token that completed its bonding curve has real liquidity in a Uniswap pool, which filters out most of the noise. Swap in launches:all for an earlier, riskier strategy.
Step 2: filter with REST checks
Each candidate gets a few quick checks before the strategy sees it:
const api = (path) => fetch(`https://api.crius.sh/v1/robinhood${path}`, { headers: { "x-api-key": KEY } }).then((r) => r.json());
async function vet(token) { const [sec, bundles, profile] = await Promise.all([ api(`/token/${token}/security`), api(`/token/${token}/bundles`), api(`/token/${token}`), ]); const reasons = []; if (sec.data.honeypot.is_honeypot) reasons.push(`honeypot: ${sec.data.honeypot.reason}`); if ((sec.data.tax.sell_pct ?? 0) > 10) reasons.push(`sell tax ${sec.data.tax.sell_pct}%`); if (sec.data.risk === "high") reasons.push("high risk"); if (profile.data.holders.top10_pct > 60) reasons.push("top 10 hold over 60%"); if (profile.data.market.quote_liquidity_usd < 5000) reasons.push("under $5k of real liquidity"); return { ok: reasons.length === 0, reasons, sec, bundles };}
setInterval(async () => { const c = queue.shift(); if (!c) return; const v = await vet(c.token); if (v.ok) strategy(c, v); else console.log("skip", c.token, v.reasons.join(", "));}, 500);Good filters to consider:
- Tax:
/securityreports buy and sell tax measured from real trades, plus a simulated sell. Skip anything you can’t sell, or that taxes sells heavily. - Real liquidity: use
quote_liquidity_usd(the ETH or USDG you could actually get out), not the 2×liquidity_usd. - Snipers and bundles:
/bundlesshows how much supply the first-block buyers and coordinated wallets hold. They’re often the first to sell. - The creator:
/dev/{address}shows their past tokens. A creator whose last twenty tokens all went to zero is a signal.
Step 3: track what you hold
When the strategy buys, add the token to held and subscribe to price:<token>. Price updates arrive as the pool moves, so stop-losses and take-profits react within a block or two, without polling:
function onPrice(token, usd) { const pos = positions.get(token); if (!pos) return; if (usd <= pos.entry * 0.7 || usd >= pos.entry * 2) exit(token, usd);}To see the flow behind a move, subscribe to trades:<token> as well: every trade comes with the attributed trader, side and USD value.
Step 4: reconnects and reorgs
Two things that separate a toy bot from a reliable one:
- Reconnect with resume. Keep the last
seqper channel, and after reconnecting send{"op":"resume","seqs":{…}}. The server replays up to 60 seconds of missed messages. The stream example has a complete client with backoff and idle detection. - Undo reorged events. If blocks are replaced, you get a
reorgmessage and then every affected event again with"removed": trueand the sameid. If a graduation you queued gets removed, drop it. If you need certainty before acting (larger positions), subscribe with"finality": "safe": events then arrive once their batch is on Ethereum, minutes later instead of milliseconds.
Budget
Streams cost 1 credit per connection, not per message, and most REST checks cost 1–10 credits. A bot vetting a few hundred candidates a day fits comfortably in the Free plan’s 1,000,000 monthly credits; plans and limits has the exact costs.
Nothing in this article is trading advice: test against small amounts, and remember that every filter is a heuristic.
Build with Crius
Robinhood Chain data in one API
Free plan with 1M credits a month. Your key in under a minute.
More from the blog
- Trading terminalWebSocket
How to Build a Real-Time Robinhood Chain Trading Terminal
Build a Robinhood Chain trading terminal: REST bootstrap, WebSocket updates, a live candle chart, trade tape and risk panels, with working code.
- PricesTutorial
How to get real-time token prices on Robinhood Chain
Three ways to get live Robinhood Chain token prices (single, batch and streaming), how on-chain prices are derived, and how to avoid bad prices from thin liquidity.
- PonsLaunchpads
Pons Launchpad API: Track Token Launches and Graduations in Real Time
Track every Pons launch on Robinhood Chain in real time: new tokens, bonding curve progress, graduations into Uniswap v4, fees and creator history, with code.