尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证NFL tight end stats, usage and touchdown odds, updated through the season
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗Estimates each NFL tight end's chance to score a touchdown from usage data, compares it with sportsbook prices, and grades the picks after the games.
Site: https://mattrudy13.github.io/te-tracker/
Best Bets (index.html, the home page): this week's TD picks in six categories: most likely to
score, best value, longshots, due for a TD, fades, and first-TD value. Each pick shows the best price, model %, market %, edge,
expected profit per $10 bet and a one-line reason. Below that is a track record of every past pick, graded after
the games (W–L–void, hit rate, units, ROI, and closing-line value). Players listed as Out, Doubtful or on IR are never picked.
Matchups (matchups.html): this week's games (next week's once Monday night is final) with
kickoff, network, spread, total and implied team points. Expand a game to see both teams' tight ends:
Finished games show the TE box score with the pregame TD price and receptions line, and how each one
landed. ?open=<gameId>,… keeps games expanded.
Leaders (leaders.html): usage and touchdown leaderboard, per game or season totals: targets, target
share, receptions, catch %, yards, yards per target, TDs, red-zone targets, xTD and TD − xTD, plus this
week's receptions line and best anytime-TD price. Filter by team, week range, minimum targets or your
★ watchlist.
Touchdowns (touchdowns.html): this week's anytime-TD or first-TD odds for every TE (an Anytime / 1st TD toggle,
?mkt=first; sorted by model-vs-book edge), red-zone usage
(targets inside the 20 / 10 / 5), expected TDs (xTD) vs actual, and the TE touchdown rate by
field position that the model uses.
Player (player.html?id=<espn id>, click any player name): this week's game with the receptions line
(best over/under, how often the player has gone over it), anytime-TD and first-TD model vs book; season usage; touchdown
profile; charts of targets, receptions against the line, red-zone targets and yards; and a game log.
Filters live in the URL, so any view can be shared. The watchlist is saved in your browser.
No server and no build step: GitHub Actions write JSON into data/, and GitHub Pages serves the HTML plus
that JSON.
update-data.yml every 3 h Thu–Mon + Tue build-data.mjs (ESPN) → grade-picks.mjs
snapshot-odds.yml Thu 11 AM + Sun 4 AM ET build-data.mjs → fetch-odds.mjs (The Odds API) → record-picks.mjs
check-assets.yml on push stamp-assets.mjs --check
↓
data/2026.json · odds-2026.json · picks-2026.json → GitHub Pages
| File | What it is |
|---|---|
index.html, matchups.html, leaders.html, touchdowns.html, player.html | The pages. Each keeps its page logic in an inline script |
model.js | Data and model code (aggregation, TD model, injuries, best bets), shared by the pages and the scripts |
common.js | Browser helpers: data loading, formatting, tables, URL state, watchlist |
style.css | All styles (light/dark) |
scripts/ | build-data, fetch-odds, record-picks, grade-picks, stamp-assets (Node 20+, no dependencies) |
data/ | Generated JSON, committed by the workflows |
scripts/build-data.mjs:
data/positions-<season>.json).Games already in the file are reused, so a rerun only fetches new games. A game that can't be read (an ESPN error, or a game roster that isn't posted yet) is skipped and tried again on the next run. Picks on it aren't graded until it goes through.
.github/workflows/update-data.yml runs every 3 hours Thursday–Monday plus Tuesday morning
(UTC) from September through February. It commits only when the data changed. You can also run it
by hand from the Actions tab ("Run workflow"). Both data workflows build from the latest main, so
re-running an old failed run works, though the next scheduled run catches up on its own.
scripts/fetch-odds.mjs takes a snapshot of tight end props from The Odds API:
anytime-TD and first-TD-scorer prices and the receptions over/under, from US-licensed books only (DraftKings, FanDuel, BetMGM,
Caesars, BetRivers, ESPN BET, Fanatics…). Offshore books (BetOnline.ag, Bovada, BetUS, MyBookie, LowVig) are
dropped before the best price and market median are chosen, so every price on the site can be bet at a
licensed book. It writes data/odds-<season>.json.
.github/workflows/snapshot-odds.yml runs it Thursday at 11 AM ET (before TNF) and Sunday at 4 AM ET. Both are early on purpose: GitHub often
starts scheduled runs hours late.
Games that have already kicked off keep their earlier snapshot. GitHub can start scheduled runs hours
late (the first Thursday run started at 9 PM ET, after TNF kickoff), so TNF picks may come from an earlier snapshot. Each snapshot costs 1 credit per market per
game (3 markets, ~15 games), so about 30–45 credits, ~85 a week and ~375 a month. That leaves ~125 for
manual runs on the free tier (500/month). Each run logs the credits left.
The key is the ODDS_API_KEY repository secret, so it's only used inside the workflow. Set or replace it
with gh secret set ODDS_API_KEY -R mattrudy13/te-tracker. To run locally:
ODDS_API_KEY=... node scripts/fetch-odds.mjs. Without the file, the odds columns just show "–".
First-TD markets carry a 25–40% margin, so the snapshot also stores a de-vigged fairProb: each book's
prices are divided by that book's total implied probability over every first-TD outcome in the game
(books listing fewer than 20 outcomes are skipped, since a partial list understates the margin).
Sportsbooks post most TE props midweek, so a Monday-night or Tuesday run prices only a few players. Thursday's snapshot is the one that counts.
Where the odds show up:
The picks logic is bestBets() in model.js. That file is shared by the site and the Node scripts, so the
Action computes exactly what the page shows.
| Category | Rule (top 5 each) |
|---|---|
| Most likely to score | Highest model TD % |
| Best value | Expected profit > 0 at the best price, price under +400, model ≥ 15%, ≥ 2 books |
| Longshots | Price +400 or longer, expected profit > 0, at least 1 red-zone target, at least 2 targets in the team's last 2 games |
| Due for a TD | TD − xTD ≤ −0.8 with ≥ 3 red-zone targets |
| Fades | Price +250 or shorter and model at least 8 points below the market |
| First TD value | First-TD bet: expected profit > 0 at the best price, model ≥ 4%, ≥ 2 books, ≥ 1 red-zone target, ≥ 2 targets in the team's last 2 games |
scripts/record-picks.mjs runs after each odds snapshot, following a fresh stats/injury build. It saves the
picks to data/picks-<season>.json. Picks lock at kickoff: Sunday's snapshot only replaces picks for games
that haven't started. A replaced pick keeps the price it was first picked at (openPrice, openMarketProb), so
the last snapshot before kickoff serves as the closing line.scripts/grade-picks.mjs runs after every stats build. It grades final games: a TD (receiving or rushing)
wins, a box-score line without a TD loses, and no game row (inactive, or dressed but never took a snap) is void. Profit is stored per $100 at the recorded price; the page shows it per $10 bet.
Fades are graded right/wrong only. First-TD picks win only if the player scored the game's first TD
(firstTd on the game row) and lose otherwise, including games with no TD. Reruns don't change graded picks.model.js.TD_PER_POINT (0.105, about
2.4 TDs on 23 points). If TDs arrive independently, the first one is the player's with chance λ/Λ, and
there is one at all with chance 1 − e^(−Λ): P = λ/Λ · (1 − e^(−Λ)). TD_PER_POINT isn't calibrated against
the first-TD market yet. Over weeks 1–4 a TE scored first in 10 of 64 games (16%); the model's TE share is about 20%.build-data.mjs reads ESPN's scoringPlays and flags the TE row that scored the game's
first TD (firstTd: true). Games processed before this existed were filled in with
node scripts/build-data.mjs --backfill-first-td.GitHub Pages lets browsers cache files for 10 minutes. The pages load model.js, common.js and
style.css with a content-hash stamp (model.js?v=1a2b3c4d), so a new page never runs against a stale
cached script. After editing any of those three files, run node scripts/stamp-assets.mjs before
committing. The "Check asset stamps" workflow fails on a push if you forget.
node scripts/build-data.mjs # current season; or pass a year
python3 -m http.server 8000 # then open http://localhost:8000
Ideas and next steps are in ENHANCEMENTS.md.