How Lazy Edge Works
From raw data to actionable trading signals in under 2 seconds.
Architecture Overview
End-to-end pipeline from raw data ingestion to signal delivery.
Data Sources
ESPN Play-by-Play
We poll the ESPN scoreboard API every 60 seconds during game hours (6 PM – midnight ET). For every active game, we fetch possession-level play-by-play events: made/missed shots, turnovers, steals, fouls, rebounds, and timeouts.
live_eventsKalshi Prediction Markets
Every 5 minutes we snapshot all open NBA markets from Kalshi across three series: KXNBAWIN (moneyline), KXNBASPREAD (spread), and KXNBAPTS (totals). We capture bid/ask, implied probability, spread value, and 24h volume.
kalshi_snapshotsElo Power Ratings
Pre-game power ratings updated after every game. Factors in home-court advantage, rest days, back-to-backs, and recent form over the last 10 games. Each team carries a rolling Elo that regresses toward the mean at season boundaries.
Coaching, Lineups, Pace
We ingest coaching profiles (timeout tendencies, adjustment windows), lineup clustering via ANC (Agglomerative Nested Clustering), and pace metrics to enrich signals with context the market often ignores.
ML Engine
HMM State Detection
A Hidden Markov Model identifies the current game state from the sequence of possession outcomes. Four states are modeled:
- RUN Scoring burst
- DROUGHT Scoring drought
- EQUILIB Equilibrium
- MOMENTUM — Shift in progress
Hawkes Process Momentum
A self-exciting point process models clustering of scoring events. When a team goes on a run, the intensity spikes—and our model detects it before the market adjusts. Decay rate is tuned per-team based on historical pace.
Pregame Feature Matrix
Five signal layers feed the pregame model:
- Elo differential (home vs. away)
- Rest & schedule context
- Lineup ANC cluster matchup
- Coaching tendency profile
- Pace & venue adjustment
Edge & Position Sizing
edge = our_prob - kalshi_implied
Position sizing uses quarter-Kelly criterion:
kelly = 0.25 × (p × odds - (1-p)) / odds
Where p = our probability, odds = derived from Kalshi implied.
Quarter-Kelly balances growth with drawdown protection.
Signal Types
Trade Signals
Our model thinks the team is underpriced. The market hasn't caught up to a momentum shift, lineup change, or coaching adjustment.
edge: +5.2% • kelly: 3.1% • conf: HIGH
Our model thinks the team is overpriced. Fade the public—the market is lagging behind a drought or matchup problem.
edge: -4.8% • kelly: 2.7% • conf: MED
No actionable edge. The market is efficiently priced for this game right now.
edge: +0.8% • kelly: 0.0% • conf: LOW
Enrichment Indicators
Coach hasn't called a timeout during an opponent run of 8+ points. Historical data shows teams that don't break runs here lose the spread 67% of the time.
A starter has 4+ fouls before the 4th quarter. Lineup degradation incoming—net rating drops ~6 pts/100 possessions on average.
Current 5-man unit clusters into an archetype with known strengths/weaknesses. Matchup context the market rarely prices in.
Home-court Elo boost, altitude factor (DEN/UTA), and rest-day differential create a pre-game edge layer.
API Reference
Full endpoint documentation. For an interactive explorer, see the dedicated API docs.
/health
Service health check
curl https://api.lazyedge.net/health
{
"status": "ok",
"timestamp": "2026-03-21T02:15:00Z",
"version": "2.1.0"
}/games/today
Today's NBA games
curl https://api.lazyedge.net/games/today
{
"date": "2026-03-21",
"games": [
{
"game_id": "401584567",
"home": "BOS", "away": "LAL",
"status": "in_progress",
"quarter": 3, "clock": "4:32",
"home_score": 78, "away_score": 72
}
]
}/elo/{team}
Pre-game Elo rating for a team
curl https://api.lazyedge.net/elo/BOS
{
"team": "BOS",
"elo": 1642,
"rank": 2,
"last_updated": "2026-03-20T06:00:00Z"
}/signal/live/{game_id}
Live edge signals for a game
curl -H "X-API-Key: le_your_key_here" \ https://api.lazyedge.net/signal/live/401584567
{
"game_id": "401584567",
"signal": "BUY",
"team": "BOS",
"edge": 0.052,
"our_prob": 0.68,
"kalshi_implied": 0.628,
"timestamp": "2026-03-21T02:15:00Z"
}/signal/buy
All current BUY signals
curl -H "X-API-Key: le_your_key_here" \ https://api.lazyedge.net/signal/buy
{
"signals": [
{
"game_id": "401584567",
"team": "BOS", "edge": 0.052,
"signal": "BUY", "kelly": 0.031
}
],
"count": 1
}/edge/team/{team_abbr}
Team edge profile
curl -H "X-API-Key: le_your_key_here" \ https://api.lazyedge.net/edge/team/BOS
{
"team": "BOS",
"elo": 1642,
"avg_edge_30d": 0.028,
"buy_signals_30d": 14,
"win_rate_on_buy": 0.71
}/signal/live/{game_id}/full
Full signals with enrichment data
curl -H "X-API-Key: le_your_key_here" \ https://api.lazyedge.net/signal/live/401584567/full
{
"game_id": "401584567",
"signal": "BUY", "team": "BOS",
"edge": 0.052, "kelly": 0.031,
"our_prob": 0.68, "kalshi_implied": 0.628,
"hmm_state": "momentum",
"hawkes_intensity": 0.84,
"enrichment": {
"coaching_inaction": false,
"foul_trouble": ["J. Tatum"],
"lineup_anc_cluster": "elite_spacing",
"venue_edge": 0.018
},
"timestamp": "2026-03-21T02:15:00Z"
}/coaching/{team_abbr}
Coaching analytics profile
curl -H "X-API-Key: le_your_key_here" \ https://api.lazyedge.net/coaching/BOS
{
"team": "BOS",
"coach": "Joe Mazzulla",
"timeout_tendency": "passive",
"avg_timeout_delay_seconds": 142,
"adjustment_window_q": 2,
"challenge_success_rate": 0.48
}/lineup/{team_abbr}
Lineup clustering profiles
curl -H "X-API-Key: le_your_key_here" \ https://api.lazyedge.net/lineup/BOS
{
"team": "BOS",
"lineups": [
{
"players": ["Tatum","Brown","White","Holiday","Porzingis"],
"anc_cluster": "elite_spacing",
"net_rating": 12.4,
"minutes": 284
}
]
}/pace/{team_abbr}
Pace analytics
curl -H "X-API-Key: le_your_key_here" \ https://api.lazyedge.net/pace/BOS
{
"team": "BOS",
"pace": 98.7,
"pace_rank": 14,
"half_court_freq": 0.62,
"transition_freq": 0.38
}/webhook/register
Register BUY signal webhook
curl -X POST -H "X-API-Key: le_your_key_here" \
-H "Content-Type: application/json" \
-d '{"url":"https://your-server.com/hook","secret":"your_hmac_secret"}' \
https://api.lazyedge.net/webhook/register{
"id": "wh_abc123",
"url": "https://your-server.com/hook",
"status": "active",
"created_at": "2026-03-21T02:15:00Z"
}/webhooks
List your registered webhooks
curl -H "X-API-Key: le_your_key_here" \ https://api.lazyedge.net/webhooks
{
"webhooks": [
{
"id": "wh_abc123",
"url": "https://your-server.com/hook",
"status": "active",
"created_at": "2026-03-21T02:15:00Z"
}
]
}/webhook/{id}
Deactivate a webhook
curl -X DELETE -H "X-API-Key: le_your_key_here" \ https://api.lazyedge.net/webhook/wh_abc123
{
"id": "wh_abc123",
"status": "deactivated"
}/historical/edges
Backtested edge data (paginated)
curl -H "X-API-Key: le_your_key_here" \ "https://api.lazyedge.net/historical/edges?page=1&per_page=50"
{
"edges": [
{
"game_id": "401584100",
"date": "2026-03-18",
"team": "GSW", "signal": "BUY",
"edge": 0.061, "result": "win"
}
],
"page": 1, "per_page": 50, "total": 1243
}/signal/stream
Server-Sent Events real-time stream
curl -N -H "X-API-Key: le_your_key_here" \ https://api.lazyedge.net/signal/stream
event: signal
data: {"game_id":"401584567","signal":"BUY","team":"BOS","edge":0.052}
event: signal
data: {"game_id":"401584590","signal":"SELL","team":"MIA","edge":-0.041}/ws/live
WebSocket real-time stream
// JavaScript const ws = new WebSocket( "wss://api.lazyedge.net/ws/live?api_key=le_your_key_here" ); ws.onmessage = (e) => console.log(JSON.parse(e.data));
{
"type": "signal_update",
"game_id": "401584567",
"signal": "BUY", "team": "BOS",
"edge": 0.052, "kelly": 0.031,
"timestamp": "2026-03-21T02:15:00Z"
}Authentication
API Key Authentication
Pass your API key in the X-API-Key header with every request:
curl -H "X-API-Key: le_your_key_here" \ https://api.lazyedge.net/signal/buy
Your API key is generated when you subscribe to a paid plan. You can view it on your
Account page. Keys are prefixed with le_ for easy identification.
Rate Limits
When rate-limited, the API returns 429 Too Many Requests with a
Retry-After header in seconds.
Web Dashboard Sessions
The web dashboard uses session cookies (HttpOnly, SameSite=Lax) set at login. Sessions expire after 24 hours. No API key is needed for dashboard access—just log in.
Webhook Guide
Registering a Webhook
Pro and Elite users can register webhooks to receive BUY signals in real-time. Provide a publicly accessible HTTPS URL and an HMAC secret:
curl -X POST -H "X-API-Key: le_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhook/lazy-edge",
"secret": "your_hmac_secret_here"
}' \
https://api.lazyedge.net/webhook/registerPayload Format
When a BUY signal fires, we POST the following JSON to your registered URL:
{
"event": "signal.buy",
"timestamp": "2026-03-21T02:15:00Z",
"data": {
"game_id": "401584567",
"team": "BOS",
"edge": 0.052,
"kelly": 0.031,
"our_prob": 0.68,
"kalshi_implied": 0.628,
"hmm_state": "momentum"
}
}HMAC Signature Verification
Every webhook request includes an X-LE-Signature header containing an HMAC-SHA256
signature of the request body using your secret:
# Python verification example
import hmac, hashlib
def verify_signature(payload_body, signature, secret):
expected = hmac.new(
secret.encode(), payload_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)Retry Policy
If your endpoint returns a non-2xx status or times out (10s), we retry with exponential backoff:
- Retry 1: after 30 seconds
- Retry 2: after 2 minutes
- Retry 3: after 10 minutes
After 3 failed retries, the webhook is marked as failing. After 24 hours of continuous
failures, it is automatically deactivated. Check your webhook status via GET /webhooks.
Dashboard Guide
What Each Tier Sees
Free Dashboard
- Tonight's game cards (teams, scores, status)
- Pre-game Elo ratings
- Game schedule and start times
Basic Dashboard
- Everything in Free
- Live signal table (BUY / SELL / HOLD badges)
- Edge percentage for each game
- Team edge profile lookups
Pro Dashboard
- Everything in Basic
- Full signal cards with Kelly fraction
- Enrichment indicators on each game card
- Coaching, lineup, and pace analytics panels
Elite Dashboard
- Everything in Pro
- Real-time streaming feed (auto-updates)
- Historical edge data explorer
- Backtest performance charts
Game Cards
Each game is shown as a card with teams, score, quarter/clock, and signal status. The signal badge (BUY/SELL/HOLD) updates in real-time for paid users. Edge percentage and Kelly fraction are shown alongside the badge for Pro+ users.
Signal Badges
Signal badges are color-coded for quick scanning:
Enrichment Indicators
Pro+ game cards show contextual enrichment tags below the signal. These highlight factors like coaching inaction, foul trouble, favorable lineup matchups, and venue edge—context the market is often slow to price in.
Ready to Find Your Edge?
Start with a free account. Upgrade anytime for live signals, enrichment data, and API access.