尚未偵測到更新。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.