def test_presentation_options():
    doc = pl.Presentation(
        [
            pl.Section([
                pl.Frame(['woo'], title='One-One'),
                pl.Frame(['woo2'], title='One-Two')
            ],
                       title="One"),
            pl.Section([
                pl.Frame(['woo3'], title='Two-One'),
                pl.Frame(['woo4'], title='Two-Two')
            ],
                       title="Two")
        ],
        packages=['hyperref'],
        title='Test Presentation',
        authors=['Nick DeRobertis', 'Someone Else'],
        date='2020-10-19',
        short_title='Pres',
        subtitle='A Presentation for Testing Purposes',
        short_author='People',
        institutions=[['University of Florida', 'Line two'],
                      ['Virginia Commonwealth University']],
        short_institution='UF & VCU',
        font_size=15,
        nav_header=True,
        toc_sections=True,
    )
    name = 'presentation with options'
    assert_same_or_generate_presentation(doc, name)
    doc.to_pdf(outfolder=GENERATED_FILES_DIR, outname=name)
    compare_pdfs_in_generated_vs_input_by_name(name)
Ejemplo n.º 2
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')
    ]
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.º 4
0
def test_basic_resume():
    contents = [
        pl.Section(
            [
                'An overview'
            ],
            title='Normal section'
        ),
        lr.SpacedSection(
            [
                JOB,
                EDUCATION,
                PUBLICATION,
                AWARD,
                REFERENCE
            ],
            title='Spaced Section'
        )
    ]
    doc = lr.Resume(
        contents,
        contact_lines=CONTACT_LINES
    )
    assert str(doc) == '\\documentclass[11pt]{resume}\n\\newenvironment{absolutelynopagebreak}{\\par\\nobreak\\vfil\\penalty0\\vfilneg\\vtop\\bgroup}{\\par\\xdef\\tpd{\\the\\prevdepth}\\egroup\\prevdepth=\\tpd}\n\\usepackage[left=0.75in,top=0.6in,right=0.75in,bottom=0.6in]{geometry}\n\\usepackage{xcolor}\n\\definecolor{darkblue}{RGB}{50,82,209}\n\\usepackage[hidelinks]{hyperref}\n\\usepackage{ragged2e}\n\\address{Nick DeRobertis}\n\\address{Location, here}\n\\address{Contact 1 \\\\ Contact 2}\n\\begin{document}\n\\begin{section}{Normal section}\nAn overview\n\\end{section}\n\\begin{section}{Spaced Section}\n\\vspace{0.2cm}\n\\begin{absolutelynopagebreak}\n\\begin{employment}{Company Name}{2015 - Present}{Job Title}{Location, Here}\n\\item \\begin{itemize}\n\\item I did\n\\item some things\n\\item today\n\\end{itemize}\nExtra contents\n\\end{employment}\n\\end{absolutelynopagebreak}\n\n\\begin{absolutelynopagebreak}\n\\textbf{Some School}\n (GPA 4.0/4.0)\n\\hfill\n\\textbf{May 2020}\n\\\\\n\\textit{Bachelor of Science in Something}\n\\hfill\nLocation, Here\n\\\\[-8pt]\n\\end{absolutelynopagebreak}\n\n\\begin{absolutelynopagebreak}\n\\hangindent=1cm\n\\href{https://www.example.com/}{\\underline{\\textcolor{darkblue}{Publication Title}}},\n\\textit{Journal of Awesome}\n with \nCoauthor One\n and \nCoauthor Two\nThis was a really neat paper\n\n\\justifying\nA description of the paper\n\\vspace{0.2cm}\n\\vspace{0.2cm}\n\\end{absolutelynopagebreak}\n\n\\begin{absolutelynopagebreak}\n\\textbf{Cool Award}\n (Some extra info)\n\\hfill\nMay 2020\n\\\\[-8pt]\n\\end{absolutelynopagebreak}\n\n\\begin{absolutelynopagebreak}\n\\textsc{\\textbf{My Reference}}\n\\\\\n\\textit{Reference Title}\n\\\\\n\\textit{Can be Multiple Lines}\n\\\\\nOrganization\n\\\\\nAddress\n\\\\\nPhone\n\\\\\nWhatever contact\n\\\\\[email protected]\n\\\\\n\\\\[-8pt]\n\\end{absolutelynopagebreak}\n\\vspace{-0.2cm}\n\\end{section}\n\\end{document}'
    name = 'resume basic'
    doc.to_pdf(outfolder=GENERATED_FILES_DIR, outname=name)
    compare_pdfs_in_generated_vs_input_by_name(name)
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')
    ]
Ejemplo n.º 6
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.º 7
0
    def to_pyexlatex(
            self,
            lectures: Dict[str, List[Lecture]],
            lab_exercises: List[LabExerciseLecture],
            week_num: int,
            start_date: datetime.date,
            end_date: datetime.date,
            project_date: Optional[datetime.date] = None) -> pl.Section:
        if project_date is None:
            project_date = start_date

        start_fmt = start_date.strftime(self.date_fmt)
        end_fmt = end_date.strftime(self.date_fmt)
        project_fmt = project_date.strftime(self.date_fmt)

        section_contents = []

        if lectures:
            content = []
            for lecture_group_title, lecture_list in lectures.items():
                lecture_contents = pl.UnorderedList(
                    [lect.title for lect in lecture_list])
                content.append(
                    pl.UnorderedList([lecture_group_title, lecture_contents]))

            section_contents.append(
                pl.SubSection(content, title='Lectures Covered'))

        if self.assigned_projects:
            section_contents.append(
                pl.SubSection([
                    pl.UnorderedList(
                        [proj.display_name for proj in self.assigned_projects])
                ],
                              title='Projects Assigned'))

        if self.projects_due:
            section_contents.append(
                pl.SubSection([
                    pl.UnorderedList(
                        [proj.display_name for proj in self.projects_due])
                ],
                              title=f'Projects Due by {project_fmt}'))

        if lab_exercises:
            section_contents.append(
                pl.SubSection(
                    [pl.UnorderedList([lab.title for lab in lab_exercises])],
                    title=f'Lab Exercises Due by {end_fmt}'))

        date_str = f'{start_fmt} - {end_fmt}'
        section = pl.Section(section_contents,
                             title=f'Week {week_num} ({date_str})')
        return section
def test_figure_in_presentation():
    graphic = pl.Graphic(str(EXAMPLE_IMAGE_PATH), width=0.4)
    fig = pl.Figure([graphic], caption='My Figure')
    doc = pl.Presentation([
        pl.Section([
            pl.Frame([fig], title='Figure'),
        ], title="Section"),
    ], )
    name = 'presentation with figure'
    assert_same_or_generate_presentation(doc, name)
    doc.to_pdf(outfolder=GENERATED_FILES_DIR, outname=name)
    compare_pdfs_in_generated_vs_input_by_name(name)
Ejemplo n.º 9
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'
                   )
    ]
Ejemplo n.º 10
0
def test_package_conflict():
    section = pl.Section(['woo'], title='Section')
    section.init_data()
    section.add_package(pl.Package('hyperref', modifier_str='hidelinks'))
    # Without eq_on_modifier=False, raises error for package options conflict
    section.add_package(
        pl.Package('hyperref',
                   modifier_str='linktoc=all',
                   eq_on_modifier=False))
    doc = pl.Document([section])
    doc.to_pdf(GENERATED_FILES_DIR, outname='package conflict document')
    compare_pdfs(INPUT_FILES_DIR / 'package conflict document.pdf',
                 GENERATED_FILES_DIR / 'package conflict document.pdf')
Ejemplo n.º 11
0
def test_table_in_presentation():
    df = pd.DataFrame([(1, 2, 3.546), (4, 5, 66546.4), (7, 8, 96.54)],
                      columns=['a', 'b', 'c'])
    table = pl.Table.from_list_of_lists_of_dfs(
        [[df]],
        caption='My Table Title',
        below_text='My below text',
        align='L{5cm}c.',
        mid_rules=False,
    )
    doc = pl.Presentation([
        pl.Section([
            pl.Frame([table], title='Table'),
        ], title="Section"),
    ], )
    name = 'presentation with table'
    assert_same_or_generate_presentation(doc, name)
    doc.to_pdf(outfolder=GENERATED_FILES_DIR, outname=name)
    compare_pdfs_in_generated_vs_input_by_name(name)
Ejemplo n.º 12
0
def test_tabular_list_from_table_in_presentation():
    df = pd.DataFrame([(1, 2, 3.546), (4, 5, 66546.4), (7, 8, 96.54)],
                      columns=['a', 'b', 'c'])
    table = pl.Table.from_list_of_lists_of_dfs([[df], [df + 10]],
                                               caption='My Table Title',
                                               below_text='My below text',
                                               align='L{5cm}c.')
    frames = [
        pl.Frame(tab, title=f'Tabular {i + 1}') for i, tab in enumerate(
            table.tex_obj(as_document=False, as_panel_tabular_list=True))
    ]

    doc = pl.Presentation([
        pl.Section([
            frames,
        ], title="Section"),
    ], )
    name = 'presentation with tabular list'
    assert_same_or_generate_presentation(doc, name)
    doc.to_pdf(outfolder=GENERATED_FILES_DIR, outname=name)
    compare_pdfs_in_generated_vs_input_by_name(name)
Ejemplo n.º 13
0
    def __init__(self,
                 contents,
                 title: str,
                 end_adjustment: float = -0.2,
                 num_cols: int = 1):
        self.end_adjustment = end_adjustment
        self.num_cols = num_cols

        if not isinstance(contents, (list, tuple)):
            contents = [contents]

        all_contents: Union[List[Union[pl.VSpace, str]],
                            MultiColumn] = [pl.VSpace(0.2)]
        for content in contents:
            all_contents.append(content)
            all_contents.append('')
        all_contents[-1] = pl.VSpace(end_adjustment)  # replace final spacing

        if self.num_cols > 1:
            all_contents = MultiColumn(all_contents, num_cols=self.num_cols)

        self.contents = pl.Section(all_contents, title=title)
        super().__init__()
Ejemplo n.º 14
0
def get_content():
    random.seed(1000)
    site_link = Hyperlink(SITE_URL, 'the course site')
    lecture = get_getting_started_with_python_and_excel_lecture()

    full_fix = Monospace('\$A\$2')
    col_fix = Monospace('\$A2')
    row_fix = Monospace('A\$2')
    notebook = Monospace('jupyter notebook')
    lab = Monospace('jupyter lab')
    list_ = Monospace('list')
    for_ = Monospace('for')
    append = Monospace('append')
    numpy = Monospace('numpy')
    cmd = Monospace('cmd')
    terminal = Monospace('terminal')
    in_block = Monospace('In [ ]:')
    numpy_financial = pl.Monospace('numpy_financial')

    example_python_iteration = Block(
        Python("""
inputs = [5, 10, 15]
for item in inputs:
    new_value = item + 2
    print(new_value)

7
12
17
        """),
        title='Python Iteration'
    )
    return [
        pl.Section(
            [
                TwoColumnGraphicDimRevealFrame(
                    [
                        'The focus today is to get familiar working in both Excel and Python',
                        'We will approach this by building a simple model with both tools',
                        'In later lectures, we will move to combining the tools'
                    ],
                    graphics=[
                        images_path('equations-chalkboard.jpg')
                    ],
                    title='Approaching a Problem with Two Tools'
                ),
                DimRevealListFrame(
                    [
                        "Let's take what is perhaps the simplest finance problem, which everyone should understand",
                        "While you may have approached such a problem with a calculator before, we will build models for it instead",
                        "Martha is saving for retirement. She earns \$60,000 per year and is able to save 25% of that. If she invests "
                        "her savings, earning 5% per year, and she needs \$1,500,000 to retire, how soon can she retire?"
                    ],
                    title='A Simple Retirement Problem'
                ),
                ModelFlowchartFrame(
                    [
                        [
                            'Wages, Savings',
                            'Investment',
                            Node('Cash in the bank, person retires',
                                 options=real_world_style + ['text width=2.5cm'])
                        ],
                        [
                            Node('Cash Flows, Savings Rate, Interest Rates',
                                 options=model_style + ['text width=3.5cm']),
                            'Model',
                            Node('FV of CF, time until retirement', options=model_style + ['text width=2.5cm'])
                        ]
                    ],
                    title='Breaking Down the Retirement Problem'
                ),
            ],
            title='An Introductory Model',
            short_title='Basic Problem'
        ),
        pl.Section(
            [
                TwoColumnGraphicDimRevealFrame(
                    [
                        "It is easy to use Excel as a calculator and just type the math in directly. But we want to build a model.",
                        "Changing inputs should result in a change to outputs. The way to do this in Excel is cell references",
                        rf"Fixed references become important when trying to drag formulas, e.g. {full_fix} (fully fixed), {col_fix} (fixed on "
                        rf"column), or {row_fix} (fixed on row)."
                    ],
                    graphics=[
                        images_path('excel-logo.png')
                    ],
                    title='Solving the Problem in Excel'
                ),
                InClassExampleFrame(
                    [
                        ['Go to', site_link, 'and download Simple Retirement Model Excel'],
                        'Follow along as I recreate the simple model.'
                    ],
                    title='Simple Retirement Problem in Excel',
                    block_title='Intro Excel Exercise'
                )
            ],
            title='Excel Solution'
        ),
        pl.Section(
            [
                TwoColumnGraphicDimRevealFrame(
                    [
                        pl.TextSize(-1),
                        "Using Python in the terminal is kind of a pain. And so, tools were born.",
                        "Jupyter is a graphical interface we can use for Python. It also supports over 40 other "
                        "languages such as R, SAS, Julia, and Scala",
                        f"You can use {notebook} or {lab}. The latter has a lot more features outside of the notebook. "
                        f"We will focus on using {lab} in this class as it is the future of Jupyter."
                    ],
                    graphics=[
                        images_path('jupyter-notebook.png')
                    ],
                    title="How We'll Work in Python"
                ),
                Frame(
                    [
                        LabBlock(
                            [
                                OrderedList([
                                    "Launch Anaconda Navigator",
                                    "Find Jupyter Notebook on the main screen, and click launch",
                                    "You should see a list of folders and files. Click New and then Python 3",
                                    f"Now you should see a code cell with {in_block} next to it"
                                ])
                            ],
                            title='Launch Jupyter Notebook'
                        ),
                        AlertBlock(
                            f"If you don't have Anaconda Navigator, just open a terminal (search {cmd} on Windows, {terminal} on Mac). Then in the "
                            f"terminal, type {lab} and enter. Then continue with the third step."
                        )
                    ],
                    title="Let's Get Set up with Jupyter"

                ),
                DimRevealListFrame(
                    [
                        "In Excel, the basic unit is a cell. In Python, the basic unit is an object.",
                        "In Excel, content in a cell is either a number (123) or a string (ABC)",
                        "In Python, all objects have types. They might also be a number or a string, or something else.",
                        f"Rather than using a cell reference like {full_fix}, we assign names to objects in Python",
                        Python("""
                        my_number = 6
                        my_string = 'ABC'
                        """)
                    ],
                    title='Some Python Basics'
                ),
                TwoColumnFrame(
                    [
                        pl.Graphic(images_path('numpy-logo.png')),
                        pl.Block(
                            [
                                pl.TextSize(-2),
                                'In the future, these numpy financial functions are being moved '
                                'to a separate package', f'{numpy_financial}.', 'For',
                                "the purposes of this class, this won't matter, but in the future you may have "
                                "to install", numpy_financial, 'to use these functions.',
                                'In the meantime, you will see a warning come up when calling the functions.'
                            ],
                            title='Note: Deprecation warning'
                        ),
                    ],
                    [
                        UnorderedList([
                            DimAndRevealListItems(
                                [
                                    "Basic operations in Python are straightforward",
                                    Python('2 + 5 = 7'),
                                    Python('6 - 2 = 4'),
                                    Python('2 * 3 = 6'),
                                    Python('5 / 2 = 2.5'),
                                    f'A lot more is available using the {numpy} package',
                                    Python("np.pv, np.nper,\nnp.fv, np.pmt"),
                                    Hyperlink(
                                        'https://numpy.org/doc/stable/reference/routines.financial.html',
                                        f'All numpy financial functions')
                                ],
                                dim_earlier_items=False
                            )
                        ])
                    ],
                    title='Doing Some Math in Python'
                ),
                InClassExampleFrame(
                    [
                        ['Go to', site_link, 'and download Simple Retirement Model Python'],
                        'In Jupyter, then navigate to your Downloads folder (or wherever you saved it)',
                        'You should then see Simple Retirement Model.ipynb come up in the list of files in Jupyter. '
                        'Click it to open it and follow along.'
                    ],
                    title='Simple Retirement Problem in Python',
                    block_title='Intro Python Exercise'
                )
            ],
            title='Python Solution'
        ),
        pl.Section(
            [
                DimRevealListFrame(
                    [
                        "Now we've got basic models to determine how long it will take Martha to retire.",
                        "We've got a few assumptions built into the model. One is that Martha will earn 5% on her investments",
                        "Rates of return are volatile, so we want to see how long it would take her to retire if her return was different"
                    ],
                    title='Extending the Model - Multiple Interest Rates'
                ),
                DimRevealListFrame(
                    [
                        "In programming, for model building or otherwise, you often need to repeat the same process for multiple different things",
                        "In Excel, you would do this by dragging formulas.",
                        f"In Python, as in most other programming languages, we would use a {for_} loop",
                        "This says, do something, for each value I pass into the loop"
                    ],
                    title='Programming Fundamentals - Iteration'
                ),
                BasicTwoColumnFrame(
                    [
                        example_python_iteration
                    ],
                    [
                        Block(
                            Graphic(
                                images_path('excel-iteration.png')
                            ),
                            title='Excel Iteration'
                        )
                    ],
                    title='Iteration - Python vs. Excel'
                ),
                TwoColumnFrame(
                    [
                        UnorderedList([
                            DimAndRevealListItems([
                                "There's a few things to unpack here",
                                f"Here's another type of object: not a number or a string, but a {list_}",
                                f"A {list_} holds multiple objects, and you can add or remove items from {list_}s",
                            ])
                        ])
                    ],
                    [
                        example_python_iteration
                    ],
                    title='Explaining Python Iteration'
                ),
                TwoColumnFrame(
                    [
                        UnorderedList([
                            DimAndRevealListItems([
                                "Here we define a list of three numbers as inputs",
                                f"Then we use a {for_} loop to get each input out of the list, and add 2 to it to create the new value",
                                "Finally we print each value as it is generated"
                            ])
                        ])
                    ],
                    [
                        example_python_iteration
                    ],
                    title='Explaining Python Iteration (pt. 2)'
                ),
                InClassExampleFrame(
                    [
                        'I will now expand the existing Excel and Python models to examine multiple interest rates',
                        'Continue viewing the same previously downloaded files.'
                    ],
                    title='Iterating the Existing Model',
                    block_title='Expanding on Python and Excel'
                ),
                get_simple_retirement_lab_lecture().to_pyexlatex().presentation_frames(),
            ],
            title='Extending the Model and Iteration',
            short_title='Extend & Iterate'
        ),
        pl.PresentationAppendix(
            [
                lecture.pyexlatex_resources_frame,
                pl.TextSize(-1),
                get_simple_retirement_lab_lecture().to_pyexlatex().appendix_frames(),
                pl.TextSize(0),
            ]
        )
    ]
    I am also providing the IRRs for each possible default situation in the model with base case inputs 
    and a 20% interest rate. This way you
    can check your model without having to run lots of iterations. Make sure that your model can reproduce each of the
    IRRs corresponding to each default case, and then you will only need the full solutions to check that the probabilities
    are set correctly. Note that unlike the full solutions, you should be able to match these default case solutions 
    exactly.
    """

    return [
        pl.Section([
            pl.SubSection([
                problem_definition_pre_prob,
                pl.Equation(str_eq=default_prob_eq_str, inline=False),
                problem_definition_post_prob
            ],
                          title='Problem Definition'),
            pl.SubSection([main_q_str], title='Main Question'),
            pl.SubSection([pl.UnorderedList(notes)], title='Notes'),
            pl.SubSection([inputs_content], title='Inputs'),
            pl.SubSection([bonus_q_str], title='Bonus Question'),
        ],
                   title='Overview'),
        pl.Section([
            pl.SubSection([submission_str], title='Submission'),
            pl.SubSection([
                solutions_str,
                pl.Center(
                    pl.Graphic(images_path('project-2-solutions.png'),
                               width=0.5), ),
                case_solutions_str,
                pl.UnorderedList(case_solutions_list),
Ejemplo n.º 16
0
def get_content():
    pd_mono = pl.Monospace('pandas')
    dfs_mono = pl.Monospace('DataFrames')
    df_mono = pl.Monospace('DataFrame')
    next_slide = lp.Overlay([lp.UntilEnd(lp.NextWithIncrement())])
    df_to_excel_example = pl.Python(
        "df.to_excel('data.xlsx', sheet_name='My Data', index=False)")
    df_from_excel_example = pl.Python(
        "df = pd.read_excel('data.xlsx', sheet_name='My Data')")
    index_false_mono = pl.Monospace('index=False')
    addin_install_mono = pl.Monospace('xlwings addin install')
    addin_install_success = pl.Monospace(
        'Successfuly installed the xlwings add-in! Please restart Excel.')
    random_seed_py = pl.Monospace('random_seed.py')
    random_seed_excel = pl.Monospace('random_seed.xlsm')
    quickstart_mono = pl.Monospace('xlwings quickstart')
    quickstart_project_mono = pl.Monospace(
        'xlwings quickstart my_project_name')
    cd_mono = pl.Monospace('cd')
    xw_func_decorator = pl.Monospace('@xw.func')
    xw_arg_decorator = pl.Monospace('@xw.arg')
    xw_ret_decorator = pl.Monospace('@xw.ret')
    x_mono = pl.Monospace('x')
    expand_table_mono = pl.Monospace("expand='table'")
    random_choice_mono = pl.Monospace('random_choice')
    random_choice_py = pl.Monospace('random.choices')

    lecture = get_combining_excel_python_lecture()
    pd_read_write_exercise = get_read_write_excel_pandas_lab_lecture(
    ).to_pyexlatex()
    xlwings_exercise = get_read_write_xlwings_lab_lecture().to_pyexlatex()

    read_from_excel_example = pl.Python("""
my_value = sht.range("G11").value  # single value
# all values in cell range
my_value = sht.range("G11:F13").value  
# expands cell range down and right getting all values
my_values = sht.range("G11").expand().value  
""")

    write_to_excel_example = pl.Python("""
sht.range("G11").value = 10
sht.range("G11").value = [10, 11]  # horizontal
sht.range("G11:G12").value = [10, 11]  # vertical
# table, DataFrame from elsewhere
sht.range("G11").value = df  
""")

    return [
        pl.Section([
            lp.DimRevealListFrame([
                "We have learned how to use both Excel and Python to solve problems. Throughout this process, there "
                "were advantages and disadvantages of each tool for each problem.",
                "I wanted you to know both tools so you could pick whichever is best to tackle your problem",
                "For larger problems, you'll likely find some parts are better with Excel and some with Python",
                "After this lecture, you won't need to choose one anymore, you can use both at once."
            ],
                                  title='Leveraging the Power of Both Tools'),
        ],
                   title='Introduction'),
        pl.Section([
            lp.DimRevealListFrame([
                [pd_mono, 'has built-in tools for working with Excel'],
                [
                    pd_mono, 'can read Excel workbooks into', dfs_mono,
                    'and it can write', dfs_mono, 'back to Excel workbooks'
                ],
                'For simple uses, this may be enough. If you just need to get data from somewhere once and put it in your '
                'workbook, or you have your data in Excel and want to analyze it in Python, this is sufficient',
                [
                    "If you want to manipulate your workbook from Python, or you want to run Python code from your "
                    "workbook, look to", xlwings_mono
                ]
            ],
                                  title=f'How Far does {pd_mono} Get Us?'),
            lp.Frame([
                lp.Block([
                    df_from_excel_example,
                    pl.VSpace(-0.3),
                    pl.UnorderedList([
                        "If you don't pass a sheet name, it will take the first sheet."
                    ])
                ],
                         title='Reading Excel Files',
                         overlay=next_slide),
                pl.VFill(),
                lp.Block(
                    [
                        df_to_excel_example,
                        pl.VSpace(-0.3),
                        pl.UnorderedList(
                            [[
                                'We are passing', index_false_mono,
                                'because usually the 0, 1, 2 ... index is not useful'
                            ],
                             [
                                 "If you had set your index to something useful, then don't include",
                                 index_false_mono
                             ]])
                    ],
                    title='Writing to Excel Files',
                    overlay=next_slide),
                pl.VFill(),
                lp.AlertBlock([[
                    'When', pd_mono,
                    'writes to a workbook, it replaces the file. Do not write over an existing '
                    'workbook that you want to keep!'
                ]],
                              title='Careful When Writing!',
                              overlay=next_slide),
            ],
                     title=f'Reading and Writing to Excel Files with {pd_mono}'
                     ),
            lp.Frame([
                InClassExampleBlock([
                    pl.UnorderedList([
                        'Download the contents of the "Read Write Excel Pandas" folder in Examples',
                        'Ensure that you put the Excel file and notebook in the same folder for it to work',
                        'Follow along with the notebook'
                    ])
                ],
                                    title=
                                    f'Read and Write to Excel using {pd_mono}')
            ],
                     title='Showcasing Reading and Writing to Excel Files'),
            pd_read_write_exercise.presentation_frames(),
        ],
                   title=f'To and From Excel with {pd_mono}',
                   short_title=pd_mono),
        pl.Section([
            lp.TwoColumnGraphicDimRevealFrame([[
                'The easiest way to use Python from in Excel, or Excel from in Python, is',
                xlwings_mono
            ], "In Windows, it's based off the Microsoft COM API, which is some common tools they give for creating "
                                               "plugins.",
                                               "It's still in active development, but overall it works pretty well and is far beyond where we were "
                                               "a few years ago"],
                                              graphics=[
                                                  images_path(
                                                      'xlwings-logo.png')
                                              ],
                                              title=
                                              f'Introducing {xlwings_mono}'),
            lp.DimRevealListFrame(
                [['There are two main ways to use', xlwings_mono],
                 [
                     'You can',
                     pl.
                     Bold('manipulate Excel from Python,'),
                     'which gives you the full power of Excel from',
                     "within Python. In this class we'll focus on reading and writing values, but you can do anything",
                     "that you would normally be able to in Excel, but by executing Python code."
                 ],
                 [
                     'Or you can',
                     pl.Bold('run Python from Excel'),
                     'using one of two approaches:',
                     pl.Underline('Python as a VBA replacement'), 'and',
                     pl.Underline('user-defined functions (UDFs)')
                 ],
                 'We will focus on manipulating Excel from Python in this class. I encourage you to explore '
                 'the other two approaches on your own.'],
                title=f'What are the Main Ways to use {xlwings_mono}?'),
            lp.TwoColumnGraphicDimRevealFrame([
                pl.TextSize(-1),
                [
                    xlwings_mono,
                    'allows us to write Python values into Excel and fetch Excel values into Python'
                ],
                'There is also a complete VBA API, meaning you can do everything that you could do with VBA '
                'from within Python, which means you have the full capabilities of Excel within Python',
                'There are also convenient features to work with entire tables at once rather than '
                'a single value'
            ],
                                              graphics=[
                                                  images_path(
                                                      'python-excel-logo.png')
                                              ],
                                              title=
                                              'Using Python to Drive Excel Models'
                                              ),
            lp.Frame([
                lp.Block([read_from_excel_example],
                         title='Read Values from Excel'),
                lp.Block([write_to_excel_example],
                         title='Write Values to Excel')
            ],
                     title='Write and Read Values to and from Excel'),
            InClassExampleFrame([
                'Download the contents of the "xlwings" folder in Examples',
                'Ensure that you put the Excel file and notebook in the same folder for it to work',
                'Follow along with the notebook'
            ],
                                title=f'How to Use {xlwings_mono}',
                                block_title=f'Trying out {xlwings_mono}'),
            xlwings_exercise.presentation_frames(),
        ],
                   title=
                   f'Introducing Full Python-Excel Connection with {xlwings_mono}',
                   short_title=f'{xlwings_mono}'),
        pl.PresentationAppendix([
            lecture.pyexlatex_resources_frame,
            pd_read_write_exercise.appendix_frames(),
            xlwings_exercise.appendix_frames(),
        ])
    ]
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),
    ]
def get_content():
    return [
        pl.Section([
            'You will be graded across several dimensions in completing projects. These dimensions include, but '
            'are not limited to: ',
            pl.UnorderedList([
                'Model Accuracy',
                'Model Readability',
                'Model Formatting',
                'Following the Template',
            ]),
            'Some projects may have their own specific categories. If so, the criteria for that category will '
            "be defined in that project's description."
        ],
                   title='The Grading Categories'),
        pl.Section([
            'I will first look at all the models before grading any of them. This is how I will establish what '
            'to expect. The grading is somewhat absolute and somewhat relative. For example, if your model is '
            'completely accurate, you will receive a 100% for model accuracy. But, you could also receive a high '
            'grade for model accuracy even if there are errors, if the rest of the class made similar errors. '
            'Partial credit will be given in every category. The amount of points given will be proportional '
            'to how well you completed the category, on an absolute basis if applicable and also relative to '
            'other students.'
        ],
                   title='The Score in a Category'),
        pl.Section([
            'The weights of each category will be specific to the project. Generally, Model Accuracy will '
            'carry the highest weight, and Model Formatting will carry the lowest weight. Look '
            'to the project description for a breakdown of the weights.'
        ],
                   title='The Grading Weights of the Categories'),
        pl.Section([
            pl.UnorderedList([
                'Does the model obtain the correct results?',
                'When inputs are changed, does the output change appropriately?',
                'Can the model handle the full range of possible values?'
            ])
        ],
                   title='Model Accuracy'),
        pl.Section([
            "Model readability is all about how easily can I understand what you're doing in the model, "
            "and how easily I can navigate through it.",
            pl.SubSection([
                pl.UnorderedList([
                    'Is the model organized into sections using tabs?',
                    'Are there clear names for inputs, outputs, and table headers?',
                    'Is each tab organized to separate inputs, outputs, and calculation?',
                    'Are there any comments explaining complex parts of the model?'
                ])
            ],
                          title='Excel'),
            pl.SubSection([
                pl.UnorderedList([
                    'Is the model organized into functions and sections?',
                    'Are all inputs at the top and main outputs at the bottom?',
                    'Are there docstrings, comments, or Jupyter markdown explaining things?',
                    'Does the submitted notebook or Python script have clear sections?',
                    'Are the length of code lines limited to the size of Jupyter cells (no long lines)?',
                    'Are the results of intermediate calculations shown? Should not be just one answer at end.',
                    [
                        'Do variable, function, and class names follow conventions? See',
                        Hyperlink(
                            'https://realpython.com/python-pep8/#naming-conventions',
                            'Naming Conventions')
                    ],
                ])
            ],
                          title='Python')
        ],
                   title='Model Readability'),
        pl.Section([
            "Model formatting is about the visual representation of the model.",
            pl.SubSection([
                pl.UnorderedList([
                    'Are tables formatted nicely?',
                    'Are inputs and outputs sections formatted to separate them from calculations?'
                ])
            ],
                          title='Excel'),
            pl.SubSection([
                pl.UnorderedList([
                    'Are model outputs displayed with nice formatting?',
                    pl.UnorderedList([
                        'Number formatting (percentages are percentages, '
                        'currency has dollar sign, commas, and two decimals, etc.)',
                        'Sentence explaining results is printed',
                        'Tables are used where appropriate and are well formatted',
                        'Plots have axis names and are appropriately sized'
                    ])
                ])
            ],
                          title='Python')
        ],
                   title='Model Formatting'),
        pl.Section([
            "Following the template is about conforming to the requested structure of the project "
            "such that it can be graded in a uniform way.",
            pl.SubSection([
                pl.UnorderedList([
                    'Use any provided template to start from',
                    'Do not move any of the inputs or outputs from the template',
                    'It is fine to change formatting of the inputs and outputs so long as the cell '
                    'reference location stay the same'
                ])
            ],
                          title='Excel'),
            pl.SubSection([
                pl.UnorderedList([
                    'Use any provided template to start from',
                    'Do not change the name of the ModelInputs class and be sure to use model_data as '
                    'the name of the variable containing the inputs',
                    'Do not rename variables in the ModelInputs dataclass. You may add additional variables '
                    'if you wish.',
                    'Keep the inputs at the top and outputs at the bottom',
                    'The instructions for a project may ask you to define certain variables and that they '
                    'should conform to certain data structures. Ensure that you do this and do not use '
                    'a different name or data structure.',
                    'For example, it may ask for cash_flows as a list of numbers. Ensure that you actually '
                    'have numbers in it and not formatted strings. However when you show the output '
                    'you should format it.'
                ])
            ],
                          title='Python')
        ],
                   title='Following the Template'),
    ]
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')
    ]
import pyexlatex as pl
import pytest
from pyexlatex.logic.builder import build

from plufthesis.transformers import elevate_sections_by_one_level

SUB_SUB_SECTION = pl.SubSubSection("Sub sub content", title="Sub Sub section")
SUB_SECTION = pl.SubSection(["Sub content", SUB_SUB_SECTION],
                            title="Sub section")
SECTION = pl.Section(["Section content", SUB_SECTION], title="Section")
CHAPTER = pl.Chapter(["Chapter content", SECTION], title='Chapter')

SECTIONS_BY_TEXT = r"""
\section{Section}
Section content
\subsection{Sub section}
Sub content
\subsubsection{Sub Sub section}
Sub sub content
"""

CHAPTERS_BY_TEXT = r"""
\chapter{Chapter}
Chapter content
""" + SECTIONS_BY_TEXT


def test_elevate_sections_objects_success():
    content = build([SECTION])
    revised = elevate_sections_by_one_level(content)
    assert (
Ejemplo n.º 21
0
def get_content():
    random.seed(1000)

    lecture = get_visualization_lecture()
    intro_pandas_lab = get_intro_to_pandas_lab_lecture().to_pyexlatex()
    styling_pandas_lab = get_pandas_styling_lab_lecture().to_pyexlatex()
    graphing_lab = get_intro_python_visualization_lab_lecture().to_pyexlatex()
    appendix_frames = [
        lecture.pyexlatex_resources_frame,
        intro_pandas_lab.appendix_frames(),
        styling_pandas_lab.appendix_frames(),
        graphing_lab.appendix_frames()
    ]

    ret_model = RetirementModel()
    ret_df = ret_model.get_formatted_df(num_years=12)
    ret_table = lt.Tabular.from_df(ret_df, extra_header=pl.Bold('Retirement Info'))
    plt_mono = pl.Monospace('matplotlib')
    df_mono = pl.Monospace('DataFrame')
    df_basic_example = pl.Python(
"""
>>> import pandas as pd
>>> df = pd.DataFrame()
>>> df['Sales'] = [1052, 212, 346]
>>> df['Category'] = ['Aprons', 'Apples', 'Bowties']
df
"""
    )
    plot_example_code = pl.Python(
"""
>>> %matplotlib inline
>>> ret_df.plot.line(x='Time', y='Salaries')
"""
    )

    return [
        pl.Section(
            [
                lp.DimRevealListFrame(
                    [
                        "So far we've had one main output from our model, number of years",
                        "Salaries and wealth over time have also been outputs, but we haven't had a good way of understanding "
                        "that output. It's a bunch of numbers.",
                        "This is where visualization comes in. We have some complex result, and want to make it easily "
                        "interpretable."
                    ],
                    title='Why Visualize?'
                ),
                lp.Frame(
                    [
                        pl.Center(ret_table)
                    ],
                    title='What we Have so Far'
                ),
                lp.GraphicFrame(
                    images_path('excel-insert-chart.png'),
                    title='Visualization in Excel'
                ),
                lp.GraphicFrame(
                    lg.ModifiedPicture(
                        images_path('python-visualization-landscape.jpg'),
                        [
                            lg.Path('draw', [(0.52, 0.52), (0.85, 0.67)], options=['red'], draw_type='rectangle',
                                    overlay=lp.Overlay([2]))
                        ]
                    ),
                    title='An Overwhelming Number of Options in Python'
                ),
                lp.DimRevealListFrame(
                    [
                        ["Ultimately, we will be creating graphs using", plt_mono, "but we won't use it directly."],
                        ["Instead, we will use", pd_mono],
                        [pd_mono, "is actually creating its graphs using", plt_mono,
                         "for us, but it is simpler to use."]
                    ],
                    title='Explaining Python Visualization in This Class'
                ),
                InClassExampleFrame(
                    [
                        'I will now go back to the "Dynamic Salary Retirement Model.xlsx" Excel model to '
                        'add visualization',
                        'I have also uploaded the completed workbook from this exercise '
                        'as "Dynamic Salary Retirement Model Visualized.xlsx"',
                        'Follow along as I go through the example.',
                    ],
                    title='Visualization in Excel',
                    block_title='Adding Graphs to the Dynamic Salary Retirement Excel Model'
                ),

            ],
            title='Visualization Introduction',
            short_title='Intro'
        ),
        pl.Section(
            [
                lp.DimRevealListFrame(
                    [
                        [pd_mono, "does", pl.Bold('a lot'), 'more than just graphing. We will use it throughout the '
                                                            'rest of the class.'],
                        "Previously we've worked with lists, numbers, strings, and even our custom types (our model dataclasses)",
                        [pd_mono, "provides the", df_mono, "as a new type that we can use."],
                        f'Before we can get to graphing, we must learn how to use the {df_mono}.'

                    ],
                    title='Some Setup Before we can Visualize in Python'
                ),
                lp.Frame(
                    [
                        ['A', df_mono, 'is essentially a table. It has rows and columns, just like in Excel.'],
                        pl.VFill(),
                        lp.Block(
                            [
                                pl.UnorderedList([
                                    'Add or remove columns or rows',
                                    'Group by and aggregate',
                                    'Load in and output data from/to Excel and many other formats',
                                    'Merge and join data sets',
                                    'Reshape and pivot data',
                                    'Time-series functionality',
                                    'Slice and query your data',
                                    'Handle duplicates and missing data'
                                ])
                            ],
                            title=f'Some Features of the {df_mono}'
                        )

                    ],
                    title=f'What is a {df_mono}?'
                ),
                lp.Frame(
                    [
                        df_basic_example,
                        pl.Graphic(images_path('df-basic-example.png'), width=0.3)

                    ],
                    title=f'A Basic {df_mono} Example'
                ),
                InClassExampleFrame(
                    [
                        'I will now go through the notebook in '
                        '"Intro to Pandas and Table Visualization.ipynb"',
                        'Follow along as I go through the example.',
                        'We will complete everything up until DataFrame Styling'
                    ],
                    title='Introduction to Pandas',
                    block_title='Creating and Using Pandas DataFrames'
                ),
                intro_pandas_lab.presentation_frames(),
                lp.DimRevealListFrame(
                    [
                        ['It is possible to add styling to our displayed tabular data by styling the', df_mono],
                        'The styling is very flexible and essentially allows you to do anything',
                        'Out of the box, it is easy to change colors, size, and positioning of text, add a caption, do '
                        'conditional formatting, and draw a bar graph over the cells.'
                    ],
                    title='Styling Pandas DataFrames'
                ),
                InClassExampleFrame(
                    [
                        'I will now go through the next section in '
                        '"Intro to Pandas and Table Visualization.ipynb"',
                        'Follow along as I go through the example.',
                        'This time we are covering the remainder of the notebook starting from "DataFrame Styling"'
                    ],
                    title='Introduction to Pandas',
                    block_title='Creating and Using Pandas DataFrames'
                ),
                styling_pandas_lab.presentation_frames(),
            ],
            title='Tables with Pandas DataFrames',
            short_title='Pandas'
        ),
        pl.Section(
            [
                lp.Frame(
                    [
                        lp.Block(
                            [
                                plot_example_code,
                                pl.Graphic(images_path('python-salaries-line-graph.pdf'), width=0.5)
                            ],
                            title=f'Line Graphs using {pd_mono}'
                        )
                    ],
                    title='A Minimal Plotting Example'
                ),
                lp.MultiGraphicFrame(
                    [
                        images_path('excel-salaries-line-graph.png'),
                        images_path('python-salaries-line-graph.pdf'),
                    ],
                    vertical=False,
                    title='Basic Graph Types: Line Graphs'
                ),
                lp.MultiGraphicFrame(
                    [
                        images_path('excel-salaries-bar-graph.png'),
                        images_path('python-salaries-bar-graph.pdf'),
                    ],
                    vertical=False,
                    title='Basic Graph Types: Bar Graphs'
                ),
                lp.MultiGraphicFrame(
                    [
                        images_path('excel-salaries-box-whisker-plot.png'),
                        images_path('python-salaries-box-graph.pdf'),
                    ],
                    vertical=False,
                    title='Basic Graph Types: Box and Whisker Plots'
                ),
                InClassExampleFrame(
                    [
                        'I will now go through '
                        '"Intro to Graphics.ipynb"',
                        'Follow along as I go through the entire example notebook.',
                    ],
                    title='Introduction to Graphing',
                    block_title='Graphing Using Pandas'
                ),
                graphing_lab.presentation_frames(),
            ],
            title='Graphing using Pandas',
            short_title='Graphs'
        ),
        pl.PresentationAppendix(appendix_frames)
    ]
Ejemplo n.º 22
0
def get_content():
    random.seed(1000)
    next_until_end_ov = lp.Overlay([lp.UntilEnd(lp.NextWithIncrement())])
    next_slide = lp.Overlay([lp.NextWithIncrement()])
    numpy_mono = pl.Monospace('numpy')
    lecture = get_dynamic_salary_python_lecture()


    return [
        pl.Section(
            [
                lp.DimRevealListFrame(
                    [
                        'We have seen how structure and organization can help the readability and maintainability of '
                        'an Excel model. The same concept exists for our Python models.',
                        ['We already learned that we should use functions to organize logic and a',
                         pl.Monospace('dataclass'),
                         'for the model inputs'],
                        "Typically you'll have functions for each step, those may be wrapped up into other functions which "
                        "perform larger steps, and ultimately you'll have one function which does everything by calling the"
                        "other functions.",
                        "Those are good ideas with any Python model, but working in Jupyter allows us some additional "
                        "organization and presentation of the model"
                    ],
                    title='How to Structure a Python Financial Model'
                ),
                lp.DimRevealListFrame(
                    [
                        'In Jupyter, we can have code, nicely formatted text, equations, sections, hyperlinks, '
                        'and graphics, all in one document',
                        ['For all you can do with these nicely formatted "Markdown" cells, see',
                         Hyperlink('https://www.markdownguide.org/basic-syntax/', 'here'), 'and',
                         Hyperlink('https://www.markdownguide.org/extended-syntax/', 'here.')],
                        'We can think of sections in Jupyter as analagous to Excel sheets/tabs. One section for each '
                        'logical part of your model. Then you can have smaller headings for subsections of the model.',
                        'Break your code up into small sections dealing with each step, with nicely formatted text '
                        'explaining it. Add comments where anything is unclear in the code.',
                    ],
                    title='Using Jupyter for Structure of a Model'
                ),
                lp.GraphicFrame(
                    [
                        get_model_structure_graphic()
                    ],
                    title='Structuring a Python Model'
                ),
                lp.DimRevealListFrame(
                    [
                        'When I develop in Jupyter, I have lots of cells going everywhere testing things out',
                        ['When I finish a project in Jupyter, I remove these testing cells and make sure it runs and '
                         'logically flows from end to end', pl.Monospace('(restart kernel and run all cells)')],
                        "Run your model with different inputs, and make sure the outputs change in the expected fashion. This "
                        "is a good way to check your work.",
                        'There may be outputs in each section, but the final output should be at the end of the notebook',
                    ],
                    title='Workflow and Final Output'
                ),
            ],
            title='Structuring a Model in Python and Jupyter',
            short_title='Model Structure'
        ),
        pl.Section(
            [
                lp.DimRevealListFrame(
                    [
                        'The first project is aimed at approaching a new time value of money and cash flow model',
                        'It covers the same concepts as the retirement model, but in a capital budgeting setting',
                        'We need to introduce some economic equations to handle this model. You should have covered these in microeconomics.'
                    ],
                    title='Introducing Project 1'
                ),
                lp.GraphicFrame(
                    images_path('supply-demand-graph.png'),
                    title='A Quick Review of Supply and Demand'
                ),
                lp.Frame(
                    [
                        lp.Block(
                            [
                                "There are a couple of basic economic equations we haven't talked about that "
                                "we'll need for this:",
                                pl.Equation(str_eq='R = PQ', inline=False),
                                pl.Equation(str_eq='Q = min(D, S)', inline=False),
                                pl.UnorderedList([
                                    f'{pl.Equation(str_eq="R")}: Revenue',
                                    f'{pl.Equation(str_eq="Q")}: Quantity Purchased',
                                    f'{pl.Equation(str_eq="D")}: Quantity Demanded',
                                    f'{pl.Equation(str_eq="S")}: Quantity Supplied',
                                ])
                            ],
                            title='New Required Equations'
                        )
                    ],
                    title='Equations for Project 1'
                ),
                lp.Frame(
                    [
                        pl.UnorderedList([
                            lp.DimAndRevealListItems([
                                'We need to cover one more Python concept and one gotcha before you can complete the first project.',
                                "On the next slide I'll introduce error handling, and show an example of how it's useful"
                            ],
                                vertical_fill=True)
                        ]),
                        lp.AlertBlock(
                            [
                                pl.UnorderedList([
                                    f'The NPV function in {numpy_mono} works slightly differently than the NPV function in Excel.',
                                    f'Excel treats the first cash flow as period 1, while {numpy_mono} treats the first cash flow as period 0.',
                                    'If taking NPV where the first cash flow is period 1, pass directly to Excel, and for Python, pass 0 as the first cash flow, then the rest.',
                                    'If taking NPV where the first cash flow is period 0, pass from period 1 to end to Excel and add period 0 separately, pass directly to Python.'
                                ])
                            ],
                            title='NPV Gotcha',
                            overlay=next_slide
                        )
                    ],
                    title='A Couple More Things on the Python Side'
                ),
            ],
            title='Project 1 Additional Material',
            short_title='Project 1'
        ),
        pl.Section(
            [
                get_retirement_model_overview_frame(),
                lp.Frame(
                    [
                        lp.Block(
                            salary_block_content,
                            title='Salary with Promotions and Cost of Living Raises'
                        )
                    ],
                    title='Revisiting the Model Salary Equation'
                ),
                lp.Frame(
                    [
                        pl.UnorderedList([
                            'For wealths, we need to add the investment return and then the savings in each year',
                        ], overlay=next_until_end_ov),
                        pl.VFill(),
                        lp.Block(
                            [
                                lp.adjust_to_full_size_and_center(
                                    pl.Equation(str_eq=r'W_t = W_{t-1}  (1 + r_i) + S_t  v')),
                                pl.UnorderedList([
                                    f'{pl.Equation(str_eq="S_t")}:  Salary at year {pl.Equation(str_eq="t")}',
                                    f'{pl.Equation(str_eq="W_t")}:  Wealth at year {pl.Equation(str_eq="t")}',
                                    f'{pl.Equation(str_eq="r_i")}:  Investment return',
                                    f'{pl.Equation(str_eq="t")}:  Number of years',
                                    f'{pl.Equation(str_eq="v")}:  Savings rate',
                                ])
                            ],
                            title='Calculating Wealth',
                            overlay=next_until_end_ov,
                        )
                    ],
                    title='Building the Wealth Model'
                ),
                InClassExampleFrame(
                    [
                        'I will now show the process I use to create a full model.',
                        'I will be recreating the model "Dynamic Salary Retirement Model.ipynb"',
                        'Go ahead and download that to follow along as you will also extend it in a lab exercise',
                    ],
                    title='Creating a Full Model in Python',
                    block_title='Dynamic Salary Retirement Model in Python',
                ),
                get_extend_dynamic_retirement_python_lab_lecture().to_pyexlatex().presentation_frames(),
                LabExercise(
                    [
                        [
                            "Usually I would try to have smaller labs but it didn't fit the format of this lecture. "
                            "Most will not be able to complete this during class.",
                            "For this lab, attempt the practice problem "
                            '"P1 Python Retirement Savings Rate Problem.pdf"',
                            'This is similar to how the projects will be assigned, so it is good preparation',
                            "I would encourage you to try it from scratch. If you are totally stuck, try working off "
                            "of the retirement model I completed today to have a lot of the structure already. If you "
                            "still are having trouble with that, check the solution and see me in office hours.",
                            'Note: this is not an official lab exercise you need to submit, it is practice only, but '
                            'I would highly encourage you to complete it.'
                        ]
                    ],
                    block_title='Practice Building A Model',
                    frame_title='Extending the Simple Retirement Model in a Different Way',
                    label='lab:retire-model'
                ),
            ],
            title='Building the Dynamic Salary Retirement Model',
            short_title='Build the Model'
        ),
        pl.PresentationAppendix(
            [
                lecture.pyexlatex_resources_frame,
                get_extend_dynamic_retirement_python_lab_lecture().to_pyexlatex().appendix_frames(),
            ]
        )
    ]
Ejemplo n.º 23
0
def get_content():
    lecture = get_advanced_modeling_lecture()

    pd_mono = pl.Monospace('pandas')
    selenium_mono = pl.Monospace('selenium')
    requests_mono = pl.Monospace('requests')
    matplotlib_mono = pl.Monospace('matplotlib')
    holoviews_mono = pl.Monospace('holoviews')
    open_mono = pl.Monospace('open')
    os_mono = pl.Monospace('os')
    shutil_mono = pl.Monospace('shutil')
    pathlib_mono = pl.Monospace('pathlib')
    git_mono = pl.Monospace('git')
    sqlalchemy_mono = pl.Monospace('SQLAlchemy')
    fin_model_types = {
        'Portfolio valuation and optimization': 'Find the returns, value, and risk of a portfolio and select the best '
                                                'asset allocation for the portfolio',
        'Additional Funds Needed (AFN)': 'Budgeting model which uses forecasted financial statements to determine '
                                         'how much capital should be raised',
        'Lease or Own': 'Guides the decision of whether to rent or buy an asset',
        'Event Studies': 'Tries to determine the impact of an event',
        'Merger and Aquisition (M&A)': 'A DCF valuation of a target company with operations being combined '
                                       'with the parent at a merger date. Detetermines M&A price.',
        'Leveraged Buyout (LBO)': 'A specialized M&A model used for when large amounts of debt are being used '
                                  'to purchase the target firm.',
        'Derivatives Valuation': 'Value options, swaps, forwards, etc.',
        'Debt models': 'Immunization models are about having the right amount of cash in the future, term structure '
                       'models estimate the rates for different maturity bonds, and default-adjusted return models '
                       'factor in default in determining debt returns',
        'Value at Risk (VaR)': 'Determine how much an investment might lose with a certain probability in a certain '
                               'time span',
    }
    fin_model_items = [f'{pl.Underline(key)}: {value}' for key, value in fin_model_types.items()]

    return [
        pl.Section(
            [
                lp.DimRevealListFrame(
                    [
                        pl.TextSize(-1),
                        'Throughout the Financial Modeling with Python and Excel course, '
                        'we have covered Python and Excel basics',
                        'We have also covered financial modeling specifics, such as how to structure a '
                        'financial model in both Python and Excel, cash flow and probability modeling, '
                        'sensitivity analysis, scenario analysis, and Monte Carlo simulations',
                        'As far as types of financial models, we covered a retirement model, a '
                        'capital budgeting model, a lender profitability model, and the discounted '
                        'cash flow (DCF) valuation of a stock',
                        "There is a lot I didn't cover in that course. Let's "
                        "do a quick overview of it today.",
                        "This will serve as a roadmap to learn additional topics after completing the "
                        "first course. This is also the beginning of a new "
                        "Advanced Financial Modeling with Python course"
                    ],
                    title='What we Covered and What is Left'
                )
            ],
            title='Introduction'
        ),
        pl.Section(
            [
                lp.DimRevealListFrame(
                    fin_model_items[:5],
                    title='Financial Models 1'
                ),
                lp.DimRevealListFrame(
                    fin_model_items[5:9],
                    title='Financial Models 2'
                ),
                lp.DimRevealListFrame(
                    [
                        'Here are some links with free resources to learn more about types of models',
                        'The following examples will be using Excel only',
                        Hyperlink('http://macabacus.com/learn', 'Macabacus'),
                        Hyperlink(
                            'https://corporatefinanceinstitute.com/resources/knowledge/modeling/',
                            'Corporate Finance Institute'
                        ),
                        Hyperlink('https://fminstitute.com/learning/', 'Financial Modeling Institute'),
                        'And I found a couple Python resources, though the coding standards are not great:',
                        Hyperlink('http://www.financeandpython.com/Finance.html', 'Finance and Python'),
                        Hyperlink(
                            'https://www.datacamp.com/community/tutorials/finance-python-trading',
                            'Build a Trading Algorithm in Python',
                        )
                    ],
                    title='Financial Model Resources'
                )
            ],
            title='Types of Financial Models'
        ),
        pl.Section(
            [
                lp.TwoColumnGraphicDimRevealFrame(
                    [
                        'Data pipelines are about getting the input data into your model in a '
                        'standardized way',
                        'Within data pipelines, there are two main steps: data collection and '
                        'data wrangling (cleaning + reformatting).',
                        'Either step can be automated, ideally both would be, but it always comes down '
                        'to a tradeoff with modeler time'
                    ],
                    graphics=[
                        images_path('data-pipeline.png')
                    ]
                ),
                lp.DimRevealListFrame(
                    [
                        pl.TextSize(-1),
                        'Data can come from many sources, but most typically it originates from the Internet',
                        'If you can manually download the data, you can automate it via web scraping',
                        'You can also extract different types of data with web scraping, even if it is not structured '
                        'as a dataset',
                        'Some data comes from an API, where you need to send requests to download the data',
                        [selenium_mono, 'uses Python code to drive a browser such as Chrome while', requests_mono,
                         'is a more lightweight, text based way to make web requests (good for APIs).'],
                        ['Another common source of data is SQL databases. While you will still need to have a basic '
                         'understanding of SQL to query them, Python can help with', sqlalchemy_mono, 'which allows',
                         'you to write the queries in Python.', pd_mono, 'also has functionality to work with SQL']
                    ],
                    title='Data Collection'
                ),
                lp.DimRevealListFrame(
                    [
                        pl.TextSize(-1),
                        ['We have already covered the best general-purpose tool for wrangling data:', pd_mono],
                        'We did not cover it in enough detail to cover all data cleaning cases',
                        'The main material left is selecting, merging, grouping, and reshaping',
                        'Even if your data is without issues, you may still need to change the format, combine '
                        'sources, aggregate, etc.',
                        'Regular expressions are a way of matching any possible string and extracting parts of '
                        'it, which useful for messy data',
                    ],
                    title='Data Wrangling'
                ),
                lp.DimRevealListFrame(
                    [
                        Hyperlink(
                            'https://stackabuse.com/getting-started-with-selenium-and-python/',
                            'Get Started Browser-Based Web Scraping with Selenium'
                        ),
                        Hyperlink(
                            'https://github.com/mherrmann/selenium-python-helium',
                            'Helium - A Higher-Level API to Selenium'
                        ),
                        Hyperlink(
                            'https://realpython.com/python-requests/',
                            'Get Started Text-Based Web Scraping with Requests'
                        ),
                        Hyperlink(
                            'https://pandas.pydata.org/pandas-docs/stable/getting_started/10min.html',
                            'Pandas Intro, Covers Basics of Needed Topics'
                        ),
                        Hyperlink(
                            'https://pandas.pydata.org/pandas-docs/stable/user_guide/cookbook.html#cookbook',
                            'Advanced Pandas'
                        ),
                        Hyperlink(
                            'https://scotch.io/tutorials/an-introduction-to-regex-in-python',
                            'Intro to Regular Expressions'
                        ),
                        Hyperlink(
                            'https://docs.python.org/3/library/re.html',
                            'Regular Expression Reference'
                        ),
                        Hyperlink(
                            'https://auth0.com/blog/sqlalchemy-orm-tutorial-for-python-developers/',
                            'SQLAlchemy Overview Tutorial'
                        ),
                        Hyperlink(
                            'https://towardsdatascience.com/sqlalchemy-python-tutorial-79a577141a91',
                            'SQLAlchemy Simple Tutorial and Examples'
                        ),
                        Hyperlink(
                            'https://docs.sqlalchemy.org/en/13/intro.html',
                            'SQLAlchemy Documentation'
                        ),
                    ],
                    title='Data Pipelines Resources',

                )
            ],
            title='Data Pipelines'
        ),
        pl.Section(
            [
                lp.TwoColumnGraphicDimRevealFrame(
                    [
                        'We covered basic mathematical tools including basic probability theory, '
                        'algebra, variance/standard deviation, averages, and basic regressions',
                        'Most financial modeling does not take very advanced math, with the exception '
                        'of some derivatives models',
                        "But there are a few more useful tools we didn't have time to cover"
                    ],
                    graphics=[
                        images_path('equations-chalkboard-2.jpg')
                    ],
                    title='What Math we Covered'
                ),
                lp.DimRevealListFrame(
                    [
                        ['Often we want to maximize or minimize something, e.g. maximize returns or NPV, '
                         'minimize risk. We can do this in general with a mathematical technique called',
                         pl.Underline('optimization')],
                        ['If you have a complicated custom model, such that the algebra is getting too difficult '
                        'to do by hand, you can use a', pl.Underline('computer algebra system')],
                        [pl.Underline('Levenshtein (edit) distance'), 'can be used to say how similar two strings are,',
                         'which is useful for data cleaning and more.']
                    ],
                    title='General Math Tools'
                ),
                lp.DimRevealListFrame(
                    [
                        'We covered Ordinary Least Squares (OLS) regressions, which is what anyone means if they '
                        'just say regression',
                        ["There are many more kinds of regressions, we can't even mention them all here. "
                         "But most likely to be useful include", pl.Underline('logistic regression'), 'for when',
                         'probabilities are dependent variables and', pl.Underline('panel regression + fixed effects'),
                         'for when you are dealing',
                         'with multiple instruments over time'],
                        'There are many time-series models to cover, as was mentioned in the forecasting lecture',
                        [pl.Underline('Machine learning/AI'), 'can be used to make classifications or predictions']
                    ],
                    title='Statistics Tools'
                ),
                lp.DimRevealListFrame(
                    [
                        Hyperlink(
                            'https://towardsdatascience.com/optimization-with-scipy-and-application-ideas-to-machine-learning-81d39c7938b8',
                            'Optimization with SciPy'
                        ),
                        Hyperlink(
                            'https://docs.sympy.org/latest/tutorial/preliminaries.html',
                            'Computer Algebra with SymPy'
                        ),
                        Hyperlink(
                            'https://www.geeksforgeeks.org/fuzzywuzzy-python-library/',
                            'Levenshtein Distance using fuzzywuzzy'
                        ),
                        Hyperlink(
                            'https://towardsdatascience.com/logistic-regression-python-7c451928efee',
                            'Intro to Logistic Regression in Python'
                        ),
                        Hyperlink(
                            'https://medium.com/pew-research-center-decoded/using-fixed-and-random-effects-models-for-panel-data-in-python-a795865736ab',
                            'Intro to Panel Regression in Python'
                        ),
                        Hyperlink(
                            'https://www.statsmodels.org/stable/py-modindex.html',
                            'Statistical Models in statsmodels'
                        ),
                        Hyperlink(
                            'https://bashtage.github.io/linearmodels/doc/index.html',
                            'More Statistical Models in linearmodels'
                        ),
                        Hyperlink(
                            'https://docs.scipy.org/doc/scipy/reference/stats.html',
                            'More Statistical Tools in Scipy'
                        ),
                        Hyperlink(
                            'https://machinelearningmastery.com/machine-learning-in-python-step-by-step/',
                            'Getting Started with Machine Learning in Python'
                        ),
                        Hyperlink(
                            'https://machinelearningmastery.com/start-here/',
                            'General Introduction to Machine Learning'
                        ),
                        Hyperlink(
                            'https://datacamp.com/community/tutorials/deep-learning-python',
                            'Deep Learning (AI) in Python using Keras'
                        ),
                        Hyperlink(
                            'https://github.com/automl/auto-sklearn/',
                            'Automated Machine Learning with auto-sklearn'
                        ),
                    ],
                    title='Mathematical Tools Resources'
                )
            ],
            title='Mathematical Tools'
        ),
        pl.Section(
            [
                lp.TwoColumnGraphicDimRevealFrame(
                    [
                        "We didn't have very much time to cover presenting the model in Python, other than formatting text",
                        "For Excel, the model is already presented so just structure the workbook well",
                        "A well structured Jupyter notebook or Python script is important for another modeler to "
                        "pick up where you left off. But it still is not an ideal format for non-technical consumers "
                        "of your model"
                    ],
                    graphics=[
                        images_path('example-report.png')
                    ],
                    title='Presenting Model Results'
                ),
                lp.DimRevealListFrame(
                    [
                        "One easy way that doesn't require anything we haven't learned is separating model logic "
                        "and presentation",
                        "Develop as you will while building the model. But when it's time to share the results, "
                        "separate the main model logic (classes and functions) into separate Python file(s)",
                        "Then the Jupyter notebook will just show high-level calls to your model and the results"
                    ],
                    title='Present with Basic Jupyter'
                ),
                lp.DimRevealListFrame(
                    [
                        'Less technical consumers of the model may just want the model conclusions and not '
                        'to actually use the model themselves',
                        'In this case, it is useful to generate reports containing the model results',
                        'There are three major ways to make reports: HTML, LaTeX, and direct PDF solutions',
                        'If all you need is PDF output, a direct solution is fine, but HTML and LaTeX (which '
                        'can be converted to HTML) can both be converted to PDF and have the added advantage of '
                        'being viewable as a web page',
                        'Templating is also easier with HTML and LaTeX'
                    ],
                    title='Create Reports'
                ),
                lp.DimRevealListFrame(
                    [
                        'There is another way for non-technical consumers of your model to interact with it: '
                        'via an app',
                        'It is possible to build apps right in a Jupyter notebook using widgets',
                        'A web app could also be created with a web framework',
                        'With an app, a non-technical consumer of your model can adjust the inputs and see '
                        'the outputs, without having any knowledge of Python or instructions'
                    ],
                    title='Publish Reports and Models'
                ),
                lp.DimRevealListFrame(
                    [
                        ['We covered very basic plots using', pd_mono],
                        [matplotlib_mono, 'provides all the plotting functionality to', pd_mono, 'and any', pd_mono,
                         'plots can be adjusted using', matplotlib_mono, 'options'],
                        'Several libraries exist for interactive plots, which allow for dropdowns, sliders, '
                        'selecting points, zooming, tooltips, and more',
                        ['Other plotting styles are becoming more popular, such as', holoviews_mono + ',', 'in which',
                         'you just describe the data and it can generate interactive plots for you']
                    ],
                    title='Advanced Plotting'
                ),
                lp.DimRevealListFrame(
                    [
                        pl.TextSize(-1),
                        Hyperlink(
                            'https://dev.to/goyder/automatic-reporting-in-python---part-1-from-planning-to-hello-world-32n1',
                            'Intro to Creating HTML Reports in Python',
                        ),
                        Hyperlink(
                            'https://towardsdatascience.com/creating-pdf-reports-with-python-pdfkit-and-jinja2-templates-64a89158fa2d',
                            'Create HTML Reports and Output to PDF',
                        ),
                        Hyperlink(
                            'https://realpython.com/primer-on-jinja-templating/',
                            'Templating HTML and LaTeX Using Jinja'
                        ),
                        Hyperlink(
                            'https://www.reportlab.com/docs/reportlab-userguide.pdf',
                            'Direct PDF Output with Reportlab',
                        ),
                        Hyperlink(
                            'https://nickderobertis.github.io/py-ex-latex/',
                            'Direct to LaTeX Using pyexlatex'
                        ),
                        Hyperlink(
                            'https://www.datacamp.com/community/tutorials/matplotlib-tutorial-python',
                            'Matplotlib Plotting Tutorial'
                        ),
                        Hyperlink(
                            'https://holoviews.org/getting_started/index.html',
                            'Get started with Holoviews'
                        ),
                        Hyperlink(
                            'https://www.youtube.com/watch?v=L91rd1D6XTA&ab_channel=Enthought',
                            'Introduction to Panel for Building Apps in Jupyter'
                        ),
                        Hyperlink(
                            'https://panel.holoviz.org/getting_started/index.html',
                            'Tutorial for Panel'
                        ),
                        Hyperlink(
                            'https://voila.readthedocs.io/en/stable/',
                            'Convert a Jupyter Notebook to a Web App using Voila'
                        ),
                        Hyperlink(
                            'https://voila-gallery.org/services/gallery/',
                            'Examples of Voila Web Apps'
                        ),
                        Hyperlink(
                            'https://scotch.io/tutorials/getting-started-with-flask-a-python-microframework',
                            'Get Started Building Web Apps with Flask'
                        ),
                        Hyperlink(
                            'https://anvil.works/learn/tutorials/jupyter-notebook-to-web-app',
                            'Convert a Jupyter Notebook to a Web App using Anvil'
                        ),
                        Hyperlink(
                            'https://www.fullstackpython.com/',
                            'Full Tutorials for Python Web Development'
                        ),
                    ],
                    title='Presentation Resources'
                )
            ],
            title='Present Results'
        ),
        pl.Section(
            [
                lp.TwoColumnGraphicDimRevealFrame(
                    [
                        'We were only able to cover basic Python, and certainly not a lot of practices that would '
                        'typically be used in programming',
                        'Python is very flexible in that you can be productive in it with very little understanding '
                        'or mastery of it',
                        'But if you do gain a greater knowledge of it, it can unlock new potential.',
                        'Further, there is more we can learn from the software engineering world in how to improve '
                        'our programming'
                    ],
                    graphics=[
                        images_path('python-code-blur.jpeg')
                    ],
                    title='Your Programming Future'
                ),
                lp.DimRevealListFrame(
                    [
                        pl.TextSize(-1),
                        'We can learn a few things from the software engineers that are programming all day every day',
                        [pl.Underline('Version control'), 'or', pl.Underline('source control'), 'is a way of tracking',
                         'changes to code over time. You can get the full history of the project, and multiple',
                         'people can work on the same project at the same time and later merge the changes together.',
                         git_mono, 'is the gold standard for this.'],
                        ['Share', git_mono, 'repositories with the world via Github (or others), allowing anyone to '
                         'use and improve your project'],
                        "Automated testing of your code allows you to make changes ensuring it won't break anything",
                        "Input validation is useful for when others interact with your model directly",
                        'Use an integrated development environment (IDE) such as PyCharm or VS Code for better code '
                        'completion and linking',
                        'Automatically run tests, style your code, deploy Python packages or web apps, and more with '
                        'continuous integration/continuous deployment (CI/CD)'
                    ],
                    title='General Programming'
                ),
                lp.DimRevealListFrame(
                    [
                        ['Python can work with the files on your computer through the', open_mono, 'command and the',
                         os_mono, pathlib_mono,
                         'and', shutil_mono, 'modules'],
                        'Get unique items, unions, intersections using sets',
                        'Override how objects work by overriding double-underscore (dunder) class methods',
                        'Modify existing functions using decorators',
                        'Store Python objects by pickling them',
                        'Check yourself, make your code easier to understand, and power up your IDE using type annotations',
                        'Structure projects using packages and modules',
                        'Isolate project requirements using virtual environments',
                    ],
                    title='Python Programming'
                ),
                lp.DimRevealListFrame(
                    [
                        pl.TextSize(-1),
                        Hyperlink(
                            'https://product.hubspot.com/blog/git-and-github-tutorial-for-beginners',
                            'Get Started with Git and Github'
                        ),
                        Hyperlink(
                            'https://desktop.github.com/',
                            'Github Desktop is an App that Makes Git Easy'
                        ),
                        Hyperlink(
                            'https://realpython.com/python-testing/',
                            'Get Started with Automated Testing in Python'
                        ),
                        Hyperlink(
                            'https://www.youtube.com/watch?v=IL3eZYiV70g',
                            'Intro to Input Validation in Python'
                        ),
                        Hyperlink(
                            'https://www.jetbrains.com/pycharm/',
                            'PyCharm IDE'
                        ),
                        Hyperlink(
                            'https://code.visualstudio.com/',
                            'Visual Studio Code (VS Code) IDE'
                        ),
                        Hyperlink(
                            'https://semaphoreci.com/blog/cicd-pipeline',
                            'Intro to CI/CD'
                        ),
                        Hyperlink(
                            'https://github.com/features/actions',
                            'CI/CD Using Github Actions'
                        ),
                        Hyperlink(
                            'https://www.pythonforbeginners.com/files/reading-and-writing-files-in-python',
                            'Intro to Reading and Writing Files with Python'
                        ),
                        Hyperlink(
                            'https://realpython.com/python-pathlib/',
                            'Beyond the Basics of Working with Files in Python'
                        ),
                    ],
                    title='Programming Resources 1'
                ),
                lp.DimRevealListFrame(
                    [
                        pl.TextSize(-1),
                        Hyperlink(
                            'https://realpython.com/python-sets/',
                            'Work with Sets in Python'
                        ),
                        Hyperlink(
                            'https://dbader.org/blog/python-dunder-methods',
                            'Get Started with Dunder Methods in Python'
                        ),
                        Hyperlink(
                            'https://realpython.com/python-data-classes/',
                            'Advanced Dataclasses'
                        ),
                        Hyperlink(
                            'https://ipython.readthedocs.io/en/stable/config/integrating.html',
                            'Rich Object Display in Jupyter'
                        ),
                        Hyperlink(
                            'https://realpython.com/primer-on-python-decorators/',
                            'Get Started with Python Decorators'
                        ),
                        Hyperlink(
                            'https://www.datacamp.com/community/tutorials/pickle-python-tutorial',
                            'Store Python Objects with pickle and dill'
                        ),
                        Hyperlink(
                            'https://dev.to/dstarner/using-pythons-type-annotations-4cfe',
                            'Intro to Type Annotations in Python'
                        ),
                        Hyperlink(
                            'https://docs.python-guide.org/writing/structure/',
                            'Intro to Project Structure in Python'
                        ),
                        Hyperlink(
                            'https://www.dabapps.com/blog/introduction-to-pip-and-virtualenv-python/',
                            'Introduction to Virtual Environments in Python'
                        ),
                        Hyperlink(
                            'https://realpython.com/pipenv-guide/',
                            'Virtual Environments Made Easy with pipenv'
                        )
                    ],
                    title='Programming Resources 2'
                )

            ],
            title='Programming'
        ),
        pl.Section(
            [
                lp.DimRevealListFrame(
                    [
                        Hyperlink(
                            'https://docs.python-guide.org/',
                            "The Hitchhiker's Guide to Python"
                        ),
                        Hyperlink(
                            'https://realpython.com/',
                            'Real Python'
                        ),
                        Hyperlink(
                            'https://automatetheboringstuff.com/',
                            'Automate the Boring Stuff with Python'
                        ),
                        Hyperlink(
                            'https://pbpython.com/',
                            'Practical Business Python'
                        )

                    ],
                    title='General Resources'
                )
            ],
            title='Extras'
        ),
        pl.PresentationAppendix([lecture.pyexlatex_resources_frame]),
    ]
Ejemplo n.º 24
0
def get_content():
    random.seed(1000)
    next_slide_ov = Overlay([NextWithIncrement()])
    next_until_end_ov = Overlay([UntilEnd(NextWithIncrement())])
    lecture = get_intro_lecture()

    input_model_output_fc = TikZPicture(
        LinearFlowchart(['Inputs', 'Model', 'Outputs'],
                        node_options=in_out_style))

    anaconda_link = Hyperlink('https://www.anaconda.com/products/individual')
    mono_python = Monospace('python')
    interpreter_mono = Monospace('>>>')

    return [
        pl.Section([
            TwoColumnGraphicDimRevealFrame([
                'This is a skills-based course focused on teaching financial modeling techniques in Python and Excel',
                'The focus is not a lot of specific models, but rather general model-building techniques',
                'The focus will be simple models, but extending them in powerful ways'
            ],
                                           graphics=[
                                               images_path('python-logo.png'),
                                               images_path('excel-logo.png')
                                           ],
                                           title='What is this Class?'),
            GraphicFrame(input_model_output_fc, title='What is a Model?'),
            ModelFlowchartFrame(
                [
                    [
                        'Wages, Savings', 'Investment',
                        Node('Cash in the bank, person retires',
                             options=real_world_style + ['text width=2.5cm'])
                    ],
                    [
                        Node('Cash Flows, Savings Rate, Interest Rates',
                             options=model_style + ['text width=3.5cm']),
                        'Model',
                        Node('FV of CF, time until retirement',
                             options=model_style + ['text width=2.5cm'])
                    ],
                ],
                title='A Retirement Problem',
            ),
            ModelFlowchartFrame([
                [
                    Node('Microsoft creates software',
                         options=real_world_style + ['text width=2cm']),
                    'Sells the software',
                    Node('Generates cash for investors, stock reaches a price',
                         options=real_world_style + ['text width=3cm'])
                ],
                [
                    Node(
                        'Revenue, COGS, SG&A, growth rates, costs of capital, etc.',
                        options=model_style + ['text width=3.5cm']), 'Model',
                    Node('Stock price, stock returns',
                         options=model_style + ['text width=2.5cm'])
                ]
            ],
                                title='Valuing a Company (DCF Model)'),
        ],
                   title='Introduction to Financial Modeling',
                   short_title='Intro'),
        pl.Section(
            [
                GraphicFrame(images_path('xkcd-python.png'),
                             title='Why Python?'),
                Frame([
                    UnorderedList([
                        DimAndRevealListItems([
                            "The easiest to learn mainstream programming language",
                            'Heavily used in the financial industry'
                        ],
                                              dim_last_item=True,
                                              vertical_fill=True)
                    ]),
                    VFill(),
                    Block(MultiCol([
                        UnorderedList([
                            'Modeling',
                            'Data science',
                            'Algorithmic Trading',
                            'Scripting',
                        ]),
                        UnorderedList([
                            'Devices',
                            'Web Development',
                            'Web Scraping',
                            'Even these slides',
                        ])
                    ]),
                          title=
                          'Python is the Most Flexible of the Top Languages',
                          overlay=next_slide_ov)
                ],
                      title='Python is a Good Choice for Finance'),
                GraphicFrame(
                    images_path('python-popularity.PNG'),
                    title='Python is the Fastest Growing Programming Lanugage'
                ),
                DimRevealListFrame(
                    [
                        "Open source - completely free and open",
                        "Focus on readability - almost pseudo-code",
                        "Take as much as you need. Easy for beginners, many features for experts.",
                        "Deep integrations with Excel - VBA replacement, run Python in Excel, run Excel from Python"
                    ],
                    title="More Python Advantages",
                ),
                GraphicFrame(images_path('python-terminal.png'),
                             title='Why Not use Python?'),
                DimRevealListFrame([
                    "No graphical interface (by default)",
                    "Hard to get others working with it if they don't know Python",
                    "Can take more work to get started on a project"
                ],
                                   title="Python Disadvantages"),
                GraphicFrame(images_path('vba-terminal.png'),
                             title='Why Not use VBA?'),
                TwoColumnGraphicDimRevealFrame([
                    "Code is not as readable as Python",
                    "Power is limited to working within Microsoft Office",
                    "Python has a complete VBA API built into a package - Python can do VBA and more"
                ], [images_path('vba-logo.png')],
                                               title="VBA is Old-School"),
                DimRevealListFrame([
                    "Excel is everywhere. Most of the world's data is in Excel spreadsheets",
                    '(Nearly) everyone knows how use it',
                    "You can see what you're doing (without effort)",
                    "Easy introspection into a particular value"
                ],
                                   title="We Can't Ditch Excel Yet"),
                GraphicFrame(images_path('excel-hell.jpg'),
                             title='Escaping Excel Hell'),
                DimRevealListFrame([
                    "Code and view are mixed together, code is hidden",
                    "Both cell formulas and VBA macros - What is going on?",
                    "Easy to make mistakes (one cell different)",
                    "Some tasks which are very simple in Python are very complex in Excel"
                ],
                                   title="The Pains of Excel"),
                Frame([
                    LabBlock(
                        [
                            pl.TextSize(-1),
                            OrderedList([
                                f'Go to {anaconda_link} to download Python 3.8',
                                'Follow the steps in the installer',
                                'You will hit "Advanced Installation Options". It is very important that you select "Add '
                                'Anaconda to my PATH environment variable". It says it is not recommended, and will '
                                'highlight it in red when checked, but we will need it later in the course.',
                                'Open CMD (windows key, search cmd)',
                                f'Type {mono_python} and hit enter. You should see Python 3.8 and a {interpreter_mono} come up.'
                            ])
                        ],
                        title='Install Steps',
                    ),
                    AlertBlock(
                        'Make sure you have selected Python 3.8 and not 2.7')
                ],
                      title="Let's Get Python Set Up on your System")
            ],
            title='Introduction to the Modeling Toolset',
            short_title='Tools and Skills',
        ),
        pl.PresentationAppendix([
            lecture.pyexlatex_resources_frame,
        ])
    ]
def get_content():
    lecture = get_python_basics_lecture()
    conditionals_lab = get_python_basics_conditionals_lab_lecture().to_pyexlatex()
    lists_lab = get_python_basics_lists_lab_lecture().to_pyexlatex()
    functions_lab = get_python_basics_functions_lab_lecture().to_pyexlatex()
    data_types_lab = get_python_basics_data_types_lab_lecture().to_pyexlatex()
    classes_lab = get_python_basics_classes_lab_lecture().to_pyexlatex()
    appendix_frames = [
        *conditionals_lab.appendix_frames(),
        *lists_lab.appendix_frames(),
        *functions_lab.appendix_frames(),
        *data_types_lab.appendix_frames(),
        *classes_lab.appendix_frames()
    ]


    next_slide = lp.Overlay([lp.NextWithIncrement()])
    function_example = pl.Python(
"""
def my_func(a, b, c=10):
    return a + b + c

>>> my_func(5, 6)
21
""")

    use_class_example = pl.Python(
"""
from car_example import Car

>>> my_car = Car('Honda', 'Civic')
>>> print(my_car)
Car(make='Honda', model='Civic')
>>> type(my_car)
car_example.Car
>>> my_car.make
'Honda'
>>> my_car.drive()
'The Honda Civic is driving away!'
""")

    dataclass_example = pl.Python(
"""
from dataclasses import dataclass

@dataclass
class ModelInputs:
    interest_rates: tuple = (0.05, 0.06, 0.07)
    pmt: float = 1000

>>> inputs = ModelInputs(pmt=2000)
>>> print(inputs)
ModelInputs(interest_rates=(0.05, 0.06, 0.07), pmt=2000)
>>> type(inputs)
__main__.ModelInputs
>>> inputs.interest_rates
(0.05, 0.06, 0.07)
>>> inputs.pmt
2000
""")

    if_example = [pl.Python(
"""
>>> if 5 == 6:
>>>     print('not true')
>>> else:
>>>     print('else clause')
>>> 
>>> this = 'woo'
>>> that = 'woo'
>>> 
>>> if this == that:
>>>     print('yes, print me')
>>> if this == 5:
>>>     print('should not print')
"""
    ), pl.Monospace('else clause'), OutputLineBreak(), pl.Monospace('yes, print me')]

    build_list_example = pl.Python(
"""
>>> inputs = [1, 2, 3]
>>> outputs = []
>>> for inp in inputs:
>>>     outputs.append(
>>>         inp + 10
>>>     )
>>> outputs.insert(0, 'a')
>>> print(outputs)
['a', 11, 12, 13]
"""
    )

    enumerate_example = [pl.Python(
"""
>>> inputs = ['a', 'b', 'c']
>>> for i, inp in enumerate(inputs):
>>>     print(f'input number {i}: {inp}')
"""
    ),
        pl.Monospace('input number 0: a'),
        OutputLineBreak(),
        pl.Monospace('input number 1: b'),
        OutputLineBreak(),
        pl.Monospace('input number 2: c')
    ]

    list_indexing_example = pl.Python(
"""
>>> my_list = ['a', 'b', 'c', 'd']
>>> my_list[0]  # first item
'a'
>>> my_list[1]  # second item
'b'
>>> my_list[-1]  # last item
'd'
>>> my_list[:-1]  # up until last item
['a', 'b', 'c']
>>> my_list[1:]  # after the first item
['b', 'c', 'd']
>>> my_list[1:3]  # from the second to the third item
['b', 'c']
"""
    )
    f_string_example = pl.Python(
"""
>>> my_num = 5 / 6
>>> print(my_num)
0.8333333333333334
>>> print(f'My number is {my_num:.2f}')
'My number is 0.83'
"""
    )
    f_string = pl.Monospace("f''")
    f_mono = pl.Monospace('f')
    try_except_example = pl.Python(
"""
>>> my_list = ['a', 'b']
>>> try:
>>>     my_value = my_list[10]
>>> except IndexError:
>>>     print('caught the error')
caught the error
"""
    )
    list_100_5 = pl.Monospace('[100] * 5')
    next_slide = lp.Overlay([lp.NextWithIncrement()])
    annuity_example = pl.Python(
"""
>>> annuity = [100] * 5
>>> annuities = [
>>>     annuity,
>>>     [0, 0, 0] + annuity
>>> ]
>>> n_years = 10
>>> output = [0] * n_years
>>> for i in range(n_years):
>>>     for ann in annuities:
>>>         try:
>>>             output[i] += ann[i]
>>>         except IndexError:
>>>             pass
>>> print(output)   
[100, 100, 100, 200, 200, 100, 100, 100, 0, 0]
"""
    )

    site_link = Hyperlink(SITE_URL, 'the course site')

    return [
        pl.Section(
            [
                lp.TwoColumnGraphicDimRevealFrame(
                    [
                        "Now we are going to build our first complex Python model",
                        "We will also learn a bit more Python before we can get there",
                        "Just as we did in Excel, we need to add structure to make the model navigatable",
                        "Logic should be organized in functions and be documented",
                    ],
                    graphics=[
                        images_path('python-logo.png')
                    ],
                    title='An Organized Structure of an Advanced Python Model'
                ),
                lp.GraphicFrame(
                    [
                        get_model_structure_graphic()
                    ],
                    title='The Structure of a Complex Model'
                ),
            ],
            title='Introduction',
            short_title='Intro'
        ),
        pl.Section(
            [
                lp.Frame(
                    [
                        lp.Block(
                            [
                                pl.TextSize(-1),
                                if_example,
                            ],
                            title='If Statements in Python'
                        ),
                    ],
                    title='Python Conditionals - If Statement'
                ),
                lp.DimRevealListFrame(
                    [
                        'Use two equals signs to compare things (single to assign things)',
                        'Else is equivalent to value if false behavior in Excel',
                        'We can do a lot more than just set a single value, anything can be done in an if or else statement',
                        [pl.Monospace('elif'),
                         ' is a shorthand for else if, e.g. not the last condition, but this condition']
                    ],
                    title='Explaining the If-Else Statements'
                ),
                InClassExampleFrame(
                    [
                        f"On {site_link}, there is a Jupyter notebook called Python Basics containing all "
                        f"of the examples for today's lecture",
                        'Now I will go through the example material under "Conditionals"'
                    ],
                    title='Conditionals Example',
                    block_title='Trying out Conditionals'
                ),
                conditionals_lab.presentation_frames(),
            ],
            title='Conditionals'
        ),
        pl.Section(
            [
                lp.Frame(
                    [
                        lp.Block(
                            build_list_example,
                            title='List Building'
                        ),
                        pl.UnorderedList([
                            lp.DimAndRevealListItems([
                                ['Use ', pl.Monospace('.append'), ' to add an item to the end of a list'],
                                ['Use ', pl.Monospace('.insert'), ' to add an item at a certain position'],
                            ])
                        ])
                    ],
                    title='Python Patterns - Building a List'
                ),
                lp.Frame(
                    [
                        pl.UnorderedList([
                            'Index is base zero (0 means first item, 1 means second item)',
                        ]),
                        pl.VFill(),
                        list_indexing_example,
                    ],
                    title='List Indexing and Slicing'
                ),
                InClassExampleFrame(
                    [
                        "We will keep working off of Python Basics.ipynb",
                        'Now I will go through the example material under "Working more with Lists"'
                    ],
                    title='Lists Example',
                    block_title='Doing More with Lists'
                ),
                lists_lab.presentation_frames(),
            ],
            title='More with Lists',
            short_title='Lists'
        ),
        pl.Section(
            [
                lp.DimRevealListFrame(
                    [
                        "In Python, we can group logic into functions",
                        "Functions have a name, inputs, and outputs",
                        "Functions are objects like everything else in Python",
                        function_example,
                    ],
                    title='Functions - Grouping Reusable Logic'
                ),
                InClassExampleFrame(
                    [
                        "We will keep working off of Python Basics.ipynb",
                        'Now I will go through the example material under "Functions"'
                    ],
                    title='Functions Example',
                    block_title='Structuring Code using Functions'
                ),
                functions_lab.presentation_frames(),
            ],
            title='Functions'
        ),
        pl.Section(
            [
                lp.DimRevealListFrame(
                    [
                        'In Python, everything is an object except for variable names, which are references to objects',
                        'Every object has a type. We have learned about strings, numbers, lists, and booleans (True, False)',
                        'In the next section on classes, we will learn more about the relationship between the type '
                        'and the object'
                    ],
                    title='What are Types?'
                ),
                # TODO [#12]: add f-strings to Jupyter example
                lp.Frame(
                    [
                        pl.UnorderedList([
                            lp.DimAndRevealListItems([
                                'You may have noticed that we can end up with a lot of decimals in Python output',
                                'Further, you may want to include your results as part of a larger output, such as a sentence.',
                                f'For these operations, we have {f_mono} strings: {f_string}'
                            ],
                                vertical_fill=True)
                        ]),
                        lp.Block(
                            f_string_example,
                            title='Example',
                            overlay=next_slide
                        )
                    ],
                    title='Formatting Python Strings'
                ),
                lp.DimRevealListFrame(
                    [
                        'So far I have just said that numbers are a type in Python, but this is a simplification',
                        ['There are two main types of numbers in python:', pl.Monospace('float'), 'and',
                         pl.Monospace('int'), 'corresponding to a floating point number and an integer, respectively'],
                        ['An', pl.Monospace('int'), 'is a number without decimals, while a', pl.Monospace('float'),
                         'has decimals, regardless of whether they are zero'],
                        ['For example,', pl.Monospace('3.5'), 'and', pl.Monospace('3.0'), 'are floats, while',
                         pl.Monospace('3'), 'is an int, even though', pl.Monospace('3.0 == 3 is True')],
                        ["Usually, this doesn't matter. But to loop a number of times, you must pass an",
                         pl.Monospace('int')]
                    ],
                    title='Numeric Types'
                ),
                lp.DimRevealListFrame(
                    [
                        ['A', pl.Monospace('tuple'), 'is like a', pl.Monospace('list'), "but you can't change it after "
                         "it has been created (it is immutable)"],
                        ['Tuples are in parentheses instead of brackets, e.g.', pl.Monospace('("a", "b")')],
                        ['A', pl.Monospace('dict'), 'short for dictionary, stores a mapping. Use them if you want '
                         'to store values associated to other values'],
                        ['We will come back to', pl.Monospace('dicts'), 'later in the course, but I wanted to',
                         'introduce them now as they are a very fundamental data type']
                    ],
                    title='Additional Built-In Types'
                ),
                InClassExampleFrame(
                    [
                        "We will keep working off of Python Basics.ipynb",
                        'Now I will go through the example material under "Exploring Data Types"'
                    ],
                    title='Data Types Example',
                    block_title='Understanding the Different Data Types'
                ),
                data_types_lab.presentation_frames(),
            ],
            title='More about Data Types',
            short_title='Data Types'
        ),
        pl.Section(
            [
                lp.GraphicFrame(
                    images_path('class-object.pdf'),
                    title='Overview of Classes and Objects'
                ),
                lp.DimRevealListFrame(
                    [
                        'In Python, everything is an object except for variable names, which are references to objects',
                        'Strings, floats, ints, lists, and tuples are types of objects. There are many more types of '
                        'objects and users can define their own types of objects',
                        'A class is a definition for a type of object. It defines how it is created, the data '
                        'stored in it, and the functions attached to it',
                        'We can write our own classes to create new types of objects to work with'
                    ],
                    title='Everything is an Object. Every Object has a Class'
                ),
                lp.DimRevealListFrame(
                    [
                        'From a single class definition, an unlimited number of objects can be created',
                        'Typically the class definition says it should accept some data to create the object',
                        'Then when you have multiple objects of the same type (created from the same class), '
                        'they will have the same functions (methods) attached to them, but different data stored within',
                        ['For example, we can create two different lists. They will have different contents, but we can',
                        'do', pl.Monospace('.append'), 'on either of the lists']
                    ],
                    title='Many Objects to One Class'
                ),
                lp.MultiGraphicFrame(
                    [
                        images_path('class-object.pdf'),
                        images_path('list-object.pdf')
                    ],
                    title='Lists are Objects',
                    vertical=False
                ),
                lp.MultiGraphicFrame(
                    [
                        images_path('class-object.pdf'),
                        images_path('car-object.pdf')
                    ],
                    title='We can Make Custom Objects Too',
                    vertical=False
                ),
                lp.Frame(
                    [
                        pl.UnorderedList(['Constructing an object from a class looks like calling a function:']),
                        lp.Block(
                            [
                                pl.TextSize(-1),
                                use_class_example,
                            ],
                            title='Using Custom Classes in Python'
                        ),
                    ],
                    title='Creating and Using Objects'
                ),
                lp.DimRevealListFrame(
                    [
                        'I will not be teaching you about creating general classes in this course. It is very useful '
                        'but is generally more advanced. I encourage you to learn them outside the course.',
                        "We covered this material for two reasons:",
                        ['To give a better understanding of how Python works in general, and why sometimes we '
                        'call functions as', pl.Monospace('something.my_func()'), 'rather than',
                         pl.Monospace('my_func()')],
                        ['We are going to use', pl.Monospace('dataclasses'), 'to store our model data. They are',
                         'a simplified version of classes used mainly for storing data.']
                    ],
                    title='Where we Will Focus in This Course'
                ),
                lp.Frame(
                    [
                        pl.UnorderedList(['An organized way to store our model input data:']),
                        lp.Block(
                            [
                                pl.TextSize(-3),
                                dataclass_example,
                            ],
                            title='Using Dataclasses in Python'
                        ),
                    ],
                    title='Dataclass Intro'
                ),
                lp.DimRevealListFrame(
                    [
                        ['A', pl.Monospace('dataclass'), 'is just a class which is more convenient to create, and',
                         'is typically used to group data together'],
                        ['If you need to pass around multiple variables together, they make sense. For our models, we '
                        'will want to pass around all the inputs, so one', pl.Monospace('dataclass'), 'for all the',
                         'inputs to the model makes sense'],
                        'This way instead of having to pass around every input individually to every function, just '
                        'pass all the input data as one argument',
                        ['Also enables easy tab-completion. What were the names of my inputs? Just hit tab after',
                         pl.Monospace('data.')]
                    ],
                    title='What, When and Why Dataclasses?'
                ),
                InClassExampleFrame(
                    [
                        "We will keep working off of Python Basics.ipynb",
                        'For this example, also go and download car_example.py and put it in the same folder',
                        'Now I will go through the example material under "Working with Classes"'
                    ],
                    title='Classes Example',
                    block_title='Working with Classes and Creating Dataclasses'
                ),
                classes_lab.presentation_frames(),
            ],
            title='Classes and Dataclasses',
            short_title='Classes'
        ),
        pl.Section(
            [
                # TODO [#13]: add error handling to Jupyter example
                lp.Frame(
                    [
                        pl.UnorderedList([
                            lp.DimAndRevealListItems([
                                "You have certainly already seen errors coming from your Python code. When they have come up, the code doesn't run.",
                                'Sometimes you actually expect to get an error, and want to handle it in some way, rather than having your program fail.'
                            ],
                                vertical_fill=True)
                        ]),
                        lp.Block(
                            try_except_example,
                            title='Example',
                            overlay=next_slide
                        )
                    ],
                    title='Python Error Handling'
                ),
                lp.DimRevealListFrame(
                    [
                        "Let's say you're receiving annuities. There is a single annuity which produces \$100 for 5 years. You receive this annuity in year 0 and in year 3.",
                        f"You might define the annuity cash flows as a list of 100, 5 times ({list_100_5})",
                        'Then you want to come up with your overall cash flows, going out to 15 years'
                    ],
                    title='An Example where Error Handling is Useful'
                ),
                lp.Frame(
                    [
                        lp.Block(
                            [
                                pl.TextSize(-1),
                                annuity_example,
                            ],
                            title='Calculating the Sum of Unaligned Annuity Cash-Flows'
                        )
                    ],
                    title='Applying Error Handling'
                ),
            ],
            title='Error Handling',
            short_title='Errors'
        ),
        pl.PresentationAppendix(
            [
                lecture.pyexlatex_resources_frame,
                *appendix_frames
            ]
        )
    ]
Ejemplo n.º 26
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')
    ]
Ejemplo n.º 27
0
def get_content():
    non_cash_items = [
        'depreciation',
        'amortization',
        'stock-based compensation',
        'impairment charges',
        'gains/losses on investments'
    ]
    non_cash_str = ', '.join(non_cash_items[:-1]) + ', and ' + non_cash_items[-1]
    non_cash_eq = pl.Equation(
        str_eq=f'{pl.Text("Adjustments")} = {" + ".join([str(pl.Text(item)) for item in non_cash_items])}',
    )

    lecture = get_dcf_fcf_lecture()
    fcf_exercise = get_fcf_calculation_lab_lecture().to_pyexlatex()
    simple_ts_exercise = get_simple_forecast_lab_lecture().to_pyexlatex()
    complex_ts_exercise = get_complex_forecast_lab_lecture().to_pyexlatex()
    tv_exercise = get_dcf_tv_lab_lecture().to_pyexlatex()

    return [
        pl.Section(
            [
                lp.DimRevealListFrame(
                    [
                        'There are two main parts to the FCF part of the DCF model',
                        'First is to find all the historical FCFs. This is the straightforward part of '
                        'plugging values into set calculations.',
                        'The more difficult and important part is projecting future cash flows',
                        'We will discuss a variety of approaches for this'
                    ],
                    title='FCF Overview'
                ),
                lp.DimRevealListFrame(
                    [
                        'Free cash flow (FCF) represents cash a company earns after paying for its operations.',
                        'It is not to be confused with net income, which amortizes costs across years and '
                        'includes non-cash expenses',
                        'FCF represents only the cash flows from that year, and so can be a lot more variable than '
                        'net income',
                        'FCF is the actual cash earned, and so it is what we should use for valuation'
                    ],
                    title='What is FCF?'
                ),
                lp.TwoColumnGraphicDimRevealFrame(
                    [
                        'We can follow a simple formula to get FCFs from historical financials',
                        'All we have to do is calculate the formula for each year of historical data',
                        'Each of the components to this calculation besides net income themselves require '
                        'a calculation. In the Historical FCF section we will cover each component.',
                        'The formula is all about reversing the non-cash adjustments to net income'
                    ],
                    graphics=[
                        images_path('fcf-formula.png')
                    ],
                    title='Historical FCFs'
                ),
                lp.DimRevealListFrame(
                    [
                        'The challenge in the FCF model is to project the cash flows',
                        ['There are two main approaches to getting future FCFs:', pl.Underline('forecast the FCFs'),
                         'and', pl.Underline('forecast the financial statements.')],
                        'Forecasting FCFs is much easier but is not as accurate, both due to lack of granularity and '
                        'due to typically uneven FCFs',
                        ['We will use', pl.Underline('time-series methods'), 'to forecast the financial statements, '
                         'either in the', pl.Underline('levels'), 'of the item, the', pl.Underline('growth'),
                         'of the item, or as a', pl.Underline('percentage of another item')]
                    ],
                    title='Forecasting FCFs'
                )
            ],
            title='Overview'
        ),
        pl.Section(
            [
                SingleBlockDimRevealListFrame(
                    [
                        'Non-cash expenses is just the sum of all items on the income statement that do not '
                        'affect cash.',
                        f'This includes {non_cash_str}'
                    ],
                    block_contents=[non_cash_eq],
                    block_title='Calculate Non-Cash Expenses',
                    title='Non-Cash Expenses'
                ),
                SingleBlockDimRevealListFrame(
                    [
                        'Net Working Capital (NWC) represents cash actively tied up in daily transactions',
                        'Cacluating the change in NWC requires information from this period '
                        'as well as last period.',
                        'First, calculate the NWC in each period using accounts receivable, '
                        'inventory, and accounts payable.',
                        "Then, take the difference between this period's NWC and last to get the change"
                    ],
                    block_contents=[
                        pl.Equation(
                            str_eq=rf'\Delta{pl.Text("NWC")} = {pl.Text("NWC")}_t - {pl.Text("NWC")}_{{t-1}}',
                            inline=False
                        ),
                        pl.Equation(
                            str_eq=rf'{pl.Text("NWC")} = {pl.Text("Accounts Receivable")} + {pl.Text("Inventory")} '
                                   rf'- {pl.Text("Accounts Payable")}',
                            inline=False
                        )
                    ],
                    block_title='Calculate Change in NWC',
                    title='Change in Net Working Capital'
                ),
                SingleBlockDimRevealListFrame(
                    [
                        'Capital Expenditures (CapEx) are outlays for fixed assets which get used over time, such '
                        'as buildings or machinery.',
                        'The change in Property, Plant and Equipment from the balance sheet can be used to estimate '
                        'CapEx.',
                        'Then you just need to add back the current depreciation & amortization, as they decreased '
                        'PPE even though no cash exchanged hands'
                    ],
                    block_contents=[
                        pl.Equation(
                            str_eq=fr'{pl.Text("CapEx")} = \Delta{pl.Text("PPE")} + '
                                   fr'{pl.Text("Depreciation & Amortization")}',
                            inline=False
                        )
                    ],
                    block_title='Calculate CapEx',
                    title='Capital Expenditures'
                ),
                SingleBlockDimRevealListFrame(
                    [
                        'Again, the FCF formula takes net income and reverses the non-cash adjustments',
                        'Add back the non-cash expenses because no actual cash was spent',
                        'Decrease by the change in NWC as an increase means additional cash was used for operations',
                        'Decrease by CapEx because this cash was spent for a new building, machinery, etc.'
                    ],
                    block_contents=[
                        pl.Equation(
                            str_eq=fr'{pl.Text("FCF")} = {pl.Text("Net Income")} + {pl.Text("Non-Cash Expenses")} - '
                                   fr'\Delta{pl.Text("NWC")} - {pl.Text("CapEx")}',
                            inline=False
                        )
                    ],
                    block_title='Calculating FCF',
                    title='Put it All Together'
                ),
                InClassExampleFrame(
                    [
                        'Go to the course site and download the files in Historical FCF',
                        'There should be a Jupyter notebook as well as a data file',
                        'We will go through a couple approaches to calculating FCFs in Python.'
                    ],
                    title='Example for Calculating FCFs',
                    block_title='Two Ways to Calculate FCFs in Python'
                ),
                fcf_exercise.presentation_frames(),
            ],
            title='Calculating Historical Free Cash Flows',
            short_title='Historical FCF',
        ),
        pl.Section(
            [
                lp.DimRevealListFrame(
                    [
                        pl.TextSize(-1),
                        'As mentioned in the intro, we will use time-series methods on the levels of the item, '
                        'the growth of the item, or as a percentage of another item',
                        'Time-series methods are about numerically estimating future values based on past values',
                        'Levels mean we forecast the numbers of the item itself, e.g. sales was 1M two years ago and '
                        '1.5M last year so we feed those numbers into our time-series model and predict 2M for the '
                        'next year',
                        'Growth means to first calculate the historical growth rate of the item, then forecast that. '
                        'E.g. sales grew 10% two years ago and 8% last year so we expect it to grow 6% this year',
                        'Percentage of item methods link an item to another item. E.g. setting cost of goods sold to '
                        '60% of sales. That percentage still needs to be forecasted',
                        "Any forecast can be adjusted by the analyst's qualitative projections of the future. The "
                        "forecast method may also have to be chosen with the qualitative analysis in mind"
                    ],
                    title='Overview of the Methods'
                ),
                lp.TwoColumnGraphicDimRevealFrame(
                    [
                        'Time-series methods seek to predict the future using the past',
                        'There is a large variety of possible time-series models to use for forecasting',
                        'They each use different characteristics of the past to assist in predicting the future'
                    ],
                    graphics=[
                        images_path('time-series-linear-plot.png')
                    ],
                    title='What Are Time-Series Methods?'
                ),
                lp.DimRevealListFrame(
                    [
                        ['The simplest models are to use the', pl.Underline('average of historical values'), 'or the',
                         pl.Underline('most recent value'), 'as the prediction for all future values'],
                        ['A more realistic model will also include estimating the', pl.Underline('trend'),
                         f'or {pl.Underline("growth")} of the historical values and applying that to the future'],
                        'More advanced models use autoregressive terms (recent values predict future values), moving '
                        'average terms (recent errors predict future values), or conditional heteroskedasticity terms '
                        '(changing variance over time)',
                        'Examples of these advanced models include AR, MA, ARMA, ARCH, GAM, and many more'
                    ],
                    title='What are the Time-Series Models?'
                ),
                lp.DimRevealListFrame(
                    [
                        'The choice of a time-series model will depend on the amount of data, the frequency of the '
                        'data, and the historical patterns in the data',
                        'If the data is historically constant or expected to be constant in the future, using the '
                        'average or most recent value should be enough',
                        "If the data follows a defined trend or growth and doesn't have historical patterns, "
                        "then using the "
                        "trend or growth models should be enough",
                        'If there are historical patterns in the data, such as seasonality, then more advanced '
                        'models are required.'
                    ],
                    title='Which Time-Series Model to Use?'
                ),
                lp.DimRevealListFrame(
                    [
                        ['The best place to start is to', pl.Underline('examine the history'), 'either by a plot',
                         'or just by looking at the numbers if you only have a few'],
                        ['Based on the amount of historical data, any perceived patterns in the historical data, '
                         'and any qualitative knowledge of the data,', pl.Underline('choose a time-series model.')],
                        [pl.Underline('Fit'), 'the time-series model on historical data, then', pl.Underline('predict'),
                         'the future values using the fitted model'],
                        ['Finish by', pl.Underline('examining the forecast'), 'to ensure it worked as intended, ',
                         'typically via a plot.']
                    ],
                    title='Steps to Forecasting'
                ),
                lp.DimRevealListFrame(
                    [
                        'When we forecast levels, just use the forecasted values and you are done',
                        'When we forecast growth, calculate the historical growth, run the forecast on that, then '
                        'apply the predicted future growth from the final historical period to generate '
                        'the forecasted levels',
                        'For percentage of item methods, calculate the historical percentage of the item, '
                        'forecast future item percentages, then use these in combination with '
                        'the forecast of the referenced item to generate the prediction',
                        'E.g. use the average approach to say historically COGS was 40% of sales, and so estimate '
                        'COGS as 40% of sales going forward. Multiply the forecasted sales by 40% to get the COGS',
                    ],
                    title='What to Forecast?'
                )
            ],
            title='Approaches to Forecasting',
            short_title='Forecasting Overview'
        ),
        pl.Section(
            [
                SingleBlockDimRevealListFrame(
                    [
                        [
                            pl.Bold('Fit:'),
                            'To fit the historical average model, take an average of the historical values'
                        ],
                        [
                            pl.Bold('Predict:'),
                            'To predict, use that average value for all future values'
                        ]
                    ],
                    [
                        EquationWithVariableDefinitions(
                            r'y_{T + n} = \frac{1}{T} \sum_{t=0}^T y_t + \epsilon_t',
                            [
                                '$t$: Current time period',
                                '$T$: Last time period of historical data',
                                '$y_t$: The current value of the data',
                                '$y_T$: The last historical value of the data',
                                '$n$: Number of periods forecasted'
                            ]
                        )
                    ],
                    title='Using the Historical Average Model',
                    block_title='Historical Average Model'
                ),
                SingleBlockDimRevealListFrame(
                    [
                        [
                            pl.Bold('Fit:'),
                            'To fit the most recent value model, take the latest value.'
                        ],
                        [
                            pl.Bold('Predict:'),
                            'To predict, use that latest value for all future values'
                        ]
                    ],
                    [
                        pl.Equation(str_eq=r'y_t = y_{t-1} + \epsilon_t', inline=False)
                    ],
                    title='Using the Recent Value Model',
                    block_title='Recent Value Model'
                ),
                SingleBlockDimRevealListFrame(
                    [
                        [
                            pl.Bold('Fit:'),
                                [
                                    'Run an OLS regression with a constant and time as the independent variable, '
                                    'where time is measured in number of periods since the beginning',
                                ],
                        ],
                        [
                            pl.Bold('Predict:'),
                                [
                                    r'For each $t$ you want to predict, calculate $a + \beta t$',
                                ],
                        ]
                    ],
                    [
                        pl.Equation(str_eq=r'y_t = a + \beta t + \epsilon_t', inline=False)
                    ],
                    title='Using the Trend Model',
                    block_title='Trend Model'
                ),
                SingleBlockDimRevealListFrame(
                    [
                        [
                            pl.Bold('Fit:'),
                            [
                                'Calculate the compounded annual growth rate (CAGR) as',
                                pl.Equation(str_eq=r'\frac{y_T}{y_0}^{\frac{1}{n}} - 1')
                            ]
                        ],
                        [
                            pl.Bold('Predict:'),
                            ['Calculate future periods by compounding CAGR on the latest historical period',
                            pl.Equation(str_eq=rf'y_{{T + f}} = y_T * (1 + {pl.Text("CAGR")})^f')]
                        ]
                    ],
                    [
                        pl.Equation(str_eq=r'y_{{T + f}} = y_T * (\frac{y_T}{y_0}^{\frac{1}{n}})^f', inline=False)
                    ],
                    title='Using the CAGR Model',
                    block_title='CAGR'
                ),
                InClassExampleFrame(
                    [
                        'Go to the course site and download the files in Examples > DCF > Forecasting > Simple',
                        'There should be a Jupyter notebook as well as two Excel files. Place these all in the '
                        'same folder',
                        'We will walk through "Sales COGS Forecasted.xlsx" to show forecasting in Excel, and '
                        '"Forecast Sales COGS Simple.ipynb" for forecasting in Python. "Sales COGS.xlsx" '
                        'contains the source data'
                    ],
                    title='Forecasting Simple Time-Series in both Excel and Python',
                    block_title='Example for Simple Time-Series Forecasting'
                ),
                simple_ts_exercise.presentation_frames(),
                InClassExampleFrame(
                    [
                        'Go to the course site and download "Forecasting Financial Statements.ipynb"',
                        f'We will walk through using {pl.Monospace("finstmt")} to forecast financial statements '
                        'using simple time-series models',
                    ],
                    title='Forecasting Financial Statements with Simple Time-Series in Python',
                    block_title='Use finstmt for Financial Statement Forecasting'
                ),
            ],
            title='Forecasting Simple Time-Series',
            short_title='Simple Forecast'
        ),
        pl.Section(
            [
                lp.TwoColumnGraphicDimRevealFrame(
                    [
                        "Shown to the left is Walmart's quarterly sales",
                        'You can see that a plain trend line is never going to accurately forecast these values',
                        'Advanced time-series models can capture these characteristics easily, and many more patterns'
                    ],
                    graphics=[
                        images_path('time-series-plot.png')
                    ],
                    graphics_on_right=False,
                    title='Why Does it get so Complicated?'
                ),
                lp.TwoColumnGraphicDimRevealFrame(
                    [
                        ['There is a distinct', pl.Bold('seasonality'), "to Walmart's quarterly sales"],
                        'The time-series model used to create the plot on the prior slide split the history into '
                        'two parts: a trend component and an annual seasonality component',
                        "Walmart's sales are high at the end of January and neutral for the other quarters",
                        'By plotting components of the time-series model, the analyst can gain a greater understanding '
                        'of the business.'
                    ],
                    graphics=[
                        images_path('time-series-plot-components.png')
                    ],
                    title='Explaining Seasonal Data'
                ),
                lp.DimRevealListFrame(
                    [
                        "So you've determined a trend alone will not fit the historical data. What are next steps?",
                        ['Generally fitting the best time-series model is an involved process which requires '
                         'substantial knowledge of how the models work, see',
                         Hyperlink(
                             'https://www.seanabu.com/2016/03/22/time-series-seasonal-ARIMA-model-in-python/',
                             'this blog post'
                         ), 'for details'],
                        ['An easier version is to use an OLS regression model with time and dummy variables '
                        'for month of year, etc., we can call this the ', pl.Underline('quarterly seasonal trend model.')],
                        ['The easiest version is to let time-series software, such as',
                         Hyperlink('https://facebook.github.io/prophet/docs/quick_start.html', 'prophet'),
                         'make the choice for you']
                    ],
                    title='Predicting Complex Time-Series'
                ),
                SingleBlockDimRevealListFrame(
                    [
                        [
                            pl.Bold('Fit:'),
                            'Create dummy variables for the quarters, then run an OLS regression with the number '
                            'of time periods as well as the four dummy variables as the $X$ variables'
                        ],
                        [
                            pl.Bold('Predict:'),
                            r'For each $t$ you want to predict, calculate $a + \beta t$ adding the appropriate '
                            r'dummy for the quarter of the period.'
                        ]
                    ],
                    [
                        pl.Equation(str_eq=r'y_t = a + \beta_t t + \beta_{d1} D1 + \beta_{d2} D2 + '
                                           r'\beta_{d3} D3 + \beta_{d4} D4  + \epsilon_t', inline=False)
                    ],
                    title='Using the Quarterly Seasonal Trend Model',
                    block_title='Quarterly Seasonal Trend Model'
                ),
                InClassExampleFrame(
                    [
                        'Go to the course site and download the files in Examples > DCF > Forecasting > Complex',
                        'There should be a Jupyter notebook as well as two Excel files. Place these all in the '
                        'same folder',
                        'We will walk through "Forecasting Quarterly Financial Statements.ipynb" to show forecasting '
                        'in Python using both the Quarterly Seasonal Trend Model and the automated software approach.'
                    ],
                    title='Forecasting Complex Time-Series in Python',
                    block_title='Example for Complex Time-Series Forecasting'
                ),
                complex_ts_exercise.presentation_frames(),
            ],
            title='Forecasting Complex Time-Series',
            short_title='Complex Forecast'
        ),
        pl.Section(
            [
                lp.DimRevealListFrame(
                    [
                        'As mentioned in the intro, we can either directly forecast FCFs, or forecast the financial '
                        'statements, then calculate future FCFs from the future financial statements',
                        "Forecasting FCFs doesn't allow the analyst control over individual "
                        "line items. Therefore it is generally preferred to forecast financial statements.",
                        'If you have a short amount of time to put together the model, it can make sense as it is '
                        'less steps and it requires less knowledge of the company.',
                        'It can also make sense to do a FCF forecast alongside the financial statement forecast, as '
                        'a check on your valuation.'
                    ],
                    title='What to Forecast?'
                ),
                lp.DimRevealListFrame(
                    [
                        'Assuming you are going with forecasting financial statements, you should '
                        'forecast only line items which cannot be calculated from other line items',
                        'For example, sales, COGS, SG&A should be forecasted, not operating profit',
                        'You should set your model up so that these calculatable items are calculated '
                        'in the historicals, then carry that through to the forecasted',
                        'Set items as a percentage of other items when it is logical that they should '
                        'scale together. For example, interest expense should be forecasted as a percentage '
                        'of total debt, as if the company takes on more debt, interest expense should increase '
                        'proportionally',
                    ],
                    title='Which Line Items to Forecast?'
                ),
                lp.DimRevealListFrame(
                    [
                        'Despite forecasting line items individually, you must attempt to keep the balance sheet '
                        'balanced in the future',
                        'If your forecast shows assets growing to be much greater than liabilities and equity, '
                        'that implies that the company will need to raise additional funds to finance the '
                        'growth in the assets. Usually increasing debt is the solution.',
                        'If your forecast shows assets lower than liabilities and equity, it means that the profits '
                        'or other sources of funds are not being properly allocated to the assets side. Usually '
                        'increasing cash is the solution',
                    ],
                    title="Don't Be Out of Balance"
                ),
                lp.DimRevealListFrame(
                    [
                        pl.TextSize(-1),
                        'The general process is to run your forecasts, then use another approach to adjust either '
                        'cash or debt to make the balance sheet balance. ',
                        'These adjusted values are called "plugs" because we are "plugging" in whatever makes the '
                        'forecast valid',
                        'To make the adjustment in Excel, calculate the absolute value of the '
                        'difference between assets and liabilities + '
                        'equity, then use goal seek (single year forecast) or solver (multi-year forecast) '
                        'to minimize the value',
                        'In Python, the steps would be similar, only using scipy minimize instead of solver, '
                        'but finstmt handles this automatically for you. When you run a forecast, it will balance '
                        'the balance sheet without any further action from you. You can change how accurate it '
                        'is by setting bs_diff_max and you can change which line items are used as plugs '
                        'in the forecast config',
                    ],
                    title='Balancing the Balance Sheet'
                )
            ],
            title='Forecasting Free Cash Flows',
            short_title='Future FCFs'
        ),
        pl.Section(
            [
                lp.DimRevealListFrame(
                    [
                        'As mentioned in the intro to the DCF model, we can value any asset by taking the present value '
                        'of future cash flows',
                        'These forecasted FCFs represent the future cash flows for the company',
                        'But we have a limited forecast period, beyond which forecasts are getting too innaccurate, '
                        'typically 5 years at most. So what happens after 5 years? The company will probably still be '
                        'earning FCFs in the future.',
                        ['We can calculate a', pl.Bold('terminal value'), 'for the company, which is an estimate of '
                         'how much the company would be sold for if it was sold at the end of the forecast period. '
                         'In other words, it is the future predicted enterprise value.']
                    ],
                    title='What we use FCFs For'
                ),
                lp.DimRevealListFrame(
                    [
                        'The terminal value is an enterprise value at the end of the forecast period. But the bulk of '
                        'the DCF model is getting to an enterprise value, so we have to use a different method '
                        'to estimate the terminal value otherwise we would have an infinitely nested DCF model that could '
                        'never be solved.',
                        ['The two common methods for estimating the terminal value in a DCF model are',
                         pl.Underline('exit multiples'), 'and', pl.Underline('perpetuity growth')],
                        'The exit multiple method uses current values of valuation ratios and applies them to the '
                        'future financials',
                        'The perpetuity growth method assumes that the FCFs will grow at a constant rate after the '
                        'final forecast period.'
                    ],
                    title='How to Get the Terminal Value'
                ),
                lp.DimRevealListFrame(
                    [
                        'There are typically publicly available valuation ratios for public companies such as EV/EBIT, '
                        'EV/EBITDA, EV/Sales, EV/FCF, and P/E',
                        'The idea behind this approach is to use those ratios applied to your final period projected '
                        'financials.',
                        'Each ratio will yield a different terminal value, leading to a different final stock price '
                        'in your model. It is typical to report results with the different measures to get a range.',
                        'For all the EV ratios, multiply the statement item by the ratio to get the EV, then adjust the '
                        'EV using final forecasted values to get the equity value and stock price',
                        'For P/E, calculate final period earnings per share and multiply by the ratio to get the '
                        'stock price'
                    ],
                    title='Finding the Terminal Value via Exit Multiples'
                ),
                lp.DimRevealListFrame(
                    [
                        'The perpetuity growth model follows the same mathematics as the dividend discount model',
                        "We just assume that the last period's FCF continues to grow at some terminal growth rate "
                        "which we set.",
                        pl.Equation(str_eq=r'TV = \frac{FCF (1 + g)}{WACC - g}'),
                        ['The stock price is', pl.Underline('highly'), 'sensitive to the choice of terminal growth '
                         'rate, so there should absolutely be sensitivity analysis and Monte Carlo simulations varying '
                         'it'],
                        'Typical terminal growth rates are around 3%, approximately GDP growth rate'
                    ],
                    title='Finding the Terminal Value via Perpetuity Growth'
                ),
                lp.DimRevealListFrame(
                    [
                        'The last step to get the current enterprise value is to combine the FCFs with the TV',
                        'The TV cash flow should come in the final forecast period, such that the final cash flow '
                        'is $FCF + TV$',
                        'Take the NPV of the cash flows, including the TV',
                        'Follow the adjustments described in the intro lecture to get the stock price from that'
                    ],
                    title='Finding EV Using TV and FCFs'
                ),
                pl.TextSize(-2),
                tv_exercise.presentation_frames(),
                pl.TextSize(0)
            ],
            title='Using the Forecasted FCFs in the DCF Model',
            short_title='Valuation'
        ),

        pl.PresentationAppendix(
            [
                lecture.pyexlatex_resources_frame,
                fcf_exercise.appendix_frames(),
                simple_ts_exercise.appendix_frames(),
                complex_ts_exercise.appendix_frames(),
                tv_exercise.appendix_frames(),
            ]
        )
    ]
Ejemplo n.º 28
0
EXAMPLE_BODY = [
    pl.Chapter([
        'Some content',
        pl.UnorderedList(['a', 'b', 'c']),
    ],
               title='First'),
    pl.Chapter([
        'Chapter content',
        pl.Section([
            'Section content',
            pl.SubSection([
                'Subsection content',
                pl.SubSubSection([
                    'Subsubsubsection content',
                    pl.CiteP('person'),
                ],
                                 title='First sub sub')
            ],
                          title='First sub')
        ],
                   title='First section')
    ],
               title='Second')
]
EXAMPLE_BODY_NEXT_LEVEL_DOWN = [
    pl.Section([
        'Some content',
        pl.UnorderedList(['a', 'b', 'c']),
    ],
               title='First'),
def get_content():
    random.seed(1000)

    lecture = get_sensitivity_analysis_lecture()
    sensitivity_excel_lab = get_sensitivity_analysis_excel_lab_lecture().to_pyexlatex()
    dictionaries_lab = get_dictionaries_lab_lecture().to_pyexlatex()
    list_comp_lab = get_list_comprehensions_lab_lecture().to_pyexlatex()
    sensitivity_python_lab = get_sensitivity_analysis_python_lab_lecture().to_pyexlatex()
    appendix_frames = [
        lecture.pyexlatex_resources_frame,
        sensitivity_excel_lab.appendix_frames(),
        dictionaries_lab.appendix_frames(),
        list_comp_lab.appendix_frames(),
        sensitivity_python_lab.appendix_frames(),
    ]

    pd_mono = pl.Monospace('pandas')
    series_mono = pl.Monospace('Series')
    df_mono = pl.Monospace('DataFrame')
    apply_mono = pl.Monospace('apply')
    import_mono = pl.Monospace('import')
    for_mono = pl.Monospace('for')
    dict_mono = pl.Monospace('dict')
    np_mono = pl.Monospace('numpy')
    pd_mono = pl.Monospace('pandas')
    import_something_mono = pl.Monospace('import something')
    something_file = pl.Monospace('something.py')
    numpy_file = pl.Monospace('numpy.py')
    def_mono = pl.Monospace('def')
    class_mono = pl.Monospace('class')
    sensitivity_file_mono = pl.Monospace('sensitivity.py')
    sensitivity_import = pl.Monospace('import sensitivity')
    sensitivity_func_mono = pl.Monospace('sensitivity.sensitivity_hex_plots?')
    pip_install_mypackage = pl.Monospace('pip install mypackage')
    jupyter_install_mypackage = pl.Monospace('!pip install mypackage')
    itertools_product = pl.Monospace('itertools.product')
    sensitivity = pl.Monospace('sensitivity')

    series_ex_1 = pl.Python(
"""
>>> df = pd.DataFrame()
>>> df['Numbers'] = [1, 2, 3]
>>> df['Categories'] = ['apple', 'apple', 'orange']
>>> df
"""
    )
    series_ex_2 = pl.Python(
"""
>>> df['Categories']
0     apple
1     apple
2    orange
Name: Categories, dtype: object
>>> type(df['Categories'])
pandas.core.series.Series
"""
    )
    series_ex_3 = pl.Python(
"""
>>> cats = df['Categories']
>>> cats
0     apple
1     apple
2    orange
Name: Categories, dtype: object
>>> cats[2]
'orange'
>>> cats.index = ['a', 'b', 'c']
>>> cats
a     apple
b     apple
c    orange
Name: Categories, dtype: object
>>> cats['b']
'apple'
"""
    )

    list_comprehension_ex_1 = pl.Python(
"""
>>> out_values = []
>>> for i in range(5):
>>>     out_values.append(i + 10)
>>> out_values
[10, 11, 12, 13, 14]
"""
    )

    list_comprehension_ex_2 = pl.Python(
"""
>>> out_values = [i + 10 for i in range(5)]
>>> out_values
[10, 11, 12, 13, 14]
"""
    )
    dict_example = pl.Python(
"""
>>> coffee_levels_emotions = {
>>>     'high': 'happy',
>>>     'pretty high': 'happy',
>>>     'medium': 'neutral',
>>>     'low': 'sad',
>>>     'empty': 'desparate'
>>> }
>>> coffee_levels_emotions['pretty high']
'happy'
>>> for coffee_level, emotion in coffee_levels_emotions.items():
>>>     print(f"I'm {emotion} when my coffee is {coffee_level}")
"""
    )

    dict_printout = """
I'm happy when my coffee is high
I'm happy when my coffee is pretty high
I'm neutral when my coffee is medium
I'm sad when my coffee is low
I'm desparate when my coffee is empty
    """

    dict_printouts_mono = [pl.Monospace(item) for item in dict_printout.split('\n') if item]
    dict_printout_output = []
    for po in dict_printouts_mono:
        dict_printout_output.append(po)
        dict_printout_output.append('')

    dict_example_2 = pl.Python(
"""
>>> coffee_levels_emotions.update({'overflowing': 'burned'})
>>> coffee_levels_emotions['negative'] = 'confused'
>>> high_value = coffee_levels_emotions.pop('high')
>>> coffee_levels_emotions
{'pretty high': 'happy',
 'medium': 'neutral',
 'low': 'sad',
 'empty': 'desparate',
 'overflowing': 'burned',
 'negative': 'confused'}
>>> high_value
'happy'
"""
    )

    plain_sensitivity_example = pl.Python(
"""
inp1_values = [1, 2]
inp2_values = [4, 5]
results = []
for inp1 in inp1_values:
    for inp2 in inp2_values:
        result = model(inp1, inp2,)
        results.append(
            (inp1, inp2, result)
        )
pd.DataFrame(results, columns=['inp1', 'inp2',  'Result'])
"""
    )

    easy_sensitivity_example = pl.Python(
"""
from sensitivity import SensitivityAnalyzer

sensitivity_values = {
    'inp1': [1, 2],
    'inp2': [4, 5],
}
sa = SensitivityAnalyzer(sensitivity_values, model)
sa.df
"""
    )

    return [
        pl.Section(
            [
                lp.DimRevealListFrame(
                    [
                        'So far, I have given you some inputs to use and you have been getting one or more outputs from '
                        'those inputs',
                        'We have not considered how those inputs may change, and how that affects the outputs',
                        'This is where building a model vs. doing a calculation really starts to pay off'
                    ],
                    title='Moving from a Static Model'
                ),
                lp.GraphicFrame(
                    explore_parameters_graphic(),
                    title='How to Explore Inputs and their Affect on Outputs'
                ),
                lp.DimRevealListFrame(
                    [
                        pl.TextSize(-1),
                        'In this lecture, we will be discussing sensitivity analysis as an approach to exploring the '
                        'parameter space.',
                        'After we cover probabilistic modeling, we will revisit exploring the parameter space with other '
                        'methods: scenario analysis and Monte Carlo Simulation.',
                        'In sensitivity analysis, a fixed set of values for the parameters are chosen, while in Monte Carlo '
                        'Simulation, each parameter is assigned a distribution.',
                        'In scenario analysis, several realistic cases of the inputs are chosen which represent '
                        'possible real-world situations',
                        'All three methods may be used together to fully understand a model.'
                    ],
                    title='Methods of Parameter Exploration'
                ),
            ],
            title='Introduction to Parameter Exploration',
            short_title='Explore Parameters'
        ),
        pl.Section(
            [
                lp.Frame(
                    [
                        'For the model given by:',
                        pl.Equation(str_eq='y = f(X)', inline=False),
                        pl.Equation(str_eq='X = [x_1, x_2, ..., x_n]', inline=False),
                        pl.UnorderedList([
                            [pl.Equation(str_eq='y:'), 'Model output'],
                            [pl.Equation(str_eq='X:'), 'Model input matrix'],
                            [pl.Equation(str_eq='x_i:'), 'Value of $i$th $x$ variable']

                        ]),
                        'Follow the following steps:',
                        pl.OrderedList([
                            ['Choose a set of values for each', pl.Equation(str_eq='x_i')],
                            ['Take the cartesian product of these values as',
                             pl.Equation(str_eq='[X_1, X_2, ..., X_m]')],
                            ['For each', pl.Equation(str_eq='X_i'), 'calculate', pl.Equation(str_eq='y_i = f(X_i)')],
                            ['Store the values of', pl.Equation(str_eq='X_i'), 'mapped to', pl.Equation(str_eq='y_i')],
                            ['Visualize', pl.Equation(str_eq='y_i'), 'versus', pl.Equation(str_eq='X_i')]
                        ])
                    ],
                    title='Sensitivity Analysis, Formally'
                ),
                get_sensitivity_analysis_example_frames(),
            ],
            title='Sensitivity Analysis Theory',
            short_title='SA Theory'
        ),
        pl.Section(
            [
                lp.GraphicFrame(
                    images_path('excel-data-table.png'),
                    title='Sensitivity Analysis in Excel'
                ),
                lp.DimRevealListFrame(
                    [
                        'There are two main ways to visualize sensitivity analysis results in Excel: graphing and '
                        'conditional formatting.',
                        'Graphing is usually appropriate for one-way data tables',
                        'Conditional formatting is usually appropriate for two-way data tables'
                    ],
                    title='Visualizing Sensitivity Analysis in Excel'
                ),
                lp.GraphicFrame(
                    images_path('excel-conditional-formatting.png'),
                    title='Conditional Formatting in Excel'
                ),
                InClassExampleFrame(
                    [
                        'I will now go through adding sensitivity analysis to the Dynamic Salary Retirement Model '
                        'in Excel',
                        'The completed exercise on the course site, '
                        '"Dynamic Salary Retirement Model Sensitivity.xlsx"'
                    ],
                    title='Sensitivity Analysis in Excel',
                    block_title='Adding Sensitivity Analysis to the Dynamic Retirement Excel Model'
                ),
                sensitivity_excel_lab.presentation_frames(),
            ],
            title='Sensitivity Analysis in Excel with Data Tables',
            short_title='SA Excel'
        ),
        pl.Section(
            [
                lp.Frame(
                    [
                        "We'll cover a couple more Python patterns and a new data type before jumping into sensitivity analysis",
                        pl.UnorderedList([
                            'Dictionaries',
                            'List comprehensions',
                            ['Python', import_mono, 'system and custom code']
                        ])
                    ],
                    title=f'Going Deeper into Python Code Structure'
                ),
                lp.TwoColumnGraphicDimRevealFrame(
                    [
                        ['A dictionary, or', dict_mono,
                         'for short, is another basic Python data type like lists, numbers, and strings.'],
                        'Like a list, it is a collection: it holds other objects.',
                        ['Unlike a list, a', dict_mono,
                         'is composed of key-value pairs. It holds relationships between objects.']
                    ],
                    graphics=[
                        lg.ModifiedPicture(
                            images_path('dictionary-book.jpg'),
                            draw_items=[
                                lg.Path('draw', [(0.5, 0.5)], draw_type='circle',
                                        options=['radius=0.4', 'red', 'line width=5mm']),
                                lg.Path('draw', [(0.2, 0.75), (0.8, 0.2)], draw_type='--',
                                        options=['red', 'line width=5mm'])
                            ]
                        )
                    ],
                    title='What is a Dictionary?'
                ),
                lp.Frame(
                    [
                        lp.Block(
                            [
                                pl.TextSize(-2),
                                dict_example,
                                *dict_printout_output
                            ],
                            title='Basic Dictionary Example'
                        )
                    ],
                    title='How to Use Dictionaries'
                ),
                lp.Frame(
                    [
                        lp.Block(
                            [
                                dict_example_2,
                            ],
                            title='Add and Delete Items from Dictionaries'
                        )
                    ],
                    title='How to Modify Dictionaries'
                ),
                InClassExampleFrame(
                    [
                        'I will now start going through the example notebook called '
                        '"Python Dicts, List comprehensions, and Imports.ipynb"',
                        'I will go through the Dictionaries section for now'
                    ],
                    title='More About Dictionaries in Python',
                    block_title='Using Dictionaries'
                ),
                dictionaries_lab.presentation_frames(),
                lp.Frame(
                    [
                        pl.TextSize(-1),
                        lp.Block(
                            [
                                list_comprehension_ex_1
                            ],
                            title=f'The Original Way'
                        ),
                        lp.Block(
                            [
                                list_comprehension_ex_2
                            ],
                            title=f'With List Comprehension'
                        ),
                        lp.Block(
                            ['You', pl.Bold('never'),
                             'need to use list comprehension, it is just for convenience. The original', for_mono,
                             'loop syntax will always work fine.'],
                            title='Notice'
                        )
                    ],
                    title=f"An Easier way to Build Simple Lists from Loops"
                ),
                InClassExampleFrame(
                    [
                        'I will continue going through the example notebook '
                        '"Python Dicts, List comprehensions, and Imports.ipynb"',
                        'I will go through the List Comprehensions section for now'
                    ],
                    title='Easier Loops in Python',
                    block_title='Using List Comprehensions'
                ),
                list_comp_lab.presentation_frames(),
                lp.DimRevealListFrame(
                    [
                        ['In the past we have used', import_mono, 'to load packages such as', np_mono, 'and', pd_mono],
                        ['These packages are just Python files. We can also write our own Python files and',
                         import_mono,
                         'them the same way'],
                        [f'When you {import_something_mono}, Python first searches the current directory for a file',
                         something_file, "and if it doesn't find it, it searches your installed packages"],
                        ['In fact if you added a', numpy_file, 'in the current directory and tried to', import_mono,
                         np_mono,
                         'it would', import_mono, 'the contents of that file rather than the', np_mono, 'package.']
                    ],
                    title=f'Understanding Python {import_mono}s'
                ),
                lp.DimRevealListFrame(
                    [
                        ['You can write your own functions and classes, then put them in a Python file and',
                         import_mono,
                         'them into your notebook.'],
                        ['When you', import_mono,
                         'a file, it executes the contents of that file. So you generally want just '
                         'function and class definitions, and not really anything outside of', def_mono, 'or',
                         class_mono,
                         'statements.'],
                        'Using Python files is a more maintainable structure for building complex models and apps versus '
                        'Jupyter notebooks only.'
                    ],
                    title='Importing Custom Code'
                ),
                lp.DimRevealListFrame(
                    [
                        'Sometimes you will need a package which does not already come installed with Anaconda',
                        ['The general way to do this is with', pip_install_mypackage, 'replacing mypackage with',
                         'the package you want to install'],
                        ['You would run this in Anaconda Prompt, or in Jupyter you can run it but you need to put an '
                        'exclaimation mark before it to say you want to run it in a terminal. So in Jupyter it would be',
                        jupyter_install_mypackage]
                    ],
                    title='Installing Packages'
                ),
                InClassExampleFrame(
                    [
                        'I will continue going through the example notebook '
                        '"Python Dicts, List comprehensions, and Imports.ipynb"',
                        'I will go through the Imports and Installing Packages section for now'
                    ],
                    title='Installing Packages in Python',
                    block_title='How to Install Packages'
                ),

            ],
            title='Python List Comprehensions, Installing Packages, and More on Dictionaries',
            short_title='Extra Python Basics'
        ),
        pl.Section(
            [
                lp.GraphicFrame(
                    images_path('python-sensitivity-hex-bins.pdf'),
                    title='Sensitivity Analysis in Python - Hex-Bin'
                ),
                lp.GraphicFrame(
                    images_path('sensitivity-analysis-styled-df.png'),
                    title='Sensitivity Analysis in Python - Styled DataFrame'
                ),
                lp.DimRevealListFrame(
                    [
                        'Generally, to do sensitivity analysis in Python without any special tools, you would just '
                        'create one nested for loop for each input, and finally within all the loops, run your model '
                        'with the inputs from the loops',
                        'This will work fine, but you will have many nested loops which can become hard to read. Also '
                        'it is a fair bit of setup involved.',
                        ['You can avoid the nested loops with', itertools_product, 'but then this becomes more '
                         'difficult to use and read']

                    ],
                    title='How to Do Sensitivity Analysis in Python (The Hard Way)'
                ),
                lp.Frame(
                    [
                        pl.TextSize(-3),
                        pl.UnorderedList([
                            'Say you have a function which runs your model, called model, which takes inputs of '
                            'inp1 and inp2'
                        ]),
                        lp.Block(
                            [
                                plain_sensitivity_example,
                                pl.Graphic(images_path('plain-sensitivity-result.png'), width=0.2),
                            ],
                            title='Sensitivity Analysis in Python with No Libraries'
                        )
                    ],
                    title='Sensitivity Analysis Example (Hard Way)'
                ),
                lp.DimRevealListFrame(
                    [
                        "When I first created this course, I thought there should be a good sensitivity analysis "
                        "tool in Python and I couldn't find it",
                        "The beauty of Python is if you want a tool that doesn't exist, you can create it, and "
                        "share it with others so that nobody else has to deal with the problem.",
                        ['So I created', sensitivity, 'a package for sensitivity analysis in Python, '
                                                      'which makes it very easy']

                    ],
                    title='How to Do Sensitivity Analysis in Python (The Easy Way)'
                ),
                lp.Frame(
                    [
                        pl.TextSize(-3),
                        pl.UnorderedList([
                            'Say you have a function which runs your model, called model, which takes inputs of '
                            'inp1 and inp2'
                        ]),
                        lp.Block(
                            [
                                easy_sensitivity_example,
                                pl.Graphic(images_path('plain-sensitivity-result.png'), width=0.2),
                            ],
                            title=f'Sensitivity Analysis in Python with {sensitivity}'
                        )
                    ],
                    title='Sensitivity Analysis Example (Easy Way)'
                ),
                InClassExampleFrame(
                    [
                        'I will now go through Sensitivity Analysis example Jupyter notebook',
                        'This notebook shows both the standard approach and using the sensitivity package',
                    ],
                    title='Intro to Sensitivity Analysis in Python',
                    block_title='An Overview of the Manual and Automated Approaches'
                ),
                InClassExampleFrame(
                    [
                        'I will now go through adding sensitivity analysis to the Dynamic Salary Retirement Model '
                        'in Python',
                        'The completed exercise available on the course site is called '
                        '"Dynamic Salary Retirement Model Sensitivity.ipynb"'
                    ],
                    title='Applying Sensitivity Analysis in Python',
                    block_title='Adding Sensitivity Analysis to the Dynamic Retirement Python Model'
                ),
                sensitivity_python_lab.presentation_frames(),
            ],
            title='Sensitivity Analysis in Python',
            short_title='SA Python'
        ),
        pl.PresentationAppendix(appendix_frames),
    ]
Ejemplo n.º 30
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'
        )
    ]