STAT-API

Rank a DFS slate by salary and value

Value is points per dollar, and it is the screen that decides most lineups. A 9,800-salary running back who scores 20 points returns less than a 3,600 receiver who scores 15. dfs.player_stats reports the salary and the points on the same row, so this needs one endpoint and no join. Salaries below the floor are excluded, because a minimum-priced player who scores once distorts any ratio.

  1. 1. Page the slate's scoring rows

    Salary, position, and points all arrive together.

    curl -sS --compressed \
      -H 'Authorization: Bearer YOUR_API_KEY' \
      'https://api.stat-api.com/api/v1/dfs/player_stats?slate_id=129036'
  2. 2. Drop the players who did not play

    fantasy_pts is null for anyone in the pool who never took the field.

    const scored = stats.filter((row) => row.fantasy_pts !== null && row.fantasy_pts !== undefined)
  3. 3. Drop minimum-salary players

    A $3,000 player who returns one touchdown shows an enormous ratio and tells you nothing repeatable. A floor of 4,000 keeps the board honest.

    const playable = scored.filter((row) => row.salary >= 4000)
  4. 4. Compute points per $1,000 of salary

    Value = points / salary × 1000. Multiplying by 1,000 puts the number on a readable scale — roughly 2 to 6 for NFL classic scoring.

    const board = playable
      .map((row) => ({
        player_id: row.player_id,
        position: row.position,
        salary: row.salary,
        points: row.fantasy_pts ?? 0,
        value: ((row.fantasy_pts ?? 0) / row.salary) * 1000,
      }))
      .sort((a, b) => b.value - a.value)
      .slice(0, 10)
    console.log(['player_id', 'position', 'salary', 'points', 'per $1k'].join('\t'))
    for (const r of board) {
      console.log([r.player_id, r.position, r.salary, r.points, r.value.toFixed(2)].join('\t'))
    }