How it works
The full mechanics - voting, cutoff, trades, and how the two portfolios are tracked over time.
Three ways to vote
Every market day you can vote for the Mob's pick from three places. They all feed the same daily tally:
- The website. Type a ticker into the search box on the homepage and click Vote. One vote per browser per day, no login required.
- Twitch chat. In any channel where the bot is connected, post
$AAPL(or any other ticker). The bot parses the message and records one vote per Twitch account per day. Streamers can submit their channel to get the bot in chat. - Discord chat. In any server that's added the Mob vs Monkey bot, post
$AAPLin a channel the bot can see. One vote per Discord account per day.
Vote rules
- One vote per source per identity per day. Browser cookies, Twitch user IDs, and Discord user IDs are deduped independently. (Yes, you could vote once on the website plus once on Twitch plus once on Discord, but that's as far as it goes.)
- First $TICKER wins. In chat messages with multiple tickers, only the first one counts. Lets people pre-empt vote-splitting jokes.
- Eligibility check. Tickers must be in the daily eligible pool - roughly the curated set of liquid US-listed equities the Monkey draws from. Penny stocks and illiquid names are filtered out before the day starts. Votes for ineligible tickers are silently ignored.
- The day's votes reset every morning. Whatever you voted yesterday doesn't carry forward.
The 1 PM Eastern cutoff
Voting closes at 1:00 PM ET every market day. At that exact moment:
- The vote tally is locked. Late votes (web or chat) are rejected.
- The Mob's pick is whichever ticker has the most votes. If two or more tickers tie for first, the daily dollar amount is split evenly across them.
- The Monkey's pick is drawn at random from the eligible pool. If the dice roll matches the Mob's ticker, we re-roll so the comparison stays fair.
- Both orders go to a single Alpaca brokerage account as notional market orders (a fixed dollar amount each, not a fixed share count) so we get fractional shares when needed.
Markets are closed on weekends and US market holidays - no votes, no trades, no Monkey on those days.
One account, two portfolios
Both bots trade through the same Alpaca account, but every order is tagged with which side placed it. The website's portfolio chart is computed from those tags rather than from Alpaca's account-level totals:
- Mob value = sum of (Mob shares of each ticker × current price).
- Monkey value = sum of (Monkey shares of each ticker × current price).
- No selling. This is a buy-and-hold experiment - every day, both sides accumulate one more position. The longer it runs, the more the two portfolios diverge based on whose picks were better.
The portfolio chart
The chart on the homepage updates every 60 seconds during market hours. It's built from snapshots taken every 15 minutes between 9:30 AM and 4:00 PM ET, plus an end-of-day snapshot at 4:30 PM that seals the day's closing values.
Both portfolios start at $0 on day one and grow as the daily trades stack up. The chart shows total value over time, not gain/loss - since both sides are deposited the same dollar amount on the same day, the gap between the two lines is the comparison.
Paper, then real money
The system runs on Alpaca's paper-trading sandbox first: fake money, real market data. After a clean soak period to verify the scheduler, the trade pipeline, and the chart, the head monkey funds a real Alpaca account from $0 and the system flips to live trading.
Trade size is intentionally small - a few dollars per side per day. This is a meme experiment, not a hedge fund. Site visitors and voters never own any positions or share in any returns.
What it's built on
Next.js (App Router) for the website, Postgres for durable trade / snapshot history, Redis for the live vote leaderboard, Railway for hosting. Trades go through Alpaca's notional market-order API. The chat bots run as a single long-lived worker process - Twitch via tmi.js, Discord via discord.js.