Users Guide

This document replicates the Users guide, except that it’s using owlplanner live.

An example of Owl’s functionality

With about 10 lines of Python code, one can generate a full case study. Here is a typical plan with some comments. A plan starts with the names of the individuals, their birth years and life expectancies, and a name for the plan. Dollar amounts are in k$ (i.e. thousands) and ratios in percentage.

# Load owlplanner

import owlplanner as owl

Participants

  • Jack was born in 1962-07-04 and expects to live to age 89.
  • Jill was born in 1965-12-01 and hopes to live to age 92.
  • Plan starts on Jan 1st of the earliest year
plan = owl.Plan(['Jack', 'Jill'], 
                ['1962-07-14', '1965-12-01'], 
                [89, 92], 
                'jack & jill - tutorial' )

Assets

  • Jack has $90.5k in a taxable investment account, $600.5k in a tax-deferred account and $70k from 2 tax-free accounts.
  • Jill has $60.2k in her taxable account, $150k in a 403b, and $40k in a Roth IRA.
plan.setAccountBalances(
        taxable=[90.5, 60.2],
        taxDeferred=[600.5, 150], 
        taxFree=[50.6 + 20, 40.8]
)

Wages and Contributions

  • An Excel file contains 2 tabs (one for Jill, one for Jack) describing anticipated wages and contributions.
plan.readHFP('../../examples/HFP_jack+jill.xlsx')
True

Asset allocations

Over their lifetime, Jack and Jill will want to reset their asset allocations.

  • Jack will glide an s-curve for asset allocations from a 60/40 -> 70/30 stocks/bonds portfolio.
  • Jill will do the same thing but is a bit more conservative from 50/50 -> 70/30 stocks/bonds portfolio.
plan.setInterpolationMethod('s-curve')
plan.setAllocationRatios('individual', 
        generic=[
          [[60, 40, 0, 0], [70, 30, 0, 0]], 
          [[50, 50, 0, 0], [70, 30, 0, 0]]]
)

Pensions and Social Security

  • Jack has no pension, but Jill will receive $10k per year at 65 yo.
plan.setPension([0, 10.5], [65, 65])
  • Jack anticipates receiving social security of $28.4k at age 70.
  • Jill $19.7k at age 62. All values are in today’s $.
plan.setSocialSecurity([28.4, 19.7], [70, 62])

Spending

  • Instead of a ‘flat’ profile, we select a ‘smile’ spending profile, with 60% needs for the survivor.
plan.setSpendingProfile('smile', 60)

Rate Scenario

For this example, we will reproduce the historical sequence of returns starting in year 1969.

plan.setRates('historical', 1969)

Planning Goals

  • Jack and Jill want to leave a bequest of $500k
  • They want to limit Roth conversions to $100k per year.
  • Jill’s 403b plan does not support in-plan Roth conversions.

We solve for the maximum net spending profile under these constraints.

plan.solve(
        'maxSpending', 
        options={
          'maxRothConversion': 100,
          'bequest': 500, 
          'noRothConversions': 'Jill'}
)
2026-06-14 16:17:52 | INFO | plan:_build_sc_loop_policy:3574 | Using relTol=5.0e-05, absTol=1.0e+02, and gap=1.0e-04.
2026-06-14 16:17:54 | INFO | plan:_scSolve:3902 | Converged on full solution with monotonic behavior.
2026-06-14 16:17:54 | INFO | plan:_scSolve:3939 | Self-consistent loop returned after 3 iterations.
2026-06-14 16:17:54 | INFO | plan:_scSolve:3941 | Optimal
2026-06-14 16:17:54 | INFO | plan:_scSolve:3942 | Objective: $1,657,418

Results

Once we set our goals and solve, OWL can tell us more about what’s happening

The output can be seen using the following commands that display various plots of the decision variables in time.

Net Spending

plan.showNetSpending()

Accounts and balances

plan.showAccounts()

Asset distributions

plan.showAssetComposition()

By default, all these plots are in nominal dollars. To get values in today’s $, a call to

plan.setDefaultPlots('today')

would change all graphs to report in today’s dollars. Each plot can also override the default by setting the value parameters to either nominal or today, such as in the following example, which shows the taxable ordinary income over the duration of the plan, along with inflation-adjusted extrapolated tax brackets. Notice how the optimized income is surfing the boundaries of tax brackets.

Gross Income vs Tax Brackets

plan.showGrossIncome(value='nominal')

Optimal Spending Profile

The optimal spending profile is shown in the next plot (in today’s dollars). Notice the drop (recall we selected 60% survivor needs) at the passing of the first spouse.

plan.showProfile('today')

Account balances

The following plot shows the account balances in nominal value for all savings accounts owned by Jack and Jill. It was generated using

plan.showAccounts(value='nominal')

Cash flows and sources

This plot shows the complex cash flow from all sources.

plan.showSources(value='nominal')

Tax liabilities

For taxes, the following call will display Medicare premiums (including Part B IRMAA fees) and federal income tax

plan.showTaxes(value='nominal')

Asset distributions

For the case at hand, recall that asset allocations were selected above through

plan.setAllocationRatios('individual', generic=[[[60, 40, 0, 0], [70, 30, 0, 0]], [[50, 50, 0, 0], [70, 30, 0, 0]]])

Gliding from a 60%/40% stocks/bonds portfolio to 70%/30% for Jack, and 50%/50% -> 70%/30% for Jill. Assets distribution in all accounts in today’s $ over time can be displayed from

plan.showAssetComposition(value='today')

Rates

These plots are irregular because we used historical rates from 1969. The volatility of the rates offers Roth conversion benefits which are exploited by the optimizer. The rates used can be displayed by:

plan.showRates()

Correlations

Values between brackets <> are the average values and volatility over the selected period.

For the statisticians, rates distributions and correlations between them can be shown using:

plan.showRatesCorrelations()

Summary

A short text summary of the outcome of the optimization can be displayed through using:

plan.summary()
2026-06-14 16:17:54 | INFO | plan:summary:5018 | SUMMARY ================================================================
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Case name: jack & jill - tutorial
2026-06-14 16:17:54 | INFO | plan:summary:5021 | --- Overview ---: 
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Net yearly spending basis: $61,269
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Effective tax rate (plan average): 10.3%
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Net spending for year 2026: $67,042
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Net spending remaining in year 2026: $36,919
2026-06-14 16:17:54 | INFO | plan:summary:5021 | --- Spending & income (horizon totals) ---: 
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total net spending (today's $): $1,813,576
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total net spending (nominal): $4,891,234
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total fixed income (today's $): $530,210
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total fixed income (nominal): $592,524
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Social Security (today's $): $14,443
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Social Security (nominal): $44,111
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Pension (today's $): $1,267
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Pension (nominal): $3,412
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Wages (today's $): $514,500
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Wages (nominal): $545,000
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total Roth conversions (today's $): $251,488
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total Roth conversions (nominal): $349,000
2026-06-14 16:17:54 | INFO | plan:summary:5021 | --- Taxes & premiums (horizon totals) ---: 
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total tax paid on ordinary income (today's $): $97,899
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total tax paid on ordinary income (nominal): $145,068
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Tax bracket 10% (today's $): $44,381
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Tax bracket 10% (nominal): $88,196
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Tax bracket 12/15% (today's $): $27,360
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Tax bracket 12/15% (nominal): $29,030
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Tax bracket 22/25% (today's $): $26,159
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Tax bracket 22/25% (nominal): $27,841
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Tax bracket 24/28% (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Tax bracket 24/28% (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Tax bracket 32/33% (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Tax bracket 32/33% (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Tax bracket 35% (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Tax bracket 35% (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Tax bracket 37/40% (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Tax bracket 37/40% (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Early withdrawal penalty (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Early withdrawal penalty (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total tax paid on gains and dividends (today's $): $5,447
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total tax paid on gains and dividends (nominal): $8,708
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total net investment income tax paid (today's $): $180
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total net investment income tax paid (nominal): $315
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total Medicare premiums paid (today's $): $129,044
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total Medicare premiums paid (nominal): $359,911
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Covered by HSA (today's $): $23,294
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Covered by HSA (nominal): $60,428
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total ACA premiums paid (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total ACA premiums paid (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total debt payments (today's $): $130,935
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total debt payments (nominal): $191,313
2026-06-14 16:17:54 | INFO | plan:summary:5021 | --- Partial bequest ---: 
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Year of partial bequest: 2051
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Sum of spousal transfer to Jill (today's $): $392,927
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Sum of spousal transfer to Jill (nominal): $1,657,122
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Spousal transfer to Jill - taxable (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Spousal transfer to Jill - taxable (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Spousal transfer to Jill - tax-def (today's $): $49,472
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Spousal transfer to Jill - tax-def (nominal): $208,643
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Spousal transfer to Jill - tax-free (today's $): $343,455
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Spousal transfer to Jill - tax-free (nominal): $1,448,478
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Spousal transfer to Jill - HSA (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Spousal transfer to Jill - HSA (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Sum of post-tax non-spousal bequest from Jack (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Sum of post-tax non-spousal bequest from Jack (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Post-tax non-spousal bequest from Jack - taxable (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Post-tax non-spousal bequest from Jack - taxable (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Post-tax non-spousal bequest from Jack - tax-def (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Post-tax non-spousal bequest from Jack - tax-def (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Post-tax non-spousal bequest from Jack - tax-free (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Post-tax non-spousal bequest from Jack - tax-free (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Post-tax non-spousal bequest from Jack - HSA (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Post-tax non-spousal bequest from Jack - HSA (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | --- Final bequest ---: 
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Year of final bequest: 2057
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total after-tax value of final bequest (today's $): $500,000
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Total after-tax value of final bequest (nominal): $2,450,821
2026-06-14 16:17:54 | INFO | plan:summary:5021 | » After-tax value of savings assets (today's $): $500,000
2026-06-14 16:17:54 | INFO | plan:summary:5021 | » After-tax value of savings assets (nominal): $2,450,821
2026-06-14 16:17:54 | INFO | plan:summary:5021 | » Fixed assets liquidated at end of plan (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | » Fixed assets liquidated at end of plan (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | » With heirs assuming tax liability of (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | » With heirs assuming tax liability of (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | » After paying remaining debts of (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | » After paying remaining debts of (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Post-tax final bequest account value - taxable (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Post-tax final bequest account value - taxable (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Post-tax final bequest account value - tax-def (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Post-tax final bequest account value - tax-def (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Post-tax final bequest account value - tax-free (today's $): $500,000
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Post-tax final bequest account value - tax-free (nominal): $2,450,821
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Post-tax final bequest account value - HSA (today's $): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | »  Post-tax final bequest account value - HSA (nominal): $0
2026-06-14 16:17:54 | INFO | plan:summary:5021 | --- Plan & solver ---: 
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Case starting date: 2026-06-14
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Cumulative inflation factor at end of final year: 4.90
2026-06-14 16:17:54 | INFO | plan:summary:5021 |           Jack's life horizon: 2026 -> 2051
2026-06-14 16:17:54 | INFO | plan:summary:5021 |           Jack's years planned: 26
2026-06-14 16:17:54 | INFO | plan:summary:5021 |           Jack's SS claiming age: 70y 00m
2026-06-14 16:17:54 | INFO | plan:summary:5021 |           Jill's life horizon: 2026 -> 2057
2026-06-14 16:17:54 | INFO | plan:summary:5021 |           Jill's years planned: 32
2026-06-14 16:17:54 | INFO | plan:summary:5021 |           Jill's SS claiming age: 62y 00m
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Number of decision variables: 1224
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Number of constraints: 1115
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Convergence: monotonic
2026-06-14 16:17:54 | INFO | plan:summary:5021 | Case executed on: 2026-06-14 at 16:17:54
2026-06-14 16:17:54 | INFO | plan:summary:5022 | ------------------------------------------------------------------------

The output of the last command reports that if future rates are exactly like those observed starting from 1969 and the following years, Jack and Jill could afford an annual spending of \$97k starting this year (with a basis of \$88.8k - the basis multiplies the profile which can vary over the course of the plan). The summary also contains some details:

Saving results

And an Excel workbook can be saved with all the detailed amounts over the years by using the following command:

plan.saveWorkbook(overwrite=True)