stopifnot(file.exists("../../DESCRIPTION"))
stopifnot(!isFALSE(getOption("knitr.use.stringr")))

Introduction

This article outlines the calculations used in Grattan Institute’s tax modelling. The model is simple:

  1. Project (“uprate”) the latest sample files to the years required
  2. Use model_income_tax with the required parameters.

First load the packages we’ll need.

library(fst)
library(fastmatch)
library(ggplot2)
library(scales)
library(magrittr)
library(ggrepel)
library(viridis)
library(knitr)
library(hutils)
library(magrittr)
library(data.table)
library(grattan)

We also load the taxstats package. The other packages are private as the ATO has suppressed the information from the public: unfortunately, only approved institutions can use this data sets.

library(taxstats)
#' @details 700ms vs 57ms
get_near_term <- function(fy_year = c("2016-17", "2017-18", "2018-19")) {
  fy_year <- match.arg(fy_year)
  h <- as.integer(fy2yr(fy_year) - 2016L)
  syyyy <- paste0(substr(fy_year, 3, 4), substr(fy_year, 6, 7))
  if (file.exists(syyyy.fst <- sprintf("budget-2018_cache/%s.fst", syyyy)) && cache) {
    s <- read_fst(syyyy.fst, as.data.table = TRUE)
  } else {
    s <- 
      if (file.exists("~/ozTaxData/data-raw/2016_sample_file.csv")) {
        sample_file_1516 <- fread("~/ozTaxData/data-raw/2016_sample_file.csv")
        project(sample_file_1516, h = h , fy.year.of.sample.file = "2015-16")
      } else {
        project(sample_file_1415_synth, h = h + 1L, fy.year.of.sample.file = "2014-15")
      }
    s <- model_income_tax(s, "2017-18")
    s[, Taxable_Income_percentile := ntile(Taxable_Income, 100)]
    write_fst(s, syyyy.fst)
  }
}

These tables come from the Budget papers and will be passed to project so that the uprating can be set with fixed values. (By default project forecasts the series using the forecast package.)

wage_forecasts <- 
  data.table(fy_year = yr2fy(2018:2028),
             r = c(2.25, 2.75, 3.25, 3.5, 3.5, rep(3.5, 6)) / 100)
lf_forecasts <- 
  data.table(fy_year = yr2fy(2018:2028),
             r = c(2.75, 1.50, 1.50, 1.50, 1.25, rep(1.25, 6)) / 100)

These are functions of years from 2015-16 that return the tax rates and tax thresholds that the Government has proposed in the Budget. They are used so that the out years can be modelled conveniently as a function of the year only.

These functions increase the thresholds for the Medicare levy for low-income earners. Technically such measures have to be approved each financial year, but are as a matter of a routine.

.project_useGrattans <- lapply(1:12, .project_to, use.Treasury = FALSE)
.project_useGrattans80 <- lapply(1:12, function(h) {
  project(sample_file_1516, h = h, wage.series = wage_r80)
})
.project_useGrattans20 <- lapply(1:12, function(h) {
  project(sample_file_1516, h = h, wage.series = wage_r20)
})
.project_useGrattans2.75 <- lapply(1:12, function(h) {
  project(sample_file_1516, h = h, wage.series = 0.0275)
})
#' @param level Prediction interval level.
#' @param wage.r A string like "2.75\%", the wage growth as a percentage.
model_Budgets <- function(fy_year, 
                          use.Treasury = TRUE,
                          .debug = FALSE,
                          level = NULL, 
                          wage.r = NULL) { 
  h <- as.integer(fy2yr(fy_year) - 2016L)
  s1920 <- NULL
  if (use.Treasury) {
    if (missing(level) && missing(wage.r)) {
      s1920 <- .project_useTreasurys[[h]]
    } else {
      stop("`use.Treasury = TRUE` yet `level` or `wage.r` are supplied.")
    }
  } else {
    if (is.null(level)) {
      if (is.null(wage.r)) {
        s1920 <- .project_useGrattans[[h]]
      } else {
        if (!is.character(wage.r) || length(wage.r) != 1) {
          stop("`wage.r` must be a string.")
        } 
        switch(wage.r, 
               "2.75%" = {
                 s1920 <- .project_useGrattans2.75[[h]]
               }, 
               stop("`wage.r = ", wage.r, "` not supported."))
      }
    } else {
      if (level == 20) {
        s1920 <- .project_useGrattans20[[h]]
      } else if (level == 80) {
        s1920 <- .project_useGrattans80[[h]]
      } else {
        stop("Level not supported.")
      }
    }
  }
  model_income_tax <- function(...,
                               lamington = FALSE,
                               lito_202223 = FALSE, 
                               watr = FALSE) {
    grattan::model_income_tax(
      sample_file = s1920, 
      baseline_fy = "2017-18",
      medicare_levy_lower_threshold = medicare_levy_lower_threshold(fy_year),
      medicare_levy_lower_sapto_threshold = medicare_levy_lower_sapto_threshold(fy_year),
      medicare_levy_lower_family_threshold = medicare_levy_lower_family_threshold(fy_year),
      medicare_levy_lower_family_sapto_threshold = medicare_levy_lower_family_sapto_threshold(fy_year),
      medicare_levy_lower_up_for_each_child = medicare_levy_lower_up_for_each_child(fy_year),
      warn_upper_thresholds = FALSE,
      Budget2018_lamington = lamington,
      Budget2018_lito_202223 = lito_202223,
      Budget2018_watr = watr,
      ...) %>%
      .[, .(Ind, age_range, Total_PP_BE_amt, Total_NPP_BE_amt, Taxable_Income, new_tax, baseline_tax, WEIGHT)] %>%
      setkey(Taxable_Income) %>%
      .[, new_tax := as.integer(new_tax)] %>%
      .[, delta := new_tax - baseline_tax] %>%
      
      .[]
  }
  
  is_lamington <- fy_year %in% c("2018-19", "2019-20", "2020-21", "2021-22")
  
  list(
    Budget2018_baseline = model_income_tax(),
    Baseline_brackets_cpi = model_income_tax(ordinary_tax_thresholds = cpi_inflator(ordinary_tax_thresholds(1),
                                                                                               from_fy = "2017-18",
                                                                                               to_fy = fy_year)),
    Budget2018_just_rates = model_income_tax(ordinary_tax_rates =  ordinary_tax_rates(fy_year),
                                             ordinary_tax_thresholds = ordinary_tax_thresholds(fy_year),
                                             lito_202223 = FALSE,
                                             lamington = FALSE),
    Budget2018_lamington_et_LITO = model_income_tax(lito_202223 = fy_year >= "2022-23",
                                                      lamington = is_lamington),
    Budget2018 = model_income_tax(ordinary_tax_rates = ordinary_tax_rates(fy_year),
                                  ordinary_tax_thresholds = ordinary_tax_thresholds(fy_year),
                                  lito_202223 = fy_year >= "2022-23",
                                  lamington = is_lamington),
    Budget2018_Step1and2 = model_income_tax(ordinary_tax_rates = ordinary_tax_rates(pmin(fy_year, "2022-23")), 
                                            ordinary_tax_thresholds = ordinary_tax_thresholds(pmin(fy_year, "2022-23")),
                                            lito_202223 = fy_year >= "2022-23", 
                                            lamington = is_lamington),
    ALP2018 = model_income_tax(ordinary_tax_rates = ordinary_tax_rates(pmin(fy_year, "2022-23")), 
                               ordinary_tax_thresholds = ordinary_tax_thresholds(pmin(fy_year, "2022-23")),
                               lamington = FALSE,
                               watr = TRUE))
}
.ntile <- function(x, n) {
  if (is.unsorted(x)) {
    stop("`x` must be sorted.")
  }
  as.integer(floor(n * (seq_along(x) - 1)/length(x) + 1))
}
.ntile2 <- function(x, n, N = length(x)) {
  if (is.unsorted(x)) {
    stop("`x` must be sorted.")
  }
  as.integer(floor(n * (seq_len(N) - 1)/N + 1))
}
percentile2quintile <- function(p) {
  {{p - 1L} %/% 20L} + 1L
}
stopifnot(identical(ntile(1:100, 5), percentile2quintile(1:100)))
x <- rnorm(1009)
stopifnot(identical(ntile(x, 5), percentile2quintile(ntile(x, 100))))
rm(x)
bind_Budget2018_models <- function(chunk, .cache = cache, ...) {
  if (is_knitting()) {
    current_chunk <- opts_current$get(name = "label")
    if (!identical(chunk, current_chunk)) {
      stop("`chunk = ", chunk, "`, yet\n", 
           "current chunk: ", current_chunk, ".")
    }
  }
  
  if (file.exists(x.fst <- sprintf("budget-2018_cache/%s.fst", chunk)) && .cache) {
    read_fst(x.fst, as.data.table = TRUE)
  } else {
    Budget_1922 <- lapply(unique_fy_year, model_Budgets, ...)
    names(Budget_1922) <- unique_fy_year
    
    if (is_knitting()) {
      revenue_fy_year <- 
        sapply(Budget_1922, sapply, revenue_foregone, USE.NAMES = TRUE) %>%
        divide_by(1e9)
      revenue_by_id <-
        revenue_fy_year %>%
        rowSums
      
      revenue_fy_year <- rowname2column(revenue_fy_year)
      revenue_by_id <- rowname2column(revenue_by_id)
      setnames(revenue_by_id, "V1", "Revenue/$bn")
      
      file_suffix <- sub("bound_models_?", "", current_chunk)
      if (nzchar(file_suffix)) {
        # i.e. -- designates deviation from budget
        file_suffix <- paste0("--", file_suffix)
      }
      fwrite(revenue_fy_year, sprintf("revenue-by-fy_year-id%s.csv", file_suffix))
      fwrite(revenue_by_id, sprintf("revenue-by-id%s.csv", file_suffix))
    }
    
    a <- lapply(Budget_1922, rbindlist, use.names = TRUE, fill = TRUE, idcol = "id")
    b <- rbindlist(a, use.names = TRUE, fill = TRUE, idcol = "fy_year")
    setkey(b, fy_year, id, Taxable_Income)
    b[, Taxable_Income_percentile := .ntile(Taxable_Income, 100), 
      keyby = c("fy_year", "id")]
    b[, Quintile := percentile2quintile(Taxable_Income_percentile)]
    setkey(b, fy_year, id, Taxable_Income)
    write_fst(b, x.fst)
    b[]
  } 
}

Costings 2018-19 to 2027-28 (Govt growth assumptions)

id 2018-19 2019-20 2020-21 2021-22 2022-23 2023-24 2024-25 2025-26 2026-27 2027-28
Budget2018_baseline 0.0 -0.1 -0.1 -0.1 -0.2 -0.2 -0.3 -0.3 -0.3 -0.4
Baseline_brackets_cpi -1.7 -3.5 -5.7 -7.9 -10.3 -12.8 -15.5 -18.3 -21.2 -24.3
Budget2018_just_rates -0.4 -0.5 -0.5 -0.6 -14.0 -14.6 -21.4 -22.6 -23.8 -25.2
Budget2018_lamington_et_LITO -3.7 -3.8 -3.9 -4.0 -0.7 -0.7 -0.7 -0.8 -0.8 -0.8
Budget2018 -4.1 -4.2 -4.3 -4.4 -14.5 -15.1 -21.8 -23.0 -24.3 -25.6
Budget2018_Step1and2 -4.1 -4.2 -4.3 -4.4 -14.5 -15.1 -15.8 -16.4 -17.1 -17.7
ALP2018 -6.8 -7.0 -7.2 -7.3 -20.8 -21.4 -22.1 -22.8 -23.5 -24.2

Costings 2018-19 to 2027-28 (Grattan default forecasts)

id 2018-19 2019-20 2020-21 2021-22 2022-23 2023-24 2024-25 2025-26 2026-27 2027-28
Budget2018_baseline 0.0 -0.1 -0.1 -0.2 -0.2 -0.3 -0.3 -0.3 -0.4 -0.4
Baseline_brackets_cpi -1.7 -3.5 -5.6 -7.9 -10.2 -12.7 -15.2 -17.9 -20.7 -23.6
Budget2018_just_rates -0.4 -0.5 -0.5 -0.6 -13.7 -14.3 -20.0 -20.9 -21.9 -22.8
Budget2018_lamington_et_LITO -3.7 -3.9 -4.0 -4.1 -0.7 -0.8 -0.8 -0.9 -0.9 -1.0
Budget2018 -4.1 -4.2 -4.4 -4.5 -14.3 -14.8 -20.6 -21.5 -22.4 -23.3
Budget2018_Step1and2 -4.1 -4.2 -4.4 -4.5 -14.3 -14.8 -15.4 -15.9 -16.5 -17.1
ALP2018 -6.8 -7.1 -7.3 -7.5 -20.7 -21.4 -22.1 -22.8 -23.5 -24.2

80% wage optimistic

id 2018-19 2019-20 2020-21 2021-22 2022-23 2023-24 2024-25 2025-26 2026-27 2027-28
Budget2018_baseline 0.0 -0.1 -0.1 -0.2 -0.2 -0.2 -0.3 -0.3 -0.4 -0.4
Baseline_brackets_cpi -1.7 -3.5 -5.7 -8.0 -10.4 -13.0 -15.7 -18.5 -21.5 -24.7
Budget2018_just_rates -0.4 -0.5 -0.5 -0.6 -14.0 -14.7 -21.0 -22.2 -23.4 -24.7
Budget2018_lamington_et_LITO -3.7 -3.9 -4.0 -4.1 -0.7 -0.8 -0.8 -0.8 -0.9 -0.9
Budget2018 -4.1 -4.2 -4.4 -4.5 -14.5 -15.2 -21.6 -22.7 -23.9 -25.2
Budget2018_Step1and2 -4.1 -4.2 -4.4 -4.5 -14.5 -15.2 -15.9 -16.6 -17.3 -18.0
ALP2018 -6.8 -7.1 -7.3 -7.5 -21.0 -21.8 -22.6 -23.4 -24.2 -25.0

20% wage pessimistic

id 2018-19 2019-20 2020-21 2021-22 2022-23 2023-24 2024-25 2025-26 2026-27 2027-28
Budget2018_baseline 0.0 -0.1 -0.1 -0.2 -0.2 -0.3 -0.3 -0.4 -0.4 -0.5
Baseline_brackets_cpi -1.7 -3.5 -5.6 -7.8 -10.1 -12.4 -14.8 -17.3 -19.9 -22.5
Budget2018_just_rates -0.4 -0.5 -0.5 -0.6 -13.4 -13.9 -19.1 -19.7 -20.3 -20.8
Budget2018_lamington_et_LITO -3.7 -3.9 -4.0 -4.1 -0.7 -0.8 -0.9 -0.9 -1.0 -1.0
Budget2018 -4.1 -4.2 -4.4 -4.5 -14.0 -14.4 -19.6 -20.2 -20.8 -21.4
Budget2018_Step1and2 -4.1 -4.2 -4.4 -4.5 -14.0 -14.4 -14.9 -15.3 -15.7 -16.1
ALP2018 -6.8 -7.1 -7.3 -7.5 -20.4 -21.0 -21.6 -22.1 -22.7 -23.2

minIncome_by_decile <- 
  s1718[, .(minIncome = min(Taxable_Income)), keyby = .(Decile = ntile(Taxable_Income, 10))] %>%
  .[, minIncome := as.integer(round(minIncome, -3))] %>%
  .[]
avg_tax_rates_by_percentile_facet_fy <-
{
  rbindlist(
    list(
      "Budget2018" = {
        bound_models %>%
          .[.(unique_fy_year, "Budget2018"),
            .(avg_tax_rate = mean(coalesce(new_tax / Taxable_Income, 0)),
              avg_tax_bill = mean(new_tax),
              total_tax = sum(new_tax * WEIGHT / 1e9),
              min_income = min(Taxable_Income),
              max_income = max(Taxable_Income),
              avg_income = mean(Taxable_Income + 0)),
            keyby = .(fy_year, Taxable_Income_percentile)] %>%
          .[, facet := "Budget 2018"]
      },
      "Grattan 20%" = {
        bound_models_Grattan20 %>%
          .[.(unique_fy_year, "Budget2018"),
            .(avg_tax_rate = mean(coalesce(new_tax / Taxable_Income, 0)),
              avg_tax_bill = mean(new_tax),
              total_tax = sum(new_tax * WEIGHT / 1e9),
              min_income = min(Taxable_Income),
              max_income = max(Taxable_Income),
              avg_income = mean(Taxable_Income + 0)),
            keyby = .(fy_year, Taxable_Income_percentile)] %>%
          .[, facet := "Budget 2018 (20% wage forecast)"]
      },
      "Grattan 80%" = {
        bound_models_Grattan80 %>%
          .[.(unique_fy_year, "Budget2018"),
            .(avg_tax_rate = mean(coalesce(new_tax / Taxable_Income, 0)),
              avg_tax_bill = mean(new_tax),
              total_tax = sum(new_tax * WEIGHT / 1e9),
              min_income = min(Taxable_Income),
              max_income = max(Taxable_Income),
              avg_income = mean(Taxable_Income + 0)),
            keyby = .(fy_year, Taxable_Income_percentile)] %>%
          .[, facet := "Budget 2018 (80% wage forecast)"]
      },
      
      "Baseline" = {
        bound_models[.(unique_fy_year, "Budget2018_baseline"),
          .(avg_tax_rate = mean(coalesce(new_tax / Taxable_Income, 0)),
            avg_tax_bill = mean(new_tax),
            total_tax = sum(new_tax * WEIGHT / 1e9),
            min_income = min(Taxable_Income),
            max_income = max(Taxable_Income),
            avg_income = mean(Taxable_Income + 0)),
          keyby = .(fy_year, Taxable_Income_percentile)] %>%
          .[, facet := "Baseline"] %>%
          .[]
      },
      "Current" = {
        s1718[,
              .(avg_tax_rate = mean(coalesce(new_tax / Taxable_Income, 0)),
                avg_tax_bill = mean(new_tax),
                min_income = min(Taxable_Income),
                max_income = max(Taxable_Income),
                total_tax = sum(new_tax * WEIGHT / 1e9),
                avg_income = mean(Taxable_Income + 0)), 
              keyby = .(Taxable_Income_percentile)] %>%
          .[, facet := "2017-18"] %>%
          .[, fy_year :=  "2017-18"]
      }),
      use.names = TRUE, fill = TRUE, 
    idcol = "id")
  } %>% 
  .[, "Financial year ending" := fy2yr(fy_year)] %>%
  setkey(fy_year, id, Taxable_Income_percentile) %>%
  .[, avg_tax_rate := round(avg_tax_rate, 3)] %>%
  .[, total_tax := round(total_tax, 3)] %>%
  setnames("total_tax", "total_tax_bn") %T>%
  fwrite(file = "avg_tax_rates-by-facet-percentile.csv") %>%
  .[]

New Grattan Institute analysis highlights that most of the revenue reductions from the Turnbull Government’s full Personal Income Tax Plan are the result of lower taxes on high-income earners. Once the three-stage plan – including removing the 37c bracket – is complete, $16.4~billion of the annual $25.6~billion cost of the plan will result from collecting less tax from the top 20% of income earners, who currently have a taxable income of $68,000 or more.

The PIT plan will do little to unwind bracket creep’s gradual reduction of the progressivity of the tax system. Even with the PIT plan, average tax rates are forecast to be higher for all taxpayers in 2027-28 – except for very high-income earners who are effectively shielded from bracket creep by the plan. A taxpayer who earns $117,000 today (more than 90% of other taxpayers) will pay an average tax rate of NA per cent in 2027-28, unchanged from today. In contrast, average tax rates for middle-income earners will continue to rise. The average tax rate for a taxpayer who earns $27,000-a-year today (more than 30% of other taxpayers) will increase 6 percentage points (from NA per cent to NA per cent ). As a result, the highest-income taxpayers will bear a lower share of the total tax burden.

Costing and distributional analysis of PIT plan

The 2018-19 budget shows the annual cost of the PIT Plan until 2022. The Treasurer has indicated the ten-year cost of the plan is $140 billion. Grattan’s analysis shows the annual costs of the plan until 2028. The Grattan costing takes into account all elements of the PIT plan.

Most of the revenue reductions until 2021-22 are a result of the Low and Middle Income Tax Offset (“the Lamington”). But once the plan is fully implemented in 2024-25, there are much bigger revenue reductions because the top of the 32.5 cent bracket increases first to $120,000 and then to $200,000 (removing the 37c bracket). In 2028, these bracket changes account for \(-\)$25.2~billion of the \(-\)$25.6~billion in lower revenue.

Once fully implemented, most of the reduction in revenue under the PIT is retained by the top 20% of income earners, with a taxable income of $87,000 or more. In 2028, the reduction in tax collected from this group will account for $15 billion of the $25 billion cost of the plan.

# Quintile and financial year to tax cut
Qfy2Cut <- function(Quintile, fy) {
  q <- factor(as.integer(Quintile), levels = 1:5)
  stopifnot(haskey(avg_individual_impact_by_Quintile_fy), 
            identical(key(avg_individual_impact_by_Quintile_fy), 
                      c("id", "fy_year", "Quintile")), 
            length(fy) == 1L, 
            length(q) == 1L)
  ans <- -1*avg_individual_impact_by_Quintile_fy[.("Budget2018", fy, q), avg_delta]
  grattan_dollar(round(ans, -2))
}

By 2024-25, the income tax cuts are much larger for high-income earners, both in absolute terms and as a proportion of income. Those in the top 20 per cent will get an average tax cut of $5,000 a year, compared to $500 a year for someone in the second income quintile ($9,000 - $19,000).

Impact of the PIT plan on tax system progressivity

Australia’s progressive tax system ensures that people with higher incomes pay higher average rates of personal income tax. Without changes to tax scales, bracket creep gradually increases average tax rates for all taxpayers. Middle-income earners are affected most in terms of higher average tax rates.

The government claims the PIT plan protects middle-income Australians from bracket creep. Certainly the plan reduces average tax rates in 2027-28 for all taxpayers compared to what they would be if there were no changes to rates or brackets over that period.

avgTaxRate50 <- function(idd, fy) {
  stopifnot(identical(key(avg_tax_rates_by_percentile_facet_fy), 
                      c("fy_year", "id", "Taxable_Income_percentile")),
            length(idd) == 1L,
            length(fy) == 1L, 
            "avg_tax_rate" %in% names(avg_tax_rates_by_percentile_facet_fy))
  avg_tax_rates_by_percentile_facet_fy[.(fy, idd, 50L), avg_tax_rate]
}

But middle-income earners are not spared from bracket creep under the PIT plan. The average tax rate for a taxpayer at the 50th percentile will still increase by 3 percentage points (from 14.6% to 18.0% ) compared to 2017-18. Without further changes, average tax rates will be higher for most taxpayers.

The exception is the top 10% of income earners. Average tax rates for those on the highest incomes are virtually unchanged under this plan.

Once fully implemented, the PIT plan doesn’t change the progressivity of the tax system much. Overall, those on high incomes will pay a similar proportion of total tax revenues with or without the plan. But because of bracket creep, high income earners will be paying a lower proportion than today.

Table 1: Share of personal income tax paid falls for highest income earners under PIT plan

Share of total personal income tax paid by income decile (%)

ShareTaxPaid_by_Decile_id <- 
  list("2017-18" = select_grep(s1718, "^(new_)?tax$", .and = "Taxable_Income"),
       "2027-28 baseline" = bound_models[.("2027-28", "Budget2018_baseline"), .(Taxable_Income, tax = new_tax)],
       "2027-28 budget" = bound_models[.("2027-28", "Budget2018_baseline"), .(Taxable_Income, tax = new_tax)]
  ) %>%
  rbindlist(use.names = TRUE,
            fill = TRUE,
            idcol = "id") %>%
  .[, Decile := ntile(Taxable_Income, 10), keyby = "id"] %>%
  .[, .(tot = sum(tax)), keyby = .(id, Decile)] %>%
  .[, share := tot / sum(tot), keyby = "id"]

ShareTaxPaid_by_Percentile_id <- 
  list("2017-18" = select_grep(s1718, "^(new_)?tax$", .and = "Taxable_Income"),
       "2027-28 baseline" = bound_models[.("2027-28", "Budget2018_baseline"), .(Taxable_Income, tax = new_tax)],
       "2027-28 budget" = bound_models[.("2027-28", "Budget2018_baseline"), .(Taxable_Income, tax = new_tax)]
  ) %>%
  rbindlist(use.names = TRUE,
            fill = TRUE,
            idcol = "id") %>%
  .[, Percentile := ntile(Taxable_Income, 100), keyby = "id"] %>%
  .[, .(tot = sum(tax)), keyby = .(id, Percentile)] %>%
  .[, share := tot / sum(tot), keyby = "id"]

rbindlist(
  list(ShareTaxPaid_by_Decile_id %>%
         .[Decile != 10L] %>%
         dcast(Decile ~ id, value.var = "share") %>%
         .[, Decile := as.character(Decile)], 
       ShareTaxPaid_by_Percentile_id %>%
         .[Percentile > 90L] %>%
         .[, .(share = sum(share)), 
           by = .(id, Decile = 10L * (Percentile %/% 10L))] %>%
         dcast(Decile ~ id, value.var = "share")),
  use.names = TRUE,
  fill = TRUE) %>%
  .[Decile %enotin% as.character(1:9), Decile := if_else(Decile == 100, "1%", "91-99 perc.")] %>%
  .[, lapply(.SD, round, 3), by = "Decile"] %T>%
  fwrite("share-of-tot-income-tax-by-decile-top1pc-budget-wage-growth.csv") %>%
  kable(align = "rrrr")
Decile 2017-18 2027-28 baseline 2027-28 budget
1 0.000 0.000 0.000
2 0.000 0.000 0.000
3 0.004 0.007 0.007
4 0.016 0.022 0.022
5 0.034 0.044 0.044
6 0.058 0.064 0.064
7 0.086 0.088 0.088
8 0.121 0.124 0.124
9 0.179 0.182 0.182
91-99 perc. 0.329 0.319 0.319
1% 0.173 0.149 0.149
ShareTaxPaid_by_Decile_id <- 
  list("2017-18" = s1718[, .(Taxable_Income, tax)],
       "2027-28 baseline" = bound_models_Grattan2.75[.("2027-28", "Budget2018_baseline"), .(Taxable_Income, tax = new_tax)],
       "2027-28 budget" = bound_models_Grattan2.75[.("2027-28", "Budget2018"), .(Taxable_Income, tax = new_tax)]
  ) %>%
  rbindlist(use.names = TRUE,
            fill = TRUE,
            idcol = "id") %>%
  .[, Decile := ntile(Taxable_Income, 10), keyby = "id"] %>%
  .[, .(tot = sum(tax)), keyby = .(id, Decile)] %>%
  .[, share := tot / sum(tot), keyby = "id"]

ShareTaxPaid_by_Percentile_id <- 
  list("2017-18" = s1718[, .(Taxable_Income, tax)],
       "2027-28 baseline" = bound_models_Grattan2.75[.("2027-28", "Budget2018_baseline"), .(Taxable_Income, tax = new_tax)],
       "2027-28 budget" = bound_models_Grattan2.75[.("2027-28", "Budget2018"), .(Taxable_Income, tax = new_tax)]
  ) %>%
  rbindlist(use.names = TRUE,
            fill = TRUE,
            idcol = "id") %>%
  .[, Percentile := ntile(Taxable_Income, 100), keyby = "id"] %>%
  .[, .(tot = sum(tax)), keyby = .(id, Percentile)] %>%
  .[, share := tot / sum(tot), keyby = "id"]

rbindlist(
  list(ShareTaxPaid_by_Decile_id %>%
         .[Decile != 10L] %>%
         dcast(Decile ~ id, value.var = "share") %>%
         .[, Decile := as.character(Decile)], 
       ShareTaxPaid_by_Percentile_id %>%
         .[Percentile > 90L] %>%
         .[, .(share = sum(share)), 
           by = .(id, Decile = 10L * (Percentile %/% 10L))] %>%
         dcast(Decile ~ id, value.var = "share")),
  use.names = TRUE,
  fill = TRUE) %>%
  .[Decile %enotin% as.character(1:9), Decile := if_else(Decile == 100, "1%", "91-99 perc.")] %>%
  .[, lapply(.SD, round, 3), by = "Decile"] %T>%
  fwrite("share-of-tot-income-tax-by-decile-top1pc-2-75-wage-growth.csv") %>%
  kable(align = "rrrr")
Decile 2017-18 2027-28 baseline 2027-28 budget
1 0.000 0.000 0.000
2 0.000 0.000 0.000
3 0.004 0.006 0.006
4 0.016 0.021 0.020
5 0.034 0.042 0.040
6 0.058 0.063 0.063
7 0.086 0.088 0.089
8 0.121 0.123 0.124
9 0.179 0.182 0.180
91-99 perc. 0.329 0.321 0.315
1% 0.173 0.154 0.162
Decile Baseline_2027-28 Budget2018_2027-28 Current_2017-18 Grattan 20%_2027-28 Grattan 80%_2027-28
1 0.0% 0.0% 0.0% 0.0% 0.0%
2 0.0% 0.0% 0.0% 0.0% 0.0%
3 0.7% 0.7% 0.4% 0.4% 0.6%
4 2.2% 2.1% 1.6% 1.8% 2.0%
5 4.4% 4.2% 3.4% 3.5% 4.0%
6 6.4% 6.4% 5.8% 5.9% 6.3%
7 8.8% 9.0% 8.6% 8.7% 8.9%
8 12.4% 12.5% 12.1% 12.3% 12.4%
9 18.2% 18.0% 17.9% 18.0% 18.0%
10 46.8% 47.1% 50.2% 49.3% 47.7%
sample_files_all %>%
  .[, .(avg_tax_rate = mean(avg_tax_rate)),
    keyby = .(fy.year, Taxable_Income_percentile)] %>%
  setnames("fy.year", "fy_year") %>%
  rbind(avg_tax_rates_by_percentile_facet_fy[CJ(unique(fy_year),
                                               c("Baseline", "Budget2018", "Current")),
                                             .SD, 
                                             .SDcols = c("id", names(.)),
                                             nomatch=0L],
        use.names = TRUE,
        fill = TRUE) %>%
  setkey(fy_year, Taxable_Income_percentile) %>%
  .[, z := fy_year %ein% "2017-18"] %>%
  .[, avg_tax_rate_rel := avg_tax_rate - median(avg_tax_rate[z]),
    keyby = .(Taxable_Income_percentile)] %>%
  .[, is_max_hist := and(fy_year < "2017-18",
                         avg_tax_rate_rel == max(avg_tax_rate_rel[fy_year < "2017-18"]))] %>%
  .[, is_min_hist := and(fy_year < "2017-18",
                         avg_tax_rate_rel == min(avg_tax_rate_rel[fy_year < "2017-18"]))] %T>%
  .[, stopifnot(Taxable_Income_percentile[is_max_hist] < 30L,
                fy_year[is_max_hist] == "2004-05",
                avg_tax_rate_rel[is_max_hist] %between% c(0.06, 0.07),
                
                Taxable_Income_percentile[is_min_hist] %between% c(45, 55),
                avg_tax_rate_rel[is_min_hist] %between% c(-0.05, -0.04),
                fy_year[is_min_hist] == "2009-10")] %>%

  .[, colour := if_else(is.na(id),
                        grey(0.5), 
                        if_else(id == "Baseline" & fy_year %in% c("2018-19", "2027-28"), 
                                if_else(fy_year == "2018-19", 
                                        gpal(6)[4],
                                        gpal(6)[5]),
                                if_else(fy_year == "2018-19", 
                                        gpal(6)[1],
                                        gpal(6)[2])))] %>%
  .[, alpha := if_else(is.na(id), 1.05 * scale01(fy2yr(fy_year)), 1)] %>%
  .[fy_year %in% c("2004-05", "2009-10"), c("alpha", "colour") := list(0.8, "black")] %>%
  .[implies(!is.na(id), fy_year %in% c("2018-19", "2027-28"))] %>%
  .[, size := 0.8] %>%
  .[fy_year %in% c("2004-05", "2009-10"), size := 1.1] %>%
  .[fy_year %in% c("2018-19", "2027-28"), size := 1.4] %>%
  .[Taxable_Income_percentile == 50L & !is.na(id),
    label := paste0(id, "\n", as.character(fy_year))] %>% 
  # .[Taxable_Income_percentile == 95L & !is.na(id), label := ""] %>%
  .[] %>%
  .[, group := paste0(fy_year, colour)] %>%
  .[, text := paste0(fy_year, " ", coalesce(id, ""), "\n",
                     formatC("Percentile: ", width = 24), Taxable_Income_percentile, "\n",
                     formatC("Avg. tax rate (17-18 = 0):", width = 24),
                     " ",
                     100 * round(avg_tax_rate_rel, 4))] %>%
  .[] %>%
  setnames("Taxable_Income_percentile", 
           "Taxable income percentile") %T>%
  fwrite("Average-tax-rates-relative-201718-vs-Taxable-income-percentile-by-FY.csv") %>%
  as.data.frame %>%
  # .[Over65==FALSE] %>%
  grplot(aes(x = `Taxable income percentile`,
             y = avg_tax_rate_rel,
             colour = colour,
             group = group)) +
  annotate("label",
           x = 20,
           y = 0.07, 
           hjust = 1,
           label.size = NA,
           label = "2004-05",
           fontface = "bold") +
  annotate("label",
           x = 45,
           y = -0.04,
           hjust = 1,
           label.size = NA,
           label = "2009-10",
           fontface = "bold") +
  scale_color_identity() +
  scale_size_identity() +
  scale_alpha_identity() +
  geom_line(aes(alpha = alpha, size = size)) +
  # geom_blank(aes(x = 105, y = 0)) +
  geom_label_repel(aes(label = label),
                   nudge_x = 2, force = 0.8,
                   na.rm = TRUE,
                   fontface = "bold",
                   label.size = NA) +
  scale_y_continuous(labels = percent) +
  ggtitle("Average tax rates relative to 2017-18") +
  theme(legend.position = "right")
#> Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing
#> scale.

sample_files_all %>%
  .[, .(avg_tax_rate = mean(avg_tax_rate)), keyby = .(fy.year, Taxable_Income_percentile)] %>%
  setnames("fy.year", "fy_year") %>%
  rbind(avg_tax_rates_by_percentile_facet_fy[, .SD, .SDcols = c("id", names(.))],
        use.names = TRUE,
        fill = TRUE) %>%
  setkey(fy_year, Taxable_Income_percentile) %>%
  .[, avg_tax_rate_rel := avg_tax_rate - first(avg_tax_rate),
    keyby = .(Taxable_Income_percentile)] %>%
  .[, colour := if_else(is.na(id),
                        grey(0.5), 
                        if_else(id == "Baseline" & fy_year %in% c("2018-19", "2027-28"), 
                                if_else(fy_year == "2018-19", 
                                        gpal(6)[4],
                                        gpal(6)[5]),
                                if_else(fy_year == "2018-19", 
                                        gpal(6)[1],
                                        gpal(6)[2])))] %>%
  .[, alpha := if_else(is.na(id), 1.05 * scale01(fy2yr(fy_year)), 1)] %>%
  # .[fy_year %in% c("2013-14"), c("alpha", "colour") := list(0.8, "black")] %>%
  .[implies(!is.na(id), fy_year %in% c("2017-18", "2018-19", "2027-28"))] %>%
  .[, size := 0.8] %>%
  .[fy_year %in% c("2004-05", "2013-14"), size := 1.1] %>%
  .[fy_year %in% c("2018-19", "2027-28"), size := 1.4] %>%
  .[Taxable_Income_percentile == 50L & !is.na(id), label := paste0(id, "\n", as.character(fy_year))] %>% 
  # .[Taxable_Income_percentile == 95L & !is.na(id), label := ""] %>%
  .[] %>%
  .[, group := paste0(fy_year, colour)] %>%
  .[, text := paste0(fy_year, " ", coalesce(id, ""), "\n",
                     formatC("Percentile: ", width = 24), Taxable_Income_percentile, "\n",
                     formatC("Avg. tax rate (03-04 = 0):", width = 24), " ", 100 * round(avg_tax_rate_rel, 4))] %>%
  .[] %>%
  setnames("Taxable_Income_percentile", 
           "Taxable income percentile") %T>%
  fwrite("Average-tax-rates-relative-200304-vs-Taxable-income-percentile-by-FY.csv") %>%
  as.data.frame %>%
  # .[Over65==FALSE] %>%
  grplot(aes(x = `Taxable income percentile`,
             y = avg_tax_rate_rel,
             colour = colour,
             group = group,
             text = text)) +
  scale_color_identity() +
  scale_size_identity() +
  scale_alpha_identity() +
  geom_line(aes(alpha = 1, size = size)) +
  # geom_blank(aes(x = 105, y = 0)) +
  geom_label_repel(aes(label = label),
                   nudge_x = 2, force = 0.8,
                   na.rm = TRUE,
                   fontface = "bold",
                   label.size = NA) +
  scale_y_continuous(labels = percent) +
  ggtitle("Average tax rates relative to 2003-04") +
  theme(legend.position = "right") + 
  facet_wrap(~fy_year)
#> Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing
#> scale.

bound_models %>%
  .[.(unique_fy_year, "Budget2018"),  
    .(total_delta_bn = sum((new_tax - baseline_tax) * WEIGHT / 1e9), 
      max_income = max(Taxable_Income),
      min_income = min(Taxable_Income), 
      avg_income = mean(Taxable_Income)), 
    keyby = c("fy_year", "Quintile")] %>%
  .[, "Financial year ending" := fy2yr(.BY[[1]]), keyby = c("fy_year", "Quintile")] %>%
  .[, total_delta_bn := round(total_delta_bn, 2), keyby = c("fy_year", "Quintile")] %>%
  .[, avg_income := round(avg_income, 2), keyby = c("fy_year", "Quintile")] %>%
  setorder(fy_year, -Quintile) %>%
  fwrite("budget2018-total-revenue-vs-fy-by-quintile.csv")
print(revenue_foregone(bound_models[.("2018-19", "Baseline_brackets_cpi")]))
#> [1] "-\\$1.7 billion"
Decile Min income Tax paid ($bn) % paid
1 $0 0.0000000 0.0000000
4 $0 0.0000000 0.0000000
5 $10,000 0.0365077 0.0001314
6 $23,000 3.3556299 0.0120803
7 $37,000 9.7351830 0.0350467
8 $50,000 24.1862939 0.0870708
9 $68,000 47.0294443 0.1693062
10 $98,000 193.4344154 0.6963647
Decile Min income Tax paid ($bn) % paid
1 $0 0 0.0000000
4 $0 0 0.0000000
5 $10,000 544637 0.0000984
6 $23,000 52978483 0.0095763
7 $37,000 152241265 0.0275189
8 $50,000 409203403 0.0739670
9 $68,000 845431511 0.1528190
10 $98,000 4071840609 0.7360203

Growth assumptions:

  • Number of taxpayers:
    • Deloitte: 1.46%
    • Budget: 1.92%
  • Number of adults:
    • Deloitte: 1.98%
    • Grattan: 1.45%
s2425_Deloitte_LF_growth <- 
  project(sample_file_1516, h = 9L) %>%
  model_income_tax(baseline_fy = "2017-18", 
                   ordinary_tax_thresholds = ordinary_tax_thresholds("2024-25"), 
                   ordinary_tax_rates = ordinary_tax_rates("2024-25"),
                   Budget2018_lito_202223 = TRUE,
                   medicare_levy_rate = 0.02,
                   medicare_levy_taper = 0.1,
                   medicare_levy_lower_threshold = 24750, # medicare_levy_lower_threshold("2024-25")
                   medicare_levy_upper_threshold = 30938,
                   medicare_levy_lower_sapto_threshold = medicare_levy_lower_sapto_threshold("2024-25"),
                   medicare_levy_upper_sapto_threshold = 48912,
                   medicare_levy_lower_family_threshold = 54930, # medicare_levy_lower_family_threshold("2024-25")
                   medicare_levy_lower_family_sapto_threshold = 54930) %>% # medicare_levy_lower_family_sapto_threshold("2024-25")) %>% # 54930
  # Ensure number of taxpayers = 11.6 million
  .[new_tax >= 1, WEIGHT := 11.6e6 / sum(new_tax > 0)] %>%
  
  # Ensure total population is 22.37 million
  .[, WEIGHT := WEIGHT * if_else(new_tax < 1,
                                 1 + (22.37e6 - 11.6e6 - sum(WEIGHT[new_tax < 1])) / sum(WEIGHT[new_tax < 1]),
                                 1)]

stopifnot(s2425_Deloitte_LF_growth[new_tax > 1, sum(WEIGHT)] %between% c(11.5e6, 11.7e6))
stopifnot(s2425_Deloitte_LF_growth[, sum(WEIGHT)] %between% c(22.2e6, 22.4e6))

s2425_Deloitte_LF_growth %>%
  .[, .(total_tax_paid = sum(new_tax * WEIGHT)),
    keyby = .(Quintile = weighted_ntile(Taxable_Income, weights = WEIGHT, n = 5))] %>%
  .[, p := total_tax_paid / sum(total_tax_paid)] %>%
  .[]
#>    Quintile total_tax_paid          p
#> 1:        1              0 0.00000000
#> 2:        2              0 0.00000000
#> 3:        3     5804519578 0.02387246
#> 4:        4    44781188089 0.18417323
#> 5:        5   192561397000 0.79195431

JD ‘How not to sell a tax cut’

Of course, a tax cut of $14 billion a year is a tricky sell when it benefits less than 2 in 10 of income earners in 2027-28. But the government has made its own life harder by using misleading statistics and not providing the numbers that could support its best argument.

Another tricky claim is that without change those earning over $180,000 will go from paying 31.1 per cent to 41.3 per cent of income tax. But this is sleight of hand: twice as many people could be expected to be earning this income – so of course they will collectively pay a greater share of income tax.

The government’s best and most honest argument is that the tax package as a whole won’t materially change the progressivity of the income tax system. Without change, the top 20% of income earners – who earn 50.7 per cent per cent of taxable income – will pay 65.148 per cent of income tax. And under the package they will pay 65.1482 per cent.

Applying timings

We can apply timing issues: 85% revenue is tax revenue and 15% at the time of assessment for those under $180,000; 75% and 25% at time of assessment.

devtools::session_info()
#> - Session info ---------------------------------------------------------------------------------------------
#>  setting  value                       
#>  version  R version 3.6.1 (2019-07-05)
#>  os       Windows 10 x64              
#>  system   x86_64, mingw32             
#>  ui       RTerm                       
#>  language (EN)                        
#>  collate  English_Australia.1252      
#>  ctype    English_Australia.1252      
#>  tz       Australia/Sydney            
#>  date     2019-11-15                  
#> 
#> - Packages -------------------------------------------------------------------------------------------------
#>  package        * version    date       lib source        
#>  anytime          0.3.5      2019-07-28 [2] CRAN (R 3.6.0)
#>  assertthat       0.2.1      2019-03-21 [1] CRAN (R 3.6.0)
#>  backports        1.1.5      2019-10-02 [1] CRAN (R 3.6.1)
#>  callr            3.3.1      2019-07-18 [1] CRAN (R 3.6.1)
#>  cli              1.1.0      2019-03-19 [1] CRAN (R 3.6.0)
#>  codetools        0.2-16     2018-12-24 [1] CRAN (R 3.6.0)
#>  colorspace       1.4-1      2019-03-18 [1] CRAN (R 3.6.0)
#>  commonmark       1.7        2018-12-01 [1] CRAN (R 3.6.0)
#>  crayon           1.3.4      2017-09-16 [1] CRAN (R 3.6.0)
#>  curl             4.2        2019-09-24 [1] CRAN (R 3.6.1)
#>  data.table     * 1.12.6     2019-10-18 [1] CRAN (R 3.6.1)
#>  desc             1.2.0      2018-05-01 [1] CRAN (R 3.6.0)
#>  devtools         2.1.0      2019-07-06 [1] CRAN (R 3.6.0)
#>  digest           0.6.21     2019-09-20 [1] CRAN (R 3.6.1)
#>  dplyr            0.8.3      2019-07-04 [1] CRAN (R 3.6.0)
#>  evaluate         0.14       2019-05-28 [1] CRAN (R 3.6.1)
#>  fastmatch      * 1.1-0      2017-01-28 [1] CRAN (R 3.6.0)
#>  forecast         8.8        2019-08-02 [1] CRAN (R 3.6.0)
#>  fracdiff         1.4-2      2012-12-02 [1] CRAN (R 3.6.0)
#>  fs               1.3.1      2019-05-06 [1] CRAN (R 3.6.0)
#>  fst            * 0.9.0      2019-04-09 [2] CRAN (R 3.6.0)
#>  fy               0.2.0      2019-10-21 [1] local         
#>  generics         0.0.2      2018-11-29 [1] CRAN (R 3.6.0)
#>  ggplot2        * 3.2.1      2019-08-10 [1] CRAN (R 3.6.1)
#>  ggrepel        * 0.8.1      2019-05-07 [2] CRAN (R 3.6.0)
#>  glue             1.3.1      2019-03-12 [1] CRAN (R 3.6.0)
#>  grattan        * 1.8.0.0    2019-11-14 [1] local         
#>  grattanCharts  * 0.11.0     2019-02-08 [2] local         
#>  gridExtra        2.3        2017-09-09 [2] CRAN (R 3.5.1)
#>  gtable           0.3.0      2019-03-25 [1] CRAN (R 3.6.0)
#>  highr            0.8        2019-03-20 [1] CRAN (R 3.6.1)
#>  htmltools        0.3.6      2017-04-28 [2] CRAN (R 3.5.1)
#>  hutils         * 1.5.1      2019-10-05 [1] CRAN (R 3.6.1)
#>  ineq             0.2-13     2014-07-21 [1] CRAN (R 3.6.0)
#>  knitr          * 1.25       2019-09-18 [1] CRAN (R 3.6.1)
#>  labeling         0.3        2014-08-23 [2] CRAN (R 3.5.0)
#>  lattice          0.20-38    2018-11-04 [1] CRAN (R 3.6.0)
#>  lazyeval         0.2.2      2019-03-15 [1] CRAN (R 3.6.0)
#>  lifecycle        0.1.0      2019-08-01 [1] CRAN (R 3.6.1)
#>  lmtest           0.9-37     2019-04-30 [1] CRAN (R 3.6.0)
#>  lubridate        1.7.4      2018-04-11 [1] CRAN (R 3.6.0)
#>  magrittr       * 1.5        2014-11-22 [1] CRAN (R 3.6.0)
#>  MASS             7.3-51.4   2019-03-31 [1] CRAN (R 3.6.0)
#>  memoise          1.1.0      2017-04-21 [1] CRAN (R 3.6.0)
#>  munsell          0.5.0      2018-06-12 [1] CRAN (R 3.6.0)
#>  nlme             3.1-141    2019-08-01 [1] CRAN (R 3.6.0)
#>  nnet             7.3-12     2016-02-02 [1] CRAN (R 3.6.0)
#>  numDeriv         2016.8-1.1 2019-06-06 [1] CRAN (R 3.6.0)
#>  pillar           1.4.2      2019-06-29 [1] CRAN (R 3.6.0)
#>  pkgbuild         1.0.4      2019-08-05 [1] CRAN (R 3.6.1)
#>  pkgconfig        2.0.3      2019-09-22 [1] CRAN (R 3.6.1)
#>  pkgdown          1.3.0      2018-12-07 [2] CRAN (R 3.5.1)
#>  pkgload          1.0.2      2018-10-29 [1] CRAN (R 3.6.0)
#>  prettyunits      1.0.2      2015-07-13 [1] CRAN (R 3.6.0)
#>  processx         3.4.1      2019-07-18 [1] CRAN (R 3.6.1)
#>  ps               1.3.0      2018-12-21 [1] CRAN (R 3.6.0)
#>  purrr            0.3.2      2019-03-15 [1] CRAN (R 3.6.0)
#>  quadprog         1.5-7      2019-05-06 [1] CRAN (R 3.6.0)
#>  quantmod         0.4-15     2019-06-17 [1] CRAN (R 3.6.0)
#>  R6               2.4.0      2019-02-14 [1] CRAN (R 3.6.0)
#>  Rcpp             1.0.2      2019-07-25 [1] CRAN (R 3.6.0)
#>  remotes          2.1.0      2019-06-24 [1] CRAN (R 3.6.0)
#>  rlang            0.4.1      2019-10-24 [1] CRAN (R 3.6.0)
#>  rmarkdown        1.11       2018-12-08 [2] CRAN (R 3.5.2)
#>  roxygen2         6.1.1      2018-11-07 [1] CRAN (R 3.6.0)
#>  rprojroot        1.3-2      2018-01-03 [1] CRAN (R 3.6.0)
#>  rstudioapi       0.10       2019-03-19 [1] CRAN (R 3.6.0)
#>  SampleFile1415   1.0        2018-07-06 [2] local         
#>  scales         * 1.0.0      2018-08-09 [1] CRAN (R 3.6.0)
#>  sessioninfo      1.1.1      2018-11-05 [1] CRAN (R 3.6.0)
#>  stringi          1.4.3      2019-03-12 [1] CRAN (R 3.6.0)
#>  stringr          1.4.0      2019-02-10 [1] CRAN (R 3.6.0)
#>  sysfonts         0.8        2018-10-11 [2] CRAN (R 3.5.1)
#>  taxstats       * 0.1.0.1415 2019-05-01 [1] local         
#>  testthat         2.2.1      2019-07-25 [1] CRAN (R 3.6.0)
#>  tibble           2.1.3      2019-06-06 [1] CRAN (R 3.6.0)
#>  tidyr            1.0.0      2019-09-11 [1] CRAN (R 3.6.1)
#>  tidyselect       0.2.5      2018-10-11 [1] CRAN (R 3.6.0)
#>  timeDate         3043.102   2018-02-21 [1] CRAN (R 3.6.0)
#>  tseries          0.10-47    2019-06-05 [1] CRAN (R 3.6.0)
#>  tsibble          0.8.3      2019-07-29 [1] CRAN (R 3.6.0)
#>  TTR              0.23-4     2018-09-20 [1] CRAN (R 3.6.0)
#>  urca             1.3-0      2016-09-06 [1] CRAN (R 3.6.0)
#>  usethis          1.5.1      2019-07-04 [1] CRAN (R 3.6.0)
#>  vctrs            0.2.0      2019-07-05 [1] CRAN (R 3.6.0)
#>  viridis        * 0.5.1      2018-03-29 [2] CRAN (R 3.5.1)
#>  viridisLite    * 0.3.0      2018-02-01 [2] CRAN (R 3.5.1)
#>  withr            2.1.2      2018-03-15 [1] CRAN (R 3.6.0)
#>  xfun             0.10       2019-10-01 [1] CRAN (R 3.6.1)
#>  xml2             1.2.1      2019-07-29 [1] CRAN (R 3.6.0)
#>  xts              0.11-2     2018-11-05 [1] CRAN (R 3.6.0)
#>  yaml             2.2.0      2018-07-25 [1] CRAN (R 3.6.0)
#>  zeallot          0.1.0      2018-01-28 [1] CRAN (R 3.6.0)
#>  zoo              1.8-6      2019-05-28 [1] CRAN (R 3.6.0)
#> 
#> [1] C:/R/R-3.6.0/library
#> [2] C:/R/R-3.5.1/library
#> [3] C:/R/R-3.6.1/library

Finished in 257.