I Built a Multi-User Trading Bot on Robinhood Testnet Chain for Arcus
How a weekend of API archaeology on dYdX’s new exchange turned into a full SaaS: Google login, auto-custody wallets, one-click funding, a…
I Built a Multi-User Trading Bot on Robinhood Testnet Chain for Arcus
How a weekend of API archaeology on dYdX’s new exchange turned into a full SaaS: Google login, auto-custody wallets, one-click funding, a 41-market trading engine and Telegram alerts — all on testnet, all open source.

TL;DR
Arcus (https://arcus.xyz) is the new decentralized exchange built by dYdX Labs on Robinhood Chain, bringing together tokenized stocks and perpetual futures trading in one place.
Perpetual trading is still waitlisted (I’m somewhere around #32,000), but the testnet is open to everyone.
Instead of waiting, I built ArcusBot:
Users can:
- Sign in with Google
- Receive an automatically generated trading wallet
- Fund it with $10,000 testnet collateral in one click
- Choose a predefined or custom risk profile
- Let a multi-signal trading engine trade across 41 different markets
- Receive real-time Telegram notifications
This article tells the engineering story behind the project — including the three invisible-character bugs that almost broke production.
🎥 Video walkthrough: https://youtu.be/xqTsFjYLrGc
Why Arcus?
Arcus combines two products that rarely exist on the same exchange:
- Tokenized stocks (spot, zero trading fees)
- Cross-margined perpetual futures
Markets include:
- Crypto
- Equities
- Commodities
- Indices
with leverage up to 50× on Robinhood Chain.
Since Arcus is built by dYdX Labs, the API feels like it was designed by people who have operated real derivatives exchanges.
Some highlights:
- REST + WebSocket APIs
- Clean OpenAPI / AsyncAPI specifications
- Ed25519 API keys generated locally
- Registration authorized by a single EIP-191 signature
- Two optimized signing schemes
- Integer ticks and quantums instead of floating-point numbers
The testnet already supports paper trading across:
- 8 crypto perpetuals
- 26 stock perpetuals (AAPL, NVDA, TSLA…)
- 3 commodities
- 4 indices
Funding is permissionless through:
mint → approve → initiateDeposit
Step 1 — A Client, an Order, a Cancel
The initial milestone was intentionally simple:
- Generate API keys
- Register them
- Place one limit order
- Cancel it
Surprisingly, everything worked on the first try.
Then the testnet started teaching me lessons the documentation didn’t mention.
Lesson 1 — goodTilTime Is Always Required
Documentation says IOC orders ignore goodTilTime.
Reality says otherwise.
Every order requires an expiration timestamp at least one month into the future — even orders that exist for only milliseconds.
Lesson 2 — TP/SL Isn’t Live Yet
Arcus already exposes an elegant position-level Take Profit / Stop Loss API.
Unfortunately, testnet currently responds with:
501 NotImplemented
The trading engine now:
- Attempts native TPSL first
- Falls back to monitoring mark price
- Closes positions manually
Once Arcus enables the feature, the bot upgrades automatically.
Lesson 3 — Phantom Liquidity Exists
One order book displayed:
Bid: 1.12 BTC
My IOC sell order responded:
IOC_CANCELED
Seventeen consecutive times.
The reason?
The order book can display stale orders that only disappear when matching is attempted.
That discovery completely changed the execution strategy.
The engine now:
- Tries several increasingly aggressive IOC orders
- Falls back to a resting GTT order
- Reprices every 60 seconds until filled
On a bursty-liquidity testnet, patience became an order type.
Step 2 — From Script to Product
Originally this was simply a personal trading script.
It used my Binance Futures strategy:
- EMA 9 / 21 / 200
- ADX
- RSI
- MACD
- 15-minute candles
Eventually the question became:
Could anyone use this?
That evolved into:
https://www.atradebot.xyz
The platform now provides:
1. Google Login
No passwords.
No registration forms.
2. Instant Trading Wallet
Every user automatically receives a dedicated testnet wallet.
The backend:
- generates keys
- registers them with Arcus
- encrypts them using Fernet
Private keys are shown exactly once.
Subsequent reveal attempts are permanently rejected.
3. One-Click Funding
A sponsor wallet:
- sends gas
- mints test USDG
- approves spending
- initiates deposit
About one minute later the account contains:
$10,000 testnet collateral
4. Flexible Risk Management
Users can choose:
- Low
- Balanced
- High
or fully customize:
- leverage
- margin
- stop loss
- take profit
- daily loss limit
The bot supports all 41 available markets with category-based selection.
Changes apply to the running engine without restart.

5. Telegram Alerts
Each user links their Telegram account through a deep link.
Notifications include:
- Position opened
- Position closed
- Daily loss limit reached
The entire platform — including trading logs — is bilingual:
- English
- Turkish

Architecture
Browser
│
▼
Vercel (FastAPI)
│
▼
Neon PostgreSQL
▲
│
Worker Engine
• Authentication
• Wallet generation
• Trading engine
• Funding queue
• Telegram polling
• User settings
The split exists because trading engines are the opposite of serverless workloads.
The website runs on:
- Vercel
- SSL
- Custom domain
- Always online
The worker currently runs on a desktop PC and will eventually move to an inexpensive cloud container.
Communication happens exclusively through PostgreSQL.
The API writes:
- funding requests
- user settings
The worker writes:
- engine state
- execution logs
- trading events

The Bugs I’ll Never Forget
Three production incidents.
All caused by invisible characters.
1. Google OAuth
Google returned:
401 invalid_client
The client ID was correct.
Except PowerShell had prepended a hidden U+FEFF Byte Order Mark.
Google saw:
9194...
instead of
9194...
2. Fernet Encryption
While fixing the OAuth issue I accidentally used:
cut -d= -f2
which removed the trailing Base64 padding:
=
The entire application immediately started returning HTTP 500.
3. Telegram
Everything worked locally.
Production kept saying:
telegram bot not configured
The Telegram module only loaded tokens from:
.env
Vercel doesn’t use .env files at runtime.
Lesson learned.
Now every environment variable:
- strips BOMs
- removes carriage returns
- checks
os.environfirst - validates expected string lengths
Cheap lessons.
Exactly what testnets are for.
What’s Next?
My roadmap includes:
- 🤖 AI-generated trade commentary via Vercel AI Gateway
- ☁️ Moving the worker to a cloud container for true 24/7 operation
- 🚀 Switching to the production Arcus endpoint once my perpetual futures waitlist finally opens
Ideally, changing environments should require nothing more than updating a single base URL.
Try It Yourself
🌐 Live Demo (Testnet)
💻 Open Source Repository
https://github.com/izzetcakmak/arcus-trade-bot
🎥 Video Walkthrough
Final Thoughts
Everything shown in this article runs entirely on Arcus Testnet using paper money.
This isn’t an investment strategy or financial advice.
It’s an engineering story about building a production-ready, multi-user trading platform while waiting for a very patient waitlist number to finally move.
메타데이터
- post_id
- 2f2bf9309938
- slug
- i-built-a-multi-user-trading-bot-on-robinhood-testnet-chain-for-arcus-2f2bf9309938
- url
- https://medium.com/@izzetcakmak35700/i-built-a-multi-user-trading-bot-on-robinhood-testnet-chain-for-arcus-2f2bf9309938
- canonical_url
- https://medium.com/@izzetcakmak35700/i-built-a-multi-user-trading-bot-on-robinhood-testnet-chain-for-arcus-2f2bf9309938
- author_url
- https://medium.com/@izzetcakmak35700
- status
- ok
- fetched_at
- 2026-07-08 18:29:56