StockSim replays real Nasdaq history a day at a time, while a paycheck and eight recurring bills move through the same account you trade from. You keep the decisions and the mistakes. You don't lose any actual money.
Everyone says you learn investing by doing it, and then the doing costs you money. We wanted the practice version: same prices, same signals, same bills, none of the downside. Be wrong as many times as it takes, because here it costs nothing.
When one of your stocks prints a pattern (golden cross, RSI extreme, volume spike), a lesson card lands on your chart quoting that bar's real numbers. New patterns are explained on sight; the ones you've met wait until they're worth re-reading.
Five pieces and nothing else: a tick loop, somewhere to get prices from, the AI layer, one database, and a page that reads all of it. If you're judging this, start with the tick loop.
One tick is one trading day. Bills settle, dividends pay, the AI queue drains, a new candle lands. All the rules live in one module, so the routes stay boring and the game stays testable.
Replay stored history until it runs out, then switch to a future generated from a seed. Both sit behind the same interface, so nothing downstream knows which one it's reading.
Gemini runs behind an MCP server that Flask spawns over stdio, so a slow model never blocks a tick. It writes the market news and the lessons. With no API key it falls back to local ones instead of dying.
Prices, sessions, trades, dividends and events live in TimescaleDB. Loading is a CLI, and the writes are batched, because a tick spends round trips, not CPU.
Price, RSI and MACD share one crosshair. Beside them sit your basket rebased to 100 and your equity curve. One play button, one speed choice, five panels.
Counted straight out of the TigerData cluster. Coverage is uneven: three symbols reach 1962 and the median one starts in 1998, so some names carry far more history than others. Pick a start date and check your ticker isn't greyed out.
Everything on that screen gets recomputed every tick: the indicators, the news, and what the bank took out of your account. Three parts of it are worth a judge's time.
SMA-20/50, RSI-14, MACD and 20-day average volume come out of the same pass as the close, so the coach quotes the exact numbers your chart is drawing.
A company story reprices that one ticker, a sector story every name you hold in it, a macro story the whole basket. Scope belongs to the event, so a story about one company stops at that company.
Trading return strips the paycheck and the bills back out, so a salary never passes for good stock picking. Total return is the account as it actually stands. Dividends count in both, because they come from what you own.
What broke: headlines and lessons come from a language model that can take seconds, rate-limit under load, or not be set up at all. The simulation clock can't sit and wait for it.
the fix
Async, with a local fallback
What broke: prices, sessions and trades live in TimescaleDB on the far side of the network, so a tick spends its time waiting on round trips, not CPU. The first version fired 24 to 29 queries on every tick.
the fix
Cached, then batched
What broke: our generated future is seeded, so in theory we could re-roll it whenever we liked. But players had already traded against those candles, and regenerating them would quietly change a decision somebody really made.
the fix
The seed locks at the fork
The simulated future
Real history runs out eventually. From there we generate the next day, and the session keeps going.
Built for Hackrice 2026 by Monty Python & HTML. Read the source, run the 136 checks yourself, or pick a basket starting in 1998 and see how long you last.