{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "ca3f462e",
      "metadata": {},
      "source": [
        "# Owl\n",
        "## Retirement planner with great wisdon"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3fbb38b5",
      "metadata": {},
      "source": [
        "This package is a retirement modeling framework for exploring the sensitivity of retirement financial decisions. Strictly speaking, it is not a planning tool, but more an environment for exploring *what if* scenarios. It provides different realizations of a financial strategy. One can certainly have a savings plan, but due to the volatility of financial investments, it is impossible to have a certain asset earnings plan. This does not mean one cannot make decisions. These decisions need to be guided with an understanding of the sensitivity of the parameters.This is exactly where this tool fits it. Given your savings and spending desires, it can generate different future realizations of your strategy under different market assumptions, helping to better understand your financial situation.\n",
        "\n",
        "The algorithm in Owl is using the open-source HiGHS linear programming solver.\n",
        "The complete formulation and detailed description of the underlying\n",
        "mathematical model can be found\n",
        "[here](https://raw.githubusercontent.com/mdlacasse/Owl/main/docs/owl.pdf).\n",
        "\n",
        "Copyright &copy; 2024 - Martin-D. Lacasse\n",
        "\n",
        "Disclaimers: *I am not a financial planner. You make your own decisions. This program comes with no guarantee. Use at your own risk.*"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "79fc57cf-fd5a-4972-8112-078282cde9fc",
      "metadata": {},
      "source": [
        "### <span style=\"color: blue\"> README FIRST </span>\n",
        "<span style=\"color:black;background:yellow;font-weight:bold\">\n",
        "Don't make changes directly to this file. Keep it as a working example. Therefore, it is recommended that you build your own case by making a copy of the template files provided where you will be able to enter your own numbers and explore your own assumptions.\n",
        "</span>"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a289fed6-6b3b-4fd6-9943-f620e1334cf9",
      "metadata": {},
      "source": [
        "# Tutorial - Using the case of Kim and Sam"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "355ed178",
      "metadata": {},
      "source": [
        "## Introduction\n",
        "This file is provided as an example to introduce you to Owl.\n",
        "\n",
        "It is assumed that you have some familiarity with using a jupyter notebook or jupyterLab, and some basic programming skills in Python. If not, a simple tutorial can guide you to the basic skills needed.\n",
        "\n",
        "For simulating your own realizations, use the files beginning with *template*. Make a copy and rename them keeping the same extension and give them your own names. Then you'll be able to personalize a case with your own numbers and start experimenting with Owl."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c2939c06-b407-48fb-91d7-560cd96d5206",
      "metadata": {},
      "source": [
        "This notebook is an empty template of a ficticious couple Kim and Sam used for demonstration."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4f1fd7ca",
      "metadata": {},
      "source": [
        "### Just some Python module bookkeeping\n",
        "This command needs to be at the beginning of every Owl notebook."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "3d37c241-356c-48c3-882b-8db71917a3c2",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Include if owlplanner not installed as a package.\n",
        "import sys\n",
        "sys.path.insert(0, \"../src\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "7744b67b",
      "metadata": {},
      "outputs": [],
      "source": [
        "import owlplanner as owl"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "d2d87b7e",
      "metadata": {},
      "source": [
        "## Initializing the life parameters for the realization\n",
        "In order to be able to generate a realization of the future, one must start with providing the year of birth of each spouse(s) and their expected lifespan(s).\n",
        "\n",
        "For selecting your own numbers, there are plenty of longevity predictors on the web. Pick your favorite:\n",
        "\n",
        "https://longevityillustrator.org\n",
        "\n",
        "https://www.livingto100.com/calculator\n",
        "\n",
        "https://www.sunlife.ca/en/tools-and-resources/tools-and-calculators/life-expectancy-calculator/\n",
        "\n",
        "or just Google life expectancy calculator.\n",
        "\n",
        "There are two values needed for couples. Single individuals just enter one value in each list between square brackets `[ ]`. For couples, always keep the same order in the pair of values when entering the data.\n",
        "\n",
        "When first creating a plan, the default values used for asset allocation ratios and rates of return will be reported. These values are listed to make you aware that these values would be used if no other choice is entered. We will cover how to do this in the next sections."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f2f8cd2e-9095-4850-8e3e-ac822516781e",
      "metadata": {},
      "source": [
        "**Enter your name(s), year(s) of birth, life expectancy(ies), and name for the plan.**"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "760e4a8e",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan = owl.Plan(['Kim', 'Sam'], ['YYYY-MM-DD', 'YYYY-MM-DD'], [AA, AA], 'Kim+Sam-spending', verbose=True)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "47f309e7-0654-4f75-87b5-921167db4a6a",
      "metadata": {},
      "source": [
        "## Specify account balances\n",
        "For each spouse, savings accounts have three buckets comprising of the total value of:\n",
        "- Individual **taxable** investment or savings accounts, including bank accounts, and CDs - do not include your safety net account which should typically be sufficient for sustaining 6 months of living expenses;\n",
        "- **Tax-deferred** savings accounts, including all IRAs, 401k, 403b, etc.;\n",
        "- **Tax-free** savings accounts, including Roth IRAs and Roth 401k.\n",
        "\n",
        "For married couples, each spouse will have to enter values for each type of savings account, following the same order as before. For single individuals, only one value is needed between square brackets `[ ]`.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6ea4c5dc-f88d-47c5-a1ec-3474d023bf23",
      "metadata": {},
      "source": [
        "You can use the `units` optional keyword to indicate that the numbers are entered in other units, such as dollars (`1`) or millions (`M`). Notice that being in Python, arithmetic can be used while entering numbers.\n",
        "\n",
        "**Enter you account balances for each spouse here.**"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "aa9b0109",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.setAccountBalances(\n",
        "    taxable=[XX, XX],\n",
        "    taxDeferred=[XX, XX],\n",
        "    taxFree=[XX, XX],\n",
        "    startDate='01-01',\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "034559d1-3392-42b6-b666-9e858feb1ae4",
      "metadata": {},
      "source": [
        "Most investment accounts have named beneficiaries. The *beneficiary* values specify the fraction of total of assets left to the other spouse at death. For example, a spouse leaving 3/4 of her fortune to her three children and the other part to her partner would have a beneficiary value of 0.25.\n",
        "\n",
        "Benificiary fractions are entered as [1, 1, 1], i.e., one for each type of account. Default is to leave everything to the living spouse."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "090914eb-78f3-4e85-bdc9-e7fa03b75aaf",
      "metadata": {},
      "source": [
        "By default, the account balances are assumed to be known as of today, and amounts will be back projected to Jan 1st using the assumed return rates. An arbitrary date can be chosen as a reference point in the current year, using the optional parameter startDate. For example, using startDate='01-01' would select January 1st, the beginning of the year. This is useful for reproducibility studies. Here is an example:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "49109e26-bea3-49df-8377-3343111ebfac",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.setAccountBalances(\n",
        "    taxable=[XX, XX],\n",
        "    taxDeferred=[XX, XX],\n",
        "    taxFree=[XX, XX],\n",
        "    startDate=\"01-01\"\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "43047edc-a21f-44bc-a89c-2383f1d6b2a9",
      "metadata": {},
      "outputs": [],
      "source": [
        "# plan.setBeneficiaryFractions([1, 1, 1])"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "de5a5c3f-bfad-4d95-a8ae-1d4f3d37661d",
      "metadata": {},
      "source": [
        "## There must be a plan for wages, savings, and Roth conversions\n",
        "The most manageable part of retirement planning is the control one has over work income, contributions to savings accounts, Roth conversions, and other big spending items in the near- and mid-term future.\n",
        "In order to execute a realization, one must provide an earning, saving, and Roth conversion plan. This is done through providing an Excel workbook with one spreadsheet (tab) per spouse with the following information:\n",
        "\n",
        "|year|anticipated wages|other inc|taxable ctrb| 401k ctrb | Roth 401k ctrb | IRA ctrb | Roth IRA ctrb | Roth conv | big-ticket items|\n",
        "|--|--|--|--|--|--|--|--|--|--|\n",
        "|2024 | | | | | | | | | |\n",
        "|2025 | | | | | | | | | |\n",
        "| ... | | | | | | | | | |\n",
        "|20XX | | | | | | | | | |\n",
        "\n",
        "Here, 20XX is the last row which could be the last year based on the life expectancy values provided. Missing years will be filled with empty values. For the columns, *anticipated wages* is the annual amount (gross minus tax-deferred contributions) that you anticipate to receive from employment or other sources (not including dividends from your taxable investment accounts). Note that column names are case sensitive and all of these entries must be in lower case. Best way to start this process is to use the template provided rightly named *template.xlsx*.\n",
        "\n",
        "For the purpose of this exercise, there is no clear definition of retirement age. There will be a year, however, from which you will stop having anticipated income, or diminished income due to decreasing your work load. This transition can be gradual or sudden. Therefore there is no need to enter a retirement age for the sole purpose of quantifying your financial future.\n",
        "\n",
        "Contributions to your savings accounts are marked as *ctrb*. Contributions to your 401k must also include your employer's contributions, if any. As this file is in Excel, one can use the native calculator to enter a percentage of the anticipated wages for contributions as this can sometimes be easier. Considering a specific example, assume that Jack earns 100k\\\\$ and contributes 5% to his 401k which his employer matches at up to 4%, then Jack's anticipated wages will be $(1-.05)*100000 = 95000$ and his 401k contributions will be $.09/(1 - .05) * 95000 = 9000 $. \n",
        "\n",
        "Roth conversion are specified in the column marked *Roth conv*. Roth conversion are typically performed in the years when the income is lower (and therefore lower tax rates), typically in the bridge years between having a full-time regular salary and collecting social security. This column is provided to override the Roth conversion optimization in Owl. When the solver is given the option `maxConversion='file'`, then these values will be used and no optimization over Roth conversions will be performed. This column is provided for flexibility and allowing comparisons.\n",
        "\n",
        "Finally, *big-ticket items* are used for accounting for the sale or purchase of a house, or any other major expense or money that you would give or receive (e.g., inheritance, or large gifts to or from you). Therefore, the sign (+/-) of entries in this column is important. Positive numbers will be considered in the cash flow for the year and surplus will be deposited in taxable savings accounts. Negative numbers will generate withdrawals and distributions from retirement accounts. This is the only column that can contain negative numbers: all other column entries should be positive.\n",
        "\n",
        "The tab name for each spreadsheet represents the name of the spouse for reporting yearly transactions affecting the plan. There has to be one tab for each individual and bearing the same name. Therefore, you need to rename these tabs to have the same names as those used to create the plan (i.e., *Jack* and *Jill* in this case).\n",
        "\n",
        "Note that the (free) LibreOffice software can be used if you do not have an Excel license, as LibreOffice can read and save `.xlsx` files. Moreover, the native file format from the LibreOffice software can also be read directly. However, you will have to install the `odfpy` package through `conda install conda-forge::odfpy` first."
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4b849a5f-7925-438d-a5c7-15130de43e09",
      "metadata": {},
      "source": [
        "**Change file name from template to your own Excel worksheet. Copy template.xlsx as a starting example.**"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "7748bcf1",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.readHFP('../examples/HFP_template.xlsx')"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6ea1d7ff",
      "metadata": {},
      "source": [
        "## What are the current and future asset allocations?\n",
        "Each savings account can invest in 4 major classes of assets:\n",
        "- Equity funds tracking the S&P 500 index;\n",
        "- Bond assets tracking the Corporate bonds (Baa) index;\n",
        "- Fixed-income securities represented by the performance of 10-year Treasury notes;\n",
        "- Inflation-indexed securities tracking the urban Consumer Price Index (common assets).\n",
        "\n",
        "The total of percentages in each class of assets for each savings account must add to 100%.\n",
        "\n",
        "You are asked to provide asset allocation ratios for today, and ones for the time at the end of your life.\n",
        "Values in between will be interpolated using a linear operator by default. This can be useful\n",
        "if you want to shift asset allocation as you age. One can also select an *S* curve for transitioning\n",
        "from the initial value to the final value. This is done by choosing *s-curve* instead of *linear* as the method for interpolation. *S-curve* take two additional parameters, the *center* of the change which defaults to 15 years from now, and the *width* which defaults to 5 years. These parameters will induce\n",
        "a gradual change from the initial allocations now, starting to change in 10 years (15 - 5), and converging to final allocations in 20 years (15 + 5). \n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "eecc3b25-ae80-4e6a-be38-1f3c66a46899",
      "metadata": {},
      "source": [
        "**Use 'linear' or 's-curve' interpolation.**\n",
        "\n",
        "**Enter your desired asset allocations over the span of the plan.**\n",
        "\n",
        "Percentages need to add up to 100%."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "ac78169f",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.setInterpolationMethod('s-curve')\n",
        "plan.setAllocationRatios(\n",
        "    'individual',\n",
        "    generic=[[[60, 40, 0, 0], [70, 30, 0, 0]], [[60, 40, 0, 0], [70, 30, 0, 0]]]\n",
        "  )"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "79299f3e-1b88-4263-9755-082821538509",
      "metadata": {},
      "source": [
        "### Show asset allocations during the time period\n",
        "The allocation of assets is shown for the three types of savings accounts (taxable, tax-deferred, and tax-free) for each spouse and for the 4 types of investments: stocks (S&P 500), corporate bonds (Baa), Treasury notes (10-y), and common assets tracking inflation."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "8afa2e05-50b1-485f-ba6b-a330bf2dac10",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.showAllocations()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8dbdb068",
      "metadata": {},
      "source": [
        "## What about anticipated fixed income?\n",
        "Pension and social security are fixed income. Pension income can be adjusted for inflation as social security benefits are. Numbers to be provided are the predicted annual amount for each spouse and the age of the commencement of benefits.\n",
        "\n",
        "By default, no pension benefits are assumed. This can also be specified explicitly by entering zeros (0) as entries, as in\n",
        "\n",
        "    plan.setPension([0, 0], [65, 65], [False, False])\n",
        "    \n",
        "For social security, one must provide the predicted monthly Primary Insurance Amount(s) and the starting age(s) at which benefits are anticipated to be received. There are plenty of social security benefit estimators on the web, including the info you can get directly from your own account at the Social Security Administration (ssa.gov). Another interesting calculator can be found at www.opensocialsecurity.com. This calculator allows you to compare different scenarios regarding your commencement age through a sensitivity plot.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "43bd9a2a-e2bf-434f-88ac-b0a70dcdd1fd",
      "metadata": {},
      "source": [
        "**Enter your anticipated social security benefits, and age of benefits.**"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "8c6e5ac9",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.setPension([XX, XX], [AA, AA])\n",
        "plan.setSocialSecurity([XX, XX], [AA, AA])"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "632049cd-dbd4-49da-89bd-06e011c063fc",
      "metadata": {},
      "source": [
        "## How much net income is desirable at retirement?\n",
        "For determining the desirable annual net income in retirement, certified planners will strongly suggest that you've must have already done a cash flow analysis on your yearly spending. After this exercise, you should have a good idea of how much you'll need in retirement. Another approach is to experiment with multiple spending scenarios and see what your current and future savings can sustain under different market conditions. As one nears retirement, both approaches will need to meet at one point.\n",
        "\n",
        "The desired income defined here is the minimum annual **net** income (i.e., after paying federal income tax) that one would like to receive starting at her/his \"retirement age\" (we provided a loose definition of the term *retirement age* above). This desired income must be adjusted for inflation and can follow an additional adjustment called a *smile* profile. A *smile* profile accounts for the fact that your spending capacity will modulate during retirement as you go from the so-called gogo years to the no-go years. A *flat* profile, on the other hand, will keep the same value, which will only be adjusted for inflation. More realistically, the income could also be modulated by the performance of assets, reducing withdrawals in market down years. These strategies (first proposed by Guyton and Klinger) could be implemented in Owl. \n",
        "\n",
        "A second optional argument can be provided to specify the fraction of income left the the survivor. The default is 60%.\n",
        "\n",
        "The target and actual net income values achieved through the realization can be plotted as will see below.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e253e7c4-9767-411a-bc55-e151c6060b80",
      "metadata": {},
      "source": [
        "**Use a *smile* curve or a *flat* line.**"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "67a8087a",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.setSpendingProfile('smile')\n",
        "plan.showProfile()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "11b572a8-2b93-428d-b121-3dc793cedb79",
      "metadata": {},
      "source": [
        "## Specify rates of return and inflation rate\n",
        "Rates of return for each class of assets can be specified, including the rate of inflation.\n",
        "These are important components for  future assumptions.\n",
        "Setting future rates is done with the `setRates()` method from which one can select different\n",
        "sources for determining the rates.\n",
        "Valid choices are *historical*, *histochastic*, *historical average*, *user*, *conservative*, *stochastic*, or *default*.\n",
        "\n",
        "For the *optimistic* case, values reported from MorningStar for the next ten years are used. It is selected by using this call:\n",
        "\n",
        "    plan.setRates('optimistic')\n",
        "\n",
        "*Conservative* rates are lower than the last ten years as most analysts are predicting lower rates from the next decade. These values are fixed rates of 6.0% for the S&P 500, 4.0% for the Corporate bonds markets, 3.5% for the 10-year Treasury notes, with an inflation at around 2.8%. Using these conservative rates can be achieved by using the following call:\n",
        "\n",
        "    plan.setRates('conservative')\n",
        "\n",
        "For the *historical*, *histochastic*, and *historical average* options, data from 1928 to the last year are available for experimenting.\n",
        "Ranges chosen smaller than the life horizon of the longest-lived individual will have rate values repeated in cycle. For example,\n",
        "choosing historical data from 1994 to (up and including) 1996 will repeat these three values over the time span of the realization.\n",
        "This would be called as follows:\n",
        "\n",
        "    plan.setRates('historical', 1994, 1996)\n",
        "\n",
        "This case is only provided as an explanatory example, as it would have little practical value.\n",
        "\n",
        "If the upper bound is not provided as the third argument, then the latest data year (i.e., last year) will be assumed by default.\n",
        "If one chooses a historical range starting from 1970, Owl will use the rates of 1970 for this year and 1971 for next, etc. This would be simulated as follows:\n",
        "\n",
        "    plan.setRates('historical', 1970)\n",
        "  \n",
        "Due to its particular sequence of rates, the worst-case historical scenario is a retirement starting in 1966. This can be simulated as follows:\n",
        "\n",
        "    plan.setRates('historical', 1966)\n",
        "\n",
        "In this case, the  current year will have the same rates as those that happened in 1966, and next year will have those from 1967, and so on. This choice is given for instructional purposes only. No one should make a plan based on the worst-case historical scenario. Nevertheless, it can be informative to test your own case. In practice, however, a success rate larger than 90% over a reasonable set of historical starting years and market assumptions would be acceptable by a large portion of rational thinkers. But this is all a personal choice. We'll cover how to model multiple starting years below.\n",
        "\n",
        "Alternatively, one can choose a *histochastic* approach in which case the rates are determined from the multivariate distribution for the 4 rates in the selected year range.  The computed statistical distribution of the selected range of data is used to generate random rate values. For example,\n",
        "\n",
        "    plan.setRates('histochastic', 1945)\n",
        "    \n",
        "will analyze the annual rates from 1945 up to last-year and compute means and covariance to generate new data that are statistically representative of the ones observed during this selected time period. The rates randomly generated for the time span can be plotted and examined as we will see below. Similarly,\n",
        "\n",
        "    plan.setRates('histochastic', 1940, 1970)\n",
        "\n",
        "would generate random rates consistent to those observed during the 1940 - 1970 time period.\n",
        "\n",
        "Rates can also be generated stochastically by choosing the *stochastic* option.\n",
        "In its simplest case, mean values, and standard deviations (volatility) need to be provided (in percent) as follows:\n",
        "\n",
        "    my_means = [8, 5, 4, 3]\n",
        "    my_stdev = [17, 8, 8, 2]\n",
        "    p.setRates('stochastic', values=my_means, stdev=my_stdev)\n",
        "    \n",
        "Here, we select 8% return on S&P 500 with 17% volatility, 5% return on corporate bonds and and 4% on T-notes, both with 8% volatility, and 3% inflation with 2% of volatility.\n",
        "\n",
        "Called as shown will assume that there is no correlation between rates of return (in mathematical terms,\n",
        "the correlation matrix defaults to the identity matrix). However, we know that rates are somehow correlated (i.e., when the inflation goes up, returns on bonds tend to go down). To account for this coupling, we\n",
        "can either provide a correlation matrix as here:\n",
        "    \n",
        "    my_means = [8, 5, 4, 3]\n",
        "    my_stdev = [17, 8, 8, 2]\n",
        "    my_corr = [[1, 0.46, 0.06, -.12], [0.46, 1, 0.68, -.27], [0.06, 0.68, 1, -.21], [-.12, -.27, -.21, 1]]\n",
        "    p.setRates('stochastic', values=my_means, stdev=my_stdev, corr=offdiag_corr)\n",
        "\n",
        "or, as the correlation matrix is symmetric, just provide the 6 off-diagonal elements as shown here:\n",
        "\n",
        "    my_means = [8, 5, 4, 3]\n",
        "    my_stdev = [17, 8, 8, 2]\n",
        "    offdiag_corr = [.46, .06, -.12, .68, -.27, -.21]\n",
        "    p.setRates('stochastic', values=my_means, stdev=my_stdev, corr=offdiag_corr)\n",
        "\n",
        "In standard matrix notation, the off-diagonal elements of correlation matrix $C$ are $c_{12}, c_{13}, c_{14}, c_{23}, c_{24}, c_{34}$. As $c_{ii} = 1$ and $C$ is symmetric, it can easily be reconstructed by Owl.\n",
        "\n",
        "To get an idea of what to expect as correlations, one can use the `getRatesDistributions(from, to)` over a range of\n",
        "years of historical data as follows:\n",
        "\n",
        "    means, stdev, corr, covar = owl.getRatesDistributions(1970, 2019)\n",
        "\n",
        "This call will analyze the data over the year range and report back on the statistical correlations found.\n",
        "\n",
        "Rates can also be set to fixed values obtained from an average over a time interval using the *historical average* option. For example, the call\n",
        "\n",
        "    plan.setRates('historical average', 1990, 2020)\n",
        "\n",
        "would set the rates to constant values being the average observed from 1990 to 2020 inclusively.\n",
        "    \n",
        "Finally one can also use fixed annual rates by providing a list of 4 entries in percent as follows:\n",
        "\n",
        "    myrates = [9.6, 4.0, 3.0, 3.8]\n",
        "    plan.setRates('user', values=myrates)\n",
        "    \n",
        "This example would use fixed rates of 9.6%, 4.0%, 3.0%, and 3.8% as average annual returns on S&P 500, corporate bonds, Treasury notes, and common assets, respectively, with an average annual inflation rate of 3.8% for the full duration of the time simulation. Recall that the common assets class consists of investments tracking inflation only. Therefore the last index serves both to track the common asset class and to adjust values for inflation.\n",
        "\n",
        "Also note that the S&P 500 rates provided always include dividends, which are assumed to be reinvested.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4f9074e2-84fa-4498-9e91-a67f4d21d9fb",
      "metadata": {},
      "source": [
        "**Pick the rates you would like to use.**"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "b53ff01e",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.setRates('historical', 1969)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2785e1c5",
      "metadata": {},
      "source": [
        "#### Show annual rates used for calculations\n",
        "As described above, there are many choices for selecting rates. This graph will display the annual rates used during the time span of this realization. Numbers between <> are the average over the period considered."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "81cec974",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.showRates()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e3955ac2-6ff5-483c-b0e9-f1e8dccd18b0",
      "metadata": {},
      "source": [
        "##### Show historical rate distribution\n",
        "Since Owl has the historical rates available, one can also display their histograms using a simple function call. This is done with `owl.showRatesDistributions()`.\n",
        "\n",
        "Given the standard deviation of each histogram, the risk/benefit between stocks and bonds is clear. Let's look at the rates distribution over the 30-year period running from 1969 to 1999. Notice how high is the average inflation."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "73defc19-8df4-48cc-b27e-4320a49fa07f",
      "metadata": {},
      "outputs": [],
      "source": [
        "means, stdev, corr, covar = owl.getRatesDistributions(1969, 1999)\n",
        "owl.showRatesDistributions(1969, 1999)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "66f25114",
      "metadata": {},
      "source": [
        "When *stochastic* or *histochastic* rates are used, the distributions and correlations betwen the different rates can be displayed by using the following method, (which can optionally share the same percentage range across all investments): "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "a3d2ee89",
      "metadata": {},
      "outputs": [],
      "source": [
        "# plan.showRatesCorrelations(shareRange=False)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "29544a7d-4b18-4fae-a746-93a4b6c170b3",
      "metadata": {},
      "source": [
        "### Other configurable parameters\n",
        "There are a few more parameters that can be configured. The following calls are provided as examples. If not specified, the default values are:\n",
        "- Heirs marginal tax rate: 30%\n",
        "- Dividend return rate on equities: 2%\n",
        "- Ability to have graphs plots by default in *nominal* values or *today*'s dollars.\n",
        "  \n",
        "These function calls are provided for reference with their default values."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "ce0b2cde-9806-4d47-ab12-81597dbdb381",
      "metadata": {},
      "outputs": [],
      "source": [
        "# plan.setHeirsTaxRate(30)\n",
        "# plan.setDividendRate(2)\n",
        "# plan.setDefaultPlots('nominal')"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c1c97249",
      "metadata": {},
      "source": [
        "## Generating the outcome of a scenario\n",
        "We're now ready to run a single instance of a scenario. "
      ]
    },
    {
      "cell_type": "markdown",
      "id": "ae05b3e9-3d36-4254-bd70-6d3db25f5a54",
      "metadata": {},
      "source": [
        "### Maximum net income\n",
        "The following function call runs all the required calculations for the time horizon over your life expectancy. The function `solve()` will optimize the selected scenario using linear programming. But we first need to select what needs to be optimized by passing options. If one individual, say 'Jane' cannot perform Roth conversions, it can be specified as:\n",
        "```python\n",
        "'noRothConversions': 'Jane'\n",
        "```\n",
        "If no Roth conversion is desired for both individuals:\n",
        "```python\n",
        "'maxRothConversion': 0\n",
        "```\n",
        "\n",
        "**Pick your objective function and related parameters.**"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "daf25c7b-f24c-4616-8678-649fc99b53cb",
      "metadata": {},
      "outputs": [],
      "source": [
        "options = {'maxRothConversion': XX, 'bequest': XX}\n",
        "plan.solve('maxSpending', options=options)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "fb8f5600",
      "metadata": {},
      "source": [
        "### Analysis"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "0bfe0dbd",
      "metadata": {},
      "source": [
        "#### Show net spending compared to target income over the years\n",
        "This graph shows how the actual net income generated by the plan realization matches the inflation-adjusted net income profile specified. Note the 40% drop in target income as one spouse passes. This drop is configurable through the `setProfile()` method. Default value is 60%."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "b6dffb3f",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.showNetSpending()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7073892b-193b-4bb2-a8c1-fa36bddd5979",
      "metadata": {},
      "source": [
        "Each plot can be called with the `value` parameter set to *nominal* or *today*, resulting in a graph that accounts for inflation or not."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "26bf683d-1f80-485c-8391-f53f6ca970fa",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.showNetIncome(value='today')"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8123cbc2",
      "metadata": {},
      "source": [
        "#### Show taxable ordinary annual income and anticipated tax brackets\n",
        "Gross income also includes Roth conversions and big-ticket items, both of which are not contributing to your net income. This graph shows Jack and Jill's gross taxable income and how it compare with some anticipated Federal tax marginal brackets. This visualization is very convenient when one wants to perform Roth conversions and remain below a certain tax bracket.\n",
        "\n",
        "Note the shift in tax brackets taking place as the Tax Cut and Job Act expires after 2025."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "2e305502",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.showGrossIncome()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1fad7e21",
      "metadata": {},
      "source": [
        "#### Show annual taxes paid over the years of the realization\n",
        "This graph shows how much Jack and Jill paid in federal taxes over the years of this realization."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "a95dad48",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.showTaxes()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "460f5547",
      "metadata": {},
      "source": [
        "#### Show sources of income over the years\n",
        "Income will typically come from multiple sources, and it can be quite complex. This graphs shows the breakdown of Jack and Jill's sources of income by spouse and by origin. Note that distributions from tax-deferred accounts (*dist*) are distinguished from required minimum distributions (*rmd*) as they serve different purposes. Other labels should be self-explanatory."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "f74ec825",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.showSources()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8d997ff3",
      "metadata": {},
      "source": [
        "#### Show savings accounts balances at the beginning of each year\n",
        "The balance for each savings account for each spouse is calculated at the beginning of each year. Another important aspect of this graph is how much is left at the end of the realization. This will be addressed in the next cell."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "6b9a9e62",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.showAccounts()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "8ae26e4d",
      "metadata": {},
      "source": [
        "To get more information about accounts at the last year of the realization, one can use\n",
        "\n",
        "      plan.summary()\n",
        "    \n",
        "which returns the value of the assets in today's \\\\$ at the last year of the scenario, assuming (in this case) a 30\\% tax burden on the taxable portion of the estate (read tax-deferred savings accounts). The `summary()` function returns two values: the total post-tax value of all savings account in today's dollars and the cumulative inflation rate between today and the last day of the realization."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "eedb9d78",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9231c810-31db-45aa-98f1-6632f717d375",
      "metadata": {},
      "source": [
        "#### Can we save this realization?\n",
        "This instance of a future realization contains information on the distribution amounts, including the required minimum distribution that had to be performed under the given assumptions. This info can be saved in an excel workbook with one spreadsheet (tab) for each spouse. Worksheet will also contain annual rates, income, income taxes, and account balances. The argument overwrite as `True/False` controls if existing file, if any, gets overwritten. Also remember that Windows will not allow the file to be overwritten while the file is being opened in Excel. In that case, the script will ask you to close the file and will retry to save.\n",
        "\n",
        "This call will save the results from the last optimization, i.e., maxSpending.\n",
        "\n",
        "Open the file in Excel to see what it looks like."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "733f2277-9a2c-4aa8-9cb4-4b7feb896248",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.saveWorkbook(overwrite=True)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "70386bcb-b523-4034-bfcd-d775c69fe8a7",
      "metadata": {},
      "source": [
        "## Maximum bequest\n",
        "Alternatively, one could optimize for maximum bequest subject to a net income constraint.\n",
        "\n",
        "**Pick your parameters.**"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "20163487",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.rename('Kim+Sam-bequest')\n",
        "options = {'maxRothConversion': XX, 'netSpending': XX}\n",
        "plan.solve('maxBequest', options=options)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2347b6eb-da42-41a4-935e-78184f62db1c",
      "metadata": {},
      "source": [
        "#### Analysis"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "3d103f90-220f-487a-8b78-28f8b076cce8",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.showNetSpending()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "0d94cef1-b510-4dc6-a230-7ac81c02ca1c",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.showGrossIncome()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "236cbeca-db62-427a-9556-d86203fe9279",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.showTaxes()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "83b5687d-b21e-4766-95a7-9ef40bba404e",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.showSources()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "10124314-e0e7-4f37-a297-9a5011fb4fa1",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.showAccounts()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "77a30382-cd0d-4e5d-b593-6d25faba41e5",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "96d1dd05",
      "metadata": {},
      "source": [
        "### Can we save this realization?\n",
        "This instance of a future realization contains information on the distribution amounts, including the required minimum distribution that had to be performed under the given assumptions. This info can be saved in an excel workbook with one spreadsheet (tab) for each spouse. Worksheet will also contain annual rates, income, income taxes, and account balances. Second `True/False` argument controls if existing files get overwritten. Also remember that Windows will not allow the file to be overwritten while the file is being opened in Excel. In that case, the script will ask you to close the file and will retry to save.\n",
        "\n",
        "This call will save the results from the last optimization, i.e., maxBequest."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "7e25fdb7",
      "metadata": {},
      "outputs": [],
      "source": [
        "plan.saveWorkbook(True)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "79c42562-575a-4c7b-8b75-ebc61f053562",
      "metadata": {},
      "source": [
        "This notebook is provided as a basic example on what you can do to assess the robustness and sensitivity of your retirement strategy. Go and explore!\n",
        "\n",
        "\n",
        "Enjoy!\n"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3 (ipykernel)",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.12.7"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
