# Install yahoo finance API package
!pip install yfinance --upgrade --no-cache-dir
!pip install PyPortfolioOpt
# Import the necessary packages
import yfinance as yf
import datetime as dt
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pypfopt import risk_models
from pypfopt import expected_returns
from pypfopt.efficient_frontier import EfficientFrontier
# Pick a list of stocks that form your all-weather portfolio
# Draw data for the past five years
#Illustrative, change into yours!
symbols_list = ["AAPL", "AMZN", "GOOG", "BP", "KMI", "BABA", "TCEHY", "BYDDY", "PAAS", "CCJ"]
start = dt.datetime(2017,8,31)
end = dt.datetime(2023,8,31)
data = yf.download(symbols_list, start=start, end=end)
# Keep only the adjusted close in the dataframe
# Note that the date is in the index
price = data["Adj Close"]
# Calculate return using method pct_change
# Find out more about .pct_change with help!
daily_returns = price.pct_change()[1:]
daily_returns.head()
# function that takes portfolio weights and creates a time-series of daily portfolio returns
def portfolio_return_series(daily_returns, weights):
'''
INPUTS
daily returns: dataframe of daily returns. Each ticker column contains the series of daily returns for the ticker
weights: numpy array of the portfolio weight on each ticker (sorted in ascending order)
OUTPUTS
portfolio_daily_returns: the portfolio return series given the weights
'''
# Create portfolio daily returns
portfolio_daily_returns = daily_returns.dot(weights)
# Calculate cumulative returns
# Hint: Use .cumprod()
portfolio_cumulative_returns=(1 + portfolio_daily_returns).cumprod()
return portfolio_daily_returns, portfolio_cumulative_returns
## Install PyPortfolioOpt package
# !pip install PyPortfolioOpt
# Import the packages
from pypfopt import risk_models
from pypfopt import expected_returns
from pypfopt.efficient_frontier import EfficientFrontier
maximum sharpe portfolio
# Calculate expected returns mu
mu = expected_returns.mean_historical_return(price)
# Calculate the covariance matrix S
sigma = risk_models.sample_cov(price)
# Obtain the efficient frontier
ef = EfficientFrontier(mu, sigma)
# Calculate weights for the maximum Sharpe ratio portfolio
raw_weights_maxsharpe = ef.max_sharpe()
cleaned_weights_maxsharpe = ef.clean_weights()
optimal_weights_maxsharpe = np.array(list(cleaned_weights_maxsharpe.values()))
print (optimal_weights_maxsharpe)
# Calculate the daily returns of the maximum Sharpe portfolio
max_sharpe_portfolio_daily_returns = (daily_returns * optimal_weights_maxsharpe).sum(axis=1)
# Create a DataFrame to store the daily returns
max_sharpe_portfolio_returns_df = pd.DataFrame(data={'Max Sharpe Portfolio Returns': max_sharpe_portfolio_daily_returns})
# Print the head of the Max Sharpe portfolio returns DataFrame
print(max_sharpe_portfolio_returns_df.head())
!pip install statsmodels
import statsmodels.api as sm
pip install openpyxl
df=pd.read_excel('F-F_Research_Data_5_Factors_2x3_daily.xlsm',skiprows=3)
factors_df = df.iloc[:, 0:7]
factors_df=factors_df.rename(columns={factors_df.columns[0]: 'Date'})
# Display the DataFrame with the 5 factors.
print(factors_df)
# Convert the "Date" column in factors_df to a datetime data type
factors_df["Date"] = pd.to_datetime(factors_df["Date"], format='%Y%m%d')
# Assuming you have another DataFrame called 'max_sharpe_portfolio_returns_df' with a "Date" column.
# Merge the two DataFrames on the "Date" column
merged_df = max_sharpe_portfolio_returns_df.merge(factors_df, on="Date")
# Display the merged DataFrame
print(merged_df)
examine visually correlation between portfolio and factor returns
import seaborn as sns
import matplotlib.pyplot as plt
# Calculate the correlation matrix
correlation_matrix = merged_df.corr()
# Create a heatmap
plt.figure(figsize=(10, 6))
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', linewidths=0.5)
plt.title('Correlation Heatmap between Portfolio and Factor Returns')
plt.show()
Regress the portfolio return on each factor and assess the portfolio's sensitivity to each factor.
import pandas as pd
import statsmodels.api as sm
# Assuming you have a DataFrame named 'merged_df' with portfolio and factor returns.
# Create a variable for the portfolio return and add a constant for the intercept.
portfolio_return = merged_df['Max Sharpe Portfolio Returns']
merged_df['Intercept'] = 1
# Create a list of factor columns for regression.
factor_columns = ['Mkt-RF','SMB', 'HML', 'RMW', 'CMA', 'RF']
# Perform linear regression for each factor and assess sensitivity.
for factor in factor_columns:
X = merged_df[['Intercept', factor]]
model = sm.OLS(portfolio_return, X).fit()
print(f"Factor: {factor}")
print(model.summary())
print("\n")
how do you test whether the intercept (i.e., alpha) is significantly different from the risk-free rate for a single-factor regression
# Create a variable for the risk-free rate
risk_free_rate = merged_df['RF']
# Perform a single-factor regression.
X = merged_df[['Intercept', 'RF']]
model = sm.OLS(portfolio_return, X).fit()
from scipy import stats
# Perform a t-test to compare alpha (Intercept) with the risk-free rate.
# The t-test tests if the alpha is significantly different from the risk-free rate.
t_statistic = (model.params['Intercept'] - risk_free_rate.mean()) / model.bse['Intercept']
p_value = 2 * (1 - stats.t.cdf(abs(t_statistic), df=model.df_resid))
# Print the results.
print(f"Alpha (Intercept): {model.params['Intercept']:.4f}")
print(f"Risk-Free Rate: {risk_free_rate.mean():.4f}")
print(f"t-statistic: {t_statistic:.4f}")
print(f"P-value: {p_value:.4f}")
# Check if the p-value is less than a significance level (e.g., 0.05) to determine significance.
if p_value < 0.05:
print("Alpha is significantly different from the Risk-Free Rate.")
else:
print("Alpha is not significantly different from the Risk-Free Rate.")
4. Regress the portfolio return on all factors and assess the portfolio's sensitivity to factors. and how do you test whether the intercept (i.e., alpha) is significantly different from the risk-free rate for a multi-factor regression?
# Perform multiple linear regression to assess sensitivity to all factors.
X = merged_df[['Intercept'] + factor_columns]
model = sm.OLS(portfolio_return, X).fit()
# Print the regression summary to assess sensitivity.
print(model.summary())
# Perform a multiple linear regression to assess sensitivity to all factors.
X = merged_df[['Intercept'] + factor_columns]
model = sm.OLS(portfolio_return, X).fit()
# Perform a t-test to compare alpha (Intercept) with the risk-free rate.
# The t-test tests if the alpha is significantly different from the risk-free rate.
t_statistic = (model.params['Intercept'] - risk_free_rate.mean()) / model.bse['Intercept']
p_value = 2 * (1 - stats.t.cdf(abs(t_statistic), df=model.df_resid))
# Print the results.
print(f"Alpha (Intercept): {model.params['Intercept']:.4f}")
print(f"Risk-Free Rate: {risk_free_rate.mean():.4f}")
print(f"t-statistic: {t_statistic:.4f}")
print(f"P-value: {p_value:.4f}")
# Check if the p-value is less than a significance level (e.g., 0.05) to determine significance.
if p_value < 0.05:
print("Alpha is significantly different from the Risk-Free Rate.")
else:
print("Alpha is not significantly different from the Risk-Free Rate.")