Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

The Fisher Two-Period Optimal Consumption Problem

badge
# Some initial setup
import ipywidgets as widgets
from ipywidgets import interact, fixed
from HARK.ConsumptionSaving.ConsIndShockModel import PerfForesightConsumerType
import numpy as np
from copy import deepcopy
from matplotlib import pyplot as plt

plt.style.use("seaborn-v0_8-darkgrid")
palette = plt.get_cmap("Dark2")


def mystr(number):
    return "{:.3f}".format(number)

This notebook creates interactive widgets illustrating a two-period optimal consumption problem. It also presents graphic representations of the decomposition of the effect of interest rates into the income, substitution, and human wealth effects.

Basic Plot: the optimal (c1,c2)(c_1,c_2) bundle.

The maximization problem is stated below:

max{c1,c2}V(c1,c2)\max_{\{c_1, c_2\}} V(c_1, c_2)

subject to:

c2=(b1+y1c1)R+y2c_2 = (b_1 + y_1 - c_1)R + y_2
# The first step in creating a widget is defining
# a function that will receive the user's input as
# parameters and generate the entity that we want
# to analyze: in this case, a figure of the optimmal
# consumption bundle given income, assets, and interest
# rates


def FisherPlot(Y_1, Y_2, B_1, R, C_1_Max, C_2_Max):
    # Basic setup of perfect foresight consumer

    # We first create an instance of the class
    # PerfForesightConsumerType, with its standard parameters.
    PFexample = PerfForesightConsumerType()

    PFexample.cycles = 1  # let the agent live the cycle of periods just once
    PFexample.T_cycle = 1  # Number of non-terminal periods in the cycle
    # No automatic growth in income across periods
    PFexample.PermGroFac = [1.0]
    PFexample.LivPrb = [1.0]  # No chance of dying before the second period
    PFexample.kLogInitStd = 0.0
    PFexample.AgentCount = 1
    CRRA = PFexample.CRRA
    beta = PFexample.DiscFac

    # Set interest rate and bank balances from input.
    PFexample.Rfree = [R]
    PFexample.kLogInitMean = B_1
    

    # Solve the model: this generates the optimal consumption function.

    # Try-except blocks "try" to execute the code in the try block. If an
    # error occurs, the except block is executed and the application does
    # not halt
    try:
        PFexample.solve()
    except:
        print("Those parameter values violate a condition required for solution!")

    # Create the figure
    C_1_Min = 0.0
    C_2_Min = 0.0
    plt.figure(figsize=(8, 8))
    plt.xlabel("Period 1 Consumption $C_1$")
    plt.ylabel("Period 2 Consumption $C_2$")
    plt.ylim([C_2_Min, C_2_Max])
    plt.xlim([C_1_Min, C_1_Max])

    # Plot the budget constraint
    C_1_bc = np.linspace(C_1_Min, B_1 + Y_1 + Y_2 / R, 10, endpoint=True)
    C_2_bc = (Y_1 + B_1 - C_1_bc) * R + Y_2
    plt.plot(C_1_bc, C_2_bc, "k-", label="Budget Constraint")

    # Plot the optimal consumption bundle
    C_1 = PFexample.solution[0].cFunc(B_1 + Y_1 + Y_2 / R)
    C_2 = PFexample.solution[1].cFunc((Y_1 + B_1 - C_1) * R + Y_2)
    plt.plot(C_1, C_2, "ro", label="Optimal Consumption")

    # Plot the indifference curve
    V = C_1 ** (1 - CRRA) / (1 - CRRA) + beta * C_2 ** (1 - CRRA) / (
        1 - CRRA
    )  # Get max utility
    C_1_V = np.linspace(((1 - CRRA) * V) ** (1 / (1 - CRRA)) + 0.5, C_1_Max, 1000)
    C_2_V = (((1 - CRRA) * V - C_1_V ** (1 - CRRA)) / beta) ** (1 / (1 - CRRA))
    plt.plot(C_1_V, C_2_V, "b-", label="Indiferrence Curve")

    # Add a legend and display the plot
    plt.legend()
    plt.show()

    return None
# We now define the controls that will receive and transmit the
# user's input.
# These are sliders for which the range, step, display, and
# behavior are defined.

# Define a slider for the interest rate
Rfree_widget = widgets.FloatSlider(
    min=1.0,
    max=2.0,
    step=0.001,
    value=1.05,
    continuous_update=True,
    readout_format=".4f",
    description="$R$",
)

# Define a slider for Y_1
Y_1_widget = widgets.FloatSlider(
    min=0.0,
    max=100.0,
    step=0.1,
    value=50.0,
    continuous_update=True,
    readout_format="4f",
    description="$Y_1$",
)

# Define a slider for Y_2
Y_2_widget = widgets.FloatSlider(
    min=0.0,
    max=100.0,
    step=0.1,
    value=50.0,
    continuous_update=True,
    readout_format="4f",
    description="$Y_2$",
)

# Define a slider for B_1
B_1_widget = widgets.FloatSlider(
    min=0.0,
    max=4.0,
    step=0.01,
    value=2.0,
    continuous_update=True,
    readout_format="4f",
    description="$B_1$",
)

# Define a textbox for C_1 max
C_1_Max_widget = widgets.FloatText(
    value=120, step=1.0, description="$C_1$ max", disabled=False
)

# Define a textbox for C_2 max
C_2_Max_widget = widgets.FloatText(
    value=120, step=1.0, description="$C_2$ max", disabled=False
)
# Make the widget
interact(
    FisherPlot,
    Y_1=Y_1_widget,
    Y_2=Y_2_widget,
    B_1=B_1_widget,
    R=Rfree_widget,
    C_1_Max=C_1_Max_widget,
    C_2_Max=C_2_Max_widget,
);

Second plot: interest rate shifts with lifetime income earned in first period.

# This follows the same process as the previous plot, but now the problem
# is solved at two different interest rates in order to illustrate their effect.


# Define a function that plots something given some bits
def FisherPlot1(Y_1, Y_2, B_1, RHi, RLo, C_1_Max, C_2_Max):
    # Basic setup of perfect foresight consumer
    PFexample = (
        PerfForesightConsumerType()
    )  # set up a consumer type and use default parameteres
    PFexample.cycles = 1  # let the agent live the cycle of periods just once
    PFexample.T_cycle = 1  # Number of non-terminal periods in the cycle
    # No automatic growth in income across periods
    PFexample.PermGroFac = [1.0]
    PFexample.LivPrb = [1.0]  # No chance of dying before the second period
    PFexample.kLogInitStd = 0.0
    PFexample.AgentCount = 1
    CRRA = 2.0
    beta = PFexample.DiscFac

    # Set the parameters we enter
    PFexample.kLogInitMean = B_1

    # Create two models, one for RfreeHigh and one for RfreeLow
    PFexampleRHi = deepcopy(PFexample)
    PFexampleRHi.Rfree = [RHi]
    PFexampleRLo = deepcopy(PFexample)
    PFexampleRLo.Rfree = [RLo]

    C_1_Min = 0.0
    C_2_Min = 0.0

    # Solve the model for RfreeHigh and RfreeLow
    try:
        PFexampleRHi.solve()
        PFexampleRLo.solve()
    except:
        print("Those parameter values violate a condition required for solution!")

    # Plot the chart
    plt.figure(figsize=(8, 8))
    plt.xlabel("Period 1 Consumption $C_1$")
    plt.ylabel("Period 2 Consumption $C_2$")
    plt.ylim([C_2_Min, C_2_Max])
    plt.xlim([C_1_Min, C_1_Max])

    # Plot the budget constraints
    C_1_bc_RLo = np.linspace(C_1_Min, B_1 + Y_1 + Y_2 / RLo, 10, endpoint=True)
    C_2_bc_RLo = (Y_1 + B_1 - C_1_bc_RLo) * RLo + Y_2
    plt.plot(C_1_bc_RLo, C_2_bc_RLo, "k-", label="Budget Constraint R Low")

    C_1_bc_RHi = np.linspace(C_1_Min, B_1 + Y_1 + Y_2 / RHi, 10, endpoint=True)
    C_2_bc_RHi = (Y_1 + B_1 - C_1_bc_RHi) * RHi + Y_2
    plt.plot(C_1_bc_RHi, C_2_bc_RHi, "k--", label="Budget Constraint R High")

    # The optimal consumption bundles
    C_1_opt_RLo = PFexampleRLo.solution[0].cFunc(B_1 + Y_1 + Y_2 / RLo)
    C_2_opt_RLo = PFexampleRLo.solution[1].cFunc((Y_1 + B_1 - C_1_opt_RLo) * RLo + Y_2)

    C_1_opt_RHi = PFexampleRHi.solution[0].cFunc(B_1 + Y_1 + Y_2 / RHi)
    C_2_opt_RHi = PFexampleRHi.solution[1].cFunc((Y_1 + B_1 - C_1_opt_RHi) * RHi + Y_2)

    # Plot the indifference curves
    V_RLo = C_1_opt_RLo ** (1 - CRRA) / (1 - CRRA) + beta * C_2_opt_RLo ** (1 - CRRA) / (
        1 - CRRA
    )  # Get max utility
    C_1_V_RLo = np.linspace(((1 - CRRA) * V_RLo) ** (1 / (1 - CRRA)) + 0.5, C_1_Max, 1000)
    C_2_V_RLo = (((1 - CRRA) * V_RLo - C_1_V_RLo ** (1 - CRRA)) / beta) ** (
        1 / (1 - CRRA)
    )
    plt.plot(C_1_V_RLo, C_2_V_RLo, "b-", label="Indiferrence Curve R Low")

    V_RHi = C_1_opt_RHi ** (1 - CRRA) / (1 - CRRA) + beta * C_2_opt_RHi ** (1 - CRRA) / (
        1 - CRRA
    )  # Get max utility
    C_1_V_RHi = np.linspace(((1 - CRRA) * V_RHi) ** (1 / (1 - CRRA)) + 0.5, C_1_Max, 1000)
    C_2_V_RHi = (((1 - CRRA) * V_RHi - C_1_V_RHi ** (1 - CRRA)) / beta) ** (
        1 / (1 - CRRA)
    )
    plt.plot(C_1_V_RHi, C_2_V_RHi, "b--", label="Indiferrence Curve R High")

    # The substitution effect
    C_1_Subs = (
        V_RHi * (1 - CRRA) / (1 + beta * (RLo * beta) ** ((1 - CRRA) / CRRA))
    ) ** (1 / (1 - CRRA))
    C_2_Subs = C_1_Subs * (RLo * beta) ** (1 / CRRA)

    C_1_bc_Subs = np.linspace(C_1_Min, B_1 + Y_1 + Y_2 / RHi, 10, endpoint=True)
    C_2_bc_Subs = (C_1_Subs + C_2_Subs / RLo - C_1_bc_Subs) * RLo + Y_2
    plt.plot(C_1_bc_Subs, C_2_bc_Subs, "k-")

    # Plot the points of interest
    plt.plot(C_1_opt_RLo, C_2_opt_RLo, "ro", label="A: Optimal Consumption R Low")
    plt.plot(
        C_1_Subs,
        C_2_Subs,
        "go",
        label="B: Income effect AB \n     Substitution effect BC ",
    )
    plt.plot(C_1_opt_RHi, C_2_opt_RHi, "mo", label="C: Optimal Consumption R High ")

    plt.legend()
    plt.show()

    return None
# Define some widgets to control the plot

# Define a slider for the high interest rate
RHi_widget1 = widgets.FloatSlider(
    min=1.0,
    max=4.0,
    step=0.01,
    value=2,
    continuous_update=True,
    readout_format=".2f",
    description="$R High$",
)

# Define a slider for the low interest rate
RLo_widget1 = widgets.FloatSlider(
    min=0.0,
    max=4.0,
    step=0.01,
    value=1.0,
    continuous_update=True,
    readout_format=".2f",
    description="$R Low$",
)

# Define a slider for Y_1
Y_1_widget1 = widgets.FloatSlider(
    min=0.0,
    max=100.0,
    step=0.1,
    value=100.0,
    continuous_update=True,
    readout_format=".1f",
    description="$Y_1$",
)

# Define a slider for Y_2
Y_2_widget1 = widgets.FloatSlider(
    min=0.0,
    max=100.0,
    step=0.1,
    value=0.0,
    continuous_update=True,
    readout_format=".1f",
    description="$Y_2$",
)

# Define a slider for B_1
B_1_widget1 = widgets.FloatSlider(
    min=0.0,
    max=4.0,
    step=0.01,
    value=0.0,
    continuous_update=True,
    readout_format=".1f",
    description="$B_1$",
)

# Define a textbox for C_1 max
c_1_Max_widget1 = widgets.FloatText(
    value=120, step=1.0, description="$C_1$ max", disabled=False
)

# Define a textbox for C_2 max
c_2_Max_widget1 = widgets.FloatText(
    value=120, step=1.0, description="$C_2$ max", disabled=False
)
# Make the widget

interact(
    FisherPlot1,
    Y_1=Y_1_widget1,
    Y_2=fixed(0.0),
    B_1=B_1_widget1,
    RHi=RHi_widget1,
    RLo=RLo_widget1,
    C_1_Max=c_1_Max_widget1,
    C_2_Max=c_2_Max_widget1,
);

Third plot: interest rate shifts with lifetime income earned in second period

# This follows the same process, but we now fix Y_1 at 0


# Define a function that plots something given some bits
def FisherPlot2(Y_1, Y_2, B_1, RHi, RLo, C_1_Max, C_2_Max):
    # Basic setup of perfect foresight consumer
    PFexample = (
        PerfForesightConsumerType()
    )  # set up a consumer type and use default parameteres
    PFexample.cycles = 1  # let the agent live the cycle of periods just once
    PFexample.T_cycle = 1  # Number of non-terminal periods in the cycle
    # No automatic growth in income across periods
    PFexample.PermGroFac = [1.0]
    PFexample.LivPrb = [1.0]  # No chance of dying before the second period
    PFexample.kLogInitStd = 0.0
    PFexample.AgentCount = 1
    CRRA = 2.0
    beta = PFexample.DiscFac

    # Set the parameters we enter
    PFexample.kLogInitMean = B_1

    # Create two models, one for RfreeHigh and one for RfreeLow
    PFexampleRHi = deepcopy(PFexample)
    PFexampleRHi.Rfree = [RHi]
    PFexampleRLo = deepcopy(PFexample)
    PFexampleRLo.Rfree = [RLo]

    C_1_Min = 0.0
    C_2_Min = 0.0

    # Solve the model for RfreeHigh
    try:
        PFexampleRHi.solve()
        PFexampleRLo.solve()
    except:
        print("Those parameter values violate a condition required for solution!")

    # Plot the chart
    plt.figure(figsize=(8, 8))
    plt.xlabel("Period 1 Consumption $C_1$")
    plt.ylabel("Period 2 Consumption $C_2$")
    plt.ylim([C_2_Min, C_2_Max])
    plt.xlim([C_1_Min, C_1_Max])

    # Plot the budget constraints
    C_1_bc_RLo = np.linspace(C_1_Min, B_1 + Y_1 + Y_2 / RLo, 10, endpoint=True)
    C_2_bc_RLo = (Y_1 + B_1 - C_1_bc_RLo) * RLo + Y_2
    plt.plot(C_1_bc_RLo, C_2_bc_RLo, "k-", label="Budget Constraint R Low")

    C_1_bc_RHi = np.linspace(C_1_Min, B_1 + Y_1 + Y_2 / RHi, 10, endpoint=True)
    C_2_bc_RHi = (Y_1 + B_1 - C_1_bc_RHi) * RHi + Y_2
    plt.plot(C_1_bc_RHi, C_2_bc_RHi, "k--", label="Budget Constraint R High")

    # The optimal consumption bundles
    C_1_opt_RLo = PFexampleRLo.solution[0].cFunc(B_1 + Y_1 + Y_2 / RLo)
    C_2_opt_RLo = PFexampleRLo.solution[1].cFunc((Y_1 + B_1 - C_1_opt_RLo) * RLo + Y_2)

    C_1_opt_RHi = PFexampleRHi.solution[0].cFunc(B_1 + Y_1 + Y_2 / RHi)
    C_2_opt_RHi = PFexampleRHi.solution[1].cFunc((Y_1 + B_1 - C_1_opt_RHi) * RHi + Y_2)

    # Plot the indifference curves
    V_RLo = C_1_opt_RLo ** (1 - CRRA) / (1 - CRRA) + beta * C_2_opt_RLo ** (1 - CRRA) / (
        1 - CRRA
    )  # Get max utility
    C_1_V_RLo = np.linspace(((1 - CRRA) * V_RLo) ** (1 / (1 - CRRA)) + 0.5, C_1_Max, 1000)
    C_2_V_RLo = (((1 - CRRA) * V_RLo - C_1_V_RLo ** (1 - CRRA)) / beta) ** (
        1 / (1 - CRRA)
    )
    plt.plot(C_1_V_RLo, C_2_V_RLo, "b-", label="Indiferrence Curve R Low")

    V_RHi = C_1_opt_RHi ** (1 - CRRA) / (1 - CRRA) + beta * C_2_opt_RHi ** (1 - CRRA) / (
        1 - CRRA
    )  # Get max utility
    C_1_V_RHi = np.linspace(((1 - CRRA) * V_RHi) ** (1 / (1 - CRRA)) + 0.5, C_1_Max, 1000)
    C_2_V_RHi = (((1 - CRRA) * V_RHi - C_1_V_RHi ** (1 - CRRA)) / beta) ** (
        1 / (1 - CRRA)
    )
    plt.plot(C_1_V_RHi, C_2_V_RHi, "b--", label="Indiferrence Curve R High")

    # The substitution effect
    C_1_Subs = (
        V_RHi * (1 - CRRA) / (1 + beta * (RLo * beta) ** ((1 - CRRA) / CRRA))
    ) ** (1 / (1 - CRRA))
    C_2_Subs = C_1_Subs * (RLo * beta) ** (1 / CRRA)

    # The Human wealth effect
    Y_2HW = Y_2 * RLo / RHi
    C_1HW = Y_2HW / (RLo + (RLo) ** (1 / CRRA))
    C_2HW = C_1HW * (RLo * beta) ** (1 / CRRA)

    C_1_bc_HW = np.linspace(C_1_Min, B_1 + Y_1 + Y_2HW / RLo, 10, endpoint=True)
    C_2_bc_HW = (Y_1 + B_1 - C_1_bc_HW) * RLo + Y_2HW
    plt.plot(C_1_bc_HW, C_2_bc_HW, "k:")

    VHW = (C_1HW ** (1 - CRRA)) / (1 - CRRA) + (beta * C_2HW ** (1 - CRRA)) / (1 - CRRA)
    C_1_V_HW = np.linspace(((1 - CRRA) * VHW) ** (1 / (1 - CRRA)) + 0.5, C_1_Max, 1000)
    C_2_V_HW = (((1 - CRRA) * VHW - C_1_V_HW ** (1 - CRRA)) / beta) ** (1 / (1 - CRRA))
    plt.plot(C_1_V_HW, C_2_V_HW, "b:")

    # Plot the points of interest
    plt.plot(C_1_opt_RLo, C_2_opt_RLo, "ro", label="A: Optimal Consumption R Low")
    plt.plot(
        C_1_Subs, C_2_Subs, "go", label="B: Income effect DB \n    Substitution effect BC"
    )
    plt.plot(C_1_opt_RHi, C_2_opt_RHi, "mo", label="C: Optimal Consumption R High")
    plt.plot(C_1HW, C_2HW, "co", label="D: HW effect AD")

    plt.legend()
    plt.show()

    return None
# Define some widgets to control the plot

# Define a slider for the high interest rate
RHi_widget2 = widgets.FloatSlider(
    min=1.0,
    max=4.0,
    step=0.01,
    value=2,
    continuous_update=True,
    readout_format=".2f",
    description="$R High$",
)

# Define a slider for the low interest rate
RLo_widget2 = widgets.FloatSlider(
    min=0.0,
    max=4.0,
    step=0.01,
    value=1.0,
    continuous_update=True,
    readout_format=".2f",
    description="$R Low$",
)

# Define a slider for Y_1
Y_1_widget2 = widgets.FloatSlider(
    min=0.0,
    max=100.0,
    step=0.1,
    value=100.0,
    continuous_update=True,
    readout_format=".1f",
    description="$Y_1$",
)

# Define a slider for Y_2
Y_2_widget2 = widgets.FloatSlider(
    min=0.0,
    max=100.0,
    step=0.1,
    value=100.0,
    continuous_update=True,
    readout_format=".1f",
    description="$Y_2$",
)

# Define a slider for B_1
B_1_widget2 = widgets.FloatSlider(
    min=0.0,
    max=4.0,
    step=0.01,
    value=0.0,
    continuous_update=True,
    readout_format=".1f",
    description="$B_1$",
)

# Define a textbox for C_1 max
c_1_Max_widget2 = widgets.FloatText(
    value=120, step=1.0, description="$C_1$ max", disabled=False
)

# Define a textbox for C_2 max
c_2_Max_widget2 = widgets.FloatText(
    value=120, step=1.0, description="$C_2$ max", disabled=False
)
# Make the widget

interact(
    FisherPlot2,
    Y_1=fixed(0.0),
    Y_2=Y_2_widget2,
    B_1=fixed(0.0),
    RHi=RHi_widget2,
    RLo=RLo_widget2,
    C_1_Max=c_1_Max_widget2,
    C_2_Max=c_2_Max_widget2,
);

Fourth plot: the effects of changes in the coefficient of risk aversion

For this exercise, we assume that no income is received in the second period. The relevant parameter is therefore M1M_1, the total market resources before consumption in period 1.

# Create plotting function
def FisherPlot3(M_1, R, beta, CRRA, C_1_Max, C_2_Max):
    # Basic setup of perfect foresight consumer

    # We first create an instance of the class
    # PerfForesightConsumerType, with its standard parameters.
    PFexample = PerfForesightConsumerType()

    PFexample.cycles = 1  # let the agent live the cycle of periods just once
    PFexample.T_cycle = 1  # One single non-terminal period
    PFexample.PermGroFac = [1.0]  # No income in the second period
    PFexample.LivPrb = [1.0]  # No chance of dying before the second period

    # Set interest rate and bank balances from input.
    PFexample.Rfree = [R]
    PFexample.CRRA = CRRA
    PFexample.DiscFac = beta

    # Solve the model: this generates the optimal consumption function.

    # Try-except blocks "try" to execute the code in the try block. If an
    # error occurs, the except block is executed and the application does
    # not halt
    try:
        PFexample.solve()
    except:
        print("Those parameter values violate a condition required for solution!")
        return

    # Create the figure
    C_1_Min = 0.0
    C_2_Min = 0.0
    plt.figure(figsize=(8, 8))
    plt.xlabel("Period 1 Consumption $C_1$")
    plt.ylabel("Period 2 Consumption $C_2$")
    plt.ylim([C_2_Min, C_2_Max])
    plt.xlim([C_1_Min, C_1_Max])

    # Plot the budget constraint
    C_1_bc = np.linspace(C_1_Min, M_1, 10, endpoint=True)
    C_2_bc = (M_1 - C_1_bc) * R
    plt.plot(C_1_bc, C_2_bc, "k-", label="Budget Constraint")

    # Plot the optimal consumption bundle
    C_1 = PFexample.solution[0].cFunc(M_1)
    C_2 = PFexample.solution[1].cFunc((M_1 - C_1) * R)
    plt.plot(C_1, C_2, "ro", label="Optimal Consumption")

    # Plot the indifference curve
    V = C_1 ** (1 - CRRA) / (1 - CRRA) + beta * C_2 ** (1 - CRRA) / (
        1 - CRRA
    )  # Get max utility
    C_1_V = np.linspace(((1 - CRRA) * V) ** (1 / (1 - CRRA)) + 0.1, C_1_Max, 1000)
    C_2_V = (((1 - CRRA) * V - C_1_V ** (1 - CRRA)) / beta) ** (1 / (1 - CRRA))
    plt.plot(C_1_V, C_2_V, "b-", label="Indiferrence Curve")

    # Add a legend and display the plot
    plt.legend()
    plt.show()

    return None
# We now define the controls that will receive and transmit the
# user's input.
# These are sliders for which the range, step, display, and
# behavior are defined.

# Define a slider for the interest rate
Rfree_widget = widgets.FloatSlider(
    min=1.0,
    max=2.0,
    step=0.001,
    value=1.02,
    continuous_update=True,
    readout_format=".4f",
    description="$R$",
)

# Define a slider for the discount factor
Beta_widget = widgets.FloatSlider(
    min=0.5,
    max=0.9,
    step=0.001,
    value=0.9,
    continuous_update=True,
    readout_format=".4f",
    description="$\beta$",
)

# Define a slider for the interest rate
Beta_widget = widgets.FloatSlider(
    min=0.5,
    max=0.9,
    step=0.001,
    value=0.9,
    continuous_update=True,
    readout_format=".4f",
    description="$\\beta$",
)

# Define a slider for the CRRA
CRRA_widget = widgets.FloatSlider(
    min=0.9,
    max=2.0,
    step=0.1,
    value=2,
    continuous_update=True,
    readout_format=".4f",
    description="$\\rho$",
)

# Define a slider for M_1
M_1_widget = widgets.FloatSlider(
    min=0.1,
    max=10.0,
    step=0.1,
    value=50.0,
    continuous_update=True,
    readout_format="4f",
    description="$M_1$",
)

# Define a textbox for C_1 max
C_1_Max_widget = widgets.FloatText(
    value=20, step=1.0, description="$C_1$ max", disabled=False
)

# Define a textbox for C_2 max
C_2_Max_widget = widgets.FloatText(
    value=20, step=1.0, description="$C_2$ max", disabled=False
)

# Make the widget
interact(
    FisherPlot3,
    M_1=M_1_widget,
    R=Rfree_widget,
    beta=Beta_widget,
    CRRA=CRRA_widget,
    C_1_Max=C_1_Max_widget,
    C_2_Max=C_2_Max_widget,
);