FAREPLAY: Prediction Markets for Toronto Transit Delays
Inspiration
On our team, a lot of us take the TTC, and a lot of the time it's late. So we put two and
two together and said: why don't we make prediction markets for how late your streetcar,
subway, or bus will be to your stop?
Real-time prediction accuracy varies significantly across routes and times of day. Instead
of just complaining about delays, we thought—what if we gamified it? What if users could put
money on their predictions and earn rewards when they're right?
What it does
FarePlay is a real-time prediction market platform where users predict TTC vehicle arrival
times and place bets (in SOL) on their predictions.
Core Features:
- Interactive Transit Map - Real-time visualization of TTC route 501 (Queen Streetcar) and
503 (King Streetcar) with live vehicle positions updated every 5 seconds
- Smart Stop Selection - Users browse routes, select stops, and see arriving vehicles in
real-time - Prediction Betting - Choose a vehicle, predict its arrival time in seconds, and place a
bet in SOL - Community Analytics - See what other players are betting on the same stop, average
prediction accuracy, and vehicle-specific statistics - Frozen Predictions - Historical comparison showing what was predicted 5 minutes ago vs.
actual arrival times - Solana Wallet Integration - Connect your wallet to track balance and bet winnings
User Flow:
- Route 501/503 → Select stop → Choose vehicle → Enter prediction (seconds) → Enter bet
amount → Place bet - Backend verifies predictions against actual TTC data
- Winners earn SOL; losers lose their bet amount
How we built it
Frontend (/frontend)
- Tech Stack: React, Next.js, TypeScript, Tailwind CSS
- Map Visualization: Mapbox GL with real-time vehicle markers and route geometry
- State Management: Centralized React state for route/stop/vehicle selection with two-way
synchronization between map and sidebar - Real-time Updates: Vehicle positions fetched every 5 seconds from backend API
Backend (/backend/ttc-predictor)
- Core Components:
- Collector Daemon (collector_daemon.py) - Continuously fetches TTC predictions every 10
seconds, records "frozen" snapshots at different time windows (0-5min, 5-10min, etc.) - Database Layer (database.py) - SQLite database tracking frozen predictions, verified
arrivals, and pre-calculated statistics - REST API (api_v2.py) - Flask server exposing endpoints for current predictions,
historical accuracy data, and route information
- Collector Daemon (collector_daemon.py) - Continuously fetches TTC predictions every 10
Data Pipeline:
- TTC NextBus API → Collector (every 10s) → Database
- Predictions "frozen" at capture time for later comparison
- Vehicles tracked between stops to verify actual arrivals
- Accuracy metrics calculated: early/late by how many seconds
Solana Integration:
- Wallet connection for SOL deposits/withdrawals
- Frontend placeholder for transaction signing (backend integration in progress)
APIs Used:
- TTC NextBus XML API for real-time predictions
- Custom Flask API for historical prediction accuracy
Challenges we ran into
- Real-time Data Consistency - TTC API predictions change constantly. We had to implement
"frozen predictions" to capture a moment in time for later comparison against actual
arrivals. - Arrival Verification - The TTC API only gives predictions, not confirmations when
vehicles actually pass. We solved this by tracking vehicle IDs between consecutive stops and calculating elapsed time. - Database Schema Complexity - Modeling the relationship between current predictions,
frozen snapshots, actual arrivals, and accuracy metrics required careful planning to avoid
data redundancy. - CORS & API Integration - Connecting frontend to backend with real-time data required
proper CORS configuration and handling race conditions in prediction updates. - Scaling Database - Storing predictions for every vehicle at every stop every 10 seconds
generates 1000s of records/day. We implemented statistics caching to keep queries fast. - Mapbox Route Rendering - Getting GeoJSON route geometry to render correctly with proper
filtering between route lines and stop points required debugging Mapbox GL layer
configuration.
Accomplishments that we're proud of
Full-stack working prototype - Frontend displays real-time map with live vehicle updates; backend has been collecting actual TTC data for weeks
Intelligent prediction system - "Frozen predictions" at multiple time windows (0-5min,
5-10min, 10-20min, 20-30min) allow sophisticated accuracy analysisBeautiful UI/UX - Interactive Mapbox visualization with color-coded routes, smooth
sidebar interactions, and intuitive betting flowReal data pipeline - Not mocked—we're actually querying TTC's real API and storing
verified accuracy dataVerified transit routes - Confirmed all configured stops exist on their routes with
proper spacing (5-15 min between stops for Route 501, 3-10 min for Route 503)Two-way component synchronization - Clicking vehicles on the map updates the sidebar;
selecting in the sidebar highlights on the map
What we learned
- Transit data is complex - Vehicle IDs change, routes have multiple directions,
predictions are probabilistic not deterministic. Real systems require careful data
validation. - Real-time systems are hard - Managing race conditions between API calls, database
updates, and UI state is non-trivial. A 1-second delay can make your data stale. - Prediction accuracy varies wildly - Some vehicles consistently arrive early; others
consistently late. Time of day, weather, and route geometry all matter. This is what makes
the prediction market interesting! - SQLite can handle moderate load - For a hackathon project, SQLite with proper indexing
and statistics caching scales surprisingly well. - Mapbox GL is powerful but requires finesse - Layer ordering, feature filtering, and click
handlers all need careful coordination.
What's next for fareplay? More transit lines!
Log in or sign up for Devpost to join the conversation.