{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "05fad639-5e11-4b6c-8911-0707768ac8ad",
   "metadata": {},
   "source": [
    "# Owl\n",
    "## A Retirement Planning Laboratory"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e98ec63-fce8-4098-8179-2d597bfb4c2e",
   "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": "01e6c7da-cd31-41de-9b67-e493ae77dea8",
   "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": "f65fbb58-4975-4a0a-beae-bff23f484b66",
   "metadata": {},
   "source": [
    "# Tutorial 3 - Exploring beneficiary fractions using the case of Jack and Jill\n",
    "This tutorial shows how to use advanced capabilities of Owl such as Monte Carlo simulations and running simulations over a historical range. We use both these capabilities to explore the effects of beneficiary fractions on *maxSpending* and *maxBequest* optimizations. We use a similar case as the one used in Tutorials 1 and 2 and introduce more of Owl's modeling capabilities. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6df2872d-93b6-47cf-9a7d-667c44901054",
   "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": "43cf8145-7f11-4074-a95f-e26220776c37",
   "metadata": {},
   "outputs": [],
   "source": [
    "# If not installing owlplanner as a module\n",
    "import sys\n",
    "sys.path.insert(0, \"../src\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "63c9604f-4e6e-4e72-93d7-cdb5788d81d5",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "import owlplanner as owl"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a1033e24-bfab-47d1-9083-e8cf739b086f",
   "metadata": {},
   "source": [
    "### Creating the plan (see tutorial 1 for details)\n",
    "We first create a plan as we did in the *Tutorial 1*. We removed the comments for reducing the clutter."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "39121d7a",
   "metadata": {},
   "outputs": [],
   "source": [
    "plan = owl.Plan(['Jack', 'Jill'], ['1962-01-15', '1965-01-16'], [89, 92], 'jack+jill-tutorial3', verbose=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ee55774b-6f33-49fa-ae5c-85d2d466e026",
   "metadata": {},
   "outputs": [],
   "source": [
    "plan.setAccountBalances(\n",
    "    taxable=[90.5, 60],\n",
    "    taxDeferred=[600.2, 150],\n",
    "    taxFree=[50 + 20.6, 40.8],\n",
    "    startDate='01-01',\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3e1ac651-ef61-47c1-9d2e-c47a0475e807",
   "metadata": {},
   "outputs": [],
   "source": [
    "plan.readHFP('../examples/HFP_jack+jill.xlsx')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "747f1a39-501e-4560-b856-b838720289fe",
   "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",
    ")\n",
    "# plan.showAllocations()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "435a0599-accb-42cd-a1c2-382b97383626",
   "metadata": {},
   "outputs": [],
   "source": [
    "plan.setPension([0, 10], [65, 65])\n",
    "plan.setSocialSecurity([2333, 2083], [70, 70])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0b622cd0-f176-4a2f-8470-a0b457294e87",
   "metadata": {},
   "outputs": [],
   "source": [
    "plan.setSpendingProfile('smile', 60)\n",
    "# plan.showProfile()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c5a0abcc-f8f5-4e23-b9d4-78d059f656b9",
   "metadata": {},
   "source": [
    "### Setting the heirs tax rate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eacb5bc8-aca8-481a-9991-6aa494b493a0",
   "metadata": {},
   "outputs": [],
   "source": [
    "plan.setHeirsTaxRate(33)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2a3d15e8-d86a-4d66-b362-2c8017551e73",
   "metadata": {},
   "source": [
    "### Introducing partial spousal bequest\n",
    "In some instances, the first spouse to pass can leave a fraction of her/his assets to the surviving spouse. Jack decides to give part of his assets to his children and leaves 25% of the value of his savings accounts to his surviving spouse. When not specified, default values are `[1, 1, 1]`. Changing the beneficiary fractions is done as follows. There is one value for each type of accounts: taxable, tax-deferred, and tax-free accounts."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "87ed21dd-a6e9-468a-9576-89e184bf84ef",
   "metadata": {},
   "outputs": [],
   "source": [
    "plan.setBeneficiaryFractions([0.25, 0.25, 0.25])\n",
    "plan.setSpousalDepositFraction(0)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9f8e040d-2dc8-48c7-89f7-b242ee1a5b17",
   "metadata": {},
   "source": [
    "### Running a single case\n",
    "We first run a single case with static *conservative* rates.\n",
    "Jack and Jill desire to leave a final bequest of \\\\$200k (in today's \\\\$), leaving some security for Jill's last years. We also limit Roth conversions to a maximum of \\\\$100k for Jack and none for Jill, similar to the case we ran in Tutorials 1 and 2."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "362f8e42-2e25-445c-8a93-c81da122d4fc",
   "metadata": {},
   "outputs": [],
   "source": [
    "plan.setRates('conservative')\n",
    "options = {'maxRothConversion': 100, 'noRothConversions': 'Jill'}\n",
    "# options['solver'] = 'MOSEK'\n",
    "options['bequest'] = 200\n",
    "plan.solve('maxSpending', options);\n",
    "plan.summary()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5812b5c8-bc0d-4d7e-95df-b84908800430",
   "metadata": {},
   "source": [
    "Looking at savings accounts, notice the drop in value taking place as Jack splits his bequest between his spouse and his children in 2051."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3f4834a1-240e-4b5a-8c87-b1764333fdba",
   "metadata": {},
   "outputs": [],
   "source": [
    "plan.showAccounts()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ec690bc0-cfba-4b4d-a11d-a8fd740346c1",
   "metadata": {},
   "source": [
    "### Running Monte Carlo simulations\n",
    "Before running Monte Carlo simulations, we need to configure a stochastic rate-generating method as explained in Tutorial 2. We will use a relatively conservative return projection of 8% +/- 17% for the S&P 500 and 5% +/ 8% for bonds, with 3% +/- 2% for the inflation. We use correlations derived from historical values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "726966bd-be52-464e-81a5-ac1b9323fcec",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Mean returns\n",
    "my_means = [8, 4, 4, 3]\n",
    "# Volatility\n",
    "my_stdev = [17, 8, 8, 2]\n",
    "# Correlations matrix between rates of return of different assets\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",
    "# These are only the off-diagonal elements\n",
    "offdiag_corr = [.46, .06, -.12, .68, -.27, -.21]\n",
    "plan.setRates('stochastic', values=my_means, stdev=my_stdev, corr=offdiag_corr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cce791e5-1dd6-4b4b-9997-cb8430900034",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Display a single instance resulting from this choice.\n",
    "# plan.showRatesCorrelations(shareRange=False)\n",
    "# plan.showRates()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ec99f081-a999-4452-87f2-572c85158643",
   "metadata": {},
   "source": [
    "### Preparing the case to run\n",
    "We now run many of those cases using the `runMC()` method. We repeat here the options used above for completeness.\n",
    "\n",
    "When setting beneficiary fractions to less than unity, the `runMC()` and `runHistoricalRange()` methods will also report a histogram of the after-tax value of the non-spousal part of the bequest made at the passing of the first spouse.\n",
    "\n",
    "What are these cases telling us? Let's look at the specific example at hand."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "856cdfb8-0472-475f-afa9-5dae92f1a52d",
   "metadata": {},
   "outputs": [],
   "source": [
    "options = {'maxRothConversion': 100, 'noRothConversions': 'Jill'}\n",
    "options['solver'] = 'MOSEK'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ede7fa05-8a6e-41b4-8b7c-a217d28ad41b",
   "metadata": {},
   "outputs": [],
   "source": [
    "options['bequest'] = 200\n",
    "plan.runMC('maxSpending', options, 500);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8553d877-c44c-43f0-a015-9055f7d76e25",
   "metadata": {},
   "source": [
    "*Partial* is the post-tax partial bequest left to individuals others than Jill at the passing of Jack, in that case, Jack's children. The range of values obtained in solutions is also reported as well as the number of solutions with 0 as an answer. The amount that Jack leaves to his children can vary from \\\\$0 to about \\\\$1 M, and shows the largest variability, explaining the large difference between the median and the average. Mean values are indicated by $\\bar{x}$. What strikes here the the number of solutions which have Jack's account depleted. We will discuss these cases.\n",
    "\n",
    "Almost all cases are successful at leaving a \\\\$200k final bequest, but the net spending required for achieving this constraint can lead to small values in some scenarios. However, the median value $M$ for net spending is about \\\\$88k, very close to the \\\\$90k desired by Jack and Jill. Recall that we are using a more conservative return of 8%, with a volatility of 17% for the S&P 500. It is therefore natural that the number we find here is slightly lower than what the historical returns of the market have been observed to provide. Some of these scenarios will yield more than the median, but some others will require a net spending of less than \\\\$50k. All these scenarios make a probability of close to 100\\% for leaving a \\\\$200k bequest at Jill's passing as requested. This is in addition to a median of about \\\\$20k left at Jack's passing. We can see that the mean value left by Jack to his children is around \\\\$130k while the median is much lower, due to many scenarios depleting Jack's account at his passing. What is to note is that several scenarios deplete Jack's account to reduce the partial bequest in view of maximizing the net spending. This is the action of the optimization working to maximize its objective function, which  is the net spending in this particular case. That is, the optimizer will select scenarios where the net spending will be increased at the expense of decreasing the partial bequest. What can potentially still hold money in Jack's account and allow to provide a partial bequest is the restriction imposed by satisfying a certain spending profile which limits the depletion of the accounts. That is, more gains can be realized in certain scenarios that the ability to spend.\n",
    "\n",
    "The probability of success might be misleading here as this is the number of cases for which a solution was found, regardless of the optimal value for a net spending basis. A more useful information would consist of the fraction of all solutions larger than a value $x$. This value can be derived from the histogram on the right. This would give an estimate of the probability of having a net spending larger than $x$ conditional to delivering a final bequest of \\\\$200k.\n",
    "\n",
    "Alternatively, one can look at the maximum bequest left at Jill's passing under the constraint of a net spending starting at \\$80k this year (obviously in today's money). This is what the next case will do."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2e63e1b0-480e-4065-bb73-a5d7561cb328",
   "metadata": {},
   "outputs": [],
   "source": [
    "options['netSpending'] = 80\n",
    "plan.runMC('maxBequest', options, 500);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd6356bb-7901-4316-80d9-2ab5e0f531a8",
   "metadata": {},
   "source": [
    "In this case, a relatively good fraction of scenarios are successful in providing the desired \\\\$80k net spending amount modulated over the duration of the plan. The median bequest left at the end of the plan is close to \\\\$500k, while Jack's partial bequest is only a little less. A success rate larger than 85% is considered relatively good, especially considering the fact that Jack and Jill are always able to re-adjust their net spending plan as other forward-looking estimates are performed in the future, and that the partial bequest left to Jack's children is a percentage, not an absolute quantity. This suggests that by reducing their spending by \\\\$10k, Jack and Jill can provide a total bequest of about \\\\$1 M in two separate bequests, a first in 2051, and then another one in 2057."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5c706722-4557-4537-94ec-4d13b29e2f61",
   "metadata": {},
   "source": [
    "### Running cases over a historical range or years\n",
    "As with full spousal asset transfer, we can also run the same cases using historical data over a range of years and compile the outcomes in a histogram. For this purpose, there is no need to pre-select specific rates using the `setRates()` method as the choice of *historical* rates is implicit. Only the year range is required.\n",
    "\n",
    "Let's look at a specific example. For optimizing the net spending amount, we specify *maxSpending* in the following call to optimize the plan over the 63 years following 1928:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6a9be559-2f2e-4326-adef-18af5c14aeb3",
   "metadata": {},
   "outputs": [],
   "source": [
    "plan.runHistoricalRange('maxSpending', options, 1928, 1990);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bccce068-c9a0-4001-a42d-868bde9d481b",
   "metadata": {},
   "source": [
    "When considering more historical data than a single year, we find that most solutions lead to empty accounts at Jack's passing. \n",
    "\n",
    "Let's now consider the case for *maxBequest* under a desired net spending."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6471720b-4704-4850-a341-1d9a0e5e58e2",
   "metadata": {},
   "outputs": [],
   "source": [
    "plan.runHistoricalRange('maxBequest', options, 1928, 1990);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7fa4f26a-0ea2-4804-8013-84b4b24a98e2",
   "metadata": {},
   "source": [
    "The resulting success rate when considering all historical data is 100% for a desired net spending of \\\\$80k. This is also not surprising as the original estimates for the net spending and the bequest were derived from running a case in 1969, the second next worst year of historical sequences of returns, and were slightly more than \\\\$80k."
   ]
  }
 ],
 "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
}
