Architecture: BotFire Bot Engine
Architecture: Bots
Kalshi live sports betting platform — Rails 8.1 + SQLite on Docker Compose.
Services (7 Docker Compose containers)
| Service | Role | Interval |
|---|---|---|
| web | Rails on port 3003, live dashboard | — |
| scanner | Polls milestones, fetches markets, refreshes prices | 1s |
| bot_engine | Evaluates triggers, places orders | 1s |
| position_monitor | Stop-loss / take-profit / settlement exits | 5s |
| consensus_bot | Detects 2+ bot agreement, reinforces | 10s |
| portfolio_grouper | Groups positions by sport/time/confidence | 60s |
| volatility_bot | Buys underdog (NO side) as hedge | 10s |
Key Files
app/services/bot_engine.rb— Core trigger evaluation loopapp/services/position_monitor.rb— Exit monitoring (excludes Volatility Bot)app/services/volatility_bot.rb— Independent underdog strategyapp/services/consensus_bot.rb— Multi-bot agreement detectorapp/services/scanner.rb— Kalshi API pollerapp/services/kalshi_client.rb— API client (auth, orders, balance)app/controllers/dashboard_controller.rb— JSON API for live dashboard
Order Pattern
All bots use IOC (immediate-or-cancel) orders. Critical invariants:
- Check
fill_count > 0before creating BotFire records - Use
average_fill_pricefrom API response, not the order price - Per-bot contract counts via
BOT_CONTRACTShash in bot_engine.rb
Data Model
Game → Market → MarketSnapshot (price history). Bot → Trigger → BotFire (position tracking with entry/exit/pnl).
Infrastructure
- Host: archbox (10.0.0.149)
- Dashboard: port 3003, tunneled via Tailscale
- Secrets:
~/secretsmounted read-only into containers - DB: SQLite (single-writer, no external DB service)