UNPKG

mls-elo

Version:

Calculate ELO rankings for Major League Soccer

176 lines (172 loc) 4.89 kB
const db = require('sqlite'); const fs = require('fs-extra'); const trueskill = require('trueskill'); const teams = require('../data/teams'); const updateElo = require('../lib/updateElo'); module.exports = async (argv) => { const {dbPath, verbose} = argv; if (verbose) { console.info(`using db in ${dbPath}`); } await db.open(dbPath, { Promise }); const startDate = new Date('December 11, 1973').getTime(); const startElo = 1300; const startTrueskillSigma = 25 / 3; const startTrueskillMu = 25; if (verbose) { console.info(`seeding table with start elo ${startElo} and trueskill sigma: ${startTrueskillSigma} mu: ${startTrueskillMu} on date ${startDate}`); } await Promise.all(teams.map(team => db.run(` INSERT INTO rankings (rankingteamid, elo, trueskillsigma, trueskillmu, date) VALUES ( (SELECT teamid FROM teams WHERE teams.abbreviation = "${team.abbreviation}"), ${startElo}, ${startTrueskillSigma}, ${startTrueskillMu}, ${startDate} ) `))); const matches = await db.all(` select competitions.k, hometeam, awayteam, homegoals, awaygoals, matches.date as date from matches inner join competitions on competitions.competitionid = matches.matchcompetition where matches.homegoals is not null order by date ASC `); if (verbose) { console.info(`processing ${matches.length} matches`); } for (const match of matches) { const awayranking = await db.get(` select rankings.elo, rankings.trueskillmu, rankings.trueskillsigma, rankings.date from rankings inner join ( select max(date) as date, max.rankingteamid from rankings as max where max.rankingteamid = ${match.awayteam} group by max.rankingteamid ) as maxranking on rankings.rankingteamid = ${match.awayteam} and rankings.date = maxranking.date `); const homeranking = await db.get(` select rankings.elo, rankings.trueskillmu, rankings.trueskillsigma, rankings.date from rankings inner join ( select max(date) as date, max.rankingteamid from rankings as max where max.rankingteamid = ${match.hometeam} group by max.rankingteamid ) as maxranking on rankings.rankingteamid = ${match.hometeam} and rankings.date = maxranking.date `); match.homeranking = homeranking.elo; match.awayranking = awayranking.elo; let homeElo, awayElo, homeTrueskill, awayTrueskill; if (match.homegoals < match.awaygoals) { homeElo = updateElo({ verbose, match, won: false, isHome: true }); awayElo = updateElo({ verbose, match, won: true, isHome: false }); homeTrueskill = { skill: [homeranking.trueskillmu, homeranking.trueskillsigma], rank: 2, }; awayTrueskill = { skill: [awayranking.trueskillmu, awayranking.trueskillsigma], rank: 1, }; } else if (match.homegoals === match.awaygoals) { homeElo = updateElo({ verbose, match, won: false, isHome: true }); awayElo = updateElo({ verbose, match, won: false, isHome: false }); homeTrueskill = { skill: [homeranking.trueskillmu, homeranking.trueskillsigma], rank: 2, }; awayTrueskill = { skill: [awayranking.trueskillmu, awayranking.trueskillsigma], rank: 2, }; } else { homeElo = updateElo({ verbose, match, won: true, isHome: true }); awayElo = updateElo({ verbose, match, won: false, isHome: false }); homeTrueskill = { skill: [homeranking.trueskillmu, homeranking.trueskillsigma], rank: 1, }; awayTrueskill = { skill: [awayranking.trueskillmu, awayranking.trueskillsigma], rank: 2, }; } trueskill.AdjustPlayers([homeTrueskill, awayTrueskill]); await Promise.all([db.run(` INSERT INTO rankings (elo, trueskillsigma, trueskillmu, date, rankingteamid) VALUES ( ${homeElo}, ${homeTrueskill.skill[1]}, ${homeTrueskill.skill[0]}, ${match.date}, ${match.hometeam} ) `), db.run(` INSERT INTO rankings (elo, trueskillsigma, trueskillmu, date, rankingteamid) VALUES ( ${awayElo}, ${homeTrueskill.skill[1]}, ${homeTrueskill.skill[0]}, ${match.date}, ${match.awayteam} ) `) ]); if (verbose) { console.info(`finished processing ${match.hometeam} vs ${match.awayteam} on ${match.date}`); } } }