For the FAANG stocks (Meta, Amazon, Apple, Netflix and Google (now Alphabet)) for September 2015 to August 2023 from Yahoo Finance, please do the following:
Estimate CAPM’s alpha and beta for each of the FAANG stocks.
Explain whether each stock is defensive or cyclical.
Compare alpha of each stock to what you would expect according to the CAPM, and describe your conclusion from this comparison.
Finally, estimate the Fama-French-3-factor model. Look at the alphas from these models, and explain any differences between these and the CAPM alphas {r setup, include=FALSE}
# Clear the workspace
rm(list = ls()) # Clear environment
gc() # Clear unused memory
## used (Mb) gc trigger (Mb) limit (Mb) max used (Mb)
## Ncells 528523 28.3 1175360 62.8 NA 669411 35.8
## Vcells 979678 7.5 8388608 64.0 16384 1851673 14.2
cat("\f") # Clear the console
The chunk below prepares the needed libraries for this assignment, including tidyverse, ggplot2, lubridate, quantmode, tidyr, dplyr, broom, tibbletime and fpp2. Using a loop, the packages will be installed if not already installed.
The next step is to load the file into the R environment and
generates a temporary file and assign it to the variable
temp_file. This temporary file will be
used to store the downloaded ZIP file.
# Load file
ff_url <- "https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/F-F_Research_Data_Factors_CSV.zip"
# Generate temporary file to store zip file
temp_file <- tempfile()
# Downloads zip file from the URL in ff_url and saves it to temp file
download.file(ff_url, temp_file)
# Unzips the downloaded zip file and assign to var FF
FF <- unzip(temp_file)
# Read file, skipping first 3 lines and it sets the column types for the columns.
# 1st column as integer and other columns as double floating-point numbers
# 1st column renamed as date and parsing using the "Y-m" format
FF <- read_csv(FF, skip = 3, col_types = cols(...1 = col_integer(),`Mkt-RF` = col_double(),
SMB = col_double(),
HML = col_double(),
RF = col_double())) %>% rename(date = ...1) %>% subset(date>100000) %>% mutate(date = ymd(parse_date_time(date, "%Y%m"))) %>% na.omit(date)
## New names:
## • `` -> `...1`
## Warning: One or more parsing issues, call `problems()` on your data frame for details,
## e.g.:
## dat <- vroom(...)
## problems(dat)
For this exercise, we will be using the FAANG stocks, which are the stocks of the five prominent American technology companies:
# Pulling stock data straight from Yahoo Finance
symbols <- c("META","AMZN","AAPL","NFLX","GOOG")
# Retrieve historical stock price data for the symbols
prices <-
getSymbols(symbols, src = 'yahoo',
from = "2015-09-01", to = "2023-08-31", # use data from sept 2015-aug 2023
auto.assign = TRUE,
warnings = FALSE) %>%
map(~Ad(get(.))) %>%
reduce(merge) %>%
`colnames<-`(symbols)
The next code chunk processes the previously obtained stock price
data to calculate monthly returns for each stock and stores the
resulting returns in a data frame called
returns_df.
returns <-
prices %>%
# Aggregate the daily stock price data into monthly intervals
to.monthly(indexAt = "firstof", OHLC = FALSE) %>%
# convert the index to a date
data.frame(date = index(.)) %>%
# now remove the index because it got converted to row names
remove_rownames() %>%
# convert from wide to long creating new variable asset that will assign ticker, conversion needed to create returns using lagged variables
gather(asset,prices,-date) %>%
# compute returns using the usual way
group_by(asset) %>%
mutate(returns=(prices/lag(prices))-1) %>%
# remove prices
select(-prices) %>%
# convert back to wide by asset
spread(asset, returns) %>%
# remove missings
na.omit()
# Create dataframe of returns
returns_df <- as.data.frame(returns)
Before conducting the regression analysis, we can visualize the stock returns data in different ways.
Firstly, we observe the returns of each of the FAANG stocks over time from September 2015 to August 2023. We can clearly see that Google’s returns are a lot more stable over time than the others. This could maybe be attributed to the fact that Google is a diversified technology company, meaning that it has multiple revenue streams which provides diversification that helps mitigate the impact of poor performance in one stream.
# Reshape from wide to long combining ind asset returns into single column while keeping data var
asset_returns_long <-
returns %>%
gather(asset, returns, -date)
# Scatterplot of returns over time
asset_returns_long %>%
ggplot(aes(x = date, y = returns)) +
geom_point(aes(colour=factor(asset))) +
facet_wrap(~asset) # create separate panels for each asset
Next, we can observe histograms of the returns for each stock in a single graph. In this visualization, we can now more clearly observe that both Netflix (NFLX) and Facebook (META)’s stock returns are a lot more spread out then that of Apple (AAPL) and Google (GOOG).
# Histograms of returns
asset_returns_long %>%
# pipe to ggplot, aes is a function for aestethics of a plot, returns on x axis, fill means different colors for different assets, alpha describes the intensity of colors, binwidth is selfexplanatory
ggplot(aes(x = returns, fill = asset)) +
geom_histogram(alpha = 1, binwidth = .01)
Finally, another graph we can use is the density plot. Here, with returns on the x-axis, we can observe the distribution of data and how likely different values are within that distribution. Simply put, the density function tells us how the probability of observing a specific stock return changes throughout the range of possible values. Based on the density functions for each asset, we can again see how Netflix and Facebook’s stock returns are a lot more spread out.
Possible reasons for Netflix’s stock returns exhibiting higher volatility compared to the other stocks may include the fact that Netflix operates in highly competitive and rapidly evolving industry, or due to changes in subscriber growth. Another reason could be due to market trends - that investors now prefer growth stocks, especially during the Covid-19 pandemic, when investments in vaccine technology shot up.
# Densities
asset_returns_long %>%
ggplot(aes(x = returns, colour = asset, fill = asset)) +
stat_density(geom = "line", alpha = 1) +
xlab("monthly returns") +
ylab("distribution")
Now, in order to build the Fama-French and CAPM models, we need to get the excess returns of each stock. To do so, we must convert the returns into excess returns by subtracting the risk-free rate.
# merging asset returns with factors, and converting returns to excess returns
ff_assets <-
returns %>%
left_join(FF, by = "date") %>%
mutate(MKT_RF = `Mkt-RF`/100,
SMB = SMB/100,
HML = HML/100,
RF = RF/100,
META = META-RF, # getting excess return by removing rf
AMZN = AMZN-RF,
AAPL = AAPL-RF,
NFLX = NFLX-RF,
GOOG = GOOG-RF) %>%
select(-RF,-`Mkt-RF`) %>%
na.omit()
To estimate the expected returns for each stock, the CAPM and Fama-French regression equations will look like the following:
Capital Asset Pricing Model (CAPM) is
\[ r_{it} - r_{ft} = \alpha_i + \beta_M [r_{Mt} - r_{ft}] + e_{it} \]
Fama-French Three-Factor Model is
\[ r_{it} - r_{ft} = \alpha_i + \beta_M[r_{Mt} - r_{ft}] + \beta_{HML} r_{HML,t} + \beta_{SMB} r_{SMB,t} + e_{it} \]
Based on the CAPM model that estimates the expected return of Facebook’s stock, beta is 1.07 meaning that the stock is cyclical because it is above 1, and this is statistically significant at the 0.001 level. This also means that when excess market returns increase by 1 percentage point, then META's beta increases by 1.07 percentage points. Moreover, alpha is estimated to be 0.0064; however, it is not statistically significant than 0, meaning that there is no evidence of abnormal returns beyond what is explained by the market risk premium.
# CAPM model
capm_meta <- lm(META ~ MKT_RF,
data = ff_assets
)
summary(capm_meta)
##
## Call:
## lm(formula = META ~ MKT_RF, data = ff_assets)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.40601 -0.03846 0.00281 0.03946 0.20912
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.006359 0.009424 0.675 0.502
## MKT_RF 1.072373 0.193126 5.553 2.7e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.08912 on 92 degrees of freedom
## Multiple R-squared: 0.251, Adjusted R-squared: 0.2429
## F-statistic: 30.83 on 1 and 92 DF, p-value: 2.704e-07
When including the size and value factors to the previous CAPM model, we get the Fama-French model. Now, beta has increased to 1.19, so it is even more volatile than the market, which tells us that the stock is still cyclical, and this is still statistically significant at the 0.001 level. Alpha, got a bit smaller, however, it is still not statistically different than 0, so this indicates that the portfolio has achieved a return that is in line with what would be expected given its level of risk.
# FAMA-FRENCH model
ff3_meta <- lm(META ~ MKT_RF + SMB + HML,
data = ff_assets
)
summary(ff3_meta)
##
## Call:
## lm(formula = META ~ MKT_RF + SMB + HML, data = ff_assets)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.36994 -0.03803 0.00069 0.03696 0.20050
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.004147 0.009091 0.456 0.6494
## MKT_RF 1.191292 0.194275 6.132 2.27e-08 ***
## SMB -0.624682 0.343997 -1.816 0.0727 .
## HML -0.534241 0.219754 -2.431 0.0170 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.08567 on 90 degrees of freedom
## Multiple R-squared: 0.3229, Adjusted R-squared: 0.3003
## F-statistic: 14.31 on 3 and 90 DF, p-value: 1.062e-07
These scatter plots are useful for visually comparing how well the two models (CAPM and the three-factor Fama-French model) predict the actual returns of the “META” stock. The reference line in both plots represents the line of perfect prediction; points above the line indicate overprediction, while points below the line indicate underprediction. The different colors (red and blue) distinguish between the two models for easy comparison.
The first scatter plot shows the actual realized returns on the x-axis and the predicted returns from the FF3 model with red points. Additionally, the black points plot the actual realized returns on the x-axis and the predicted returns from the CAPM model on the y-axis.
## Plotting realized returns vs predicted from the CAPM and the 3-factor model ##
# Create data frame that includes the actual realized returns, and predicted returns of CAPM and FF3
meta <- data.frame(ff_assets$META, predict(ff3_meta), predict(capm_meta))
# Scatter plot of actual realized returns on x-axis, and predicted returns from FF3 and CAPM
plot1 <- ggplot(meta) + geom_point(aes(x = ff_assets$META, y = predict(ff3_meta)),color="red") + geom_point(aes(x = ff_assets$META, y = predict(capm_meta))) + geom_abline(intercept = 0) +
labs(
x = "Realized Returns",
y = "Predicted Returns",
title = "Scatterplot of Realized vs. Predicted Returns (Fama-French vs. CAPM)"
)
plot1
The next scatter plot shows the predicted returns from the CAPM model on the x-axis and the predicted returns from the three-factor model on the y-axis.
# Scatter plot of predicted returns from CAPM on x-axis, and predicted returns from FF3 on y-axis
plot2 <- ggplot(meta) + geom_point(aes(x = predict(capm_meta), y = predict(ff3_meta)),color="red") + geom_abline(intercept = 0) +
labs(
x = "Predicted Returns (CAPM)",
y = "Predicted Returns (Fama-French)",
title = "Scatterplot of Predicted Returns (CAPM vs. Fama-French)"
)
plot2
The CAPM model for the expected return of Amazon’s stock estimates beta to be 1.29, meaning that the stock is cyclical, and this is statistically significant at the 0.001 level. This also means that when excess market returns increase by 1 percentage point, then AMZN's beta increases by 1.29 percentage points. The alpha on the other hand is very close to 0, however, it is not statistically different than 0.
# CAPM model
capm_amazon <- lm(AMZN ~ MKT_RF,
data=ff_assets
)
summary(capm_amazon)
##
## Call:
## lm(formula = AMZN ~ MKT_RF, data = ff_assets)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.20373 -0.03869 -0.01157 0.04884 0.19929
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.007042 0.007386 0.953 0.343
## MKT_RF 1.289108 0.151370 8.516 3.01e-13 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.06985 on 92 degrees of freedom
## Multiple R-squared: 0.4408, Adjusted R-squared: 0.4347
## F-statistic: 72.53 on 1 and 92 DF, p-value: 3.009e-13
In the Fama-French model, beta has increased to 1.34, so it is even more volatile than the market, which tells us that the stock is still cyclical, and this is still statistically significant at the 0.001 level. Alpha, got a bit smaller, however, it is still not statistically different than 0, so this indicates that the portfolio has achieved a return that is in line with what would be expected given its level of risk.
# FAMA-FRENCH model
ff3_amazon <- lm(AMZN ~ MKT_RF + SMB + HML,
data=ff_assets
)
summary(ff3_amazon)
##
## Call:
## lm(formula = AMZN ~ MKT_RF + SMB + HML, data = ff_assets)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.135203 -0.037154 -0.002174 0.038590 0.143540
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.004951 0.006242 0.793 0.430
## MKT_RF 1.338371 0.133392 10.033 2.44e-16 ***
## SMB -0.135260 0.236194 -0.573 0.568
## HML -0.943161 0.150887 -6.251 1.34e-08 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.05882 on 90 degrees of freedom
## Multiple R-squared: 0.6121, Adjusted R-squared: 0.5991
## F-statistic: 47.33 on 3 and 90 DF, p-value: < 2.2e-16
# plotting realized returns vs predicted from the CAPM and the 3-factor model
amazon <- data.frame(ff_assets$AMZN, predict(ff3_amazon), predict(capm_amazon))
# Scatter plot of actual realized returns on x-axis, and predicted returns from FF3 and CAPM
ggplot(amazon) + geom_point(aes(x = ff_assets$AMZN, y = predict(ff3_amazon)),color="red") + geom_point(aes(x = ff_assets$AMZN, y = predict(capm_amazon))) + geom_abline(intercept = 0) +
labs(
x = "Realized Returns",
y = "Predicted Returns",
title = "Scatterplot of Realized vs. Predicted Returns (Fama-French vs. CAPM)"
)
# Scatter plot of predicted returns from CAPM on x-axis, and predicted returns from FF3 on y-axis
ggplot(amazon) + geom_point(aes(x = predict(capm_amazon), y = predict(ff3_amazon)),color="red") + geom_abline(intercept = 0) +
labs(
x = "Predicted Returns (CAPM)",
y = "Predicted Returns (Fama-French)",
title = "Scatterplot of Predicted Returns (CAPM vs. Fama-French)"
)
The CAPM model for the expected return of Apple’s stock estimates beta to be 1.21, meaning that the stock is cyclical, and this is statistically significant at the 0.001 level. This also means that when excess market returns increase by 1 percentage point, then AAPL's beta increases by 1.21 percentage points. The alpha on the other hand is again very close to 0, at 0.0116. It is statistically significant than 0 at the 0.1 level, meaning that the portfolio has generated returns that are 0.0116% higher than what would be expected given its level of risk and the performance of the benchmark.
# CAPM model
capm_apple <- lm(AAPL ~ MKT_RF,
data=ff_assets
)
summary(capm_apple)
##
## Call:
## lm(formula = AAPL ~ MKT_RF, data = ff_assets)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.215090 -0.033014 0.001281 0.042379 0.145522
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.011612 0.006556 1.771 0.0798 .
## MKT_RF 1.211870 0.134355 9.020 2.64e-14 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.062 on 92 degrees of freedom
## Multiple R-squared: 0.4693, Adjusted R-squared: 0.4635
## F-statistic: 81.36 on 1 and 92 DF, p-value: 2.635e-14
In the Fama-French model, beta has increased to 1.29, so it is even more volatile than the market, which tells us that the stock is still cyclical, and this is still statistically significant at the 0.001 level. Alpha, got a bit smaller, however, it is now not statistically different than 0, so this indicates that the portfolio has achieved a return that is in line with what would be expected given its level of risk.
# FAMA-FRENCH model
ff3_apple <- lm(AAPL ~ MKT_RF + SMB + HML,
data=ff_assets
)
summary(ff3_apple)
##
## Call:
## lm(formula = AAPL ~ MKT_RF + SMB + HML, data = ff_assets)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.215282 -0.029412 -0.005535 0.037083 0.126673
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.009871 0.006097 1.619 0.10896
## MKT_RF 1.285499 0.130303 9.865 5.44e-16 ***
## SMB -0.347740 0.230723 -1.507 0.13527
## HML -0.558904 0.147392 -3.792 0.00027 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.05746 on 90 degrees of freedom
## Multiple R-squared: 0.5541, Adjusted R-squared: 0.5392
## F-statistic: 37.27 on 3 and 90 DF, p-value: 9.446e-16
# plotting realized returns vs predicted from the CAPM and the 3-factor model
apple <- data.frame(ff_assets$AAPL, predict(ff3_apple), predict(capm_apple))
# Scatter plot of actual realized returns on x-axis, and predicted returns from FF3 and CAPM
ggplot(apple) + geom_point(aes(x = ff_assets$AAPL, y = predict(ff3_apple)),color="red") + geom_point(aes(x = ff_assets$AAPL, y = predict(capm_apple))) + geom_abline(intercept = 0) +
labs(
x = "Realized Returns",
y = "Predicted Returns",
title = "Scatterplot of Realized vs. Predicted Returns (Fama-French vs. CAPM)"
)
# Scatter plot of predicted returns from CAPM on x-axis, and predicted returns from FF3 on y-axis
ggplot(apple) + geom_point(aes(x = predict(capm_apple), y = predict(ff3_apple)),color="red") + geom_abline(intercept = 0) +
labs(
x = "Predicted Returns (CAPM)",
y = "Predicted Returns (Fama-French)",
title = "Scatterplot of Predicted Returns (CAPM vs. Fama-French)"
)
The CAPM model for the expected return of Netflix’s stock estimates beta to be 1.28, meaning that the stock is cyclical, and this is statistically significant at the 0.001 level. This also means that when excess market returns increase by 1 percentage point, then NFLX's beta increases by 1.28 percentage points. The alpha on the other hand is again very close to 0, it is not statistically different than 0, so this indicates that the portfolio has achieved a return that is in line with what would be expected given its level of risk.
# CAPM model
capm_netflix <- lm(NFLX ~ MKT_RF,
data=ff_assets
)
summary(capm_netflix)
##
## Call:
## lm(formula = NFLX ~ MKT_RF, data = ff_assets)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.37892 -0.06105 -0.00205 0.04483 0.32697
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.008433 0.011073 0.762 0.448
## MKT_RF 1.283669 0.226931 5.657 1.73e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1047 on 92 degrees of freedom
## Multiple R-squared: 0.2581, Adjusted R-squared: 0.25
## F-statistic: 32 on 1 and 92 DF, p-value: 1.729e-07
In the Fama-French model, beta has decreased to 1.26, so it is a little less volatile than the market, which tells us that the stock is still cyclical, and this is still statistically significant at the 0.001 level. Alpha, got a bit smaller, however, it is now not statistically different than 0, so this indicates that the portfolio has achieved a return that is in line with what would be expected given its level of risk.
# FAMA-FRENCH model
ff3_netflix <- lm(NFLX ~ MKT_RF + SMB + HML,
data=ff_assets
)
summary(ff3_netflix)
##
## Call:
## lm(formula = NFLX ~ MKT_RF + SMB + HML, data = ff_assets)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.31844 -0.06144 -0.00205 0.04618 0.33753
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.007239 0.010450 0.693 0.490271
## MKT_RF 1.255356 0.223311 5.622 2.1e-07 ***
## SMB 0.329604 0.395412 0.834 0.406729
## HML -0.929895 0.252599 -3.681 0.000395 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.09847 on 90 degrees of freedom
## Multiple R-squared: 0.3581, Adjusted R-squared: 0.3367
## F-statistic: 16.74 on 3 and 90 DF, p-value: 1.006e-08
# plotting realized returns vs predicted from the CAPM and the 3-factor model
netflix <- data.frame(ff_assets$NFLX, predict(ff3_netflix), predict(capm_netflix))
# Scatter plot of actual realized returns on x-axis, and predicted returns from FF3 and CAPM
ggplot(netflix) + geom_point(aes(x = ff_assets$NFLX, y = predict(ff3_netflix)),color="red") + geom_point(aes(x = ff_assets$NFLX, y = predict(capm_netflix))) + geom_abline(intercept = 0) +
labs(
x = "Realized Returns",
y = "Predicted Returns",
title = "Scatterplot of Realized vs. Predicted Returns (Fama-French vs. CAPM)"
)
# Scatter plot of predicted returns from CAPM on x-axis, and predicted returns from FF3 on y-axis
ggplot(netflix) + geom_point(aes(x = predict(capm_netflix), y = predict(ff3_netflix)),color="red") + geom_abline(intercept = 0) +
labs(
x = "Predicted Returns (CAPM)",
y = "Predicted Returns (Fama-French)",
title = "Scatterplot of Predicted Returns (CAPM vs. Fama-French)"
)
The CAPM model for the expected return of Google's stock estimates beta to be 1.06, meaning that the stock is a little cyclical, and this is statistically significant at the 0.001 level. This also means that when excess market returns increase by 1 percentage point, then GOOG's beta increases by 1.06 percentage points. The alpha on the other hand is again very close to 0, it is not statistically different than 0, so this indicates that the portfolio has achieved a return that is in line with what would be expected given its level of risk.
# CAPM model
capm_google <- lm(GOOG ~ MKT_RF,
data = ff_assets
)
summary(capm_google)
##
## Call:
## lm(formula = GOOG ~ MKT_RF, data = ff_assets)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.106597 -0.028694 -0.002766 0.033713 0.126735
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.005955 0.005374 1.108 0.271
## MKT_RF 1.058053 0.110127 9.608 1.53e-15 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.05082 on 92 degrees of freedom
## Multiple R-squared: 0.5008, Adjusted R-squared: 0.4954
## F-statistic: 92.31 on 1 and 92 DF, p-value: 1.527e-15
In the Fama-French model, beta has increased to 1.13, so it is a little more volatile than the market, which tells us that the stock is still cyclical, and this is still statistically significant at the 0.001 level. Alpha, got a bit smaller, however, it is now not statistically different than 0, so this indicates that the portfolio has achieved a return that is in line with what would be expected given its level of risk.
# FAMA-FRENCH model
ff3_google <- lm(GOOG ~ MKT_RF + SMB + HML,
data = ff_assets
)
summary(ff3_google)
##
## Call:
## lm(formula = GOOG ~ MKT_RF + SMB + HML, data = ff_assets)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.106637 -0.029632 -0.004662 0.029525 0.153323
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.004582 0.005143 0.891 0.3754
## MKT_RF 1.134626 0.109914 10.323 <2e-16 ***
## SMB -0.407561 0.194622 -2.094 0.0391 *
## HML -0.312897 0.124330 -2.517 0.0136 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.04847 on 90 degrees of freedom
## Multiple R-squared: 0.5558, Adjusted R-squared: 0.541
## F-statistic: 37.53 on 3 and 90 DF, p-value: 7.957e-16
# plotting realized returns vs predicted from the CAPM and the 3-factor model
google <- data.frame(ff_assets$GOOG, predict(ff3_google), predict(capm_google))
# Scatter plot of actual realized returns on x-axis, and predicted returns from FF3 and CAPM
ggplot(google) + geom_point(aes(x = ff_assets$GOOG, y = predict(ff3_google)),color="red") + geom_point(aes(x = ff_assets$GOOG, y = predict(capm_google))) + geom_abline(intercept = 0) +
labs(
x = "Realized Returns",
y = "Predicted Returns",
title = "Scatterplot of Realized vs. Predicted Returns (Fama-French vs. CAPM)"
)
# Scatter plot of predicted returns from CAPM on x-axis, and predicted returns from FF3 on y-axis
ggplot(google) + geom_point(aes(x = predict(capm_google), y = predict(ff3_google)),color="red") + geom_abline(intercept = 0) +
labs(
x = "Predicted Returns (CAPM)",
y = "Predicted Returns (Fama-French)",
title = "Scatterplot of Predicted Returns (CAPM vs. Fama-French)"
)
Overall, the majority of stocks’ alphas in the CAPM model are not statistically different from zero. This trend persists in the Fama-French model, suggesting that the inclusion of additional factors, such as size and value, does not significantly change the alpha values. This similarity can be attributed to the stocks’ consistent betas with respect to the market in both models, leading to similar alpha values.
Regarding the stocks’ betas, when incorporating the size (SMB) and value (HML) factors in the Fama-French model, we observe only minor adjustments to the betas compared to the CAPM model. This implies that the size and value factors have a relatively limited impact on the stocks’ sensitivities to market movements. For these specific stocks, it appears that the market risk factor plays a more prominent role in explaining their returns in comparison to their size or value characteristics.