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: 289
#> Columns: 33
#> $ marketId            <chr> "68519348", "68519348", "68519348", "68519348", "6…
#> $ marketName          <chr> "EPL Winner 2022/23", "EPL Winner 2022/23", "EPL W…
#> $ shortName           <chr> "EPL Winner 2022/23", "EPL Winner 2022/23", "EPL W…
#> $ betOption           <chr> "Winner", "Winner", "Winner", "Winner", "Winner", …
#> $ betOptionSpectrumId <chr> "52", "52", "52", "52", "52", "52", "52", "52", "5…
#> $ betOptionPriority   <chr> "220", "220", "220", "220", "220", "220", "220", "…
#> $ marketUniqueId      <chr> "68519348", "68519348", "68519348", "68519348", "6…
#> $ closeTime           <chr> "2022-12-26T12:30:00.000Z", "2022-12-26T12:30: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> "278385", "278390", "278386", "278391", "278388", …
#> $ name                <chr> "Man City", "Arsenal", "Liverpool", "Newcastle", "…
#> $ returnWin           <chr> "1.42", "3.25", "34", "34", "67", "67", "251", "50…
#> $ 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> "278385", "278390", "278386", "278391", "278388", …
#> $ isOpen              <chr> "TRUE", "TRUE", "TRUE", "TRUE", "TRUE", "TRUE", "T…
#> $ sortOrder           <chr> "1", "6", "2", "7", "4", "5", "3", "10", "8", "14"…

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

epl_futures %>% 
  select(betOption) %>% distinct()
#>                              betOption
#> 1                               Winner
#> 2                      Top Goal Scorer
#> 3      Top Goal Scorer Without Haaland
#> 4                                Top 4
#> 5                           Relegation
#> 6                                Top 2
#> 7                                Top 6
#> 8                   To Finish Top Half
#> 9                  Team to Finish Last
#> 10              Season Points Handicap
#> 11 Winner without Liverpool & Man City
#> 12                Winner without Big 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)
#>                marketName     id              name returnWin
#> 1  EPL Relegation 2022/23 228288 Nottingham Forest      1.55
#> 2  EPL Relegation 2022/23 228287       Bournemouth      1.65
#> 3  EPL Relegation 2022/23 228277     Wolverhampton       1.8
#> 4  EPL Relegation 2022/23 228278           Everton       2.6
#> 5  EPL Relegation 2022/23 228285       Southampton       2.6
#> 6  EPL Relegation 2022/23 228286             Leeds         5
#> 7  EPL Relegation 2022/23 228284            Fulham       6.5
#> 8  EPL Relegation 2022/23 228279         Leicester         9
#> 9  EPL Relegation 2022/23 228282         Brentford         9
#> 10 EPL Relegation 2022/23 228275          West Ham        11
#> 11 EPL Relegation 2022/23 228283       Aston Villa        15
#> 12 EPL Relegation 2022/23 228280    Crystal Palace        21
#> 13 EPL Relegation 2022/23 228281          Brighton        67
#> 14 EPL Relegation 2022/23 228271           Chelsea       351
#> 15 EPL Relegation 2022/23 228270         Liverpool       401
#> 16 EPL Relegation 2022/23 228272           Man Utd       401
#> 17 EPL Relegation 2022/23 228273         Tottenham       751
#> 18 EPL Relegation 2022/23 228276         Newcastle       751

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> "BENDIGO", "SWAN HILL", "SANDOWN PARK", "HEALESVILLE"…
#> $ location         <chr> "VIC", "VIC", "VIC", "VIC", "VIC", "VIC", "NSW", "NSW…
#> $ venueMnemonic    <chr> "M", "M", "M", "E", "P", "P", "C", "C", "S", "S", "S"…
#> $ raceType         <chr> "R", "H", "G", "G", "R", "G", "R", "G", "R", "H", "G"…
#> $ meetingDate      <chr> "2022-05-01", "2022-05-01", "2022-05-01", "2022-05-01…
#> $ weatherCondition <chr> "FINE", "FINE", "OCAST", "OCAST", "FINE", "OCAST", "S…
#> $ trackCondition   <chr> "HVY8", "GOOD", "GOOD", "GOOD", "SOFT6", "GOOD", "HVY…
#> $ exoticPools      <list> [<data.frame[13 x 6]>], [<data.frame[12 x 6]>], [<da…
#> $ X_links          <df[,1]> <data.frame[26 x 1]>
#> $ races            <list> [<data.frame[8 x 10]>], [<data.frame[7 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,282
#> 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, …