Crypto Challenge
A multiplayer crypto portfolio simulation where students trade crypto using live market data, build portfolios, create research-backed strategies (Strats), and compete in seasonal leaderboards. Designed to teach portfolio construction, risk assessment, and market analysis to high school students.
Game Flow
Unlike action-based games, Crypto Challenge is an ongoing simulation with no fixed phases. Players navigate freely between four screens:
Home → Price Tracker ↔ Trading Desk ↔ Performance Center
- Home (
/crypto-challenge): Hero section, scrolling market ticker (top 50 coins), 3-step loop guide, starter quest checklist, current portfolio summary, coach toast notifications - Price Tracker (
/crypto-challenge/price-tracker): Top 250 coins by market cap, filterable by 9 bucket categories, sortable columns, watchlist starring - Trading Desk (
/crypto-challenge/trading-desk): Buy/sell order ticket (USD or quantity mode), inline Strat creation, holdings table with P&L, trade history, portfolio summary - Performance Center (
/crypto-challenge/performance-center): KPI cards (cash, crypto value, total return), allocation donut chart, top 5 contributors by P&L, trade log, active Strats with countdowns and reward tiers
Core Loop
- Pick Coins: Browse the Price Tracker, filter by sector buckets, add to watchlist
- Place Trades: Buy/sell on the Trading Desk, optionally attach a Strat with direction, target %, and time horizon
- Track Performance: Review returns, allocation, contributors, and Strat outcomes in the Performance Center
- Iterate: Refine strategies, rebalance, pursue Strat reward tiers
Market Data
- Source: CoinGecko API (Top 250 by market cap)
- Cache: Server-side 60s TTL, client-side 1.5s minimum between refreshes, stale fallback on failure
- API route:
/api/crypto-challenge/markets
Buckets (9 categories)
| Key | Category | Examples |
|---|---|---|
l1 | Layer 1 | Bitcoin, Ethereum, Solana |
l2 | Layer 2 & Scaling | Arbitrum, Polygon, Optimism |
stable | Stablecoins | USDT, USDC, DAI |
defi | DeFi | Uniswap, Aave, Maker |
infra | Infrastructure | Chainlink, The Graph |
utility | Utility & Governance | BNB, OKB |
nft | NFT/Metaverse/Gaming | Decentraland, The Sandbox |
privacy | Privacy Coins | Monero, Zcash |
meme | Meme & Community | Dogecoin, Shiba Inu |
Categorization uses hardcoded lists plus heuristic matching on symbol/name.
Scoring
Primary Metric: Cumulative Return
Return = (NAV - Effective Starting Cash) / Effective Starting Cash
- NAV = cash + bonus cash + sum of (position quantity x latest price)
- Effective Starting Cash = starting cash ($100,000) + total bonus rewards earned
- Positions use average cost basis across buys
Strat Rewards
Strats are research-backed trade theses. When a Strat's linked position hits a return tier, the player earns bonus cash:
| Return Tier | Reward |
|---|---|
| 3% | $100 |
| 5% | $300 |
| 10% | $1,000 |
| 25% | $5,000 |
| 50% | $20,000 |
Evaluation modes:
- Instant (no horizon set): Resolves as soon as the position crosses a tier threshold
- Time-bound (horizon in days): Evaluates at due time; success requires the direction (up/down) and optional target % to be met
Reward cash is added to bonusUsdTotal and counts toward NAV. Max 3 active Strats per player.
Starter Quest Rewards
One-time bonuses for completing onboarding actions:
| Quest | Reward |
|---|---|
| Watchlist first coin | $500 |
| First trade | $2,000 |
| Link a Strat to a trade | $5,000 |
| Visit Performance Center | $500 |
Daily Quest
Tag a trade with a Strat for a $5 bonus (once per day).
Seasons
- 6-month seasons based on a UTC baseline (default: July 1, 2025)
- Scores reset each season
- Highest cumulative return wins the season leaderboard
Technical Architecture
Key Files
| Area | File | Purpose |
|---|---|---|
| Engine | games/crypto-challenge/store.ts | Zustand store: portfolio state, order submission, performance calculations |
| App Data | games/crypto-challenge/models/app-data.ts | AppData structure, sanitization, version normalization |
| Trading | games/crypto-challenge/models/trading.ts | Trade, TradingState, buildTrade(), snapshotPortfolio(), validateOrder() |
| Market | games/crypto-challenge/models/market.ts | MarketCoin, MarketsPayload types |
| Research | games/crypto-challenge/models/research.ts | Strat, Research, blankResearch() |
| Strat Eval | games/crypto-challenge/models/strat-evaluator.ts | evaluateStrats(), StratResolution |
| Rewards | games/crypto-challenge/models/rewards.ts | applyStarterQuestReward(), STARTER_QUEST_CONFIG |
| Config | games/crypto-challenge/models/config.ts | STRAT_REWARD_TIERS, getCurrentSeasonInfo(), DEFAULT_START_CASH |
| Buckets | games/crypto-challenge/models/categorize.ts | categorize(), bucket classification logic |
| CoinGecko | games/crypto-challenge/models/coingecko.ts | CoingeckoMarketRepository, cached fetch with stale fallback |
| Ports | games/crypto-challenge/models/ports.ts | MarketRepository interface |
| Utils | games/crypto-challenge/utils.ts | formatUSD(), formatPercent(), classForChange() |
| Hook | games/crypto-challenge/hooks/use-game-actions.ts | useGameActions(), submitPortfolioScore() |
Components
Home:
| Component | Purpose |
|---|---|
crypto-home.tsx | Home page layout |
hero.tsx | Hero section with CTA |
market-ticker.tsx | Scrolling marquee of top 50 coins |
loop-stepper.tsx | 3-step onboarding guide |
beginners-rewards.tsx | Starter quest checklist with progress |
current-assets.tsx | Portfolio summary card |
coach-messages.tsx | Toast notifications for milestones |
how-to-play-dialog.tsx | Onboarding dialog |
Trading Desk:
| Component | Purpose |
|---|---|
trading-desk.tsx | Main trading interface |
order-ticket.tsx | Buy/sell form with asset selection, USD/qty toggle, inline Strat creation |
holdings-table.tsx | Current positions with P&L |
trade-history.tsx | Chronological trade log |
portfolio-summary.tsx | Cash, portfolio value, net P&L |
confirm-trade-dialog.tsx | Trade confirmation with Strat preview |
Performance Center:
| Component | Purpose |
|---|---|
performance-center.tsx | Dashboard layout |
kpi-grid.tsx | Cash, crypto value, total return cards |
allocation-donut.tsx | Portfolio allocation pie chart |
contributors-table.tsx | Top 5 assets by P&L contribution |
trades-table.tsx | Computed trade rows |
active-strat-card.tsx | Live Strat status with countdown, progress bar, reward tiers |
strat-rewards-dialog.tsx | Tier rewards explanation |
Price Tracker:
| Component | Purpose |
|---|---|
price-tracker.tsx | Market data page |
bucket-table.tsx | Sortable/filterable market table with watchlist |
Layout:
| Component | Purpose |
|---|---|
crypto-provider.tsx | Hydration/persistence provider, debounced auto-save |
game-nav.tsx | Navigation bar across all screens |
page-header.tsx | Reusable page header |
disclaimer-banner.tsx | Educational disclaimer (dismissible) |
Uses shared: GameShell, plus @repo/ui components (Button, Card, Dialog, Table, Select, Input, etc.).
Persistence
Storage key: crypto-challenge-state
Data structure (AppData v2):
{
version: 2,
trading: { startCash, trades[] },
research: { v, thesisTitle, strats[], updatedAt },
reality: { watchlist[], coachFlags },
rewards: { bonusUsdTotal, lastQuestAt, starterQuests },
strats: { resolutions, history[] }
}
- Auto-save: Debounced (2s) on state changes via
CryptoProvider - Hydration: Loads on mount, normalizes legacy data with tolerant parsing
- Trades: Each trade stores
time,type(buy/sell),coinId,price,qty, signedusd, optionaltags.stratId
Order Validation
- Positive amounts required
- Live price must be available
- Sufficient cash for buys, sufficient quantity for sells
- Real-time validation in UI before submission
Notable Mechanics
Average Cost Basis
Tracks weighted average cost per asset across multiple buys. Sells reduce quantity; cost resets to 0 when fully sold. P&L uses (currentPrice - avgCost) × qty.
Inline Strat Creation
Players can create a Strat directly on the buy order form -- direction (up/down), target %, time horizon (days), and a reason (120 char max). The Strat auto-links to the trade via tags.stratId.
Coach Messages
Context-aware toast notifications triggered by milestones (e.g., "Nice diversification move!" when adding 2+ sectors). Tracked via coachFlags to avoid repeats.
Performance Attribution
- Top Contributors: Ranked by absolute P&L contribution to the portfolio
- Allocation donut: Visual breakdown of portfolio weights by asset
- Trade-to-Strat linking: Each trade can reference its originating Strat for thesis tracking
Educational Design
- Plain-English tooltips throughout
- Dismissible disclaimer banner ("This is a simulation...")
- How-to-play dialog with step-by-step walkthrough
- Starter quests guide new players through the core loop
- Bucket categories teach crypto sector structure