How to run a paper trading bot on your own server
Set up Charles, a free trading bot with public code, on a small server with one command, Alpaca paper keys and a dashboard on your phone.
Charles is a free trading bot, with all of its code public, that runs on a server you own. It trades paper money linked to real market data through a free Alpaca paper account, and you watch it from a web dashboard on your phone. Your keys, settings and history stay on your server, and there's no subscription.
This guide walks through the whole setup. It takes about 30 minutes, and most of that is waiting for installs.
Who this is for
It's for people who like the idea of a trading bot but want to own it and see the rules it follows. You don't need to have run a server before. If you can paste a command into a terminal and press Enter, you can do this. If you know Python, you can read every line on GitHub.
What you need first
- A computer with a terminal: PowerShell on Windows, Terminal on a Mac.
- A free Alpaca account. You'll use its paper account.
- A DigitalOcean account for the server. The size Charles needs costs about $6 a month.
That's the whole list. You don't install anything on your own computer.
Step 1: Create a server
In DigitalOcean, choose Create, then Droplets. Pick any region that offers the Basic 1 GB size, and choose Ubuntu 24.04 as the image. When the server is ready, copy its IP address from the Droplets page.
Step 2: Connect to it
Open your terminal and connect, using the IP address you copied:
ssh root@YOUR_SERVER_IP
The first time, it asks whether you trust this server. Type yes. From here on, every command runs on the server, not on your computer.
Step 3: Install Charles
One command does the install. It's split in two here so you can read the script before you run it:
curl -fsSL https://charles-bot.xyz/install.sh -o install.sh bash install.sh
It first asks you to accept the Terms (you must be 18 or older). Then it takes 5 to 10 minutes. If it stops partway, run bash install.sh again. Steps that already finished are skipped.
Step 4: Add your Alpaca paper keys
In Alpaca, switch to Paper, then go to API Keys and choose Generate. Open the keys file on your server:
nano ~/charles/.env
Add your two paper keys:
ALPACA_API_KEY=your_paper_key ALPACA_SECRET_KEY=your_paper_secret
Save with Ctrl+X, then Y, then Enter. The keys stay in that file on your server. If you need to change one later, run charles-keys.
There's also an optional key for the AI that reads headlines before a new pick is bought. Charles runs without it. The setup guide shows where it goes.
Step 5: Start it and open the dashboard
charles-start charles-login
The first command starts the bot. The second prints a one-time link to your private dashboard. There are no passwords: whenever you want to log in on a new device, run charles-login and open the link it prints. A new install gets HTTPS, so the link is a normal secure web address.
Open the link on your phone. The dashboard is a web page, not an app from a store, but you can add it to your home screen so it opens like one.
What the dashboard shows
The dashboard is built for a phone screen. It shows:
- What the bot holds.
- What it did and why.
- The news about what it holds.
- Pause, which holds all orders until you resume.
You open the page when you want to look.
What to expect in the first weeks
Most days Charles places no orders, so there's not much to watch. That's the plan working as written, not a sign something is broken.
The default plan puts 80% in the whole market through SPY, plus 4 momentum picks at 5% each, chosen monthly from 100 big US companies. A safety switch moves the plan to T-bills when SPY ends a month below its 200-day average, and moves back when a month ends above it. A daily loss limit pauses buys for the rest of the day.
Aggressive mode is also on in the default plan. While SPY is above its 200-day average and calm, the core sits in SSO, a 2x S&P 500 fund that moves about twice as much as the market each day, up and down. Any choppy day sends it back to SPY, and you can turn aggressive mode off.
Every part of the plan can be changed from the dashboard with sliders or presets. You can test a change on past prices before you save it, and undo any change afterward.
Everyday commands
A few commands cover most of what you'll do on the server:
charles-status # is it running? charles-logs # watch what it's doing charles-pause # hold all orders charles-resume # allow orders again
Updates never install by themselves. When you run charles-update, it shows what changes first, and charles-restore goes back to an earlier version.
If something goes wrong
The bot won't start. Run charles-logs. It's usually a mistyped key. Fix it in ~/charles/.env, then run charles-restart.
The dashboard says it's private. Your login link has expired. Run charles-login again and open the new link within 10 minutes.
The dashboard won't load. Run charles-status to see its address, then check the web services:
systemctl status charles-web caddy
The installer stopped partway. Run bash install.sh again. It picks up where it left off.