Skip to content

Pre-match trading: gather external context for scheduled games instead of polling Shipp #4

Description

@buildkit-ai

Problem

The current TradingLoop.run() immediately enters a live event polling loop regardless of game status. For scheduled (not yet started) games, this means:

  1. Shipp's getLiveEvents() returns empty — the game hasn't started, there are no events
  2. The loop just sleeps and retries, doing nothing until tipoff
  3. Pre-game markets are actively traded on Kalshi but the bot ignores them entirely

This is a missed opportunity. Pre-game markets often have the most liquidity, and edges can exist before games start.

Proposed Solution

Split the trading loop into two distinct phases: pre-match and live.

Phase 1: Pre-match (game status = scheduled)

Instead of polling Shipp for nonexistent live events, gather context from other sources:

Data sources for pre-match context:

  • Shipp metadata (already available): team rosters from home_team_players / away_team_players stored in games.metadata
  • News headlines: recent team news via RSS or news APIs (injuries, trades, lineup changes)
  • Odds/lines: opening lines from sportsbooks as a baseline reference
  • Team stats: season record, recent form (last 5/10 games), home/away splits
  • Head-to-head history: recent matchup results between the two teams
  • Injury reports: official injury reports (out/doubtful/questionable)

Architecture:

interface PrematchDataSource {
  name: string
  gather(game: Game, sport: string): Promise<string>
}

A pluggable system where data sources are registered and called in parallel during pre-match. Each returns a text block that gets concatenated into the full pre-match context. This makes it easy to add new sources without modifying the core loop.

Built-in sources to start:

  • ShippMetadataSource — extracts rosters/venue from stored game metadata
  • NewsHeadlineSource — fetches recent headlines via Google News RSS
  • KalshiMarketSource — includes current market prices as implied probabilities

Future sources (community contributions):

  • ESPNStatsSource, NBAStatsSource — team/player statistics
  • OddsAPISource — consensus lines from sportsbooks
  • InjuryReportSource — official injury designations
  • WeatherSource — for outdoor sports (NFL, MLB, Soccer)

Phase 2: Live (game status = live)

Once the game starts, switch to the existing Shipp live event polling loop. No changes needed here.

AI Adapter Changes

Add a estimatePrematch() method alongside the existing estimateProbability():

  • Different system prompt tuned for pre-match analysis (base rates, team strength, home/away advantage)
  • Accepts a free-text prematchContext string instead of ShippEvent[]
  • Same structured output: { yesProbability, confidence, reasoning }

Risk Management Considerations

Pre-match trades may warrant different risk parameters:

  • Higher minimum edge threshold (markets are more efficient pre-game)
  • Lower confidence acceptance (less information available)
  • Optional strategy field to distinguish pre-match vs live orders in the DB (e.g., value-bet-prematch vs value-bet)

Flow

Game status = scheduled
  ├── Gather pre-match context (rosters, news, stats, market prices)
  ├── For each Kalshi market:
  │   ├── AI estimates probability from pre-match context
  │   ├── Compute edge vs market price
  │   ├── Risk check → place trade if edge exists
  │   └── Log analysis + reasoning
  ├── Log stats summary
  └── Poll for game status change (scheduled → live)
       └── When live → switch to existing live event loop

Game Lifecycle

scheduled ──[pre-match analysis]──→ waiting ──[game starts]──→ live ──[live loop]──→ completed

Context

Currently the only data flowing into the AI is Shipp's live event stream. By adding pre-match context gathering, the bot can:

  • Trade earlier (hours before tipoff when markets open)
  • Use a broader information set than just in-game events
  • Potentially find larger edges pre-game when markets haven't fully adjusted to news

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions