Score both teams' optimal starting lineups before and after swapping the given give/receive players, using the league's own lineup optimizer (see best_roster()) rather than an external trade value chart – so the answer reflects this league's actual roster settings and ESPN's own per-week projections, not a generic consensus ranking.

evaluate_trade(
  leagueId = ffl_id(),
  teamId,
  give = integer(),
  receive = integer(),
  seasonId = ffl_year(),
  scoringPeriodId = ffl_week(),
  useScore = c("projectedScore", "actualScore"),
  replacement = TRUE,
  replacementRank = 1,
  cookie = ffl_cookie()
)

Arguments

leagueId

Numeric league ID or ESPN fantasy page URL. Defaults to getOption("fflr.leagueId"). Function fails if no ID is found.

teamId

The team ID evaluating the trade (see league_teams()).

give

Integer vector of player IDs leaving teamId's roster. Every ID must currently be on that roster.

receive

Integer vector of player IDs arriving on teamId's roster, all currently rostered by other teams.

seasonId

Integer year of the NFL season. Defaults to the current season (see ffl_year()) rather than ffl_api()'s fixed default, which is only right for the year of the fflr release.

scoringPeriodId

Integer vector of one or more weeks to score, or "rest" for the rest of the regular season. Defaults to the current week (see ffl_week()).

useScore

One of "projectedScore" (default) or "actualScore".

replacement

If TRUE (default), let every lineup start a replacement-level stand-in from the waiver wire at each position (see below). FALSE scores only the players on each roster.

replacementRank

Which available player at each position is the stand-in: 1 (default) is the best one that week. The best is slightly optimistic, since only one team can claim them; use 2 or more for a more conservative baseline.

The alphanumeric espn_s2 cookie string from a signed-in session, defaulting to ffl_cookie(). Since 2025, this cookie is required by the leagueHistory endpoint. Past seasons can also be requested without a cookie by passing an explicit seasonId instead of using leagueHistory = TRUE.

Value

A tibble with one row per team per scoringPeriodId: the optimal starting score with the current roster (scoreBefore), with the trade applied (scoreAfter), and their difference (delta); the players who move into (startersIn) and out of (startersOut) the optimal starting lineup; the bench players the team would have to drop to get back under the roster limit (dropped); and which traded players, on either side, are on bye that week (byes), from nfl_teams – NA for seasons other than the one that data covers. Player lists are comma-separated names, NA when empty. A replacement stand-in in startersIn or startersOut is named with a " (replacement)" suffix, and the stand-ins each lineup starts are listed in replacementsBefore and replacementsAfter.

Details

Every receive player must be on another team's roster: the team that rosters them is the trade partner, and is scored with the same swap in reverse. If receive players come from more than one team, the partner side can't be split up and only teamId is scored, with a warning. A free agent or player on waivers is an error – that's a pickup, not a trade.

Passing more than one scoringPeriodId scores the same swap at each week separately (rosters, byes, and matchups all change week to week). Use scoringPeriodId = "rest" to score every week from the current one through the end of the regular season. That makes one API request per week, so it takes a few seconds; sum delta by teamId for a rest-of-season total.

If a team ends up with more players than the league's roster limit (not counting players on IR), its lowest-scoring non-starters are listed in dropped. Dropping non-starters never changes the starting score, so this says who you'd have to cut rather than changing the result. A warning is given if the league's trade deadline has passed.

Replacement level

Scoring only the players already on a roster treats an empty starting slot – a lone QB on bye, an injured kicker, a thin position – as worth 0, so a trade that fills it gets credit for points any manager would really pick up off waivers. With replacement = TRUE (the default), each week's before and after lineups, for both teams, can also start one stand-in per starting position (QB, RB, WR, TE, K, D/ST, or whichever single-position slots the league uses; FLEX-type slots are covered by those stand-ins): an available player, projected at their own number for that week. A stand-in is on both sides of the comparison, so it cancels out wherever the roster already has someone better, and only changes the result where a slot would otherwise score below waiver level. A trade is then valued above the waiver wire rather than above zero.

The stand-ins are chosen from the most-rostered players who are available today (free agents and players on waivers), taking the replacementRank-th best score at each position for each week. The pool is today's, not a forecast: nobody knows who will be available in a later week. There's one stand-in per position rather than per slot, so a team with two RBs on bye can only fill one of the holes – modeling one pickup per position per week. The roster spot a pickup costs is ignored: it would be the worst bench player, who doesn't start, so the lineup score is unaffected. Stand-ins are never counted towards the roster limit, dropped, or byes. Fetching the pool adds one request per position, each covering every scored week.

Examples

if (FALSE) { # \dontrun{
evaluate_trade(teamId = 6, give = 4427366, receive = 4362628)
evaluate_trade(teamId = 6, give = 4427366, receive = 4362628,
               scoringPeriodId = "rest")
} # }