Skip to contents

Overview

This vignette will outline the ways in which the functions in bettRtab can be used to extract sports and racing betting data from the TAB.


Installation

You can install the released version of bettRtab from GitHub with:

# install.packages("remotes")
remotes::install_github("JaseZiv/bettRtab")

Usage

The functions in this package should work without hitch locally, but running these in an automated way (GitHub Actions, cloud, etc) may lead to requests being blocked.

To get around this, you will need access to proxies and would need to set configs at the start of your scripts similar to the following:

httr::set_config(httr::use_proxy(url = Sys.getenv("PROXY_URL"),
                                 port = as.numeric(Sys.getenv("PROXY_PORT")),
                                 username =Sys.getenv("PROXY_USERNAME"),
                                 password= Sys.getenv("PROXY_PASSWORD")))

Sports Data

To get betting data for any currently available competition market, use the get_sports_market() function.

To get a valid list of values you can pass to the competition_name parameter, look at the competitions.name column in the file here.

Alternatively, the competition_name needed as an argument to this function can be found under the competitions page selector on the TAB website.

epl_futures <- get_sports_market(competition_name = "English Premier League Futures")

glimpse(epl_futures)
#> Rows: 60
#> Columns: 33
#> $ marketId            <chr> "83241830", "83241830", "83241830", "83241830", "8…
#> $ marketName          <chr> "2023/24 English Premier League Winner", "2023/24 …
#> $ shortName           <chr> "2023/24 EPL Winner", "2023/24 EPL Winner", "2023/…
#> $ betOption           <chr> "Winner", "Winner", "Winner", "Winner", "Winner", …
#> $ betOptionSpectrumId <chr> "52", "52", "52", "52", "52", "52", "52", "52", "5…
#> $ betOptionPriority   <chr> "380", "380", "380", "380", "380", "380", "380", "…
#> $ marketUniqueId      <chr> "83241830", "83241830", "83241830", "83241830", "8…
#> $ closeTime           <chr> "2024-05-19T15:00:00.000Z", "2024-05-19T15:00:00.0…
#> $ marketBettingStatus <chr> "Open", "Open", "Open", "Open", "Open", "Open", "O…
#> $ isFuture            <chr> "TRUE", "TRUE", "TRUE", "TRUE", "TRUE", "TRUE", "T…
#> $ onlineBetting       <chr> "TRUE", "TRUE", "TRUE", "TRUE", "TRUE", "TRUE", "T…
#> $ phoneBettingOnly    <chr> "FALSE", "FALSE", "FALSE", "FALSE", "FALSE", "FALS…
#> $ inPlay              <chr> "FALSE", "FALSE", "FALSE", "FALSE", "FALSE", "FALS…
#> $ goingInPlay         <chr> "FALSE", "FALSE", "FALSE", "FALSE", "FALSE", "FALS…
#> $ allowWin            <chr> "TRUE", "TRUE", "TRUE", "TRUE", "TRUE", "TRUE", "T…
#> $ marketAllowPlace    <chr> "FALSE", "FALSE", "FALSE", "FALSE", "FALSE", "FALS…
#> $ allowEachWay        <chr> "FALSE", "FALSE", "FALSE", "FALSE", "FALSE", "FALS…
#> $ allowMulti          <chr> "TRUE", "TRUE", "TRUE", "TRUE", "TRUE", "TRUE", "T…
#> $ allowMultiWin       <chr> "TRUE", "TRUE", "TRUE", "TRUE", "TRUE", "TRUE", "T…
#> $ allowMultiPlace     <chr> "FALSE", "FALSE", "FALSE", "FALSE", "FALSE", "FALS…
#> $ allowMultiEachWay   <chr> "FALSE", "FALSE", "FALSE", "FALSE", "FALSE", "FALS…
#> $ numberOfPlaces      <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", …
#> $ cashOutEligibility  <chr> "Enabled", "Enabled", "Enabled", "Enabled", "Enabl…
#> $ allowBundle         <chr> "FALSE", "FALSE", "FALSE", "FALSE", "FALSE", "FALS…
#> $ id                  <chr> "247128", "247129", "247130", "247131", "247133", …
#> $ name                <chr> "Man City", "Arsenal", "Liverpool", "Man Utd", "Ne…
#> $ returnWin           <chr> "1.72", "6", "9", "12", "15", "15", "41", "51", "1…
#> $ returnPlace         <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", …
#> $ bettingStatus       <chr> "Open", "Open", "Open", "Open", "Open", "Open", "O…
#> $ allowPlace          <chr> "FALSE", "FALSE", "FALSE", "FALSE", "FALSE", "FALS…
#> $ number              <chr> "247128", "247129", "247130", "247131", "247133", …
#> $ isOpen              <chr> "TRUE", "TRUE", "TRUE", "TRUE", "TRUE", "TRUE", "T…
#> $ sortOrder           <chr> "1", "2", "3", "4", "6", "5", "7", "8", "9", "10",…

We can then inspect to see which betting markets are available:

epl_futures %>% 
  select(betOption) %>% distinct()
#>   betOption
#> 1    Winner
#> 2     Top 4
#> 3     Top 6

and we can then explore some key markets… say we want to see the odds of relegation in the EPL:

epl_futures %>% 
  filter(betOption == "Relegation") %>% 
  select(marketName, id, name, returnWin)
#> [1] marketName id         name       returnWin 
#> <0 rows> (or 0-length row.names)

Live (In-Play) Sports

To get live and in-play sports markets as they’re being played, the get_live_sports() function is to be used. This will return a data frame of all sports that have an in-play market.

The user can then filter the outputted data frame on any of the variables in the data set (name, displayName, competitions.id, competitions.matches.name, etc).

live_sports <- get_live_sports()
dplyr::glimpse(live_sports)

Racing Data

This sections will outline the functions available to extract Horse, Harness and Greyhound racing.

Past Racing Data

The following section will outline how to use functions do get racing data (horses, harness racing and greyhounds) for past races run.

This section does not include functions to get current day or future racing data.

Race Meet Meta Data

To get meta data for race meets for a selected date(s), use the get_race_meet_meta() function.

The output of this function will return where and when the meet(s) were, the weather and track condition, and high level data about each of the races at the meets.

dates <- seq(from = as.Date("2022-05-01"), to=as.Date("2022-05-03"), by=1)
race_meets <- get_race_meet_meta(race_dates=dates)

glimpse(race_meets)
#> Rows: 134
#> Columns: 11
#> $ meetingName      <chr> "BAIRNSDALE", "SALE", "SANDOWN PARK", "SWAN HILL", "H…
#> $ location         <chr> "VIC", "VIC", "VIC", "VIC", "VIC", "VIC", "NSW", "NSW…
#> $ venueMnemonic    <chr> "P", "P", "M", "M", "E", "M", "S", "S", "S", "C", "C"…
#> $ raceType         <chr> "R", "G", "G", "H", "G", "R", "G", "H", "R", "G", "R"…
#> $ meetingDate      <chr> "2022-05-01", "2022-05-01", "2022-05-01", "2022-05-01…
#> $ weatherCondition <chr> "FINE", "OCAST", "OCAST", "FINE", "OCAST", "FINE", "F…
#> $ trackCondition   <chr> "SOFT6", "GOOD", "GOOD", "GOOD", "GOOD", "HVY8", "GOO…
#> $ exoticPools      <list> [<data.frame[10 x 6]>], [<data.frame[14 x 6]>], [<da…
#> $ X_links          <df[,1]> <data.frame[26 x 1]>
#> $ races            <list> [<data.frame[7 x 10]>], [<data.frame[11 x 10]>], […
#> $ sellCode         <df[,2]> <data.frame[26 x 2]>

Loading Data

Rather than scraping this information, you can instead use the load_race_meet_meta() function. This will allow you to get a whole year’s worth of race meet meta data extremely quickly. This data updates daily, so should only very rarely not have the previous day’s race meet data:

loaded_race_meets <- load_race_meet_meta(cal_year=2022)
glimpse(loaded_race_meets)
#> Rows: 16,807
#> Columns: 11
#> $ meetingName      <chr> "FLEMINGTON", "ECHUCA", "THE MEADOWS", "MORNINGTON", …
#> $ location         <chr> "VIC", "VIC", "VIC", "VIC", "VIC", "VIC", "NSW", "NSW…
#> $ venueMnemonic    <chr> "M", "M", "M", "C", "E", "P", "L", "C", "C", "T", "S"…
#> $ raceType         <chr> "R", "H", "G", "R", "R", "G", "G", "R", "G", "G", "R"…
#> $ meetingDate      <chr> "2022-01-01", "2022-01-01", "2022-01-01", "2022-01-01…
#> $ weatherCondition <chr> "FINE", "FINE", "FINE", "FINE", "FINE", "OCAST", "FIN…
#> $ trackCondition   <chr> "GOOD4", "GOOD", "GOOD", "GOOD3", "FIRM2", "GOOD", "G…
#> $ exoticPools      <list> [<data.frame[14 x 6]>], [<data.frame[15 x 6]>], [<da…
#> $ X_links          <df[,1]> <data.frame[26 x 1]>
#> $ races            <list> [<data.frame[9 x 10]>], [<data.frame[10 x 10]>], […
#> $ sellCode         <df[,2]> <data.frame[26 x 2]>

Each Race Data

To get detailed data on runners, markets, pools and dividends, the following set of functions will be used.

Past Race data output

The get_past_races() function will allow you to pass in values for four parameters to have a list of races outputted. The result of this function should be stored for use with the parsing functions to be explained shortly.

The race_num value can be left off the function call to default to returning all races on a card’s meet.

The race_type value needs to be either ‘R’, ‘H’ or ‘G’.

The rest of the parameters can have multiple arguments passed to them.

race_list_output <- get_past_races(meet_date = c('2022-09-03', '2022-09-10'), venue_mnem = 'M', race_type = 'R', race_num = c(8:9))

Alternatively, you can get the same data as above using the TAB race API URL. To get this URL, follow the below steps:

# first load in meet data
meets <- load_race_meet_meta(cal_year = 2022)

# then filter to the race(s) meets wanted
meet_dates_df <- meets %>%
   filter(venueMnemonic == "M",
          raceType == "R",
          meetingDate == "2022-01-01")

# then get the URLs
meet_url <- meet_dates_df$races[[1]]
meet_url <- meet_url$`_links`$self[1]

# finally, running the function:
race_list_output <- get_past_race_content(urls = meet_url)

Parsing Race Data

So to easily get the data you want, parsing functions have been created to operate on the stored outputs of either the get_past_races() or get_past_race_content().

Parse runners and betting market

To get a race’s runners and betting odds, use the parse_runners() function:

runners <- parse_runners(race_list = race_list_output)
glimpse(runners)
#> Rows: 61
#> Columns: 34
#> $ meetingDate                 <chr> "2022-09-03", "2022-09-03", "2022-09-03", …
#> $ location                    <chr> "VIC", "VIC", "VIC", "VIC", "VIC", "VIC", …
#> $ meetingName                 <chr> "MOONEE VALLEY", "MOONEE VALLEY", "MOONEE …
#> $ raceType                    <chr> "R", "R", "R", "R", "R", "R", "R", "R", "R…
#> $ venueMnemonic               <chr> "M", "M", "M", "M", "M", "M", "M", "M", "M…
#> $ raceNumber                  <chr> "8", "8", "8", "8", "8", "8", "8", "8", "8…
#> $ raceName                    <chr> "DRUMMOND GOLF HANDICAP", "DRUMMOND GOLF H…
#> $ raceStartTime               <chr> "2022-09-03T06:50:00+00:00", "2022-09-03T0…
#> $ raceStatus                  <chr> "Paying", "Paying", "Paying", "Paying", "P…
#> $ raceDistance                <chr> "1600", "1600", "1600", "1600", "1600", "1…
#> $ resultedTime                <chr> "2022-09-03T06:53:24+00:00", "2022-09-03T0…
#> $ substitute                  <chr> "5", "5", "5", "5", "5", "5", "5", "5", "5…
#> $ raceClassConditions         <chr> "OPEN", "OPEN", "OPEN", "OPEN", "OPEN", "O…
#> $ winBook                     <chr> "http://internal-aviato-lb-212286492.ap-so…
#> $ scratchings                 <chr> "1", "1", "1", "1", "1", "1", "1", "1", "1…
#> $ skyRacingAudio              <chr> "https://mediatabs.skyracing.com.au/Audio_…
#> $ runnerName                  <chr> "JOHNNY GET ANGRY", "DARK DREAM", "SO SI B…
#> $ runnerNumber                <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 2, 3…
#> $ finishingPosition           <int> 0, 0, 3, 0, 2, 1, 0, 0, 4, 0, 0, 0, 0, 2, …
#> $ trainerName                 <chr> "DENIS PAGAN", "BEN & JD HAYES", "BEN & JD…
#> $ barrierNumber               <int> 11, 2, 3, 6, 5, 7, 10, 4, 8, 1, 9, 9, 16, …
#> $ riderDriverName             <chr> "LACHLAN KING", "LAURA LAFFERTY", "LUKE NO…
#> $ claimAmount                 <dbl> -1.0, 3.0, -1.0, 2.0, -1.0, -1.0, -1.0, -1…
#> $ fixedOdds.returnWin         <dbl> 151.0, 31.0, 10.0, 23.0, 2.5, 3.4, 26.0, 2…
#> $ fixedOdds.returnWinOpen     <dbl> 81.0, 13.0, 12.0, 17.0, 3.0, 3.7, 13.0, 21…
#> $ fixedOdds.returnPlace       <dbl> 22.00, 6.00, 2.60, 4.60, 1.30, 1.45, 5.00,…
#> $ fixedOdds.bettingStatus     <chr> "LateScratched", "Loser", "Placing", "Lose…
#> $ fixedOdds.winDeduction      <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
#> $ fixedOdds.placeDeduction    <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
#> $ fixedOdds.propositionNumber <int> 159951, 159952, 159953, 159954, 159955, 15…
#> $ fixedOdds.scratchedTime     <chr> "2022-09-01T21:29:32+00:00", NA, NA, NA, N…
#> $ parimutuel.bettingStatus    <chr> "Scratched", "Normal", "Normal", "Normal",…
#> $ parimutuel.returnWin        <dbl> 0.0, 33.2, 10.1, 21.4, 2.5, 3.3, 21.2, 24.…
#> $ parimutuel.returnPlace      <dbl> 0.0, 6.3, 2.2, 4.7, 1.3, 1.5, 4.4, 5.2, 2.…

Parse pools

To get a race’s betting pools, use the parse_pools() function:

pools <- parse_pools(race_list = race_list_output)
glimpse(pools)
#> Rows: 120
#> Columns: 25
#> $ meetingDate         <chr> "2022-09-03", "2022-09-03", "2022-09-03", "2022-09…
#> $ location            <chr> "VIC", "VIC", "VIC", "VIC", "VIC", "VIC", "VIC", "…
#> $ meetingName         <chr> "MOONEE VALLEY", "MOONEE VALLEY", "MOONEE VALLEY",…
#> $ raceType            <chr> "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", …
#> $ venueMnemonic       <chr> "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", …
#> $ raceNumber          <chr> "8", "8", "8", "8", "8", "8", "8", "8", "8", "8", …
#> $ raceName            <chr> "DRUMMOND GOLF HANDICAP", "DRUMMOND GOLF HANDICAP"…
#> $ raceStartTime       <chr> "2022-09-03T06:50:00+00:00", "2022-09-03T06:50:00+…
#> $ raceStatus          <chr> "Paying", "Paying", "Paying", "Paying", "Paying", …
#> $ raceDistance        <chr> "1600", "1600", "1600", "1600", "1600", "1600", "1…
#> $ resultedTime        <chr> "2022-09-03T06:53:24+00:00", "2022-09-03T06:53:24+…
#> $ substitute          <chr> "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", …
#> $ raceClassConditions <chr> "OPEN", "OPEN", "OPEN", "OPEN", "OPEN", "OPEN", "O…
#> $ winBook             <chr> "http://internal-aviato-lb-212286492.ap-southeast-…
#> $ scratchings         <chr> "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", …
#> $ skyRacingAudio      <chr> "https://mediatabs.skyracing.com.au/Audio_Replay/2…
#> $ poolStatusCode      <chr> "Paying", "Paying", "Paying", "Paying", "Paying", …
#> $ wageringProduct     <chr> "OddsAndEvens", "Win", "Place", "Quinella", "Exact…
#> $ poolTotal           <dbl> 57.00, 199653.25, 72917.28, 41096.61, 14199.70, 39…
#> $ jackpot             <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
#> $ poolCloseTime       <chr> "2022-09-03T06:50:19+00:00", "2022-09-03T06:50:19+…
#> $ mergePool           <list> "Quinella", <NULL>, <NULL>, "OddsAndEvens", <NULL…
#> $ mergePoolTotal      <dbl> 41153.61, NA, NA, 41153.61, NA, NA, 93090.12, 9309…
#> $ legNumber           <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 1, 2, 1, 2,…
#> $ startTime           <chr> "2022-09-03T06:50:00+00:00", "2022-09-03T06:50:00+…

Parse dividends

To get a race’s dividends, use the parse_dividends() function:

dividends <- parse_dividends(race_list = race_list_output)
glimpse(dividends)
#> Rows: 66
#> Columns: 24
#> $ meetingDate         <chr> "2022-09-03", "2022-09-03", "2022-09-03", "2022-09…
#> $ location            <chr> "VIC", "VIC", "VIC", "VIC", "VIC", "VIC", "VIC", "…
#> $ meetingName         <chr> "MOONEE VALLEY", "MOONEE VALLEY", "MOONEE VALLEY",…
#> $ raceType            <chr> "R", "R", "R", "R", "R", "R", "R", "R", "R", "R", …
#> $ venueMnemonic       <chr> "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", …
#> $ raceNumber          <chr> "8", "8", "8", "8", "8", "8", "8", "8", "8", "8", …
#> $ raceName            <chr> "DRUMMOND GOLF HANDICAP", "DRUMMOND GOLF HANDICAP"…
#> $ raceStartTime       <chr> "2022-09-03T06:50:00+00:00", "2022-09-03T06:50:00+…
#> $ raceStatus          <chr> "Paying", "Paying", "Paying", "Paying", "Paying", …
#> $ raceDistance        <chr> "1600", "1600", "1600", "1600", "1600", "1600", "1…
#> $ resultedTime        <chr> "2022-09-03T06:53:24+00:00", "2022-09-03T06:53:24+…
#> $ substitute          <chr> "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", …
#> $ raceClassConditions <chr> "OPEN", "OPEN", "OPEN", "OPEN", "OPEN", "OPEN", "O…
#> $ winBook             <chr> "http://internal-aviato-lb-212286492.ap-southeast-…
#> $ scratchings         <chr> "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", …
#> $ skyRacingAudio      <chr> "https://mediatabs.skyracing.com.au/Audio_Replay/2…
#> $ poolStatusCode      <chr> "Paying", "Paying", "Paying", "Paying", "Paying", …
#> $ wageringProduct     <chr> "OddsAndEvens", "Win", "Place", "Place", "Place", …
#> $ jackpotCarriedOver  <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
#> $ poolCloseTime       <chr> "2022-09-03T06:50:19+00:00", "2022-09-03T06:50:19+…
#> $ mergePool           <list> "Quinella", <NULL>, <NULL>, <NULL>, <NULL>, "Odds…
#> $ mergePoolTotal      <dbl> 41153.61, NA, NA, NA, NA, 41153.61, NA, NA, NA, NA…
#> $ selections          <list> "SPLIT", 6, 6, 5, 3, <6, 5>, <6, 5>, <6, 5>, <6, …
#> $ amount              <dbl> 1.5, 3.3, 1.5, 1.3, 2.2, 3.6, 6.8, 2.1, 5.0, 4.2, …