Monte Carlo Simulation of Investment Portfolio Performance:¶

Author: Arun Kumar Pandey

Descriptive Statistics, Hypothesis Testing, and Variance Reduction Techniques

Example¶

  1. Objective: To estimate the potential future value of the investment portfolio (for example: stock+Bonds+Real states) and assess the associated risks using Monte Carlo simulation.

  2. Steps:

    • Define the investment portfolio:

      • Identify the assets in the portfolio.
      • Assign weights to each asset, representing the allocation or proportion of the portfolio invested in that asset.
      • Determine the historical returns and standard deviations of the assets.
    • Set simulation parameters:

      • Specify the number of simulations to run.
      • Define the time horizon for the simulation (e.g., number of years).
    • Perform Monte Carlo simulation:

      • Generate random samples for each asset's future returns based on their historical return distributions.
      • Calculate the future portfolio values for each simulation by combining the weighted returns of the assets over the time horizon.
    • Analyze the simulation results:

      • Calculate descriptive statistics such as mean, standard deviation, minimum, and maximum of the simulated portfolio values.
      • Construct confidence intervals to estimate the range of potential future portfolio values with a certain level of confidence.
      • Visualize the distribution of portfolio values using histograms or density plots.
      • Assess the portfolio's risk metrics, such as Value-at-Risk (VaR) or Conditional Value-at-Risk (CVaR), to measure the downside potential.
In [ ]:
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import scipy.stats as stats
In [ ]:
# Define the investment portfolio
assets = ['Stocks', 'Bonds', 'Real Estate']
weights = np.array([0.6, 0.3, 0.1])  # Asset allocation weights
returns = np.array([0.08, 0.04, 0.06])  # Historical returns
volatility = np.array([0.15, 0.08, 0.12])  # Standard deviations
In [ ]:
# Set simulation parameters
num_simulations = 1000
num_years = 10

# Perform Monte Carlo simulation
portfolio_values = np.zeros((num_years + 1, num_simulations))
portfolio_values[0] = 100000  # Initial portfolio value

for year in range(1, num_years + 1):
    for sim in range(num_simulations):
        random_returns = np.random.normal(returns, volatility)
        portfolio_value = portfolio_values[year - 1, sim] * np.dot(weights, 1 + random_returns)
        portfolio_values[year, sim] = portfolio_value
In [ ]:
# Analyze the simulation results
df_portfolio_values = pd.DataFrame(portfolio_values.T, columns=['Year ' + str(year) for year in range(num_years + 1)])
In [ ]:
df_portfolio_values.head()
Out[ ]:
Year 0 Year 1 Year 2 Year 3 Year 4 Year 5 Year 6 Year 7 Year 8 Year 9 Year 10
0 100000.0 109003.197885 113247.862822 131570.723783 123312.353384 146992.473321 142640.693484 131616.472718 135066.768355 141094.075161 162711.998639
1 100000.0 102981.339256 112062.865917 106110.447909 87606.608088 83313.313314 110015.367130 126320.294600 137647.045359 150210.163722 159066.457817
2 100000.0 105320.850973 106086.800437 108777.249393 116215.705323 119007.437712 139941.274079 167588.305769 152591.023526 160854.736596 176054.287396
3 100000.0 112835.211137 112555.005734 117231.177661 115043.166375 127394.400947 138639.717197 145530.524333 153497.546718 162871.663486 147985.410838
4 100000.0 99845.504383 111147.367423 137213.938505 141921.315183 166063.946705 170760.634883 169279.835359 172665.855638 196521.784696 212436.163506
In [ ]:
# Calculate descriptive statistics
statistics = df_portfolio_values.describe().T[['mean', 'std', 'min', 'max']]

# Print results
print("Descriptive Statistics:")
print(statistics)
Descriptive Statistics:
                  mean           std            min            max
Year 0   100000.000000      0.000000  100000.000000  100000.000000
Year 1   106750.715046   9427.376074   78859.567361  140016.548988
Year 2   114106.796433  14193.768631   74544.077801  176155.651830
Year 3   121441.052869  18757.112245   68808.813060  223375.584650
Year 4   129216.759328  22584.115990   72413.608004  238247.967635
Year 5   138049.365765  27326.931629   63843.233943  241799.936974
Year 6   146629.367755  31247.417576   64483.500162  280971.351222
Year 7   156569.820080  36011.934191   68640.823330  311978.989192
Year 8   166938.980230  41255.124863   77924.958400  323178.192312
Year 9   178311.842944  46033.540652   81556.458128  380367.023358
Year 10  189752.484011  50902.038938   72418.750290  408443.041096
In [ ]:
# Calculate confidence intervals
confidence_level = 0.95
confidence_intervals = df_portfolio_values.quantile([(1 - confidence_level) / 2, 1 - (1 - confidence_level) / 2])

print("\nConfidence Intervals ({}% confidence level):".format(int(confidence_level * 100)))
confidence_intervals
Confidence Intervals (95% confidence level):
Out[ ]:
Year 0 Year 1 Year 2 Year 3 Year 4 Year 5 Year 6 Year 7 Year 8 Year 9 Year 10
0.025 100000.0 88198.786807 87429.170263 86309.697386 89342.298971 91039.199332 92057.071511 96414.814752 99899.123523 103061.988674 105815.787605
0.975 100000.0 125844.947228 141683.361824 160447.557544 176342.215568 202015.418457 212947.609183 236856.910089 256321.180752 278642.833325 300125.417856
In [ ]:
# Calculate risk metrics
var_95 = df_portfolio_values['Year 10'].quantile(0.05)
cvar_95 = df_portfolio_values['Year 10'][df_portfolio_values['Year 10'] <= var_95].mean()
In [ ]:
print("\nRisk Metrics:")
print("Value-at-Risk (VaR) at 95% confidence level:", var_95)
print("Conditional Value-at-Risk (CVaR) at 95% confidence level:", cvar_95)
Risk Metrics:
Value-at-Risk (VaR) at 95% confidence level: 116970.35604380732
Conditional Value-at-Risk (CVaR) at 95% confidence level: 103471.82263857182
In [ ]:
# Plotting a histogram of the portfolio values using seaborn
plt.figure(figsize=(12, 8), dpi=200)
sns.histplot(df_portfolio_values['Year 10'], bins=30, kde=True, element='step')
plt.xlabel('Portfolio Value')
plt.ylabel('Density')
plt.title('Histogram of Portfolio Values after 10 Years')

# Calculate risk metrics
var_95 = df_portfolio_values['Year 10'].quantile(0.05)
cvar_95 = df_portfolio_values['Year 10'][df_portfolio_values['Year 10'] <= var_95].mean()

# Add vertical lines to mark Value-at-Risk (VaR) and Conditional Value-at-Risk (CVaR)
plt.axvline(x=var_95, color='red', linestyle='--', label='VaR (95% confidence)')
plt.axvline(x=cvar_95, color='orange', linestyle='--', label='CVaR (95% confidence)')

plt.legend()
plt.show()
No description has been provided for this image
In [ ]:
plt.figure(figsize=(12, 8), dpi=200)
for sim in range(num_simulations):
    plt.plot(range(num_years + 1), df_portfolio_values.iloc[sim, :], linewidth=1)

plt.xlabel('Year')
plt.ylabel('Portfolio Value')
plt.title('Portfolio Values Over Time (All Simulations)')
plt.show()
No description has been provided for this image

Conclusion¶

  • In this example, we consider an investment portfolio consisting of stocks, bonds, and real estate. We specify the weights, historical returns, and standard deviations for each asset. We set the simulation parameters to run 1000 simulations over a 10-year time horizon.

  • The Monte Carlo simulation generates random samples for each asset's future returns using the normal distribution with the specified mean returns and standard deviations. The future portfolio values are calculated by multiplying the previous portfolio value by the weighted returns for each simulation.

  • The simulation results are stored in a dataframe df_portfolio_values, which contains the portfolio values for each simulation and year. We calculate descriptive statistics, including mean, standard deviation, minimum, and maximum values. We construct confidence intervals to estimate the range of potential future portfolio values.

  • We visualize the distribution of portfolio values after 10 years using a histogram. Additionally, we calculate risk metrics such as Value-at-Risk (VaR) and Conditional Value-at-Risk (CVaR) at the 95% confidence level.

Note: Please note that this example assumes a simplified scenario and should not be considered as financial advice. It's crucial to conduct further research and consult with a financial professional before making any investment decisions.

Reference¶

  • https://github.com/arunsinp/MonteCarlo-simulation/tree/main