| Title: | Make Optimal Financial Decisions |
|---|---|
| Description: | Make optimal decisions for your personal or household finances. Use tools and methods that are selected carefully to align with academic consensus, bridging the gap between theoretical knowledge and practical application. They help you find your own personalized optimal discretionary spending or optimal asset allocation, and prepare you for retirement or financial independence. The optimal solution to this problems is extremely complex, and we only have a single lifetime to get it right. Fortunately, we now have the user-friendly tools implemented, that integrate life-cycle models with single-period net-worth mean-variance optimization models. Those tools can be used by anyone who wants to see what highly-personalized optimal decisions can look like. For more details see: Idzorek T., Kaplan P. (2024, ISBN:9781952927379), Haghani V., White J. (2023, ISBN:9781119747918). |
| Authors: | Kamil Wais [aut, cre, cph, fnd] (ORCID: <https://orcid.org/0000-0002-4062-055X>), Olesia Wais [aut] (ORCID: <https://orcid.org/0000-0002-8741-8674>) |
| Maintainer: | Kamil Wais <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 1.2.0.9000 |
| Built: | 2026-05-22 07:38:59 UTC |
| Source: | https://github.com/R4GoodAcademy/R4GoodPersonalFinances |
Make optimal decisions for your personal or household finances. Use tools and methods that are selected carefully to align with academic consensus, bridging the gap between theoretical knowledge and practical application. They help you find your own personalized optimal discretionary spending or optimal asset allocation, and prepare you for retirement or financial independence. The optimal solution to this problems is extremely complex, and we only have a single lifetime to get it right. Fortunately, we now have the user-friendly tools implemented, that integrate life-cycle models with single-period net-worth mean-variance optimization models. Those tools can be used by anyone who wants to see what highly-personalized optimal decisions can look like. For more details see: Idzorek T., Kaplan P. (2024, ISBN:9781952927379), Haghani V., White J. (2023, ISBN:9781119747918).
Maintainer: Kamil Wais [email protected] (ORCID) [copyright holder, funder]
Authors:
Olesia Wais [email protected] (ORCID)
Useful links:
Calculate Effective Tax Rate
calc_effective_tax_rate(portfolio, tax_rate_ltcg, tax_rate_ordinary_income)calc_effective_tax_rate(portfolio, tax_rate_ltcg, tax_rate_ordinary_income)
portfolio |
A nested |
tax_rate_ltcg |
A numeric. Tax rate for long-term capital gains. |
tax_rate_ordinary_income |
A numeric. Tax rate for ordinary income. |
A portfolio object augmented with nested columns with
effective tax rates calculations.
portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio <- calc_effective_tax_rate( portfolio, tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) portfolio$aftertax$effective_tax_rateportfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio <- calc_effective_tax_rate( portfolio, tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) portfolio$aftertax$effective_tax_rate
Calculating the Gompertz model parameters for joint survival
calc_gompertz_joint_parameters( p1 = list(age = NULL, mode = NULL, dispersion = NULL), p2 = list(age = NULL, mode = NULL, dispersion = NULL), max_age = 120 )calc_gompertz_joint_parameters( p1 = list(age = NULL, mode = NULL, dispersion = NULL), p2 = list(age = NULL, mode = NULL, dispersion = NULL), max_age = 120 )
p1 |
A list with |
p2 |
A list with |
max_age |
A numeric. The maximum age for the Gompertz model. |
A list containing:
data |
A data frame with survival rates for 'p1', 'p2', 'joint' survival, and the fitted Gompertz model |
mode |
The mode of the joint Gompertz distribution |
dispersion |
The dispersion parameter of the joint Gompertz distribution |
calc_gompertz_joint_parameters( p1 = list( age = 65, mode = 88, dispersion = 10.65 ), p2 = list( age = 60, mode = 91, dispersion = 8.88 ), max_age = 110 )calc_gompertz_joint_parameters( p1 = list( age = 65, mode = 88, dispersion = 10.65 ), p2 = list( age = 60, mode = 91, dispersion = 8.88 ), max_age = 110 )
Calculate Gompertz mode for a given life expectancy
calc_gompertz_mode(life_expectancy, current_age, dispersion, max_age = 120)calc_gompertz_mode(life_expectancy, current_age, dispersion, max_age = 120)
life_expectancy |
A numeric. Desired life expectancy. |
current_age |
A numeric. Current age. |
dispersion |
A numeric. Dispersion of the Gompertz distribution. |
max_age |
A numeric. Maximum age. Defaults to 120. |
A numeric. Mode of the Gompertz distribution.
calc_gompertz_mode( life_expectancy = 86, current_age = 25, dispersion = 8.88, max_age = 115 )calc_gompertz_mode( life_expectancy = 86, current_age = 25, dispersion = 8.88, max_age = 115 )
Calculating Gompertz model parameters
calc_gompertz_parameters( mortality_rates, current_age, estimate_max_age = FALSE )calc_gompertz_parameters( mortality_rates, current_age, estimate_max_age = FALSE )
mortality_rates |
A data frame
with columns |
current_age |
A numeric. Current age. |
estimate_max_age |
A logical. Should the maximum age be estimated? |
A list containing:
data |
The input mortality rates data frame with additional columns like 'survival_rate' and 'probability_of_death' |
mode |
The mode of the Gompertz distribution |
dispersion |
The dispersion parameter of the Gompertz distribution |
current_age |
The current age parameter |
max_age |
The maximum age parameter |
Blanchet, David M., and Paul D. Kaplan. 2013. "Alpha, Beta, and Now... Gamma." Journal of Retirement 1 (2): 29-45. doi:10.3905/jor.2013.1.2.029.
mortality_rates <- dplyr::filter( life_tables, country == "USA" & sex == "male" & year == 2022 ) calc_gompertz_parameters( mortality_rates = mortality_rates, current_age = 65 )mortality_rates <- dplyr::filter( life_tables, country == "USA" & sex == "male" & year == 2022 ) calc_gompertz_parameters( mortality_rates = mortality_rates, current_age = 65 )
Calculating Gompertz survival probability
calc_gompertz_survival_probability( current_age, target_age, mode, dispersion, max_age = NULL )calc_gompertz_survival_probability( current_age, target_age, mode, dispersion, max_age = NULL )
current_age |
Current age |
target_age |
Target age |
mode |
Mode of the Gompertz distribution |
dispersion |
Dispersion of the Gompertz distribution |
max_age |
Maximum age. Defaults to |
A numeric. The probability of survival from 'current_age' to 'target_age' based on the Gompertz distribution with the given parameters.
calc_gompertz_survival_probability( current_age = 65, target_age = 85, mode = 80, dispersion = 10 )calc_gompertz_survival_probability( current_age = 65, target_age = 85, mode = 80, dispersion = 10 )
Calculate Life Expectancy
calc_life_expectancy(current_age, mode, dispersion, max_age = 120)calc_life_expectancy(current_age, mode, dispersion, max_age = 120)
current_age |
A numeric. Current age. |
mode |
A numeric. Mode of the Gompertz distribution. |
dispersion |
A numeric. Dispersion of the Gompertz distribution. |
max_age |
A numeric. Maximum age. Defaults to 120. |
A numeric. Total life expectancy in years.
calc_life_expectancy( current_age = 65, mode = 80, dispersion = 10 )calc_life_expectancy( current_age = 65, mode = 80, dispersion = 10 )
Calculate optimal asset allocation
calc_optimal_asset_allocation( household, portfolio, current_date = get_current_date() )calc_optimal_asset_allocation( household, portfolio, current_date = get_current_date() )
household |
An R6 object of class |
portfolio |
A nested |
current_date |
A character. Current date in the format |
The portfolio with additional nested columns:
allocations$optimal - optimal joint net-worth portfolio allocations
allocations$current - current allocations
older_member <- HouseholdMember$new( name = "older", birth_date = "1980-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 7000 * 12" ) ) household$expected_spending <- list( "spending" = c( "TRUE ~ 5000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) portfolio <- calc_optimal_asset_allocation( household = household, portfolio = portfolio, current_date = "2020-07-15" ) portfolio$allocationsolder_member <- HouseholdMember$new( name = "older", birth_date = "1980-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 7000 * 12" ) ) household$expected_spending <- list( "spending" = c( "TRUE ~ 5000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) portfolio <- calc_optimal_asset_allocation( household = household, portfolio = portfolio, current_date = "2020-07-15" ) portfolio$allocations
Calculates the optimal allocation to the risky asset using the Merton Share formula.
calc_optimal_risky_asset_allocation( risky_asset_return_mean, risky_asset_return_sd, safe_asset_return, risk_aversion )calc_optimal_risky_asset_allocation( risky_asset_return_mean, risky_asset_return_sd, safe_asset_return, risk_aversion )
risky_asset_return_mean |
A numeric. The expected (average) yearly return of the risky asset. |
risky_asset_return_sd |
A numeric. The standard deviation of the yearly returns of the risky asset. |
safe_asset_return |
A numeric. The expected yearly return of the safe asset. |
risk_aversion |
A numeric. The risk aversion coefficient. |
Can be used to calculate the optimal allocation to the risky asset for vectors of inputs.
A numeric.
The optimal allocation to the risky asset.
In case of NaN() (because of division by zero)
the optimal allocation to the risky asset is set to 0.
Haghani V., White J. (2023) "The Missing Billionaires: A Guide to Better Financial Decisions." ISBN:978-1-119-74791-8.
calc_optimal_risky_asset_allocation( risky_asset_return_mean = 0.05, risky_asset_return_sd = 0.15, safe_asset_return = 0.02, risk_aversion = 2 ) calc_optimal_risky_asset_allocation( risky_asset_return_mean = c(0.05, 0.06), risky_asset_return_sd = c(0.15, 0.16), safe_asset_return = 0.02, risk_aversion = 2 )calc_optimal_risky_asset_allocation( risky_asset_return_mean = 0.05, risky_asset_return_sd = 0.15, safe_asset_return = 0.02, risk_aversion = 2 ) calc_optimal_risky_asset_allocation( risky_asset_return_mean = c(0.05, 0.06), risky_asset_return_sd = c(0.15, 0.16), safe_asset_return = 0.02, risk_aversion = 2 )
Calculate Portfolio Parameters
calc_portfolio_parameters(portfolio)calc_portfolio_parameters(portfolio)
portfolio |
A |
A list with the following elements:
value: The value of the portfolio.
weights: The weights of assets in the portfolio.
expected_return: The expected return of the portfolio.
standard_deviation: The standard deviation of the portfolio.
portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) calc_portfolio_parameters(portfolio)portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) calc_portfolio_parameters(portfolio)
Calculates changes in purchasing power over time, taking into account the real interest rate.
calc_purchasing_power(x, years, real_interest_rate)calc_purchasing_power(x, years, real_interest_rate)
x |
A numeric. The initial amount of money. |
years |
A numeric. The number of years. |
real_interest_rate |
A numeric. The yearly real interest rate. |
The real interest rate is the interest rate after inflation. If negative (e.g. equal to the average yearly inflation rate) it can show diminishing purchasing power over time. If positive, it can show increasing purchasing power over time, and effect of compounding interest on the purchasing power.
A numeric. The purchasing power.
calc_purchasing_power(x = 10, years = 30, real_interest_rate = -0.02) calc_purchasing_power(x = 10, years = 30, real_interest_rate = 0.02)calc_purchasing_power(x = 10, years = 30, real_interest_rate = -0.02) calc_purchasing_power(x = 10, years = 30, real_interest_rate = 0.02)
Calculating retirement ruin probability
calc_retirement_ruin( portfolio_return_mean, portfolio_return_sd, age, gompertz_mode, gompertz_dispersion, portfolio_value, monthly_spendings, yearly_spendings = 12 * monthly_spendings, spending_rate = yearly_spendings/portfolio_value )calc_retirement_ruin( portfolio_return_mean, portfolio_return_sd, age, gompertz_mode, gompertz_dispersion, portfolio_value, monthly_spendings, yearly_spendings = 12 * monthly_spendings, spending_rate = yearly_spendings/portfolio_value )
portfolio_return_mean |
A numeric. Mean of portfolio returns. |
portfolio_return_sd |
A numeric. Standard deviation of portfolio returns. |
age |
A numeric. Current age. |
gompertz_mode |
A numeric. Gompertz mode. |
gompertz_dispersion |
A numeric. Gompertz dispersion. |
portfolio_value |
A numeric. Initial portfolio value. |
monthly_spendings |
A numeric. Monthly spendings. |
yearly_spendings |
A numeric. Yearly spendings. |
spending_rate |
A numeric. Spending rate (initial withdrawal rate). |
A numeric. The probability of retirement ruin (between 0 and 1), representing the likelihood of running out of money during retirement.
Milevsky, M.A. (2020). Retirement Income Recipes in R: From Ruin Probabilities to Intelligent Drawdowns. Use R! Series. doi:10.1007/978-3-030-51434-1.
calc_retirement_ruin( age = 65, gompertz_mode = 88, gompertz_dispersion = 10, portfolio_value = 1000000, monthly_spendings = 3000, portfolio_return_mean = 0.02, portfolio_return_sd = 0.15 )calc_retirement_ruin( age = 65, gompertz_mode = 88, gompertz_dispersion = 10, portfolio_value = 1000000, monthly_spendings = 3000, portfolio_return_mean = 0.02, portfolio_return_sd = 0.15 )
Calculates the risk adjusted return for portfolio of given allocation to the risky asset.
calc_risk_adjusted_return( safe_asset_return, risky_asset_return_mean, risky_asset_allocation, risky_asset_return_sd = NULL, risk_aversion = NULL )calc_risk_adjusted_return( safe_asset_return, risky_asset_return_mean, risky_asset_allocation, risky_asset_return_sd = NULL, risk_aversion = NULL )
safe_asset_return |
A numeric. The expected yearly return of the safe asset. |
risky_asset_return_mean |
A numeric. The expected (average) yearly return of the risky asset. |
risky_asset_allocation |
A numeric.
The allocation to the risky asset. Could be a vector.
If it is the optimal allocation then parameters
|
risky_asset_return_sd |
A numeric. The standard deviation of the yearly returns of the risky asset. |
risk_aversion |
A numeric. The risk aversion coefficient. |
A numeric. The risk adjusted return.
Haghani V., White J. (2023) "The Missing Billionaires: A Guide to Better Financial Decisions." ISBN:978-1-119-74791-8.
calc_risk_adjusted_return( safe_asset_return = 0.02, risky_asset_return_mean = 0.04, risky_asset_return_sd = 0.15, risky_asset_allocation = 0.5, risk_aversion = 2 ) calc_risk_adjusted_return( safe_asset_return = 0.02, risky_asset_return_mean = 0.04, risky_asset_allocation = c(0.25, 0.5, 0.75), risky_asset_return_sd = 0.15, risk_aversion = 2 )calc_risk_adjusted_return( safe_asset_return = 0.02, risky_asset_return_mean = 0.04, risky_asset_return_sd = 0.15, risky_asset_allocation = 0.5, risk_aversion = 2 ) calc_risk_adjusted_return( safe_asset_return = 0.02, risky_asset_return_mean = 0.04, risky_asset_allocation = c(0.25, 0.5, 0.75), risky_asset_return_sd = 0.15, risk_aversion = 2 )
Creates a template for default portfolio with two asset classes:
GlobalStocksIndexFund
InflationProtectedBonds
create_portfolio_template()create_portfolio_template()
The template is used as a starting point for creating a portfolio.
The asset classes have some reasonable default values of
expected returns and standard deviations of returns.
The template assumes no correlations between asset classes in
the correlations matrix.
Please check and update the template assumptions if necessary.
The nested pretax columns contain default values for
parameters needed for calculating effective tax rates.
The template assumes only capital gains tax is paid.
Please customise this template to your individual situation.
The accounts nested columns have zero values for all assets
by default in both taxable and tax-advantaged accounts.
The template assumes that there is currently no financial
wealth allocated to those accounts.
Please customise this template to your individual situation.
The weights nested columns define weights of assets in
portfolios representative of the household human capital and liabilities.
The template assumes equal weights for all assets for both portfolios.
Please customise this template to your individual situation.
A nested tibble of class 'Portfolio' with columns:
name
expected_return
standard_deviation
accounts
taxable
taxadvantaged
weights
human_capital
liabilities
correlations
pretax
turnover
income_qualified
capital_gains_long_term
income
capital_gains
cost_basis
Possible sources of market assumptions:
https://www.obligacjeskarbowe.pl/oferta-obligacji/obligacje-10-letnie-edo/
(PDF) https://research.ftserussell.com/Analytics/FactSheets/Home/DownloadSingleIssue?issueName=AWORLDS&isManual=False
portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolioportfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio
Wrapper functions for printing nicely formatted values.
format_currency( x, prefix = "", suffix = "", big.mark = ",", accuracy = NULL, min_length = NULL, ... ) format_percent(x, accuracy = 0.1, ...)format_currency( x, prefix = "", suffix = "", big.mark = ",", accuracy = NULL, min_length = NULL, ... ) format_percent(x, accuracy = 0.1, ...)
x |
A numeric vector |
prefix, suffix
|
Symbols to display before and after value. |
big.mark |
Character used between every 3 digits to separate thousands.
The default ( |
accuracy |
A number to round to. Use (e.g.) Applied to rescaled data. |
min_length |
A numeric. Minimum number of characters of the string with the formatted value. |
... |
Other arguments passed on to |
A character. Formatted value.
A character. Formatted value.
format_currency(2345678, suffix = " PLN") format_percent(0.52366)format_currency(2345678, suffix = " PLN") format_percent(0.52366)
Get information about the cache
Reset the cache
Set the cache directory
get_cache_info() reset_cache() set_cache(path = file.path(getwd(), ".cache"))get_cache_info() reset_cache() set_cache(path = file.path(getwd(), ".cache"))
path |
The path to the cache directory. Defaults to the '.cache' folder in the current working directory. |
Invisibly returns the path to the cache directory or a list containing:
path |
The path to the cache directory. |
files |
The number of files in the cache. |
get_cache_info() reset_cache() set_cache()get_cache_info() reset_cache() set_cache()
If R4GPF.current_date option is not set, the current system date is used.
get_current_date()get_current_date()
A date.
get_current_date() # Setting custom date using `R4GPF.current_date` option options(R4GPF.current_date = as.Date("2023-01-01")) get_current_date() options(R4GPF.current_date = NULL) # Reset default date#' Working with cache get_current_date()get_current_date() # Setting custom date using `R4GPF.current_date` option options(R4GPF.current_date = as.Date("2023-01-01")) get_current_date() options(R4GPF.current_date = NULL) # Reset default date#' Working with cache get_current_date()
Calculates default Gompertz parameters for a given age, country and sex, based on the package build-in HMD life tables.
get_default_gompertz_parameters( age, country = unique(life_tables$country), sex = c("both", "male", "female") )get_default_gompertz_parameters( age, country = unique(life_tables$country), sex = c("both", "male", "female") )
age |
A numeric. The age of the individual. |
country |
A character. The name of the country. |
sex |
A character. The sex of the individual. |
A list containing:
mode |
The mode of the Gompertz distribution |
dispersion |
The dispersion parameter of the Gompertz distribution |
current_age |
The current age parameter |
max_age |
The maximum age parameter |
get_default_gompertz_parameters( age = 65, country = "USA", sex = "male" )get_default_gompertz_parameters( age = 65, country = "USA", sex = "male" )
The Household class aggregates information about
a household and its members.
An object of class Household.
expected_incomeSet of rules that are used to generate streams of expected income
expected_spendingSet of rules that are used to generate streams of expected spending
risk_toleranceRisk tolerance of the household
consumption_impatience_preferenceConsumption impatience preference of the household - subjective discount rate (rho). Higher values indicate a stronger preference for consumption today versus in the future.
smooth_consumption_preferenceSmooth consumption preference of the household - Elasticity of Intertemporal Substitution (EOIS) (eta). Higher values indicate more flexibility and a lower preference for smooth consumption.
print()
Printing the household object
Household$print(current_date = get_current_date())
current_dateA date in the format "YYYY-MM-DD".
get_members()
Getting members of the household
Household$get_members()
add_member()
Adding a member to the household It will fail if a member with the same name already exists.
Household$add_member(household_member)
household_memberA HouseholdMember object.
set_member()
Setting a member of the household If a member already exists, it will be overwritten.
Household$set_member(member)
memberA HouseholdMember object.
set_lifespan()
Setting an arbitrary lifespan of the household
Household$set_lifespan(value)
valueA number of years.
get_lifespan()
Getting a lifespan of the household If not set, it will be calculated based on the members' lifespans.
Household$get_lifespan(current_date = get_current_date())
current_dateA date in the format "YYYY-MM-DD".
calc_survival()
Calculating a survival rate of the household based on its members' parameters of the Gompertz model.
Household$calc_survival(current_date = get_current_date())
current_dateA date in the format "YYYY-MM-DD".
get_min_age()
Calculating a minimum age of the household members.
Household$get_min_age(current_date = get_current_date())
current_dateA date in the format "YYYY-MM-DD".
clone()
The objects of this class are cloneable with this method.
Household$clone(deep = FALSE)
deepWhether to make a deep clone.
household <- Household$new() household$risk_tolerance household$consumption_impatience_preference household$smooth_consumption_preferencehousehold <- Household$new() household$risk_tolerance household$consumption_impatience_preference household$smooth_consumption_preference
The HouseholdMember class aggregates information about
a single member of a household.
An object of class HouseholdMember.
max_ageThe maximum age of the household member
modeThe Gompertz mode parameter
dispersionThe Gompertz dispersion parameter
new()
Creating a new object of class HouseholdMember
HouseholdMember$new(name, birth_date, mode = NULL, dispersion = NULL)
nameThe name of the member.
birth_dateThe birth date of the household member
in the format YYYY-MM-DD.
modeThe Gompertz mode parameter.
dispersionThe Gompertz dispersion parameter.
print()
Printing the household member object
HouseholdMember$print(current_date = get_current_date())
current_dateA date in the format "YYYY-MM-DD".
get_name()
Getting the name of the household member
HouseholdMember$get_name()
get_birth_date()
Getting the birth date of the household member
HouseholdMember$get_birth_date()
calc_age()
Calculating the age of the household member
HouseholdMember$calc_age(current_date = get_current_date())
current_dateA date in the format "YYYY-MM-DD".
get_lifespan()
Calculating a lifespan of the household member
HouseholdMember$get_lifespan(current_date = get_current_date())
current_dateA date in the format "YYYY-MM-DD".
calc_life_expectancy()
Calculating a life expectancy of the household member
HouseholdMember$calc_life_expectancy(current_date = get_current_date())
current_dateA date in the format "YYYY-MM-DD".
calc_survival_probability()
Calculating a survival probability of the household member
HouseholdMember$calc_survival_probability( target_age, current_date = get_current_date() )
target_ageTarget age (numeric, in years).
current_dateA date in the format "YYYY-MM-DD".
get_events()
Getting the events related to the household member
HouseholdMember$get_events()
set_event()
Setting an event related to the household member
HouseholdMember$set_event(event, start_age, end_age = Inf, years = Inf)
eventThe name of the event.
start_ageThe age of the household member when the event starts.
end_ageThe age of the household member when the event ends.
yearsThe number of years the event lasts.
clone()
The objects of this class are cloneable with this method.
HouseholdMember$clone(deep = FALSE)
deepWhether to make a deep clone.
member <- HouseholdMember$new( name = "Isabela", birth_date = "1980-07-15", mode = 91, dispersion = 8.88 ) member$calc_age() member$calc_life_expectancy()member <- HouseholdMember$new( name = "Isabela", birth_date = "1980-07-15", mode = 91, dispersion = 8.88 ) member$calc_age() member$calc_life_expectancy()
A data frame based on: HMD. Human Mortality Database. Max Planck Institute for Demographic Research (Germany), University of California, Berkeley (USA), and French Institute for Demographic Studies (France). Available at www.mortality.org.
life_tableslife_tables
life_tablesA data frame with 6 columns:
Country name
Sex: "male", "female", "both"
Year
Age
Mortality rate
Life expectancy
If multiple Monte Carlo samples are provided in the scenario argument,
the normalized median of expected allocation is plotted.
plot_expected_allocation( scenario, accounts = c("all", "taxable", "taxadvantaged") )plot_expected_allocation( scenario, accounts = c("all", "taxable", "taxadvantaged") )
scenario |
A |
accounts |
A character. Plot allocation for specified types of accounts. |
A ggplot2::ggplot() object.
older_member <- HouseholdMember$new( name = "older", birth_date = "2000-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 10000 * 12" ) ) household$expected_spending <- list( "spending" = c( "TRUE ~ 5000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio$weights$human_capital <- c(0.2, 0.8) portfolio$weights$liabilities <- c(0.1, 0.9) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) scenario <- simulate_scenario( household = household, portfolio = portfolio, current_date = "2020-07-15" ) plot_expected_allocation(scenario)older_member <- HouseholdMember$new( name = "older", birth_date = "2000-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 10000 * 12" ) ) household$expected_spending <- list( "spending" = c( "TRUE ~ 5000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio$weights$human_capital <- c(0.2, 0.8) portfolio$weights$liabilities <- c(0.1, 0.9) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) scenario <- simulate_scenario( household = household, portfolio = portfolio, current_date = "2020-07-15" ) plot_expected_allocation(scenario)
Plots financial capital, human capital, total capital, and liabilities.
plot_expected_capital(scenario)plot_expected_capital(scenario)
scenario |
A |
A ggplot2::ggplot() object.
older_member <- HouseholdMember$new( name = "older", birth_date = "2000-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 10000 * 12" ) ) household$expected_spending <- list( "spending" = c( "TRUE ~ 5000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio$weights$human_capital <- c(0.2, 0.8) portfolio$weights$liabilities <- c(0.1, 0.9) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) scenario <- simulate_scenario( household = household, portfolio = portfolio, current_date = "2020-07-15" ) plot_expected_capital(scenario)older_member <- HouseholdMember$new( name = "older", birth_date = "2000-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 10000 * 12" ) ) household$expected_spending <- list( "spending" = c( "TRUE ~ 5000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio$weights$human_capital <- c(0.2, 0.8) portfolio$weights$liabilities <- c(0.1, 0.9) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) scenario <- simulate_scenario( household = household, portfolio = portfolio, current_date = "2020-07-15" ) plot_expected_capital(scenario)
Plot future income structure over household life cycle
plot_future_income( scenario, period = c("yearly", "monthly"), y_limits = c(NA, NA) )plot_future_income( scenario, period = c("yearly", "monthly"), y_limits = c(NA, NA) )
scenario |
A |
period |
A character. The amounts can be shown as yearly values (default) or averaged per month values. |
y_limits |
A numeric vector of two values. Y-axis limits. |
A ggplot2::ggplot() object.
older_member <- HouseholdMember$new( name = "older", birth_date = "1980-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 7000 * 12", "members$older$age > 65 ~ 3000 * 12" ) ) household$expected_spending <- list( "spending" = c( "TRUE ~ 5000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) scenario <- simulate_scenario( household = household, portfolio = portfolio, current_date = "2020-07-15" ) plot_future_income(scenario, "monthly")older_member <- HouseholdMember$new( name = "older", birth_date = "1980-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 7000 * 12", "members$older$age > 65 ~ 3000 * 12" ) ) household$expected_spending <- list( "spending" = c( "TRUE ~ 5000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) scenario <- simulate_scenario( household = household, portfolio = portfolio, current_date = "2020-07-15" ) plot_future_income(scenario, "monthly")
This function plots the future saving rates from a scenario object.
plot_future_saving_rates( scenario, aggregation_function = stats::median, y_limits = c(NA, NA) )plot_future_saving_rates( scenario, aggregation_function = stats::median, y_limits = c(NA, NA) )
scenario |
A |
aggregation_function |
A function used to aggregate the saving rates
for multiple Monte Carlo samples. Default is |
y_limits |
A numeric vector of two values. Y-axis limits. |
A ggplot2::ggplot() object.
older_member <- HouseholdMember$new( name = "older", birth_date = "2000-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 10000 * 12" ) ) household$expected_spending <- list( "spending" = c( "TRUE ~ 5000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio$weights$human_capital <- c(0.2, 0.8) portfolio$weights$liabilities <- c(0.1, 0.9) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) scenario <- simulate_scenario( household = household, portfolio = portfolio, current_date = "2020-07-15" ) plot_future_saving_rates(scenario)older_member <- HouseholdMember$new( name = "older", birth_date = "2000-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 10000 * 12" ) ) household$expected_spending <- list( "spending" = c( "TRUE ~ 5000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio$weights$human_capital <- c(0.2, 0.8) portfolio$weights$liabilities <- c(0.1, 0.9) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) scenario <- simulate_scenario( household = household, portfolio = portfolio, current_date = "2020-07-15" ) plot_future_saving_rates(scenario)
Plot future spending structure over household life cycle, including discretionary and non-discretionary spending. You can also plot discretionary and non-discretionary spending separately, to see structure of non-discretionary spending and possible levels of discretionary spending over time based on Monte Carlo simulations.
plot_future_spending( scenario, period = c("yearly", "monthly"), type = c("both", "discretionary", "non-discretionary"), discretionary_spending_position = c("bottom", "top"), y_limits = c(NA, NA) )plot_future_spending( scenario, period = c("yearly", "monthly"), type = c("both", "discretionary", "non-discretionary"), discretionary_spending_position = c("bottom", "top"), y_limits = c(NA, NA) )
scenario |
A |
period |
A character. The amounts can be shown as yearly values (default) or averaged per month values. |
type |
A character. Type of spending to plot: discretionary, non-discretionary, or both (default). |
discretionary_spending_position |
A character. Position of discretionary spending in plot. Bottom is the default. |
y_limits |
A numeric vector of two values. Y-axis limits. |
A ggplot2::ggplot() object
older_member <- HouseholdMember$new( name = "older", birth_date = "1980-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 9000 * 12" ) ) household$expected_spending <- list( "spending" = c( "members$older$age <= 65 ~ 5000 * 12", "TRUE ~ 4000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) scenario <- simulate_scenario( household = household, portfolio = portfolio, # monte_carlo_samples = 100, current_date = "2020-07-15" ) plot_future_spending(scenario, "monthly") plot_future_spending( scenario, "monthly", discretionary_spending_position = "top" ) plot_future_spending(scenario, "monthly", "non-discretionary") # If Monte Carlo samples are present: # plot_future_spending(scenario, "monthly", "discretionary")older_member <- HouseholdMember$new( name = "older", birth_date = "1980-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 9000 * 12" ) ) household$expected_spending <- list( "spending" = c( "members$older$age <= 65 ~ 5000 * 12", "TRUE ~ 4000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) scenario <- simulate_scenario( household = household, portfolio = portfolio, # monte_carlo_samples = 100, current_date = "2020-07-15" ) plot_future_spending(scenario, "monthly") plot_future_spending( scenario, "monthly", discretionary_spending_position = "top" ) plot_future_spending(scenario, "monthly", "non-discretionary") # If Monte Carlo samples are present: # plot_future_spending(scenario, "monthly", "discretionary")
Plotting the results of Gompertz model calibration
plot_gompertz_calibration(params, mode, dispersion, max_age)plot_gompertz_calibration(params, mode, dispersion, max_age)
params |
A list returned by |
mode |
A numeric. The mode of the Gompertz model. |
dispersion |
A numeric. The dispersion of the Gompertz model. |
max_age |
A numeric. The maximum age of the Gompertz model. |
A ggplot2::ggplot() object showing the comparison between
actual survival rates from life tables and the fitted Gompertz model.
mortality_rates <- dplyr::filter( life_tables, country == "USA" & sex == "female" & year == 2022 ) params <- calc_gompertz_parameters( mortality_rates = mortality_rates, current_age = 65 ) plot_gompertz_calibration(params = params)mortality_rates <- dplyr::filter( life_tables, country == "USA" & sex == "female" & year == 2022 ) params <- calc_gompertz_parameters( mortality_rates = mortality_rates, current_age = 65 ) plot_gompertz_calibration(params = params)
Plotting the results of Gompertz model calibration for joint survival
plot_joint_survival(params, include_gompertz = FALSE)plot_joint_survival(params, include_gompertz = FALSE)
params |
A list returned by |
include_gompertz |
A logical. Should the Gompertz survival curve be included in the plot? |
A ggplot2::ggplot() object showing the survival probabilities
for two individuals and their joint survival probability.
params <- calc_gompertz_joint_parameters( p1 = list( age = 65, mode = 88, dispersion = 10.65 ), p2 = list( age = 60, mode = 91, dispersion = 8.88 ), max_age = 110 ) plot_joint_survival(params = params, include_gompertz = TRUE)params <- calc_gompertz_joint_parameters( p1 = list( age = 65, mode = 88, dispersion = 10.65 ), p2 = list( age = 60, mode = 91, dispersion = 8.88 ), max_age = 110 ) plot_joint_survival(params = params, include_gompertz = TRUE)
Probability of dying at a given age is plotted for each member of a household. Also for each member the life expectancy is shown as dashed vertical line.
plot_life_expectancy(household)plot_life_expectancy(household)
household |
An R6 object of class |
A ggplot object.
hm1 <- HouseholdMember$new( name = "member1", birth_date = "1955-01-01", mode = 88, dispersion = 10.65 ) hm2 <- HouseholdMember$new( name = "member2", birth_date = "1965-01-01", mode = 91, dispersion = 8.88 ) household <- Household$new() household$add_member(hm1) household$add_member(hm2) plot_life_expectancy(household = household)hm1 <- HouseholdMember$new( name = "member1", birth_date = "1955-01-01", mode = 88, dispersion = 10.65 ) hm2 <- HouseholdMember$new( name = "member2", birth_date = "1965-01-01", mode = 91, dispersion = 8.88 ) household <- Household$new() household$add_member(hm1) household$add_member(hm2) plot_life_expectancy(household = household)
The function plots current versus optimal portfolio allocations for each asset class and for taxable and tax-advantaged accounts.
plot_optimal_portfolio(portfolio)plot_optimal_portfolio(portfolio)
portfolio |
A nested |
A ggplot2::ggplot() object.
older_member <- HouseholdMember$new( name = "older", birth_date = "1980-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 7000 * 12" ) ) household$expected_spending <- list( "spending" = c( "TRUE ~ 5000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio$accounts$taxadvantaged <- c(0, 20000) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) portfolio <- calc_optimal_asset_allocation( household = household, portfolio = portfolio, current_date = "2020-07-15" ) plot_optimal_portfolio(portfolio)older_member <- HouseholdMember$new( name = "older", birth_date = "1980-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 7000 * 12" ) ) household$expected_spending <- list( "spending" = c( "TRUE ~ 5000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio$accounts$taxadvantaged <- c(0, 20000) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) portfolio <- calc_optimal_asset_allocation( household = household, portfolio = portfolio, current_date = "2020-07-15" ) plot_optimal_portfolio(portfolio)
Plots the effect of real interest rates (positive or negative) on the purchasing power of savings over the span of 50 years (default).
plot_purchasing_power( x, real_interest_rate, years = 50, legend_title = "Real interest rate", seed = NA )plot_purchasing_power( x, real_interest_rate, years = 50, legend_title = "Real interest rate", seed = NA )
x |
A numeric. The initial amount of money. |
real_interest_rate |
A numeric. The yearly real interest rate. |
years |
A numeric. The number of years. |
legend_title |
A character. |
seed |
A numeric. Seed passed to |
A ggplot2::ggplot() object.
plot_purchasing_power( x = 10, real_interest_rate = seq(-0.02, 0.04, by = 0.02) )plot_purchasing_power( x = 10, real_interest_rate = seq(-0.02, 0.04, by = 0.02) )
Plotting retirement ruin
plot_retirement_ruin( portfolio_return_mean, portfolio_return_sd, age, gompertz_mode, gompertz_dispersion, portfolio_value, monthly_spendings = NULL )plot_retirement_ruin( portfolio_return_mean, portfolio_return_sd, age, gompertz_mode, gompertz_dispersion, portfolio_value, monthly_spendings = NULL )
portfolio_return_mean |
A numeric. Mean of portfolio returns. |
portfolio_return_sd |
A numeric. Standard deviation of portfolio returns. |
age |
A numeric. Current age. |
gompertz_mode |
A numeric. Gompertz mode. |
gompertz_dispersion |
A numeric. Gompertz dispersion. |
portfolio_value |
A numeric. Initial portfolio value. |
monthly_spendings |
A numeric. Monthly spendings. |
A ggplot2::ggplot() object showing the probability of
retirement ruin for different monthly spending levels.
If a specific 'monthly_spendings' value is provided,
it will be highlighted on the plot with annotations.
plot_retirement_ruin( portfolio_return_mean = 0.034, portfolio_return_sd = 0.15, age = 65, gompertz_mode = 88, gompertz_dispersion = 10, portfolio_value = 1000000, monthly_spendings = 3000 )plot_retirement_ruin( portfolio_return_mean = 0.034, portfolio_return_sd = 0.15, age = 65, gompertz_mode = 88, gompertz_dispersion = 10, portfolio_value = 1000000, monthly_spendings = 3000 )
Plots the risk adjusted returns for portfolios of various allocations to the risky asset.
plot_risk_adjusted_returns( safe_asset_return, risky_asset_return_mean, risky_asset_return_sd, risk_aversion = 2, current_risky_asset_allocation = NULL )plot_risk_adjusted_returns( safe_asset_return, risky_asset_return_mean, risky_asset_return_sd, risk_aversion = 2, current_risky_asset_allocation = NULL )
safe_asset_return |
A numeric. The expected yearly return of the safe asset. |
risky_asset_return_mean |
A numeric. The expected (average) yearly return of the risky asset. |
risky_asset_return_sd |
A numeric. The standard deviation of the yearly returns of the risky asset. |
risk_aversion |
A numeric. The risk aversion coefficient. |
current_risky_asset_allocation |
A numeric. The current allocation to the risky asset. For comparison with the optimal allocation. |
A ggplot2::ggplot() object.
Haghani V., White J. (2023) "The Missing Billionaires: A Guide to Better Financial Decisions." ISBN:978-1-119-74791-8.
plot_risk_adjusted_returns( safe_asset_return = 0.02, risky_asset_return_mean = 0.04, risky_asset_return_sd = 0.15, risk_aversion = 2, current_risky_asset_allocation = 0.8 )plot_risk_adjusted_returns( safe_asset_return = 0.02, risky_asset_return_mean = 0.04, risky_asset_return_sd = 0.15, risk_aversion = 2, current_risky_asset_allocation = 0.8 )
The plot allows to compare metrics for multiple scenarios.
If scenarios are simulated without Monte Carlo samples, so they are based only on expected returns of portfolio, two metrics are available for each scenario:
constant discretionary spending - certainty equivalent constant level of consumption that would result in the same lifetime utility as a given series of future consumption in a given scenario (the higher, the better).
utility of discretionary spending - normalized to minimum and maximum values of constant discretionary spending (the higher, the better).
If scenarios are simulated with additional Monte Carlo samples, there are four more metrics available per scenario:
constant discretionary spending (for Monte Carlo samples),
normalized median utility of discretionary spending (for Monte Carlo samples),
median of missing funds that need additional income or additional savings at the expense of non-discretionary spending, (of yearly averages of Monte Carlo samples),
median of discretionary spending (of yearly averages of Monte Carlo samples).
plot_scenarios(scenarios, period = c("yearly", "monthly"))plot_scenarios(scenarios, period = c("yearly", "monthly"))
scenarios |
A |
period |
A character. The amounts can be shown as yearly values (default) or averaged per month values. |
A ggplot2::ggplot() object.
older_member <- HouseholdMember$new( name = "older", birth_date = "1980-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "is_not_on('older', 'retirement') ~ 7000 * 12" ) ) household$expected_spending <- list( "spending" = c( "TRUE ~ 4000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(100000, 300000) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) start_ages <- c(60, 65, 75) scenarios_parameters <- tibble::tibble( member = "older", event = "retirement", start_age = start_ages, years = Inf, end_age = Inf ) |> dplyr::mutate(scenario_id = start_age) |> tidyr::nest(events = -scenario_id) scenarios <- simulate_scenarios( scenarios_parameters = scenarios_parameters, household = household, portfolio = portfolio, maxeval = 100, current_date = "2020-07-15" ) plot_scenarios(scenarios, "monthly")older_member <- HouseholdMember$new( name = "older", birth_date = "1980-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "is_not_on('older', 'retirement') ~ 7000 * 12" ) ) household$expected_spending <- list( "spending" = c( "TRUE ~ 4000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(100000, 300000) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) start_ages <- c(60, 65, 75) scenarios_parameters <- tibble::tibble( member = "older", event = "retirement", start_age = start_ages, years = Inf, end_age = Inf ) |> dplyr::mutate(scenario_id = start_age) |> tidyr::nest(events = -scenario_id) scenarios <- simulate_scenarios( scenarios_parameters = scenarios_parameters, household = household, portfolio = portfolio, maxeval = 100, current_date = "2020-07-15" ) plot_scenarios(scenarios, "monthly")
Plot survival probabilities for each household members and for the entire household when at least one member is alive. The household joint survival probability is also approximated by a Gompertz model.
plot_survival(household, current_date = get_current_date())plot_survival(household, current_date = get_current_date())
household |
An R6 object of class |
current_date |
A character. Current date in the format |
A ggplot object.
hm1 <- HouseholdMember$new( name = "member1", birth_date = "1955-01-01", mode = 88, dispersion = 10.65 ) hm2 <- HouseholdMember$new( name = "member2", birth_date = "1965-01-01", mode = 91, dispersion = 8.88 ) hm3 <- HouseholdMember$new( name = "member3", birth_date = "1975-01-01", mode = 88, dispersion = 7.77 ) household <- Household$new() household$add_member(hm1) household$add_member(hm2) household$add_member(hm3) plot_survival( household = household, current_date = "2020-01-01" )hm1 <- HouseholdMember$new( name = "member1", birth_date = "1955-01-01", mode = 88, dispersion = 10.65 ) hm2 <- HouseholdMember$new( name = "member2", birth_date = "1965-01-01", mode = 91, dispersion = 8.88 ) hm3 <- HouseholdMember$new( name = "member3", birth_date = "1975-01-01", mode = 88, dispersion = 7.77 ) household <- Household$new() household$add_member(hm1) household$add_member(hm2) household$add_member(hm3) plot_survival( household = household, current_date = "2020-01-01" )
Reading HMD life tables
read_hmd_life_tables( path = getwd(), files = c("mltper_1x1.txt", "fltper_1x1.txt", "bltper_1x1.txt") )read_hmd_life_tables( path = getwd(), files = c("mltper_1x1.txt", "fltper_1x1.txt", "bltper_1x1.txt") )
path |
A character. Path to the folder with life tables. |
files |
A character. Names of files with life tables. |
A data frame containing mortality data with columns:
sex |
Character - sex ('male', 'female', or 'both') |
year |
Integer - the year of the data |
age |
Integer - age |
mortality_rate |
Numeric - mortality rate |
life_expectancy |
Numeric - life expectancy |
HMD. Human Mortality Database. Max Planck Institute for Demographic Research (Germany), University of California, Berkeley (USA), and French Institute for Demographic Studies (France). Available at www.mortality.org
## Not run: # Download 'txt' files # ("mltper_1x1.txt", "fltper_1x1.txt", "bltper_1x1.txt") # for a given country to the working directory # from https://www.mortality.org after registration. read_hmd_life_tables(path = getwd()) ## End(Not run)## Not run: # Download 'txt' files # ("mltper_1x1.txt", "fltper_1x1.txt", "bltper_1x1.txt") # for a given country to the working directory # from https://www.mortality.org after registration. read_hmd_life_tables(path = getwd()) ## End(Not run)
Rendering a scenario snapshot
render_scenario_snapshot(scenario, index = 0, currency = "", big_mark = " ")render_scenario_snapshot(scenario, index = 0, currency = "", big_mark = " ")
scenario |
A |
index |
The index of the scenario year to render. By default, it is 0, which corresponds to the current year. |
currency |
The currency symbol to use as a suffix. |
big_mark |
The character to use as a big mark. It separates thousands. |
A gt::gt() object.
older_member <- HouseholdMember$new( name = "older", birth_date = "1980-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 9000 * 12" ) ) household$expected_spending <- list( "spending" = c( "members$older$age <= 65 ~ 5000 * 12", "TRUE ~ 4000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) scenario <- simulate_scenario( household = household, portfolio = portfolio, current_date = "2020-07-15" ) render_scenario_snapshot(scenario)older_member <- HouseholdMember$new( name = "older", birth_date = "1980-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 9000 * 12" ) ) household$expected_spending <- list( "spending" = c( "members$older$age <= 65 ~ 5000 * 12", "TRUE ~ 4000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) scenario <- simulate_scenario( household = household, portfolio = portfolio, current_date = "2020-07-15" ) render_scenario_snapshot(scenario)
Run a package app
run_app( which = c("risk-adjusted-returns", "purchasing-power", "retirement-ruin"), res = 120, shinylive = FALSE )run_app( which = c("risk-adjusted-returns", "purchasing-power", "retirement-ruin"), res = 120, shinylive = FALSE )
which |
A character. The name of the app to run. Currently available:
|
res |
A numeric. The initial resolution of the plots. |
shinylive |
A logical. Whether to use |
A shiny::shinyApp() object if shinylive is TRUE.
Runs the app if shinylive is FALSE with shiny::runApp().
run_app("risk-adjusted-returns") run_app("purchasing-power") run_app("retirement-ruin")run_app("risk-adjusted-returns") run_app("purchasing-power") run_app("retirement-ruin")
The function simulates a scenario of household lifetime finances
and returns a tibble with nested columns.
By default no Monte Carlo samples are generated, and only
single sample based on portfolio expected returns are returned with
column sample=0.
If the additional Monte Carlo samples are generated, they have
consecutive IDs starting from 1 in the sample column.
simulate_scenario( household, portfolio, scenario_id = "default", current_date = get_current_date(), monte_carlo_samples = NULL, seeds = NULL, use_cache = FALSE, auto_parallel = FALSE, debug = FALSE, ... )simulate_scenario( household, portfolio, scenario_id = "default", current_date = get_current_date(), monte_carlo_samples = NULL, seeds = NULL, use_cache = FALSE, auto_parallel = FALSE, debug = FALSE, ... )
household |
An R6 object of class |
portfolio |
A nested |
scenario_id |
A character. ID of the scenario. |
current_date |
A character. Current date in the format |
monte_carlo_samples |
An integer. Number of Monte Carlo samples.
If |
seeds |
An integer or integer vector.
If integer vector, it is a vector of random seeds
for the random number generator
used to generate random portfolio returns for each Monte Carlo sample.
If |
use_cache |
A logical. If |
auto_parallel |
A logical. If |
debug |
A logical. If |
... |
Additional arguments passed to simulation and optimization
functions. You can pass a list named |
A tibble with nested columns including:
scenario_id - (character) ID of the scenario
sample - (integer) ID of the Monte Carlo sample
index - (integer) year index starting from 0
years_left - (integer) years left to the end of the household lifespan
date - (date) date after index years from the current date
year - (integer) calendar year
survival_prob - (double) survival probability of the household
members - (nested tibble) data of each member in the household
income - (nested tibble) income streams
total_income - (double) total income of the household from all income streams
spending - (nested tibble) non-discretionary spending streams
nondiscretionary_spending - (double) total non-discretionary spending of the household from all non-discretionary spending streams
human_capital - (double) human capital of the household
liabilities - (double) liabilities of the household
portfolio - (nested tibble) state of investment portfolio
financial_wealth - (double) financial wealth of the household at the beginning of the year
net_worth - (double) net worth of the household
discretionary_spending - (double) optimal discretionary spending of the household
total_spending - (double) total spending of the household (discretionary + non-discretionary)
financial_wealth_end - (double) financial wealth of the household at the end of the year
risk_tolerance - (double) risk tolerance of the household
smooth_consumption_preference - (double) smooth consumption preference of the household
consumption_impatience_preference - (double) consumption impatience preference of the household
time_value_discount - (double) time value discount based on consumption impatience of the household
discretionary_spending_utility - (double) discretionary spending utility of the household based on the smooth consumption preference
discretionary_spending_utility_weighted - (double) discretionary spending utility of the household weighted by survival probability and time value discount.
older_member <- HouseholdMember$new( name = "older", birth_date = "1980-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 7000 * 12" ) ) household$expected_spending <- list( "spending" = c( "TRUE ~ 5000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) scenario <- simulate_scenario( household = household, portfolio = portfolio, current_date = "2020-07-15" ) names(scenario)older_member <- HouseholdMember$new( name = "older", birth_date = "1980-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 7000 * 12" ) ) household$expected_spending <- list( "spending" = c( "TRUE ~ 5000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) scenario <- simulate_scenario( household = household, portfolio = portfolio, current_date = "2020-07-15" ) names(scenario)
Simulate multiple scenarios of household lifetime finances
simulate_scenarios( scenarios_parameters, household, portfolio, current_date = get_current_date(), monte_carlo_samples = NULL, seeds = NULL, auto_parallel = FALSE, use_cache = FALSE, debug = FALSE, ... )simulate_scenarios( scenarios_parameters, household, portfolio, current_date = get_current_date(), monte_carlo_samples = NULL, seeds = NULL, auto_parallel = FALSE, use_cache = FALSE, debug = FALSE, ... )
scenarios_parameters |
A |
household |
An R6 object of class |
portfolio |
A nested |
current_date |
A character. Current date in the format |
monte_carlo_samples |
An integer. Number of Monte Carlo samples.
If |
seeds |
An integer or integer vector.
If integer vector, it is a vector of random seeds
for the random number generator
used to generate random portfolio returns for each Monte Carlo sample.
If |
auto_parallel |
A logical. If |
use_cache |
A logical. If |
debug |
A logical. If |
... |
Additional arguments passed to simulation and optimization
functions. You can pass a list named |
A tibble with nested columns.
older_member <- HouseholdMember$new( name = "older", birth_date = "1980-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 7000 * 12" ) ) household$expected_spending <- list( "spending" = c( "TRUE ~ 5000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) start_ages <- c(60, 65, 70) scenarios_parameters <- tibble::tibble( member = "older", event = "retirement", start_age = start_ages, years = Inf, end_age = Inf ) |> dplyr::mutate(scenario_id = start_age) |> tidyr::nest(events = -scenario_id) scenarios_parameters scenarios <- simulate_scenarios( scenarios_parameters = scenarios_parameters, household = household, portfolio = portfolio, current_date = "2020-07-15" ) scenarios$scenario_id |> unique()older_member <- HouseholdMember$new( name = "older", birth_date = "1980-02-15", mode = 80, dispersion = 10 ) household <- Household$new() household$add_member(older_member) household$expected_income <- list( "income" = c( "members$older$age <= 65 ~ 7000 * 12" ) ) household$expected_spending <- list( "spending" = c( "TRUE ~ 5000 * 12" ) ) portfolio <- create_portfolio_template() portfolio$accounts$taxable <- c(10000, 30000) portfolio <- portfolio |> calc_effective_tax_rate( tax_rate_ltcg = 0.20, tax_rate_ordinary_income = 0.40 ) start_ages <- c(60, 65, 70) scenarios_parameters <- tibble::tibble( member = "older", event = "retirement", start_age = start_ages, years = Inf, end_age = Inf ) |> dplyr::mutate(scenario_id = start_age) |> tidyr::nest(events = -scenario_id) scenarios_parameters scenarios <- simulate_scenarios( scenarios_parameters = scenarios_parameters, household = household, portfolio = portfolio, current_date = "2020-07-15" ) scenarios$scenario_id |> unique()