GithubHelp home page GithubHelp logo

miraisolutions / smarp Goto Github PK

View Code? Open in Web Editor NEW
19.0 8.0 9.0 75.56 MB

Shiny app for projecting retirement funds / benefits

Home Page: https://mirai-solutions.ch/gallery/smarp

R 89.28% TeX 1.08% CSS 5.92% Dockerfile 2.33% Shell 1.40%
r shiny pension retirement

smarp's Introduction

SmaRP: Smart Retirement Planning

Smart Retirement Planning (SmaRP) is a Mirai Solutions initiative designed to guide people working in Switzerland towards a strategic decision-making process for their retirement.

SmaRP is based on the Swiss pension system and reflects the complexity of its legal framework. It is implemented as an R Shiny pension calculator web app, in the form of an R package. The app features a flexible yet intuitive user interface with detailed personalization parameters and options. This allows to interactively compute and display the evolution of the retirement funds over time, split into their contributing components. A report including details regarding calculation methodology and approximations can be generated and downloaded.

Thanks to the open-source nature of the project, the underlying assumptions and calculations are fully disclosed. Unlike other pension calculators, this makes results transparent, comparable, and reproducible.

Using SmaRP

The SmaRP Shiny app is deployed to Google Cloud Platform (using Docker containers) and can be accessed at https://mirai-solutions.ch/gallery/smarp.

SmaRP is developed using a GitFlow approach, where the master branch always reflects the latest release of the live app, whereas branch develop collects the latest delivered developments for the next releases.

The R package SmaRP for the latest release can be installed from GitHub with

remotes::install_github("miraisolutions/SmaRP@master", build_opts = "")

whereas the development version can be installed via

remotes::install_github("miraisolutions/SmaRP@develop", build_opts = "")

Then, the installed package can be used to serve the app locally from R via

SmaRP::launch_application()

Note that SmaRP is deployed using version-stable images from the Rocker project. The target environment of the live app is currently bound to R 3.5.3. Therefore, the app is developed and tested with the corresponding version of R and packages, as opposed to the latest available versions. This is made easy by the containerized approach to align version-stable development and deployment environments described in our techguides.

Details and key features

The evolution of the total retirement fund over time is computed by projecting the value of the occupational fund (2nd Pillar), the private fund (3rd Pillar) and the tax relief, thus deriving their contributions at the desired retirement age.

  • Contributions to the second Pillar are calculated from the salary and any additional voluntary purchases.

  • Contributions to the third Pillar are fully voluntary and repeated every year until retirement.

  • Tax savings are built as an additional fund where tax relieves from a certain year are used as contributions for the next. Tax relieves are calculated using an approximation of the given gross salary and other factors including: residence, civil status, number on kids, etc.

Results of the calculation are available in SmaRP in 3 different ways:

  1. a graph showing the projected funds over time until retirement
  2. a table with details about projected quantities (also available for download)
  3. a downloadable PDF report including detailed explanations of the calculation methodology and inputs.

Assumptions and limitations

  • Projected funds are computed using continuously compounded returns on annual basis.
  • Constant interest rates are assumed throughout the working life.
  • Inflation is not taken into account, although it can be proxied using the salary growth rate input.
  • The retirement plan is valid for employees only, i.e. persons whose main income is a salary. Self-employed people do not belong to this category.
  • The publicly managed pay-as-you-go system (1st Pillar) is not considered.
  • All generated tax benefits are 100% reinvested as an additional fund, interpreting the same return as the private fund.
  • In case of married couples with double income, the combined amount of all variables should be entered and a 50% income distribution is assumed.

Source code

Core calculations behind this Shiny app have been implemented via several functions, collected in the main source files SmaRP/R/core.R and SmaRP/R/TaxBenefits.R.

Documentation for the relevant exported functions used in the app is also provided and can be browsed via

help(package = "SmaRP")

On a functional level, the code is covered by extensive unit tests.

The source code for the app itself is available under SmaRP/inst/application.

Data sources and references

SmaRP reflects the Swiss pension system and uses corresponding legal parameters and data. An overview of these components can be found at e.g. https://en.wikipedia.org/wiki/Pension_system_in_Switzerland. A more detailed explanation is available on the Swiss Federal Social Insurance Office website (in German).

Legal parameters in SmaRP are defined in SmaRP/inst/application/global.R, whereas data is stored under SmaRP/inst/application/data.

Accuracy

While SmaRP was developed under the utmost care and diligence, Mirai Solutions does not guarantee for its accuracy and correctness. In addition, SmaRP is based on assumptions and projections (explained in a section above and in the PDF report) and as such computed figures should be understood as general references and do not hold any legal value.

Besides standard unit tests at the functional level, results from the SmaRP web app have been checked against other online free sources for second, third Pillars and tax calculators.

To keep testing and improving SmaRP, we encourage users to get back to us! Your feedback is always highly appreciated. You can use the issue tracker on GitHub to suggest enhancements or report problems, and reach out via email at [email protected] for any questions and comments.

smarp's People

Contributors

chargothrond avatar fvitalini avatar gabifoix avatar gabrielfoix avatar lambiase avatar nfarabullini avatar riccardoporreca avatar rolandasc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

smarp's Issues

Improve Dockerfile

  • Split Dockerfile (for example, generate one image containing OS libraries + R packages installation, and another one containing the R Shiny part only)
  • Avoid installing texlive-full and only consider the texlive packages that are really needed

GoogleVis plots not re-rendered upon fast updates

I have tried to change very fast the input "Current amount" using up/down keyboard arrows, and this causes the plots not to be re-rendered, although e.g. the text "Total retirement fund" output is correctly updated.
googlevis-no-plots
The R console also does not show any particular issue.

PLZ and city/village relationship

@gabrielfoix
It would be nice to have both the postal code and the city/village displayed. However, several places might be related to the same PLZ. Do we have the data for this association available somewhere?

Missing Infobox in optional boxes

I think we should add an Infobox in the optional boxes (Desired retirement age and direct tax rate) explaining details of each option.

Clean up Code

* use coding best practices
* clean up code (comments, old versions of the taxes)
* add roxygens tags

Complete roxygen tags

Not all functions (core.R, TaxBenefit.R) have all roxygen tags.
Ad minimum, we could include a title and brief description, params, return and example for some of them.

Enhance treatment pension contributions

The contributions to pension funds (pilar 2 and 3) are deducted from the net salary, not from the gross,
NetSalary = GrossSalary - AHV - ALV - NBU
Generally speaking, the impact should not be much, but in some concrete cases for low incomes can make a difference.
Would require a small adjustment in all tax functions.

UI modular

shinyUI() is a long piece of code (+200 lines) with tones of nested functions: fluidPage(), fluidRow(), column(), etc.
Sometimes is difficult to get an overview and make changes becomes a braquets nightmare.
Talk to Riccardo for suggestions/ideas he implemented for OASIS.

Leaflet map with total tax rate per municipality

It would be nice to have a leaflet map showing the total tax rate for all the municipalities in Switzerland depending on:

  • Civil status
  • Number of kids (and their age?)
  • Double income?
  • Church affiliation
  • Age?
  • etc.

See for example:
https://blog.derbund.ch/datenblog/index.php/4117/wo-liegt-ihr-steuerparadies

The polygon information for the different municipalities can be downloaded from
https://opendata.swiss/en/dataset/swissboundaries3d-gemeindegrenzen
(see https://map.geo.admin.ch/?topic=swisstopo&lang=de&bgLayer=voidLayer&zoom=2&layers=ch.swisstopo.swissboundaries3d-gemeinde-flaeche.fill&catalogNodes=1476,1482&E=2662949.62&N=1169260.05 for a rendering of municipalities on the map of Switzerland)

The polygon data needs to be converted into a format that can be consumed by leaflet, for example geojson.
It might be useful to have a look at https://github.com/interactivethings/swiss-maps

Remove Generic case

  • Remove General case from UI
  • Remove references to Swiss vs General cases from the code
  • Remove Optional Direct Tax Rate

Not unique postalcode - gemeinde

If we want to be more accurate on small gemeinden, we could add a dropdown with the gemeinde name to distinguish cases where the same postal code applies to 2 gemeinde.
Example: 9443 (Widnau, Diepolsdau) - Taxes are quite different

Better error handling

If user types a negative number of kids, or negative retirement age, SmaRP displays a default and non informative message.
We could display useful messages or use fallback default values.

Error in Report calling webshot on plot1 if echo=FALSE

cannot use webshot on plot 1 if echo = FALSE

This is ok

webshot::webshot(plot(plot2), file = "plot2.png", delay = 5)

But

webshot::webshot(plot(plot1), file = "plot1.png", delay = 5)

crashes the latex file. And

webshot::webshot(plot(plot1), file = "plot1.png", delay = 5)

does not

UI: Right margin input boxes

The right margin of the different input boxes are not aligned.
Birthdate, Current Assets and Retirement Age box (at least) are misaligned.

Slow report generation

Generating a PDF report at the moment takes about 20 seconds.

Check whether:

  • it is possible to decrease the webshot delay
  • it is possible to use another library (for example ggplot2) for the PDF report generation only

Alternatively:

  • display a popup saying that the the report generation might take a few seconds
  • disable the "Generate report" button, such that the user cannot click on it multiple times
  • re-enable the "Generate report" button once the report has been generated

Issues with percentages

  1. In the barplot, we are displaying %, but the figures are the nominal ones.
  2. Marginal Tax Rate in the "Generic Case" is still nominal. (Header should include % for clarity)
  3. Expected salary growth rate is still nominal (Header should include % for clarity)
  4. Expected Return for the private fund is still nominal (Header should include % for clarity)

Reactive inputs when out of bounds

For example, currently, one user can type very high number in the retirement age input. SmaRP handles it on the code constraining max = 70. It would be nice r and more transparent if we could show 70 on the retirement age input when a user types a higher number.
Other fields affected: Number of Kids and Salary.

Bar plot opacity field ignored

option fill-opacity ignored in

output$plot2 <- renderGvis({ gvisBarChart( chartid = "plot2", data = BarGraphData(), xvar = "contribution", yvar= colnames(BarGraphData())[!grepl("contribution", colnames(BarGraphData()))], options = list(width = 600, height = 130, isStacked = TRUE, vAxes = "[{minValue:0}]", legend = "none", colors=miraiColors(), fill-opacity = 0.3, hAxis="{format:'#,###%'}") ) })

Legend's graphs is not dynamic

For the general case, there is no occupational pension fund, therefore, P2 should be removed from the legend. Same when, in the swiss case, there's no Private fund
In addition, the colors of both graphs should be aligned when either private or occupational funds are missing.

update README

Update that part of the Read Me related to the files structure and app structure

Retirement age constraints

If a user types in an age > 70, SmarP displays a weird message.
TODO
UI: Only integers between 55-70 should be allowed as inputs.
Core: In case the constraints on the UI are not possible, the same could be implemented when building the calendar and the different data frames.

Add return and direct variables on the graphs

Suggested by Gustavo on a tram chat:
Open the chance to see an "advanced view" of the graph with all the variables (direct P2, P3 and return P2, P3 and tax) if a tick box is selected by the user.
All the information is available on the data.frame to plot.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.