Published Document can be accessed on https://rpubs.com/TCML/HW1
Name : Chun Ming LAM, EID : 58555905
library('quantmod')
library('e1071')
library('tidyverse')
stock_list = c("AMZN","ADBE","JNJ")
from.dat = "2019-01-02"
to.dat = "2024-09-20"
Collecting data from 2019-01-02 to 2024-09-20 for Amazon, Adobe and Johnson & Johnson, plotting simple and log returns time series
get_basics <-function(stock_list, from = NULL, to = NULL, type = "Ad", print_graphs = TRUE){
# function that gets the price, simple & log returns given a list of stock tickers, type changes the type of stock price data retrieved {"Ad","Hi","Lo","Cl"}
# getting symbols
args <- list(Symbols = stock_list, auto.assign = TRUE)
# optional params
if (!is.null(from)){
args$from <- from
}
if (!is.null(to)){
args$to <- to
}
out = do.call("getSymbols",args)
sval_df = xts()
sret_df = xts()
lret_df = xts()
for (stock in stock_list) {
# getting data
sval = do.call(type,list(get(stock)))
# caculating returns
sret = (sval - lag(sval))/lag(sval)
lret = log( sval/ lag(sval))
sval_df = merge(sval_df,sval)
sret_df = merge(sret_df,sret)
lret_df = merge(lret_df,lret)
if (print_graphs){
# print simple & log returns
par(mfrow = c(1,2),mar= c(1,1,1,1))
print(plot(sret, main = "Simple Returns"))
print(plot(lret, main = "log Returns"))
mtext(stock,line = -1, outer = TRUE)
}
}
return(list(sval_df=sval_df,sret_df=sret_df,lret_df=lret_df))
}
# get stock values
out = get_basics(stock_list, from = from.dat, to = to.dat)
list2env(out,envir = .GlobalEnv)
<environment: R_GlobalEnv>
Comparing Sample Mean: in general log return mean is less than simple return. Amazon & Adobe has a much higher mean return than Johnson & Johnson
print("Simple Returns Mean")
[1] "Simple Returns Mean"
print(apply(sret_df,2, mean,na.rm = TRUE))
AMZN.Adjusted ADBE.Adjusted JNJ.Adjusted
0.0008626735 0.0008632000 0.0003619072
print("Log Returns Mean")
[1] "Log Returns Mean"
print(apply(lret_df,2, mean,na.rm = TRUE))
AMZN.Adjusted ADBE.Adjusted JNJ.Adjusted
0.0006280246 0.0005924547 0.0002874095
Comparing Sample Variance: a visual inspection of the data show that they are very similar. Here Amazon & Adobe also shows a much higher variance compared to Johnson & Johnson. This is somewhat in line with expectation for efficient markets, as we expect higher returns to compensate for higher level of risk (variance)
print("Simple Returns Variance")
[1] "Simple Returns Variance"
print(apply(sret_df,2, var,na.rm = TRUE))
AMZN.Adjusted ADBE.Adjusted JNJ.Adjusted
0.0004693387 0.0005377012 0.0001492434
print("Log Returns Variance")
[1] "Log Returns Variance"
print(apply(lret_df,2, var,na.rm = TRUE))
AMZN.Adjusted ADBE.Adjusted JNJ.Adjusted
0.0004692713 0.0005438017 0.0001489195
Comparing Sample Skewness: log skewness is in general less/ more negative compared to simple skewness. We expect the simple returns to be right skewed in general whilst log return to be normal, therefore this is inline with our expectation. Furthermore, Johnson & Johnson is also positively skewed, which is preferable to investors and not captured directly in Sharpe Ratios
print("Simple Returns Skew")
[1] "Simple Returns Skew"
print(apply(sret_df,2, skewness, na.rm = TRUE))
AMZN.Adjusted ADBE.Adjusted JNJ.Adjusted
0.0677942 -0.3195508 0.2392024
print("Log Returns Skew")
[1] "Log Returns Skew"
print(apply(lret_df,2, skewness, na.rm = TRUE))
AMZN.Adjusted ADBE.Adjusted JNJ.Adjusted
-0.13936858 -0.68562825 0.05538403
Comparing Sample Excess Kurtosis: log excess kurtosis is in general more than than simple excess kurtosis. both Adobe and Johnson & Johnson has a higher level of Kurtosis compared to Amazon, suggesting that returns more distributed (fatter tails) compared to the normal distribution, this correspond to additional risks that is not captured by Sharpe Ratios
print("Simple Returns Excess Kurtosis")
[1] "Simple Returns Excess Kurtosis"
print(apply(sret_df,2, kurtosis, na.rm = TRUE)-3)
AMZN.Adjusted ADBE.Adjusted JNJ.Adjusted
1.347341 5.534483 5.160415
print("Log Returns Excess Kurtosis")
[1] "Log Returns Excess Kurtosis"
print(apply(lret_df,2, kurtosis, na.rm = TRUE)-3)
AMZN.Adjusted ADBE.Adjusted JNJ.Adjusted
1.445325 6.041365 5.011255
Pairwise Correlation of the simple returns of stocks shows that, Amazon is highly correlated to Adobe. In general log returns shows lower correlations, although the relative magnitudes are similar.
given that Adobe has negative skew and high excess kurtosis, I believe ti is more likely to encounter big draw downs compared to the other
similarly given that Johnson & Johnson has a high positive skew, and relatively lower variance, I think it’s more likely to produce higher returns compared to losses
print('Stock Price Correlation')
[1] "Stock Price Correlation"
print(cor(sval_df, use = 'complete.obs'))
AMZN.Adjusted ADBE.Adjusted JNJ.Adjusted
AMZN.Adjusted 1.0000000 0.8641662 0.4627563
ADBE.Adjusted 0.8641662 1.0000000 0.5556758
JNJ.Adjusted 0.4627563 0.5556758 1.0000000
print('Simple Return Correlation')
[1] "Simple Return Correlation"
print(cor(sret_df, use = 'complete.obs'))
AMZN.Adjusted ADBE.Adjusted JNJ.Adjusted
AMZN.Adjusted 1.0000000 0.6134342 0.1978098
ADBE.Adjusted 0.6134342 1.0000000 0.2598150
JNJ.Adjusted 0.1978098 0.2598150 1.0000000
hist_dest_plot <- function (df){
# takes a xts object, and plot the histogram and density of all it's entries in a column wise manner
for (col in colnames(df)){
# data to be used
dat = df[,col]
# finding y range
den <- density(dat, na.rm = TRUE)
ylim_val = c(0, max(den$y)*1.1)
# plot histogram
hist(df[,col],30,probability = TRUE, main = col, xlab = "Returns", ylim = ylim_val)
# plot density line
par(lwd = 2, col = 'red')
lines(den)
# plot normal distribution
x_values <- seq(min(dat,na.rm= TRUE), max(dat,na.rm= TRUE), length = 100)
normal_dist <- dnorm(x_values, mean = mean(dat,na.rm= TRUE), sd = sd(dat,na.rm= TRUE))
par(lwd = 2, col = 'blue')
lines(x_values, normal_dist)
par(col = 'black')
legend("topright", legend = c("Red = Density", "Blue = Normal Distribution"))
}
}
# plotting the simple returns
hist_dest_plot(sret_df)
# plotting the log returns
hist_dest_plot(lret_df)
We let the null hypothesis \(H_0 : \mu = 0\) and the alternate hypothesis \(H_1 : \mu \neq 0\) , we conduct a two tailed \(t\) test to see if the sample mean t statistic is inside or outside the confidence interval
mass_t <- function(df){
for (col in colnames(df)){
dat = df[,col]
print(paste("data: ", col))
print(t.test(as.vector(dat),na.rm = TRUE))
}
}
mass_t(sret_df)
[1] "data: AMZN.Adjusted"
One Sample t-test
data: as.vector(dat)
t = 1.51, df = 1437, p-value = 0.1313
alternative hypothesis: true mean is not equal to 0
95 percent confidence interval:
-0.0002579967 0.0019833436
sample estimates:
mean of x
0.0008626735
[1] "data: ADBE.Adjusted"
One Sample t-test
data: as.vector(dat)
t = 1.4116, df = 1437, p-value = 0.1583
alternative hypothesis: true mean is not equal to 0
95 percent confidence interval:
-0.0003363134 0.0020627134
sample estimates:
mean of x
0.0008632
[1] "data: JNJ.Adjusted"
One Sample t-test
data: as.vector(dat)
t = 1.1234, df = 1437, p-value = 0.2615
alternative hypothesis: true mean is not equal to 0
95 percent confidence interval:
-0.0002700420 0.0009938563
sample estimates:
mean of x
0.0003619072
the result shows that for all 3 stocks, we cannot reject the null hypothesis at a \(5\%\) level, as the p value of the t statistic shows that they has \(13.1\%, 15.8\%\) and \(26.2\%\) chance respectively for their true mean to be equal to 0, given our sample.
getSymbols("DGS3MO", src = "FRED", from = from.dat, to=to.dat)
[1] "DGS3MO"
# convert to daily data, assume 252 trading day in a year
DGS3MO = DGS3MO/100/252
log_DGS3MO = log(1+DGS3MO)
plot(log_DGS3MO, main = "Log Daily Returns of 3 Month T Bills")
# get closing prices
out = get_basics(stock_list,from = from.dat , to = to.dat, type = "Cl", print_graphs = FALSE)
cl_lret_df = out$lret_df
Using the formula
\[ S_i = \frac{E_t\{ R_{i,t} - R_{f,t}\}}{Var_t\{R_{i,t}\}} \]
# formatting data
cols = colnames(cl_lret_df)
sharpe_data = merge(cl_lret_df,DGS3MO)
equity = sharpe_data[,cols]
DGS3MO = sharpe_data[,"DGS3MO"]
Rf = equity
Rf[,] = DGS3MO
# calculating Sharpe
s_mean <- equity %>% -Rf %>% apply(2,mean,na.rm=TRUE)
s_var <- equity %>% apply(2,var,na.rm=TRUE)
sharpe <- s_mean/ s_var
print(sharpe)
AMZN.Close ADBE.Close JNJ.Close
1.0012637 0.8479906 0.7623467
results shows that Amazon has the highest Sharpe Ratio, although the plot for the cumulative returns since “inception” shows that Amazon and Adobe also suffers from massive draw downs in this period. this reflects our discussion when comparing the stock’s skewness and kurtosis in 5. c)
cumret <- sret_df %>% merge(DGS3MO) %>% na.fill(0) %>% +1 %>% cumprod()
# plotting cumlative returns for the stocks & T Bills
plot(cumret)
legend("topleft", legend = c(cols,"Rf"))
red : AMZN, black ADBE, green: JNJ, blue: 3 Month T Bill