Monte Carlo Simulation serverless using Python Shiny Live + Code!

aktieanalys
shinylive
python
interactive
valuation
Monte
Carlo
Monte Carlo Simulations are powerful. Using Shinylive with Python, you can leverage web assebely to distribute your insights with users who do not have the possibility to access your dynamic analysis otherwise.
Author

Jakob Johannesson

Published

January 19, 2024

Modified

February 25, 2024

Example of a Monte Carlo Simulation

#| standalone: true
#| layout-nrow: 1
#| viewerHeight: 820

from shiny import App, render, ui, Inputs, Outputs, Session
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

def monte_carlo_simulation(years, initial_revenue, revenue_growth_range, profit_margin_range,fair_value):
    final_results = []
    num_simulations=10000
    #fair_value=np.number(fair_value)
    #print(fair_value)

    for _ in range(num_simulations):
        yearly_revenues = [initial_revenue]
        yearly_profits = []
        yearly_valuation = []

        for year in range(years):
            growth_rate = np.random.lognormal(revenue_growth_range[0], revenue_growth_range[1])
            profit_margin = np.random.uniform(profit_margin_range[0], profit_margin_range[1])
            

            new_revenue = yearly_revenues[-1] * (1 + growth_rate)
            profit = new_revenue * profit_margin
            valuation = profit*fair_value

            yearly_revenues.append(new_revenue)
            yearly_profits.append(profit)
            yearly_valuation.append(valuation)
        final_results.append({'Revenue': yearly_revenues[-1], 'Profit': yearly_profits[-1],
        'Valuation': yearly_valuation[-1]})
        
    return final_results

app_ui = ui.page_fluid(
    ui.layout_sidebar(
        ui.sidebar(
            ui.h1("Monte Carlo Simulation"),
            ui.input_slider("fair_value", "Fair P/E", min=5, max=40, value=25),
            ui.input_slider("years", "Number of Years", min=1, max=10, value=3),
            ui.input_numeric("initial_revenue", "Initial Revenue", value=27.5),
            ui.input_slider("revenue_growth_min", "Mean Revenue Growth", min=-0.2, max=1, value=0.25, step=0.05),
            ui.input_slider("revenue_growth_max", "Std Revenue Growth", min=0, max=1, value=0.1, step=0.05),
            ui.input_slider("profit_margin_min", "Min Profit Margin", min=0, max=1, value=0.30, step=0.01),
            ui.input_slider("profit_margin_max", "Max Profit Margin", min=0, max=1, value=0.50, step=0.01),
        ),
        ui.layout_column_wrap(
            ui.output_plot("simulation_plot")
        )
    )
)

def server(input: Inputs, output: Outputs, session: Session):
    @output
    @render.plot
    def simulation_plot():
        fair_value = input.fair_value()
        years = input.years()
        initial_revenue = input.initial_revenue()
        revenue_growth_range = (input.revenue_growth_min(), input.revenue_growth_max())
        profit_margin_range = (input.profit_margin_min(), input.profit_margin_max())
        

        results = monte_carlo_simulation(years, initial_revenue, revenue_growth_range, profit_margin_range,fair_value)

        Valuation = [result['Valuation'] for result in results]
        Valuation_mean = round(np.mean(Valuation),1)
        Valuation_std = round(np.std(Valuation),1)
        plt.hist(Valuation, bins=30)
        plt.title('Monte Carlo Simulation of Company Valuation over ' + str(years) + ' Years. Mean: ' + str(Valuation_mean)+'+-'+str(Valuation_std))
        plt.xlabel('Valuation')
        plt.ylabel('Frequency')

app = App(app_ui, server)

Code below to recreate dashboard above

```{shinylive-python}
#| standalone: true
#| layout-nrow: 1
#| viewerHeight: 820

from shiny import App, render, ui, Inputs, Outputs, Session
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

def monte_carlo_simulation(years, initial_revenue, revenue_growth_range, profit_margin_range,fair_value):
    final_results = []
    num_simulations=10000
    #fair_value=np.number(fair_value)
    #print(fair_value)

    for _ in range(num_simulations):
        yearly_revenues = [initial_revenue]
        yearly_profits = []
        yearly_valuation = []

        for year in range(years):
            growth_rate = np.random.lognormal(revenue_growth_range[0], revenue_growth_range[1])
            profit_margin = np.random.uniform(profit_margin_range[0], profit_margin_range[1])
            

            new_revenue = yearly_revenues[-1] * (1 + growth_rate)
            profit = new_revenue * profit_margin
            valuation = profit*fair_value

            yearly_revenues.append(new_revenue)
            yearly_profits.append(profit)
            yearly_valuation.append(valuation)
        final_results.append({'Revenue': yearly_revenues[-1], 'Profit': yearly_profits[-1],
        'Valuation': yearly_valuation[-1]})
        
    return final_results

app_ui = ui.page_fluid(
    ui.layout_sidebar(
        ui.sidebar(
            ui.h1("Monte Carlo Simulation"),
            ui.input_slider("fair_value", "Fair P/E", min=5, max=40, value=25),
            ui.input_slider("years", "Number of Years", min=1, max=10, value=3),
            ui.input_numeric("initial_revenue", "Initial Revenue", value=27.5),
            ui.input_slider("revenue_growth_min", "Mean Revenue Growth", min=-0.2, max=1, value=0.25, step=0.05),
            ui.input_slider("revenue_growth_max", "Std Revenue Growth", min=0, max=1, value=0.1, step=0.05),
            ui.input_slider("profit_margin_min", "Min Profit Margin", min=0, max=1, value=0.30, step=0.01),
            ui.input_slider("profit_margin_max", "Max Profit Margin", min=0, max=1, value=0.50, step=0.01),
        ),
        ui.layout_column_wrap(
            ui.output_plot("simulation_plot")
        )
    )
)

def server(input: Inputs, output: Outputs, session: Session):
    @output
    @render.plot
    def simulation_plot():
        fair_value = input.fair_value()
        years = input.years()
        initial_revenue = input.initial_revenue()
        revenue_growth_range = (input.revenue_growth_min(), input.revenue_growth_max())
        profit_margin_range = (input.profit_margin_min(), input.profit_margin_max())
        

        results = monte_carlo_simulation(years, initial_revenue, revenue_growth_range, profit_margin_range,fair_value)

        Valuation = [result['Valuation'] for result in results]
        Valuation_mean = round(np.mean(Valuation),1)
        Valuation_std = round(np.std(Valuation),1)
        plt.hist(Valuation, bins=30)
        plt.title('Monte Carlo Simulation of Company Valuation over ' + str(years) + ' Years. Mean: ' + str(Valuation_mean)+'+-'+str(Valuation_std))
        plt.xlabel('Valuation')
        plt.ylabel('Frequency')

app = App(app_ui, server) ```