Simple modelling of superannuation changes

Hugh Parsonage

2018-01-22

Introduction

Australia’s superannuation system offers a number of tax breaks. Relative to most methods of savings, less tax is paid on money contributed to a super fund, and less tax is paid on the earnings. The functions described here attempt to model changes to tax breaks on money contributed to a super fund.

Modelling

The basic functions

The two tax methods modelled are Superannuation contributions tax concessions and Division 293 tax. The two main outputs are: the extra tax payable by a particular individual (and the symmetric extra revenue), and the number of individuals affected.

To obtain these results (say for 2017-18)

library(grattan)
library(data.table)
if (requireNamespace("taxstats", quietly = TRUE)){
  library(taxstats)
  sample_files_all <- get_sample_files_all()
} else {
  templib <- tempfile()
  hutils::provide.dir(templib)
  install.packages("taxstats",
                   lib = templib,
                   repos = "https://hughparsonage.github.io/drat/",
                   type = "source")
  library("taxstats", lib.loc = templib)
  sample_files_all <- get_sample_files_all()
}
library(magrittr)
#' dollar scales
#' 
#' @name grattan_dollar
#' @param x A numeric vector
#' @param digits Minimum number of digits after the decimal point. (\code{nsmall} in \code{base::format}).
#' @details Makes negative numbers appear as \eqn{-\$10,000} instead of \eqn{\$-10,000} in \code{scales::dollar}.
#' @export
# from scales

grattan_dollar <- function (x, digits = 0) {
  #
  nsmall <- digits
  commaz <- format(abs(x), nsmall = nsmall, trim = TRUE, big.mark = ",", 
                   scientific = FALSE, digits = 1L)
  
  hutils::if_else(x < 0, 
          paste0("\U2212","$", commaz),
          paste0("$", commaz))
}

(new_revenue <- 
  sample_file_1314 %>%
  project_to(to_fy = "2017-18") %>%
  as.data.table %>%
  revenue_from_new_cap_and_div293(new_cap = 25e3, fy.year = "2016-17", new_age_based_cap = FALSE, new_div293_threshold = 250e3))
## [1] 1191537023
paste(grattan_dollar(new_revenue / 1e9), "bn")
## [1] "$1 bn"
(n_affected <-
  sample_file_1314 %>%
  project_to(to_fy = "2017-18") %>%
  as.data.table %>%
  n_affected_from_new_cap_and_div293(new_cap = 25e3, fy.year = "2016-17", new_age_based_cap = FALSE, new_div293_threshold = 250e3))
## [1] 554577.5
prettyNum(round(n_affected), big.mark = ",")
## [1] "554,578"

Notes:

  1. fy.year refers to the year the function takes the tax scales from, not the forecast year. Because we don’t have tax scales for 2017-18 yet, we model using the most recent (2017-18).
  2. The functions require their inputs to be data.tables. Sorry if you don’t like data.tables.
  3. You must use sample_file_1314 (because they have superannuation contributions variables).

Distributional analysis

By taxable income decile

Let’s create an object for sample_file_1718 avoid recreating it every time:

sample_file_1718 <-
  sample_file_1314 %>%
  project_to(to_fy = "2017-18") %>%
  as.data.table

The functions mentioned earlier return single values. In contrast, model_new_caps_and_div293 returns the sample file with extra variables, which can then be analyzed as a standard sample file. The variables of note are prv_revenue which is the tax payable under the old system, and new_revenue which is the tax payable under the proposed system. Thus:

new_sample_file_1718 <- 
  sample_file_1718 %>%
  model_new_caps_and_div293(new_cap = 25e3, fy.year = "2016-17", new_age_based_cap = FALSE, new_div293_threshold = 250e3)
library(knitr)
library(dplyr)
library(dtplyr)  # for data.table

new_sample_file_1718 %>%
  mutate(Taxable_Income_decile = ntile(Taxable_Income, 10)) %>%
  group_by(Taxable_Income_decile) %>%
  summarise(`Average increase in tax` = round(mean(new_revenue - prv_revenue), 2)) %>%
  arrange(Taxable_Income_decile) %>%
  kable
Taxable_Income_decile Average increase in tax
1 1.90
2 4.51
3 10.98
4 23.43
5 30.36
6 32.99
7 41.28
8 61.21
9 103.94
10 504.75
library(ggplot2)
new_sample_file_1718 %>%
  mutate(Taxable_Income_decile = ntile(Taxable_Income, 10)) %>%
  group_by(Taxable_Income_decile) %>%
  summarise(`Average increase in tax` = mean(new_revenue - prv_revenue)) %>%
  arrange(Taxable_Income_decile) %>%
  #
  mutate(`Taxable income decile` = factor(Taxable_Income_decile)) %>%
  ggplot(aes(x = `Taxable income decile`, y = `Average increase in tax`)) + 
  geom_bar(stat = "identity") + 
  
  # cosmetic:
  scale_y_continuous(label = grattan_dollar) + 
  theme(axis.title.y = element_text(face = "bold", angle = 90, margin = margin(1, 1, 1, 1, "lines")))