montecarlo simulation
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import minimize
file_path = '/Users//Downloads/F-F_Research_Data_Factors-2.xlsx'
df = pd.read_excel(file_path)
df['Date'] = pd.to_datetime(df['Date'], format='%m/%Y')
df_filtered = df[df['Date'] >= (df['Date'].max() - pd.DateOffset(years=30))]
factors = ['Mkt-RF', 'SMB', 'HML', 'Mom', 'LT_Rev']
returns = df_filtered[factors]
returns_normalized = returns / 100
num_portfolios = 30000
all_weights = np.zeros((num_portfolios, len(factors)))
ret_arr = np.zeros(num_portfolios)
vol_arr = np.zeros(num_portfolios)
np.random.seed(42) # For reproducibility
for i in range(num_portfolios):
weights = np.random.random(len(factors))
weights /= np.sum(weights)
all_weights[i, :] = weights
ret_arr[i] = np.sum((returns_normalized.mean() * weights * 12)) # Annualizing returns
vol_arr[i] = np.sqrt(np.dot(weights.T, np.dot(returns_normalized.cov() * 12, weights))) # Annualizing standard deviation
min_vol_idx = np.argmin(vol_arr)
min_vol_weights = all_weights[min_vol_idx]
min_vol_portfolio_return = ret_arr[min_vol_idx]
min_vol_portfolio_volatility = vol_arr[min_vol_idx]
plt.figure(figsize=(12, 8))
plt.scatter(vol_arr, ret_arr, c=ret_arr/vol_arr, marker='o')
plt.colorbar(label='Sharpe Ratio')
plt.xlabel('Expected Volatility')
plt.ylabel('Expected Return')
plt.scatter(min_vol_portfolio_volatility, min_vol_portfolio_return, c='red', s=50, marker='*', label='Minimum Variance Portfolio')
plt.legend()
plt.title('Monte Carlo Simulation of Portfolios')
plt.show()
min_vol_portfolio_details = {
'Return': min_vol_portfolio_return,
'Volatility': min_vol_portfolio_volatility,
'Weights': dict(zip(factors, min_vol_weights))
}
print(min_vol_portfolio_details)
risk_free_rate = 0 # Assuming a risk-free rate of 0 for simplicity
sharpe_ratios = ret_arr / vol_arr # Sharpe Ratio = Return / Volatility
max_sharpe_idx = np.argmax(sharpe_ratios)
max_sharpe_portfolio = {
'Return': ret_arr[max_sharpe_idx],
'Volatility': vol_arr[max_sharpe_idx],
'Sharpe Ratio': sharpe_ratios[max_sharpe_idx],
'Weights': all_weights[max_sharpe_idx]
}
max_ret_idx = np.argmax(ret_arr)
max_ret_portfolio = {
'Return': ret_arr[max_ret_idx],
'Volatility': vol_arr[max_ret_idx],
'Weights': all_weights[max_ret_idx]
}
from scipy.stats import norm
z_score_1pc = norm.ppf(1 - 0.01)
var_1pc = -z_score_1pc * vol_arr # Negative sign because VaR is typically expressed as a positive number
min_var_idx = np.argmin(var_1pc)
min_var_portfolio = {
'Return': ret_arr[min_var_idx],
'Volatility': vol_arr[min_var_idx],
'VaR 1%': var_1pc[min_var_idx],
'Weights': all_weights[min_var_idx]
}