project Feb 23, 2026

Turning Fantasy Basketball Into a Data Science Problem

Reading style:
ai sports data-analysis automation

TLDR: I’m a decade-long fantasy basketball player. This year I built an automated system that pulls live data from Yahoo Fantasy, analyzes my roster against the league, monitors injuries in real-time, and recommends waiver wire pickups tailored to my team’s specific weaknesses. It’s like having a dedicated analyst who never sleeps.


The problem

I’ve played fantasy basketball for over ten years. It’s a serious hobby — I know the categories, I know the patterns, I trust my instincts. But here’s the thing about relying on experience and intuition: you don’t actually know what you’re missing.

Am I holding a player who’s been trending down for two weeks? Maybe, but I’d have to check the stats manually to notice. Did a star player on another team just get injured, making their backup suddenly valuable on the waiver wire? I’d find out eventually, but “eventually” in fantasy basketball means someone else already grabbed them.

The information exists. Yahoo has all the stats, injury reports, and player data. But checking it all manually, across 12 scoring categories, for every relevant player, every day? That’s not a fun hobby anymore — that’s a part-time job.

What I built

An AI-powered fantasy basketball analyst that runs 24/7 and delivers insights to my phone via Telegram.

Every morning on game days, I get a breakdown: here’s how my team ranks in each of the 12 scoring categories, here’s where I’m trending up or down over the last two weeks, and here’s how my categories match up against this week’s opponent with projected wins and losses per category.

Throughout the day, the system monitors injury reports across the entire league. Not just my roster — everyone. When a key player goes down, the system immediately identifies the backup who’s about to get more playing time and checks if they’re available in my league’s free agent pool. “Ja Morant OUT 2-3 weeks. Scotty Pippen Jr. usage spike incoming. Available in your league.” That kind of alert, delivered to my phone before most people have even heard about the injury.

The waiver wire recommendations are the part I’m most proud of. Generic fantasy rankings tell you who the best available players are. My system tells me who the best available players are for my specific team. It looks at which categories I’m weakest in and finds free agents whose strengths fill exactly those gaps.

What changed

The biggest shift isn’t the data — it’s the confidence. When I make a roster move now, I can see exactly how it affects my category balance. I’m not guessing whether dropping Player A for Player B helps my assists-to-turnover ratio. I can see the numbers.

The other shift is speed. In fantasy basketball, the waiver wire is a race. The first person to spot an opportunity and act on it wins. Having a system that monitors injuries every 30 minutes and alerts me immediately means I’m consistently one of the first to react.

I still make all the decisions. The system doesn’t make moves for me — Yahoo’s API is read-only, and honestly I prefer it that way. It’s still my hobby, my league, my calls. But now I’m making those calls with significantly better information than anyone else in my league has access to.

The bigger picture

This project is a small example of something I think about a lot: AI as a force multiplier for human judgment. The system handles the tedious data crunching that I’d never do consistently. I handle the judgment calls that require context the system doesn’t have — league dynamics, trade negotiation, knowing which owners are desperate.

The best decisions happen when you combine good data with good intuition. The system gives me the data. The decade of experience gives me the intuition. Neither one alone is as good as both together.

The problem, specifically

10-team Yahoo Fantasy H2H league, 12 scoring categories: FG%, FTM, FT%, 3PTM, PTS, REB, AST, ST, BLK, TO, MIN, A/T ratio.

Architecture

Yahoo Fantasy API (OAuth 2.0, auto-refresh)
    |-- League settings, roster, standings, matchups, FA pool
    |-- Injury status changes (polled)
    |
nba_api (no auth)
    |-- Advanced stats: usage rate, pace, game logs, splits
    |
    v
Analysis Engine (Python, uv)
    |-- Category analysis: team avgs vs league, rankings, 2-week trends
    |-- Matchup projections: category-by-category W/L prediction
    |-- Injury monitor: status change detection + backup identification
    |-- FA ranker: roster-specific, category-gap-weighted recommendations
    |
    v
Delivery (OpenClaw cron -> Telegram)
    |-- Daily morning analysis (game days)
    |-- Injury alerts (polling during game windows)
    |-- On-demand queries

Key technical decisions

Yahoo OAuth with auto-refresh over re-auth flow. Token refresh happens transparently. Credentials stored locally, planned migration to a secrets manager via the MFA-gated access pattern.

Category-weighted FA ranking over generic player rankings. Standard fantasy rankings (Yahoo, ESPN, FantasyPros) rank players by overall value. Useless if you’re punting turnovers and need steals. The system ranks FAs by how much they improve YOUR weakest categories specifically. A player who’s mediocre overall but elite in your 2-3 weakest cats ranks higher than a generically “better” player.

Z-score composites with category weighting for player valuation. Raw stats are meaningless across categories (you can’t compare FG% to rebounds). Z-scores normalize everything to standard deviations from league mean. But naive z-score composites punish low-volume efficiency players — a guy shooting 55% FG on 5 attempts isn’t as valuable as 50% on 15 attempts. Need volume-adjusted category weighting. This is the area still being refined.

Polling for injuries rather than streaming. Yahoo doesn’t offer webhooks. Polling every 30 minutes during game hours catches status changes fast enough — the waiver wire race is measured in hours, not seconds. Limiting polls to game windows keeps API calls reasonable.

What’s working

  • OAuth flow stable with auto-refresh, no manual re-auth needed
  • Daily category analysis delivers accurate rankings across all 12 cats
  • Injury monitoring catches status changes within the polling window
  • Matchup projections align with actual weekly results ~70% of the time per category

Known limitations

  • Z-score composite still punishes low-volume efficiency players. Need a volume-adjusted variant that weights contribution magnitude, not just rate.
  • Yahoo API rate limits: player stats endpoint uses index [3] for player_stats; stat_type “lastmonth” works but “lasttwoweeks” doesn’t. Working around with manual date filtering.
  • No trade analysis yet — evaluating multi-player trades across 12 categories is a harder problem than single-player FA comparisons.
  • Read-only API — can’t execute roster moves programmatically (Yahoo limitation). All moves are manual, system provides recommendations only.

Stack

Python 3.14 (uv), Yahoo Fantasy OAuth 2.0, nba_api, OpenClaw cron for scheduling, Telegram for delivery. No database — analysis is computed fresh each run from API data.

A friendly robot scout with a clipboard and whistle, standing courtside at a basketball game, pointing at a glowing player on the bench.

Do you play any games with teams?

Maybe you play fantasy sports, or a card game where you build a deck, or a video game where you manage a team. If you do, you know this feeling: there are so many players or characters to keep track of that you can’t possibly watch all of them.

I play fantasy basketball. It’s a game where you pick real NBA players for your team, and when they play well in real life, you score points. I’ve been playing for over 10 years.

But here’s my secret: I built a robot scout.

The problem with too many players

In my league, there are hundreds of basketball players I could pick up. Each player is good at different things — some score a lot of points, some get a lot of rebounds, some are great at stealing the ball. My team gets scored on 12 different skills.

Keeping track of all that in my head? Impossible. I’d have to check stats for hundreds of players across 12 categories every single day. Nobody has time for that.

And here’s the worst part: in fantasy basketball, speed matters. If a great player suddenly becomes available (maybe because another player got injured and now the backup gets to play more), the first person in the league to notice and grab them wins. Everyone else misses out.

My robot scout

So I built a system that watches everything for me. It connects to the official data and checks every player, every day. Here’s what it does:

Morning report. Every game day, it tells me: “Here’s how your team is doing in all 12 categories. You’re great at steals and rebounds, but your free throw percentage is slipping. Watch out.”

Injury detective. Every 30 minutes during games, it checks if any player in the entire league got hurt. Not just my players — everyone. Why? Because when a star player gets injured, their backup suddenly gets way more playing time. If that backup is available to pick up, I want to know immediately.

Personal recommendations. This is the best part. Most fantasy advice tells you who the “best” available players are overall. But that’s not what I need. I need to know who’s best for my specific team. If my team is weak at three-point shooting, I don’t need another rebounder — I need a sharpshooter. My system knows exactly what my team needs and finds players who fill those gaps.

The lesson: data + instinct

Here’s what’s interesting: the robot scout doesn’t make decisions for me. It gives me better information, faster than I could get it myself. But I still decide what to do with it.

Sometimes the data says “pick up this player” but I know something the data doesn’t — like that player has a tough schedule coming up, or that another owner in my league is about to make a trade that changes everything.

The best results come from combining the robot’s data with my own experience and gut feeling. Neither one alone is as good as both together.

Think about your own games or hobbies. What information would help you make better decisions? What could you track or measure that would give you an edge? You don’t need to build a robot to start — sometimes just writing down patterns you notice is the beginning of your own secret weapon.