def get_content():
    return [
        pl.Section([
            pl.SubSection([
                'Create a model with two stocks, A and B. Both start at price 100. Generate stock prices for '
                '100 periods. Do this by drawing returns from normal distributions defined with the inputs '
                'below. Then apply the returns to the prior prices to get the price in each period. Create a '
                "portfolio of the two stocks, by taking the weighted-average of the stock's returns, then applying "
                "that return to a third Portfolio series starting at 100. Graph "
                "the two stocks and porfolio performance over time. Calculate the mean and standard deviation "
                "of the generated returns for the two stocks and the portfolio."
            ],
                          title='Problem Statement'),
            pl.SubSection([
                pl.Center(
                    lt.Tabular([
                        lt.TopRule(),
                        lt.ValuesTable.from_list_of_lists(
                            [['Input', 'Default Value']]),
                        lt.MidRule(),
                        lt.ValuesTable.from_list_of_lists([
                            ['Stock A Weight', '60%'],
                            ['Stock A Mean Return', '10%'],
                            ['Stock A Return Standard Deviation', '30%'],
                            ['Stock B Mean Return', '5%'],
                            ['Stock B Return Standard Deviation', '10%'],
                        ], ),
                        lt.BottomRule(),
                    ],
                               align='l|c'))
            ],
                          title='Inputs'),
        ],
                   title='Stock Portfolio')
    ]
def get_content():

    return [
        pl.Section([
            pl.SubSection([
                'You are an analyst trying to decide whether it is worth it to launch a new product line selling '
                't-shirts. The success of the t-shirt business will depend on the state of the economy. '
                'You can purchase a machine which costs \\$10,000,000 at $t=0$, then each year you will earn '
                'the profit per unit (revenue minus variable cost), multiplied by the output. The machine will '
                'last for 10 years. Should this project be undertaken? Will it be successful in all scenarios?',
            ],
                          title='Problem Statement'),
            pl.SubSection([
                pl.Center(
                    lt.Tabular([
                        lt.TopRule(),
                        lt.ValuesTable.from_list_of_lists([[
                            'State of Economy', 'Probability', 'Price',
                            'Output', 'Interest Rate'
                        ]]),
                        lt.MidRule(),
                        lt.ValuesTable.from_list_of_lists([
                            ['Expansion', '20%', '15', '1000000', '7%'],
                            ['Normal', '70%', '12', '500000', '5%'],
                            ['Recession', '10%', '10', '200000', '3%'],
                        ], ),
                        lt.BottomRule(),
                    ],
                               align='l|cccc'))
            ],
                          title='Scenarios'),
        ],
                   title='Capital Budgeting')
    ]
Ejemplo n.º 3
0
def get_content():
    return [
        pl.Section([
            pl.SubSection([
                'Create a model of stock returns and correlations. The asset returns should be based on the '
                'capital asset pricing model (CAPM), which states:',
                pl.Equation(str_eq=r'r_s = r_f + \beta (r_m - r_f) + \epsilon',
                            inline=False),
                pl.UnorderedList([
                    '$r_e$: Return on stock',
                    '$r_f$: Return on risk free asset',
                    '$r_m$: Return on the market portfolio',
                    r'$\beta$: Covariance between the market portfolio and the stock',
                    r'$\epsilon$: Idiosyncratic return, (random, normally distributed with mean 0)'
                ]), 'Your model should accept the number of assets, '
                'the average idiosyncratic standard deviation across the assets, the standard deviation of the '
                'idiosyncratic standard deviation across the assets, the market average return, the '
                'market standard deviation, the risk-free rate, and the number of periods as the inputs. You should randomly draw '
                "each asset's standard deviation of idiosyncratic returns from a normal distribution based on the "
                "inputs. You should also randomly draw the stock's beta from a uniform distribution between 0 and 2. "
                "Then draw the market returns from a normal distribution with its mean and standard deviation. Then "
                "the return for each asset in each time period will be determined by drawing its idiosyncratic return "
                "for that period from its normal distribution, then calculating the CAPM formula. After all the assets "
                "returns are generated, calculate the correlation between all the assets. Your model should be updating "
                "the number of assets and number of periods merely by changing the inputs."
            ],
                          title='Problem Definition'),
            pl.SubSection([
                pl.Center(
                    lt.Tabular([
                        lt.TopRule(),
                        lt.ValuesTable.from_list_of_lists(
                            [['Input', 'Default Value']]),
                        lt.MidRule(),
                        lt.ValuesTable.from_list_of_lists([
                            ['Number of Assets', '3'],
                            ['Number of Periods', '20'],
                            [
                                'Average Idiosyncratic Standard Deviation',
                                '20%'
                            ],
                            [
                                'Standard Deviation of Idiosyncratic Return Standard Deviation',
                                '10%'
                            ],
                            ['Market Average Return', '7%'],
                            ['Market Standard Deviation', '15%'],
                            ['Risk-Free Rate', '2%'],
                        ], ),
                        lt.BottomRule(),
                    ],
                               align='l|c'))
            ],
                          title='Model Inputs'),
        ],
                   title='Generating Asset Returns using CAPM')
    ]
Ejemplo n.º 4
0
def get_content():
    jinja_templates_path = os.path.sep.join(['pltemplates', 'projects', 'p4'])
    jinja_env = pl.JinjaEnvironment(
        loader=FileSystemLoader(jinja_templates_path))

    return [
        pl.Section([
            pl.SubSection([
                Project4ProblemModel(template_path='prob_definition.j2',
                                     environment=jinja_env),
            ],
                          title='Problem Definition'),
            pl.SubSection([
                Project4ProblemModel(template_path='notes.j2',
                                     environment=jinja_env),
            ],
                          title='Notes'),
            pl.SubSection([
                Project4ProblemModel(template_path='bonus.j2',
                                     environment=jinja_env),
            ],
                          title='Bonus')
        ],
                   title='Overview'),
        pl.Section([
            pl.SubSection([
                Project4ProblemModel(template_path='submission.j2',
                                     environment=jinja_env),
            ],
                          title='Submission'),
            pl.SubSection([
                pl.Center(
                    lt.Tabular([
                        pl.MultiColumnLabel('Grading Breakdown', span=2),
                        lt.TopRule(),
                        lt.ValuesTable.from_list_of_lists(
                            [['Category', 'Percentage']]),
                        lt.TableLineSegment(0, 1),
                        lt.ValuesTable.from_list_of_lists(
                            [['Model Accuracy', '60%'],
                             ['Model Readability', '30%'],
                             ['Model Formatting', '10%'], ['Bonus', '5%']]),
                        lt.MidRule(),
                        lt.ValuesTable.from_list_of_lists(
                            [['Total Possible', '105%']]),
                        lt.BottomRule()
                    ],
                               align='l|c'))
            ],
                          title='Grading'),
        ],
                   title='Submission & Grading')
    ]
Ejemplo n.º 5
0
def get_content():
    jinja_templates_path = os.path.sep.join(
        ['pltemplates', 'practice', 'python_retirement'])
    jinja_env = pl.JinjaEnvironment(
        loader=FileSystemLoader(jinja_templates_path))
    return [
        pl.Section([
            pl.SubSection([
                PythonRetirementPracticeProblemModel(
                    template_path='prob_definition.j2', environment=jinja_env),
            ],
                          title='Problem Definition'),
            pl.SubSection([
                pl.Center(
                    lt.Tabular([
                        lt.TopRule(),
                        lt.ValuesTable.from_list_of_lists([[
                            'Input',
                            'Default Value',
                        ]]),
                        lt.MidRule(),
                        lt.ValuesTable.from_list_of_lists([
                            ['Starting Salary', '\$50,000'],
                            ['Salary Growth', '3%'],
                            ['Mid-Salary Cutoff', r'\$80,000'],
                            ['High-Salary Cutoff', r'\$120,000'],
                            ['Low Savings Rate', '10%'],
                            ['Mid Savings Rate', '25%'],
                            ['High Savings Rate', '40%'],
                            ['Interest Rate', '5%'],
                            ['Desired Cash', r'\$1,500,000'],
                        ], ),
                        lt.BottomRule(),
                    ],
                               align='l|cc'))
            ],
                          title='Inputs'),
            pl.SubSection([
                """
                        The final answer with the default inputs should be 37 years to retirement. Try hard to get
                        there working from scratch. If you are very stuck, then try taking the Dynamic Salary
                        Retirement model and modifying it. If you are still stuck, then check the provided Jupyter 
                        notebook solution. If you have a lot of trouble with this, please see me in office hours or
                        after class, as your first project will be similar but a bit more difficult.
                        """
            ],
                          title='Solution')
        ],
                   title=
                   'Capital Budgeting Probabilities with Monte Carlo Simulation'
                   )
    ]
                          title='Selected Solutions'),
            pl.SubSection([
                pl.Center(
                    lt.Tabular([
                        lt.MultiColumnLabel('Grading Breakdown', span=2),
                        lt.TopRule(),
                        lt.ValuesTable.from_list_of_lists(
                            [['Category', 'Percentage']]),
                        lt.TableLineSegment(0, 1),
                        lt.ValuesTable.from_list_of_lists([
                            ['Model Accuracy', '60%'],
                            ['Model Readability', '20%'],
                            ['Model Formatting', '10%'],
                            ['Following the Template', '10%'], ['Bonus', '5%']
                        ]),
                        lt.MidRule(),
                        lt.ValuesTable.from_list_of_lists(
                            [['Total Possible', '105%']]),
                        lt.BottomRule()
                    ],
                               align=align))
            ],
                          title='Grading'),
        ],
                   title='Submission & Grading')
    ]


DOCUMENT_CLASS_KWARGS = dict(remove_section_numbering=True, )
OUTPUT_NAME = TITLE
def get_content():
    random.seed(1000)

    lecture = get_probability_lecture()
    scenario_excel_lab = get_scenario_analysis_excel_lab_lecture().to_pyexlatex()
    scenario_python_lab = get_scenario_analysis_python_lab_lecture().to_pyexlatex()
    randomness_excel_lab = get_randomness_excel_lab_lecture().to_pyexlatex()
    randomness_python_lab = get_randomness_python_lab_lecture().to_pyexlatex()
    random_stock_lab = get_random_stock_model_lab_lecture().to_pyexlatex()
    full_model_internal_randomness_lab = get_extend_model_internal_randomness_lab_lecture().to_pyexlatex()
    appendix_frames = [
        lecture.pyexlatex_resources_frame,
        scenario_excel_lab.appendix_frames(),
        scenario_python_lab.appendix_frames(),
        randomness_excel_lab.appendix_frames(),
        randomness_python_lab.appendix_frames(),
        random_stock_lab.appendix_frames(),
        full_model_internal_randomness_lab.appendix_frames(),
    ]

    df_mono = pl.Monospace('DataFrame')
    next_slide = lp.Overlay([lp.NextWithIncrement()])
    with_previous = lp.Overlay([lp.NextWithoutIncrement()])
    rand_mono = pl.Monospace('=RAND')
    rand_between_mono = pl.Monospace('=RANDBETWEEN')
    norm_inv_mono = pl.Monospace('=NORM.INV')
    excel_random_normal_example = pl.Monospace('=NORM.INV(RAND(), 10, 1)')
    random_module_mono = pl.Monospace('random')
    py_rand_mono = pl.Monospace('random.random')
    py_rand_uniform_mono = pl.Monospace('random.uniform')
    py_rand_norm_mono = pl.Monospace('random.normalvariate')
    py_random_link = Hyperlink('https://docs.python.org/3.7/library/random.html#real-valued-distributions',
                               '(and other distributions)')
    py_random_normal_example = pl.Monospace('random.normalvariate(10, 1)')
    random_seed_example = pl.Monospace('random.seed(0)')
    next_slide = lp.Overlay([lp.NextWithIncrement()])
    n_iter = pl.Equation(str_eq='n_{iter}')
    df_mono = pl.Monospace('DataFrame')
    df_std = pl.Monospace('df.std()')
    df_mean = pl.Monospace('df.mean()')
    random_choices_mono = pl.Monospace('random.choices')
    random_choices_example = pl.Monospace("random.choices(['Recession', 'Normal', 'Expansion'], [0.3, 0.5, 0.2])")

    return [
        pl.Section(
            [
                lp.TwoColumnGraphicDimRevealFrame(
                    [
                        'So far everything in our models has been deterministic',
                        'Further, we have not explored any scenarios in our models, we have taken the base case as '
                        'the only case',
                        'Unfortunately, the real world is very random. Many possible scenarios could occur.'
                    ],
                    [
                        images_path('dice.jpg'),
                    ],
                    title='Why Model Probability'
                ),
                lp.DimRevealListFrame(
                    [
                        'There are a few ways we can gain a richer understanding of the modeled situation by '
                        'incorporating probability',
                        f'The simplest is {pl.Bold("scenario modeling")}, in which different situations are defined with probabilities, '
                        'and the result of the model is the expected value across the cases.',
                        ['Another is', pl.Bold('internal randomness'),
                         'where randomness is incorporated directly within '
                         'the model logic'],
                        ['Finally,', pl.Bold("Monte Carlo simulation"),
                         'treats the model as deterministic but externally varies the '
                         'inputs to get a distribution of outputs.']
                    ],
                    title='How to Bring Probability In'
                ),
            ],
            title='Motivation for Probability Modeling',
            short_title='Intro',
        ),
        pl.Section(
            [
                lp.Frame(
                    [
                        pl.UnorderedList([
                            lp.DimAndRevealListItems([
                                ['When something is measured numerically, it can be either a', pl.Bold('discrete'),
                                 'variable, or a', pl.Bold('continuous'), 'variable.'],

                            ])
                        ]),
                        lp.Block(
                            [
                                pl.Equation(str_eq=r'x \in \{x_1, x_2, ... x_n\}', inline=False),
                                pl.VSpace(-0.4),
                                pl.UnorderedList([
                                    [pl.Equation(str_eq=r'\{x_1, x_2, ... x_n\}:'), 'A specific set of values'],
                                ])
                            ],
                            title='Discrete Variables'
                        ),
                        lp.Block(
                            [
                                pl.Equation(str_eq=r'x \in \mathbb{R} \text{ or } [a, b]', inline=False),
                                pl.VSpace(-0.4),
                                pl.UnorderedList([
                                    [pl.Equation(str_eq='\mathbb{R}:'), 'All real numbers'],
                                    [pl.Equation(str_eq='[a, b]:'), 'Some interval between two values or infinity'],

                                ])
                            ],
                            title='Continuous Variables'
                        ),
                    ],
                    title='Math Review: Discrete and Continuous Variables'
                ),
                lp.Frame(
                    [
                        pl.TextSize(-3),
                        pl.UnorderedList([
                            lp.DimAndRevealListItems([
                                [pl.Bold('Expected value'), 'is the average outcome over repeated trials'],
                                "It is generally useful to get a single output from multiple possible cases",
                            ], dim_earlier_items=False)
                        ]),
                        lp.Block(
                            [
                                pl.Equation(str_eq=r'E[x] = \sum_{i=1}^{N} p_i x_i', inline=False),
                                pl.VSpace(-0.4),
                                pl.UnorderedList([
                                    [pl.Equation(str_eq=r'E[x]:'), 'Expected value for', pl.Equation(str_eq='x')],
                                    [pl.Equation(str_eq=r'x_i:'), 'A specific value for', pl.Equation(str_eq='x')],
                                    [pl.Equation(str_eq=r'p_i:'), 'The probability associated with value',
                                     pl.Equation(str_eq='x_i')],
                                    [pl.Equation(str_eq=r'N:'), 'The total number of possible values of',
                                     pl.Equation(str_eq='x')],
                                ])
                            ],
                            title='Discrete Variables'
                        ),
                        lp.Block(
                            [
                                pl.Equation(str_eq=r'E[x] = \frac{1}{N} \sum_{i=1}^{N} x_i', inline=False),
                                pl.VSpace(-0.4),
                                pl.UnorderedList([
                                    [pl.Equation(str_eq=r'N:'), 'The number of samples collected for',
                                     pl.Equation(str_eq='x')],
                                ])
                            ],
                            title='Continuous Variables'
                        ),
                    ],
                    title='Math Review: Expected Value'
                ),
                lp.GraphicFrame(
                    images_path('different-variance-plot.pdf'),
                    title='Math Review: Variance in One Picture'
                ),
                lp.Frame(
                    [
                        pl.TextSize(-2),
                        pl.UnorderedList([
                            lp.DimAndRevealListItems([
                                [pl.Bold('Variance'), 'and', pl.Bold('standard deviation'),
                                 'are measures of the dispersion '
                                 'of values of a random variable.'],
                                'Variance is the real quantity of interest, but standard deviation is easier to understand '
                                'because it has the same units as the variable, while variance has units squared'
                            ], dim_earlier_items=False),
                        ]),
                        lp.Block(
                            [
                                EquationWithVariableDefinitions(
                                    r'Var[x] = \sigma^2 = \frac{1}{N - 1} \sum_{i=1}^{N} (x_i - \mu)^2',
                                    [
                                        [pl.Equation(str_eq=r'N:'), 'Number of samples of', pl.Equation(str_eq=r'x')],
                                        [pl.Equation(str_eq=r'\mu:'), 'Sample mean'],
                                    ]
                                ),
                            ],
                            title='Variance of a Continuous Variable'
                        ),
                        lp.Block(
                            [
                                EquationWithVariableDefinitions(
                                    r'\sigma = \sqrt{Var[x]}',
                                    [
                                        [pl.Equation(str_eq=r'\sigma:'), 'Standard deviation'],
                                    ],
                                    space_adjustment=-0.5
                                ),
                            ],
                            title='Standard Deviation'
                        ),
                    ],
                    title='Math Review: Variance and Standard Deviation'
                ),
                lp.TwoColumnGraphicDimRevealFrame(
                    [
                        ['A', pl.Bold('probability distribution'),
                         'represents the probabilities of different values of '
                         'a variable'],
                        'For discrete variables, this is simply a mapping of possible values to probabilities, e.g. for a coin '
                        'toss, heads = 50% and tails = 50%',
                        'For continuous variables, a continuous distribution is needed, such as the normal distribution',
                    ],
                    graphics=[
                        images_path('normal-distribution.png'),
                    ],
                    title='Math Review: Probability Distributions'
                ),
                lp.TwoColumnGraphicDimRevealFrame(
                    [
                        pl.TextSize(-2),
                        ["You've probably heard of the", pl.Bold('normal distribution'),
                         'as it is very commonly used because it occurs a lot in nature'],
                        ['It is so common because of the', pl.Bold('central limit theorem'), 'which says that '
                                                                                             'averages of variables will follow a normal distribution, regardless of the distribution of the '
                                                                                             'variable itself'],
                        'This has many applications. For example, we can view the investment rate as an average across '
                        'individual investment returns, and so it will be normally distributed.',
                    ],
                    graphics=[
                        images_path('normal-distribution-percentages.png'),
                    ],
                    title='Math Review: Normal Distribution'
                ),
                lp.Frame(
                    [
                        pl.TextSize(-3),
                        pl.UnorderedList([
                            lp.DimAndRevealListItems([
                                'We want to extend our retirement model to say that the investment return is not constant.',
                                'We can treat the interest rate as either a discrete (specific values) or a continuous '
                                '(range of values, more realistic) variable'
                            ], dim_earlier_items=False),

                        ]),
                        lp.Block(
                            [
                                pl.Center(
                                    [
                                        lt.Tabular(
                                            [
                                                lt.ValuesTable.from_list_of_lists([
                                                    ['Interest Rate', 'Probability']
                                                ]),
                                                lt.MidRule(),
                                                lt.ValuesTable.from_list_of_lists([
                                                    ['2%', '30%'],
                                                    ['5%', '50%'],
                                                    ['7%', '20%'],
                                                ]),
                                            ],
                                            align='cc'
                                        )
                                    ]
                                )
                            ],
                            title='As a Discrete Variable'
                        ),
                        lp.Block(
                            [
                                pl.Equation(str_eq=r'r_i \sim N(\mu, \sigma^2)', inline=False),
                                pl.VSpace(-0.5),
                                pl.UnorderedList([
                                    [pl.Equation(str_eq=r'N:'), 'Normal distribution'],
                                    [pl.Equation(str_eq=r'\mu:'), 'Interest rate mean'],
                                    [pl.Equation(str_eq=r'\sigma:'), 'Interest rate standard deviation'],
                                ])
                            ],
                            title='As a Continuous Variable'
                        ),
                    ],
                    title='A Non-Constant Interest Rate'
                ),
            ],
            title='Mathematical Tools for Probability Modeling',
            short_title='Math Review'
        ),
        pl.Section(
            [
                lp.Frame(
                    [
                        pl.TextSize(-1),
                        lp.Block(
                            [
                                pl.Center(
                                    [
                                        lt.Tabular(
                                            [
                                                lt.ValuesTable.from_list_of_lists([
                                                    ['State of Economy', 'Interest Rate', 'Savings Rate', 'Probability']
                                                ]),
                                                lt.MidRule(),
                                                lt.ValuesTable.from_list_of_lists([
                                                    ['Recession', '2%', '35%', '30%'],
                                                    ['Normal', '5%', '30%', '50%'],
                                                    ['Expansion', '7%', '25%', '20%'],
                                                ]),
                                            ],
                                            align='l|ccc'
                                        )
                                    ]
                                )
                            ],
                            title='Interest Rate Scenarios'
                        ),
                        pl.UnorderedList([
                            lp.DimAndRevealListItems([
                                ['In scenario modeling, different cases for model parameters are chosen. Several '
                                 'parameters may be altered at once in a given case.'],
                                "Here we are making the different cases the state of the economy. When the economy is doing "
                                "poorly, the individual earns a lower return, but also saves more because they don't want to "
                                "overspend at a bad time",
                                "When the economy does well, the individual earns a higher return, but also spends more"
                            ])
                        ]),
                    ],
                    title='Scenario Modeling'
                ),
                lp.DimRevealListFrame(
                    [
                        ['We can implement scenario modeling', pl.Bold('internal'), 'or', pl.Bold('external'),
                         'to our model'],
                        ['With an internal implementation, the cases are built', pl.Underline('into the model logic'),
                         'itself, '
                         'and model logic also takes the expected value of the case outputs. The inputs of the model',
                         'are now the cases and probabilities.'],
                        ['With an external implementation, the', pl.Underline('model logic is left unchanged,'),
                         'instead the '
                         'model is run separately with each case, then the expected value is calculated across the outputs '
                         'from the multiple model runs.'],
                    ],
                    title='Implementing Scenario Modeling'
                ),
                lp.Frame(
                    [
                        pl.Center(
                            [
                                lt.Tabular(
                                    [
                                        lt.ValuesTable.from_list_of_lists([
                                            [pl.Bold('Internal'), pl.Bold('External')]
                                        ]),
                                        lt.MidRule(),
                                        lt.MidRule(),
                                        lt.ValuesTable.from_list_of_lists([
                                            ['Original model is now an old version',
                                             'Original model can still be used normally'],
                                        ]),
                                        # TODO [#14]: each row should come one per slide, but need to allow overlays in lt items
                                        lt.MidRule(),
                                        lt.ValuesTable.from_list_of_lists([
                                            ['Model runs exactly as before',
                                             'Getting full results of model requires running the model multiple times and '
                                             'aggregating output']
                                        ]),
                                        lt.MidRule(),
                                        lt.ValuesTable.from_list_of_lists([
                                            ['Model complexity has increased', 'Model complexity unchanged']
                                        ]),
                                        lt.MidRule(),
                                        lt.ValuesTable.from_list_of_lists([
                                            ['Complexity to run model is unchanged',
                                             'Complexity to run model has increased']
                                        ]),
                                    ],
                                    align='L{5cm}|R{5cm}'
                                )
                            ]
                        )
                    ],
                    title='Internal or External Scenario Analysis?'
                ),
                lp.DimRevealListFrame(
                    [
                        'For internal scenario analysis, set up a table of the cases and probabilities. Then calculate the '
                        'expected value of these cases for each model parameter. Then use the expected value as the new '
                        'model parameter.',
                        'For external scenario analysis, a data table is useful. Create the data table of outputs for each case '
                        'and another table of case probabilities, then combine them to produce the expected value of '
                        'the output.',
                        'If you are trying to change more than two inputs at once in external scenario '
                        'analysis, this becomes more '
                        'challenging but you can assign a number to each set of inputs and have the model look up the '
                        'inputs based on the case number, using the case number as the data table input.'

                    ],
                    title='Scenario Analysis in Excel'
                ),
                InClassExampleFrame(
                    [
                        'I will now go through adding external scenario analysis to the Dynamic Salary Retirement Model '
                        'in Excel',
                        'The completed exercise on the course site as "Dynamic Salary Retirement Model Sensitivity.xlsx"',
                    ],
                    title='Scenario Analysis in Excel',
                    block_title='Adding Scenario Analysis to the Dynamic Retirement Excel Model'
                ),
                scenario_excel_lab.presentation_frames(),
                lp.DimRevealListFrame(
                    [
                        ['For internal scenario analysis, set up a', df_mono,
                         'or dictionary of the cases and probabilities. Then calculate '
                         'the expected value of these cases for each model parameter. Then use the expected value as the new '
                         'model parameter.'],
                        'For external scenario analysis, just call your model function with each input case, collect the '
                        'results, and combine them to produce the expected value of the output.'
                    ],
                    title='Scenario Analysis in Python'
                ),
                InClassExampleFrame(
                    [
                        'I will now go through adding external scenario analysis to the Dynamic Salary Retirement Model '
                        'in Python',
                        'he completed exercise on the course site as "Dynamic Salary Retirement Model Scenario.ipynb"',
                    ],
                    title='Scenario Analysis in Python',
                    block_title='Adding Scenario Analysis to the Dynamic Retirement Python Model'
                ),
                scenario_python_lab.presentation_frames(),
            ],
            title='Scenario Modeling'
        ),
        pl.Section(
            [
                lp.DimRevealListFrame(
                    [
                        ["Using the technique of", pl.Bold('internal randomness,'),
                         'something random is added internally to the model'],
                        'Instead of taking a fixed input, random values for that variable are drawn',
                        'This technique can be used with both discrete and continuous variables'
                    ],
                    title='What is Internal Randomness?'
                ),
                lp.GraphicFrame(
                    internal_randomness_graphic(),
                    title='Internal Randomness in One Picture'
                ),
                lp.DimRevealListFrame(
                    [
                        'Internal randomness makes sense when the random behavior is integral to your model',
                        'If you are just trying to see how changing inputs affects outputs, or trying to get confidence intervals for outputs, '
                        'an external method such as sensitivity analysis or Monte Carlo simulation would make more sense.',
                        'For example, if we want to allow investment returns to vary in our retirement model, an external method fits well because '
                        'the core model itself is deterministic',
                        'If instead we were modeling a portfolio, we might use internal randomness to get the returns for each asset.'
                    ],
                    title='Should I Use Internal Randomness?'
                ),
                lp.DimRevealListFrame(
                    [
                        'Similarly to our discussion of internal vs. external sensitivity analysis, internal randomness keeps '
                        'operational complexity (how to run the model) low, but increases model complexity.',
                        'The main drawback of internal randomness is that the same set of inputs will give different outputs each time the model is run',
                        'While this is the desired behavior, it can make it difficult to determine whether everything is working.'
                    ],
                    title='Internal Randomness Advantages and Pitfalls'
                ),
                lp.TwoColumnGraphicDimRevealFrame(
                    [
                        'Instead of taking the input as fixed, draw it from a distribution',
                        'We need to define a distribution for each input we want to randomize. This will typically be a normal distribution, and then '
                        'we just need to give it a reasonable mean and standard deviation',
                        'Put the most reasonable or usual value as the mean. Then think about the probabilities of the normal distribution relative '
                        'to standard deviation to set it'
                    ],
                    graphics=[
                        images_path('normal-distribution-percentages.png'),
                    ],
                    title='Internal Randomness with Continuous Variables'
                ),
                lp.DimRevealListFrame(
                    [
                        ['The main functions for randomness in Excel are', rand_mono, 'and', rand_between_mono],
                        'The latter gives a random number between two numbers, while the former gives a random number '
                        'between 0 and 1. Both of these draw from a uniform distribution (every number equally likely)',
                        ['Meanwhile, the', norm_inv_mono,
                         'function gives the value for a certain normal distribution at a certain probability (it is not random)'],
                        'We can combine these two functions to draw random numbers from a normal distribution',
                        [excel_random_normal_example,
                         'would draw a number from a normal distribution with mean 10 and standard deviation 1'],
                    ],
                    title='Internal Randomness with Continuous Variables in Excel'
                ),
                InClassExampleFrame(
                    [
                        'I will now go through generating random continuous variables '
                        'in Excel',
                        'The completed exercise on the course site is called "Generating Random Numbers.xlsx"',
                        'We will focus only on the "Continuous" sheet for now',
                    ],
                    title='Example for Continuous Random Variables in Excel',
                    block_title='Generating Random Numbers from Normal Distributions in Excel'
                ),
                randomness_excel_lab.presentation_frames(),
                lp.DimRevealListFrame(
                    [
                        ['In Python, we have the built-in', random_module_mono, 'module'],
                        ['It has functions analagous to those in Excel:', py_rand_mono, 'works like', rand_mono,
                         'and', py_rand_uniform_mono, 'works like', rand_between_mono],
                        ['Drawing numbers from a normal distribution', py_random_link, 'is easier: just one function',
                         py_rand_norm_mono],
                        [py_random_normal_example,
                         'would draw a number from a normal distribution with mean 10 and standard deviation 1']
                    ],
                    title='Internal Randomness with Continuous Variables in Python'
                ),
                InClassExampleFrame(
                    [
                        'I will now go through generating random continuous variables '
                        'in Python',
                        'The completed exercise on the course site is called "Generating Random Numbers.ipynb"',
                        'We will focus only on the "Continuous" section for now',
                    ],
                    title='Example for Continuous Random Variables in Python',
                    block_title='Generating Random Numbers from Normal Distributions in Python'
                ),
                randomness_python_lab.presentation_frames(),
                lp.DimRevealListFrame(
                    [
                        'We can also build randomness into the model for discrete variables',
                        "With discrete variables, our distribution is just a table of probabilities for the different values",
                        'To pick a random value for a discrete variable, first add another column to your table which has the '
                        'cumulative sum of the prior probabilties, and then another column which is that column plus the '
                        'current probability',
                        'Then generate a random number between 0 and 1 from a uniform distribution',
                        'If the generated number is between the probability and the cumulative sum of prior probabilities, choose that case'
                    ],
                    title='Internal Randomness with Discrete Variables'
                ),
                lp.Frame(
                    [
                        pl.TextSize(-1),
                        lp.Block(
                            [
                                pl.Center(
                                    [
                                        lt.Tabular(
                                            [
                                                lt.ValuesTable.from_list_of_lists([
                                                    ['State of Economy', 'Interest Rate', 'Probability', 'Begin Range',
                                                     'End Range']
                                                ]),
                                                lt.MidRule(),
                                                lt.ValuesTable.from_list_of_lists([
                                                    ['Recession', '2%', '30%', '0%', '30%'],
                                                    ['Normal', '5%', '50%', '30%', '80%'],
                                                    ['Expansion', '7%', '20%', '80%', '100%'],
                                                ]),
                                            ],
                                            align='L{2cm}|cccc'
                                        )
                                    ]
                                )
                            ],
                            title='Interest Rate Scenarios'
                        ),
                        pl.UnorderedList([
                            pl.TextSize(-2),
                            lp.DimAndRevealListItems([
                                'The Begin Range column is calculated as the cumulative sum of prior probabilities',
                                'The End Range column is calculated as Begin Range + Probability',
                                "Generate a random number between 0 and 1. If it is between the begin and end range, "
                                "that is the selected value",
                                "If it's 0.15, it's a recession. If it's 0.45, it's a normal period. If it's 0.94, it's "
                                "an expansion period."
                            ], vertical_fill=True)
                        ]),
                    ],
                    title='An Example of Internal Randomness with Discrete Variables'
                ),
                lp.DimRevealListFrame(
                    [
                        'The steps in the preceeding slides need to be carried out manually in Excel',
                        ['In Python, there is a built-in function which is doing all of this in the background,',
                         random_choices_mono],
                        ['Simply do', random_choices_example, 'to yield the exact same result for the prior example']
                    ],
                    title='Random Discrete Variables in Python'
                ),
                InClassExampleFrame(
                    [
                        'I will now go through generating random discrete variables '
                        'in both Excel and Python',
                        'We will be continuing with the same Excel workbook and Jupyter notebook from before, '
                        '"Generating Random Numbers.xlsx" and "Generating Random Numbers.ipynb"',
                        'We will focus only on the "Discrete" sheet/section now',
                    ],
                    title='Example for Discrete Random Variables in Excel and Python',
                    block_title='Generating Random Numbers from Discrete Distributions in Excel and Python'
                ),
                random_stock_lab.presentation_frames(),
                InClassExampleFrame(
                    [
                        'I will now add internal randomness with discrete variables to '
                        'both the Excel and Python Dynamic Salary Retirement models to simulate economic conditions '
                        'changing year by year',
                        'The completed models on the course site are called '
                        '"Dynamic Salary Retirement Model Internal Randomness.xlsx" and '
                        '"Dynamic Salary Retirement Model Internal Randomness.ipynb"',
                    ],
                    title='Adding Internal Randomness to Excel and Python Models',
                    block_title='Extending the Dynamic Salary Retirement Model with Internal Randomness'
                ),
                full_model_internal_randomness_lab.presentation_frames(),
            ],
            title='Internal Randomness'
        ),
        pl.PresentationAppendix(appendix_frames),
    ]
Ejemplo n.º 8
0
def get_content():
    align_c = lt.ColumnAlignment('c')
    align_l = lt.ColumnAlignment('l')
    align = lt.ColumnsAlignment([align_l, align_c])

    n_phones = 100000
    price_scrap = 50000
    price_phone = 500
    cogs_phone = 250
    price_machine_adv = 1000000
    n_life = 10
    n_machines = 5
    d_1 = 100000
    g_d = 0.2
    max_year = 20
    interest = 0.05

    pmm = PhoneManufacturingModel(n_phones, price_scrap, price_phone, n_life,
                                  n_machines, d_1, g_d, max_year, interest)

    scipy_mono = pl.Monospace('scipy')
    scipy_minimize_link = 'https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize_scalar.html#' \
                          'scipy-optimize-minimize-scalar'
    scipy_minimize_mono = pl.Monospace('scipy.optimize.minimize_scalar')

    possible_elasicity_str = ', '.join([
        f'($E = {ec[0]}$, $d_c = {ec[1]}$)' for ec in ELASTICITY_CONSTANT_CASES
    ])
    possible_elasicity_str = ', '.join([
        f'($E = {ec[0]}$, $d_c = {ec[1]}$)' for ec in ELASTICITY_CONSTANT_CASES
    ])
    possible_elasicity_str = '[' + possible_elasicity_str + ']'

    return [
        pl.Section([
            pl.SubSection([
                'You work for a new startup that is trying to manufacture phones. You are tasked with building '
                'a model which will help determine how many machines to invest in and how much to spend on '
                'marketing. Each machine produces $n_{output}$ phones per year. Each phone sells '
                r'for \$$p_{phone}$ and costs \$$c_{phone}$ in variable costs to produce. '
                'After $n_{life}$ years, the machine can no longer produce output, but may be scrapped for '
                r'\$$p_{scrap}$. The machine will not be replaced, so you may end up with zero total output '
                r'before your model time period ends. '
                'Equity investment is limited, so in each year you can spend $c_{machine}$ to either buy a machine or buy '
                'advertisements. In the first year you must buy a machine. Any other machine purchases must '
                'be made one after another (advertising can only begin after machine buying is done). '
                'Demand for your phones starts at '
                '$d_1$. Each time you advertise, demand increases by $g_d$%. The prevailing market interest '
                'rate is $r$.'
            ],
                          title='The Problem'),
            pl.SubSection([
                pl.UnorderedList([
                    'You may limit your model to 20 years and a maximum of 5 machines if it is helpful.',
                    'For simplicity, assume that $c_{machine}$ is paid in every year, '
                    'even after all machines have shut down.',
                    'Ensure that you can change the inputs and the outputs change as expected.',
                    'For simplicity, assume that fractional phones can be sold, you do not '
                    'need to round the quantity transacted.'
                ])
            ],
                          title='Notes'),
            pl.SubSection([
                pl.SubSubSection([
                    pl.UnorderedList([
                        '$n_{output}$: Number of phones per machine per year',
                        '$n_{machines}$: Number of machines purchased',
                        '$n_{life}$: Number of years for which the machine produces phones',
                        '$p_{phone}$: Price per phone',
                        '$p_{scrap}$: Scrap value of machine',
                        '$c_{machine}$: Price per machine or advertising year',
                        '$c_{phone}$: Variable cost per phone',
                        '$d_1$: Quantity of phones demanded in the first year',
                        '$g_d$: Percentage growth in demand for each advertisement',
                        '$r$: Interest rate earned on investments'
                    ])
                ],
                                 title='Inputs'),
                pl.SubSubSection([
                    pl.UnorderedList([
                        'Cash flows in each year, up to 20 years',
                        'PV of cash flows, years 1 - 20',
                    ])
                ],
                                 title='Outputs')
            ],
                          title='The Model'),
            pl.SubSection([
                "It is unrealistic to assume that price and demand are unrelated. To extend the model, "
                "we can introduce a relationship between price and demand, given by the following equation: ",
                pl.Equation(str_eq=r'd_1 = d_c - Ep_{phone}', inline=False),
                pl.UnorderedList([
                    f'{pl.Equation(str_eq="E")}: Price elasticity of demand',
                    f'{pl.Equation(str_eq="d_c")}: Demand constant'
                ]),
                [
                    f"For elasticities and constants {possible_elasicity_str} "
                    f"({len(ELASTICITY_CONSTANT_CASES)} total cases), and taking the other "
                    "model inputs in the ",
                    pl.NameRef('check-work'),
                    ' section, determine the optimal price for each '
                    'elasticity, that is the price which maximizes the NPV.'
                ],
                pl.SubSubSection([
                    pl.UnorderedList([
                        '$d_1$ is no longer an input, but an output.',
                        'This bonus requires optimization, which we have not yet covered in class.',
                        'In Excel, you can use Solver.',
                        [
                            f'In Python, the {scipy_mono} package provides optimization tools. You will '
                            f'probably want to use:',
                        ],
                        pl.UnorderedList([
                            Hyperlink(scipy_minimize_link,
                                      scipy_minimize_mono),
                            "You will need to write a function which accepts price and returns NPV, "
                            "with other model inputs fixed.",
                            pl.UnorderedList([[
                                'Depending on how you set this up,',
                                Hyperlink(
                                    'https://www.learnpython.org/en/Partial_functions',
                                    'functools.partial'),
                                'may be helpful for this.'
                            ]]),
                            "It will actually need to return negative NPV, as the optimizer only minimizes, "
                            "but we want maximum NPV.",
                            [
                                'No answers to check your work are given for this bonus. The',
                                pl.NameRef('check-work'),
                                'section only applies to without the bonus.'
                            ]
                        ])
                    ])
                ],
                                 title='Notes')
            ],
                          title='Bonus Problem'),
        ],
                   title='Overview'),
        pl.Section([
            'You must start from "Project 1 Template.xlsx". Ensure that you reference all inputs from '
            'the Inputs/Outputs tab. Also ensure that all outputs are referenced back to the Inputs/Outputs tab. '
            'Do not change any locations of the inputs or outputs. '
            'The final submission is your Excel workbook.'
        ],
                   title='Excel Exercise'),
        pl.Section([[
            'You must start from "Project 1 Template.ipynb". '
            'I should be able to run all the '
            'cells and get the output of your model at the bottom. ',
            [
                'You should not change the name of the',
                pl.Monospace('ModelInputs'), 'class or the',
                pl.Monospace('model_data'), 'variable.'
            ], 'You need to define',
            pl.Monospace('cash_flows'), 'as your output cash flows (numbers, '
            'not formatted), and ',
            pl.Monospace('npv'),
            'as your NPV (number, not formatted). When you '
            'show your final outputs in the notebook, then they should be formatted.'
        ]],
                   title='Python Exercise'),
        pl.Section([
            Center(
                lt.Tabular([
                    lt.MultiColumnLabel('Grading Breakdown', span=2),
                    lt.TopRule(),
                    lt.ValuesTable.from_list_of_lists(
                        [['Category', 'Percentage']]),
                    lt.TableLineSegment(0, 1),
                    lt.ValuesTable.from_list_of_lists([[
                        'Model Accuracy', '60%'
                    ], ['Model Readability', '20%'], [
                        'Model Formatting', '10%'
                    ], ['Following the Template', '10%'], ['Bonus', '5%']]),
                    lt.MidRule(),
                    lt.ValuesTable.from_list_of_lists(
                        [['Total Possible', '105%']]),
                    lt.BottomRule()
                ],
                           align=align))
        ],
                   title='Grading'),
        pl.Section(
            [
                'If you pass the following inputs (to the basic model, not bonus model): ',
                pl.UnorderedList([
                    f'{pl.Equation(str_eq="n_{output}")}: {n_phones:,.0f}',
                    f'{pl.Equation(str_eq="p_{scrap}")}: \${price_scrap:,.0f}',
                    f'{pl.Equation(str_eq="p_{phone}")}: \${price_phone:,.0f}',
                    f'{pl.Equation(str_eq="c_{machine}")}: \${price_machine_adv:,.0f}',
                    f'{pl.Equation(str_eq="c_{phone}")}: \${cogs_phone:,.0f}',
                    f'{pl.Equation(str_eq="n_{life}")}: {n_life}',
                    f'{pl.Equation(str_eq="n_{machines}")}: {n_machines}',
                    f'{pl.Equation(str_eq="d_1")}: {d_1:,.0f}',
                    f'{pl.Equation(str_eq="g_d")}: {g_d:.0%}',
                    f'{pl.Equation(str_eq="r")}: {interest:.0%}',
                ]),
                'You should get the following result:',
                # TODO [#10]: replace project 1 result using notebook executor
                """
                Cash Flows:

Year 1: \$24,000,000

Year 2: \$24,000,000

Year 3: \$24,000,000

Year 4: \$24,000,000

Year 5: \$24,000,000

Year 6: \$29,000,000

Year 7: \$35,000,000

Year 8: \$42,200,000

Year 9: \$50,840,000

Year 10: \$61,208,000

Year 11: \$73,699,600

Year 12: \$74,050,000

Year 13: \$49,050,000

Year 14: \$24,050,000

Year 15: \$-950,000

Year 16: \$-1,000,000

Year 17: \$-1,000,000

Year 18: \$-1,000,000

Year 19: \$-1,000,000

Year 20: \$-1,000,000



NPV: \$369,276,542
                """
            ],
            title='Check your Work',
            label='check-work')
    ]
def get_content():
    jinja_templates_path = os.path.sep.join(['pltemplates', 'projects', 'p3'])
    jinja_env = pl.JinjaEnvironment(
        loader=FileSystemLoader(jinja_templates_path))

    with open(ANSWERS_OUTPUT_PATH, 'r') as f:
        answers_json = json.load(f)
    answers_dict = answers_json[0]

    beta_std = answers_dict['beta_std']
    mkt_ret_std = answers_dict['mkt_ret_std']
    bond_price_std = answers_dict['bond_price_std']
    tax_rate_std = answers_dict['tax_rate_std']
    bond_years = answers_dict['bond_years']
    bond_coupon = answers_dict['bond_coupon']
    bond_price = answers_dict['bond_price']
    bond_par = answers_dict['bond_par']
    risk_free = answers_dict['risk_free']
    price = answers_dict['price']
    shares_outstanding = answers_dict['shares_outstanding']
    libor_rate = answers_dict['libor_rate']

    inputs_table = pl.Center(
        lt.Tabular([
            pl.MultiColumnLabel('Baseline Inputs', span=2),
            lt.TopRule(),
            lt.ValuesTable.from_list_of_lists([['Variable', 'Baseline Value']
                                               ]),
            lt.TableLineSegment(0, 1),
            lt.ValuesTable.from_list_of_lists([
                ['Market Bond Maturity (Years)', f'{bond_years:.0f}'],
                ['Market Bond Coupon', f'{bond_coupon:.2%}'],
                ['Market Bond Price', rf'\${bond_price:.2f}'],
                ['Market Bond Par Value', rf'\${bond_par:.2f}'],
                ['Risk Free Rate', f'{risk_free:.2%}'],
                ['Stock Price', rf'\${price:.2f}'],
                ['Shares Outstanding', f'{shares_outstanding:,.0f}'],
                ['LIBOR Rate', f'{libor_rate:.2%}'],
            ]),
            lt.BottomRule()
        ],
                   align='l|c'))

    stdev_table = pl.Center(
        lt.Tabular([
            pl.MultiColumnLabel('Standard Deviations', span=2),
            lt.TopRule(),
            lt.ValuesTable.from_list_of_lists(
                [['Variable', 'Standard Deviation']]),
            lt.TableLineSegment(0, 1),
            lt.ValuesTable.from_list_of_lists([
                [r'$\beta$', beta_std],
                ['Market Return', f'{mkt_ret_std:.0%}'],
                ['Walmart Bond Market Price', rf'\${bond_price_std}'],
                ['Tax Rate', f'{tax_rate_std:.0%}'],
            ]),
            lt.BottomRule()
        ],
                   align='l|c'))

    return [
        pl.Section([
            Project3ProblemModel(template_path='prob_definition.j2',
                                 environment=jinja_env),
            Project3ProblemModel(template_path='notes.j2',
                                 environment=jinja_env),
            Project3ProblemModel(template_path='bonus.j2',
                                 environment=jinja_env),
            pl.SubSection([inputs_table],
                          title='Baseline Model Inputs',
                          label='baseline-inputs'),
            pl.SubSection(
                [stdev_table], title='Monte Carlo Inputs', label='mc-inputs'),
        ],
                   title='Overview'),
        pl.Section([
            Project3ProblemModel(template_path='submission.j2',
                                 environment=jinja_env),
            pl.SubSection([
                'Selected solutions with the baseline inputs:',
                pl.UnorderedList([
                    f'WACC: {answers_dict["wacc"]:.2%}',
                    rf'MV Debt: \${answers_dict["mv_debt"] / 1000000000:.1f} billion',
                    f'Cost of Equity: {answers_dict["coe"]:.2%}',
                    f'Pre-Tax Cost of Debt: {answers_dict["pretax_cost_of_debt"]:.2%}'
                ])
            ],
                          title='Solutions'),
            pl.SubSection([
                pl.Center(
                    lt.Tabular([
                        pl.MultiColumnLabel('Grading Breakdown', span=2),
                        lt.TopRule(),
                        lt.ValuesTable.from_list_of_lists(
                            [['Category', 'Percentage']]),
                        lt.TableLineSegment(0, 1),
                        lt.ValuesTable.from_list_of_lists([
                            ['Model Accuracy', '60%'],
                            ['Model Readability', '20%'],
                            ['Model Formatting', '10%'],
                            ['Following the Template', '10%'], ['Bonus', '5%']
                        ]),
                        lt.MidRule(),
                        lt.ValuesTable.from_list_of_lists(
                            [['Total Possible', '105%']]),
                        lt.BottomRule()
                    ],
                               align='l|c'))
            ],
                          title='Grading'),
        ],
                   title='Submission & Grading')
    ]
Ejemplo n.º 10
0
def get_content():
    return [
        pl.Section(
            [
                pl.SubSection(
                    [
                        'You are a financial analyst for an aircraft manufacturer. Your company is trying to decide '
                        'how large its next line of planes should be. Developing a line of planes takes a one-time '
                        'research cost, then each plane has a cost to manufacture afterwards. The larger the plane, '
                        'the higher the research and manufacture costs, but also the more revenue per plane. The '
                        'larger planes are more risky because if the economy goes poorly, not many airlines will want '
                        'to invest in such a large plane, but if the economy goes well, airlines will be rushing to the '
                        'larger planes to fit rising demand.',
                        '',
                        """
                        The research cost will be paid at $t=0$. For simplicity, assume that all planes are manufactured 
                        at $t=1$ and sold at $t=2$. The interest rate is given in the below table.
                        
                        Find the expected NPV and standard deviation of NPV for each plane. Which plane has the lowest
                        chance of a negative NPV? Which has the highest chance of a positive NPV? Visualize the range
                        of possible NPVs for each plane, as well as the probability of acheiving different NPV levels 
                        (probability table). For the mid-size plane, which has a larger impact on the NPV, an 
                        additional plane sold or a decrease in the interest rate by 1%? In your opinion, which
                        plane should the manufacturer create?
                        """
                    ],
                    title='Problem Definition'
                ),
                pl.SubSection(
                    [
                        pl.Center(
                            lt.Tabular(
                                [
                                    lt.TopRule(),
                                    lt.ValuesTable.from_list_of_lists([[
                                        'Plane', 'Research Cost', 'Manufacture Cost', 'Sale Price', 'Expected Unit Sales', 'Stdev Unit Sales'
                                    ]]),
                                    lt.MidRule(),
                                    lt.ValuesTable.from_list_of_lists(
                                        [
                                            ['Super Size', r'\$100,000,000', r'\$10,000,000', r'\$11,500,000', '200', '120'],
                                            ['Large', r'\$50,000,000', r'\$5,000,000', r'\$5,600,000', '400', '50'],
                                            ['Mid-size', r'\$25,000,000', r'\$3,000,000', r'\$3,350,000', '500', '20'],
                                        ],
                                    ),
                                    lt.BottomRule(),
                                ],
                                align='l|ccccc'
                            )
                        )
                    ],
                    title='Possible Planes'
                ),
                pl.SubSection(
                    [
                        pl.Center(
                            lt.Tabular(
                                [
                                    lt.TopRule(),
                                    lt.ValuesTable.from_list_of_lists([[
                                        'Input', 'Default Value', 'Default Stdev'
                                    ]]),
                                    lt.MidRule(),
                                    lt.ValuesTable.from_list_of_lists(
                                        [
                                            ['Interest Rate', '7%', '4%'],
                                        ],
                                    ),
                                    lt.BottomRule(),
                                ],
                                align='l|cc'
                            )
                        )
                    ],
                    title='Other Inputs'
                )
            ],
            title='Capital Budgeting Probabilities with Monte Carlo Simulation'
        )
    ]