# 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()
Run to view results
# 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
Run to view results
## 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
Run to view results
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)
Run to view results
# 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())
Run to view results
!pip install statsmodels
import statsmodels.api as sm
Run to view results
pip install openpyxl
Run to view results
df=pd.read_excel('F-F_Research_Data_5_Factors_2x3_daily.xlsm',skiprows=3)
Run to view results
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)
Run to view results
# 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)
Run to view results
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()
Run to view results
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")
Run to view results
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.")
Run to view results
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())
Run to view results
# 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.")
Run to view results