# packages
library(tidyquant)  
library(tidyverse)  
library(broom)       
library(knitr)       
library(dplyr)      
library(kableExtra)  
library(car)         
library(onewaytests) 
library(ggpubr)      
library(tibble)      
library(e1071)        
library(qqplotr)    
library(stargazer)    
library(stats)       
library(Deriv)      
library(here)

Import the Data

# load data
stock_data<-c("HUM","AMZN", "MT") %>%
  tq_get(get = "stock.prices", from = "2000-01-01") %>%
  select(symbol, date, adjusted)
# output the first 6 rows of your data frame:

head(stock_data, n = 6 )%>%
   kable(caption = "The first 6 rows of stock data")
The first 6 rows of stock data
symbol date adjusted
HUM 2000-01-03 6.805113
HUM 2000-01-04 6.861352
HUM 2000-01-05 7.030074
HUM 2000-01-06 7.311279
HUM 2000-01-07 7.873686
HUM 2000-01-10 7.536240

The Analysis

Plot prices over time

ggplot(stock_data, aes(x = date, y = adjusted, color = symbol)) + 
  geom_line(alpha = 0.8, lwd = 0.5) + 
  facet_wrap(~ symbol, scales = "free_y") +
  labs(title = "Time Series Price Trend of Each Stock",
       y = "Adjusted Price (US$)", x = "Dates") +
  theme(legend.position = "bottom", plot.title = element_text(hjust = 0.5))
Time Series Price Trend of Each Stock

Time Series Price Trend of Each Stock

Discussion

AMZN

The line graph for AMZN (Stock 2) shows a strong rise over time. This emphasizes how its value in the market has grown steadily and consistently. Even though prices go up and down, they all join to make a good direction. A big jump in costs shows something important happening in the market. Clearly marked axes, with time on the bottom and Amazon prices shown in dollars at top help to make it much easier understanding what’s being showed. This visualization, called “AMZN Prices Over Time” shows how AMZN’s value has changed over the years.

HMU

Changing Over Time A line chart for HUM (Stock 1) shows prices going up steadily during the watched time. Even though things change now and then, showing quick ups and downs in the market, overall it shows steady growth. Important is a big increase in costs, showing strong effects on the market. Properly marked lines show time on the x-axis (in years), giving a complete look at how HUM has done through history. On the y-axis, HUM prices are shown in US dollars. This big picture shows how HUM’s worth changes over time. It includes both long-term improvements and short moments of market action.

MT

Evolution Over Time series plot of MT (Stock 3) over time shows how prices change during the observed period. Background changes suggest possible market change and complicated actions. A clear increase in prices shows a big change in the market. Labels that show time on the top and MT prices on the side (in adjusted dollars) help us see better how well MT has done. It makes it easier to understand its past performance too. This picture, called “MT Prices Over Time” perfectly shows how MT’s worth has changed over time.

2.2 Calculate returns and plot returns over time

Calculate the daily percentage returns of each asset using the following formula:

\[r_t = 100*\ln\Big(\frac{P_t}{P_{t-1}}\Big)\]

Where \(P_t\) is the asset price at time \(t\). Then plot the returns for each asset over time.

stock_data<-stock_data%>%
group_by(symbol)%>%
mutate("Returns" = 100*log(adjusted/lag(adjusted)))
# Plotting the daily returns of the 3 stocks

ggplot(stock_data, aes(x = date, y = Returns, color=symbol))+
geom_line(alpha=0.6, lwd=0.5)+
facet_wrap(factor(symbol, levels=c("HUM", "AMZN", "MT"))~.)+
  ylim(-20,20)+
labs(title = "Price Returns of Each Stock Overtime", 
y = "Price Returns (%)", x = "Dates")+
  theme(legend.position="bottom", plot.title = element_text(hjust = 0.5))
Price Returns of Each Stock Overtime

Price Returns of Each Stock Overtime

Histogram of returns

Create a histogram for each of the returns series

stock_data%>% 
  group_by(symbol)%>%
    summarise(n = n())
## # A tibble: 3 × 2
##   symbol     n
##   <chr>  <int>
## 1 AMZN    6065
## 2 HUM     6065
## 3 MT      6065
samplesize <- sum(stock_data$symbol=='HUM')
samplesize
## [1] 6065
 sturgerule <-  1+ 3.322*log(samplesize)


ggplot(stock_data, aes(x=Returns,  fill=symbol, color=symbol))+ 
  geom_histogram(aes(y=..density..), bins=35  , alpha=0.8)+
 
  facet_wrap(factor(symbol, levels=c("HUM", "AMZN", "MT"))~.) +

  facet_wrap(factor(symbol, levels=c("HUM", "AMZN", "MT"))~.) +
  xlim(-10,10)+
  labs(title = "Histogram Price Returns of Each Stock", 
y = "Frequency", x = "Price Returns")+
 geom_density(col ="black", lwd=0.3, linetype=5, alpha=0) +
  theme(legend.position="bottom", plot.title = element_text(hjust = 0.5))
Histogram of Returns of Each Stock

Histogram of Returns of Each Stock

choice of bins

To comprehensively understand the distribution of returns for each stock, histograms were generated, providing insights into the frequency of different return levels. Employing Sturges’ rule for bin calculation, the number of bins was determined as 1+3.22.log(sample size), ensuring an optimal representation of the distribution characteristics. Sturges’ rule strikes a balance between granularity and interpretability. By considering the logarithm of the sample size, it adjusts the bin count to be suitable for datasets of varying sizes. This adaptability ensures that the resulting histograms effectively capture the distribution characteristics without introducing unnecessary noise.

AMZN

The histogram for AMZN Returns shows a positive skew, focusing on steady good returns over time. Sometimes, big jumps in stock prices happen. These are times when the market is really busy or something huge impacts how Amazon’s shares do.

HUM

The histogram for HUM Returns shows a spread with the highest part around zero. This means it’s like a typical normal distribution. This means that stock prices often change a bit over time. Big ups and downs on the histogram show times when the market is sometimes more unstable.

MT

The histogram for MT Returns showcases a distribution with a more even spread, indicating varying levels of volatility over time. Peaks and troughs in the histogram capture the dynamics of MT’s performance, reflecting fluctuating market conditions.

Formula Hint

The choice of Sturges’ rule for bin calculation ensures an appropriate representation of the data’s characteristics without oversmoothing or undersmoothing. This method takes into account the sample size, providing a data-driven approach to bin determination.

Statistocal graphs

library(ggplot2)
library(dplyr)

# The dataset is provided in the gapminder library
library(gapminder)
data <- gapminder %>% filter(year=="2007") %>% dplyr::select(-year)

# Most basic bubble plot
data %>%
  arrange(desc(pop)) %>%
  mutate(country = factor(country, country)) %>%
  ggplot(aes(x=gdpPercap, y=lifeExp, size = pop)) +
    geom_point(alpha=0.5) +
    scale_size(range = c(.1, 24), name="Population (M)")

# Create data 
library(GGally)
data <- data.frame( var1 = 1:100 + rnorm(100,sd=20), v2 = 1:100 + rnorm(100,sd=27), v3 = rep(1, 100) + rnorm(100, sd = 1)) 
data$v4 = data$var1 ** 2 
data$v5 = -(data$var1 ** 2) 
 
# Check correlations (as scatterplots), distribution and print corrleation coefficient 
ggpairs(data, title="correlogram with ggpairs()")

# From the help page:
data(flea)
ggpairs(flea, columns = 2:4, ggplot2::aes(colour=species)) 

library(GGally)
 
# Create data 
data <- data.frame( var1 = 1:100 + rnorm(100,sd=20), v2 = 1:100 + rnorm(100,sd=27), v3 = rep(1, 100) + rnorm(100, sd = 1)) 
data$v4 = data$var1 ** 2 
data$v5 = -(data$var1 ** 2) 
 
# Check correlation between variables
#cor(data) 
 
# Nice visualization of correlations
ggcorr(data, method = c("everything", "pearson")) 

summary table of returns

# Create a table for the mean, median, variance,
#Standard deviation, skewness and kurtosis of the returns


stock_data%>%
 group_by(symbol)%>%
      select(Returns)%>%
    drop_na()%>%
 summarise(
 "Mean"=sprintf("%.3f", mean(Returns)), 
 "Median" =sprintf("%.3f",median(Returns)),
 "Variance" =sprintf("%.3f", var(Returns)),
 "Standard Deviation" =sprintf("%.3f", sd(Returns)),
 "Skewness" =sprintf("%.3f", skewness(Returns)),
 "Kurtosis" =sprintf("%.3f", kurtosis(Returns)),
 "n"=sprintf("%.3f",n()))%>%
 mutate(symbol=fct_relevel(symbol, "HUM", "AMZN", "MT")) %>% 
  arrange(symbol) %>% 
  kable(caption ="Statistical Table for the Returns of Each Stock", 
        label = "stock1", align=rep('c', 8)) %>% 
kable_styling(latex_options = c("hold_position", "striped", 
                                "scale_down"), position="center", stripe_color="blue!8")%>% 
  kableExtra::row_spec(0, bold = TRUE)
Statistical Table for the Returns of Each Stock
symbol Mean Median Variance Standard Deviation Skewness Kurtosis n
HUM 0.066 0.058 5.912 2.431 -0.851 14.045 6064.000
AMZN 0.060 0.049 9.687 3.112 0.424 12.715 6064.000
MT -0.003 0.000 12.139 3.484 0.124 10.154 6064.000

Conclusion drawn from the summary table of returns

The summary table of returns for each stock—HUM, AMZN, and MT—provides comprehensive insights into various statistical measures, revealing distinct characteristics of their return distributions.

Mean and Median

The average return shows how each stock usually does. HUM has the highest average gain at 0.070, showing a good normal return. AMZN closely watches with a little lower average of 0.058, showing good performance most of the time. On the other hand, MT has a small negative mean of -0.003 which suggests that it usually gives out more than usual in return. Noticing that middle numbers are often smaller than averages suggests there might be a skewed pattern. This means it’s important to study returns more closely and understand their shape better.

Variance and Standard Deviation

The change and standard of deviation give us ways to measure how much the returns vary. MT is special because it has the biggest difference (12.183) and normal change size (3.490). This shows that its profits can be more high or low compared to HUM and AMZN’s results. Even though HUM and AMZN have less variation, they still show big changes. This shows that these stocks are risky by nature.

Skewness

Skewness checks how uneven the return distributions are. HUM and MT both show a lower skewness, which means their distributions have an extended left side. This means that bad returns happen more often than good ones. Instead, AMZN shows a good positive skew. This means it has longer right tails and more frequent high returns compared to other stocks or investments. Knowing about skewness is very important to see how and often extreme profits happen.

Kurtosis

All three stocks have high kurtosis value, which means the distributions are more extreme compared to normal distribution. HUM has the biggest kurtosis at 14.122. This means the distribution has more extreme or big values. Understanding kurtosis is crucial for measuring how likely extreme events or unusual outcomes are in return patterns.

Sample Size (n)

The uniform sample size of 6037 for each stock signifies a substantial dataset for analysis. This large sample size enhances the reliability of the statistical measures, providing a robust foundation for drawing meaningful conclusions.

Conclusions

HUM shows a skewed pattern with bigger kurtosis and more extreme values in its gains. AMZN showing a positive distribution with some amount of extreme returns. MT, with a skewed distribution that’s negative, the highest variance and standard deviation shows more variation. This can lead to potential risk too.

2.5 Are average returns significantly different from zero?

Part 1

Step 1: Formulate Hypotheses

Null Hypothesis \[(H_0):\mu=0\] The expected return is not significantly different from zero)

Alternative Hypothesis \[(H_1):\mu \neq 0\] The expected return is significantly different from zero)

Step 2: Choose Significance Level

Significance level \(\alpha = 0.01\)

Step 3: Select Test Statistic

statistical t test was used. The formula is give as

\[t = \frac{\bar{X}-\mu_0}{S{\sqrt n}}\] where \(\bar{X}\) is the sample mean \(\mu_0\) is the hypothesized population mean (in this case, 0), S is the sample standard deviation, and n is the sample size.

Step 4: Calculate Critical Value(s) or P-value

With a significance level of 0.01 and degrees of freedom\(n - 1\) , find the critical values or P-value.

Step 5: Make a Decision

If the calculated test statistic falls in the rejection region (beyond the critical values), we reject the null hypothesis. Otherwise, we fail to reject the null hypothesis.

Part 2

HUM

t_test_HUM <- t.test(stock_data$Returns[stock_data$symbol == "HUM"], 
                     alternative = "two.sided", mu = 0)
print(t_test_HUM)
## 
##  One Sample t-test
## 
## data:  stock_data$Returns[stock_data$symbol == "HUM"]
## t = 2.1108, df = 6063, p-value = 0.03483
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
##  0.004697825 0.127115673
## sample estimates:
##  mean of x 
## 0.06590675
if (t_test_HUM$p.value < 0.01) {
  cat("For HUM: Reject the null hypothesis. 
      Expected return is significantly different from zero.\n")
} else {
  cat("For HUM: Fail to reject the null hypothesis.
      Expected return is not significantly different from zero.\n")
}
## For HUM: Fail to reject the null hypothesis.
##       Expected return is not significantly different from zero.

AMZN

t_test_AMZN <- t.test(stock_data$Returns[stock_data$symbol == "AMZN"],
                      alternative = "two.sided", mu = 0)
print(t_test_AMZN)
## 
##  One Sample t-test
## 
## data:  stock_data$Returns[stock_data$symbol == "AMZN"]
## t = 1.512, df = 6063, p-value = 0.1306
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
##  -0.01791965  0.13878144
## sample estimates:
##  mean of x 
## 0.06043089
if (t_test_AMZN$p.value < 0.01) {
  cat("For AMZN: Reject the null hypothesis. 
      Expected return is significantly different from zero.\n")
} else {
  cat("For AMZN: Fail to reject the null hypothesis.
      Expected return is not significantly different from zero.\n")
}
## For AMZN: Fail to reject the null hypothesis.
##       Expected return is not significantly different from zero.

MT

t_test_MT <- t.test(stock_data$Returns[stock_data$symbol == "MT"],
                    alternative = "two.sided", mu = 0)
print(t_test_MT)
## 
##  One Sample t-test
## 
## data:  stock_data$Returns[stock_data$symbol == "MT"]
## t = -0.061068, df = 6063, p-value = 0.9513
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
##  -0.09044347  0.08497883
## sample estimates:
##    mean of x 
## -0.002732321
if (t_test_MT$p.value < 0.01) {
  cat("For MT: Reject the null hypothesis. 
      Expected return is significantly different from zero.\n")
} else {
  cat("For MT: Fail to reject the null hypothesis.
      Expected return is not significantly different from zero.\n")
}
## For MT: Fail to reject the null hypothesis.
##       Expected return is not significantly different from zero.

Part 3

Prompt for Chat-GPT

Ask Chat-GPT to explain the general steps and details involved in conducting a hypothesis test for the average returns of a sample. Emphasize the importance of the five steps and the equation for the test statistic. Also, inquire about the interpretation of the results and how one would decide whether to reject the null hypothesis.

Expected Answer

Chat-GPT is likely to provide a general explanation of the steps involved in a one-sample t-test, including formulating hypotheses, choosing the significance level, calculating the test statistic, determining critical values or p-values, and making a decision based on the results. The response might also include an interpretation of the p-value and guidance on decision-making.

Comparison to the Answer

While the answer is specific to the dataset and involves practical implementation in R, Chat-GPT’s response would be more general and focused on the theoretical aspects of hypothesis testing. There might be differences in the level of detail and specificity. The answer is tailored to the data, while Chat-GPT’s response would be applicable to a broad understanding of hypothesis testing.

2.6 Are average returns different from each other?

Part 1: Details for Each Hypothesis Test

Step 1: Formulate Hypotheses

Null Hypothesis \(H_0 = \mu_1 = \mu_2 = \mu_3\) (The mean returns are equal for all stocks)

Alternative Hypothesis At least one pair of means is different

Step 2: Choose Significance Level \(\alpha = 0.01\)

Step 3: Select Test Statistic

Since we are comparing means of three independent groups, we would typically use Analysis of Variance (ANOVA). If ANOVA indicates significant differences, we proceed to post hoc tests for pairwise comparisons.

Step 4: Calculate Critical Value(s) or P-value

Perform ANOVA to get the p-value. If the p-value is less than 0.01, we can proceed with post hoc tests.

Step 5: Make a Decision

If ANOVA is significant, conduct post hoc tests to identify which pairs of means are significantly different.

Part 2: Calculation and Reporting

# Assuming stock_data contains the necessary data
anova_result <- aov(Returns ~ symbol, data = stock_data)
print(summary(anova_result))
##                Df Sum Sq Mean Sq F value Pr(>F)
## symbol          2     18   8.824   0.954  0.385
## Residuals   18189 168175   9.246               
## 3 observations deleted due to missingness
# Post hoc tests (assuming equal variances)
posthoc <- TukeyHSD(anova_result)
print(posthoc)
##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = Returns ~ symbol, data = stock_data)
## 
## $symbol
##                  diff        lwr        upr     p adj
## HUM-AMZN  0.005475855 -0.1239584 0.13491014 0.9945936
## MT-AMZN  -0.063163216 -0.1925975 0.06627107 0.4870882
## MT-HUM   -0.068639070 -0.1980734 0.06079522 0.4278345

Interpretation

The analysis of variance (ANOVA) results for comparing the average returns of the three stocks (HUM, AMZN, MT) yields an F-value of 0.999 with a corresponding p-value of 0.368. Given that the p-value is greater than the chosen significance level of 0.01, we fail to reject the null hypothesis of equal means among the stocks. This suggests that, at a 1% level of significance, there is insufficient evidence to conclude that the average returns of HUM, AMZN, and MT are statistically different.

To further explore potential differences between individual pairs of means, a Tukey post hoc test was conducted. The results indicate that none of the pairwise mean differences are statistically significant after adjusting for multiple comparisons. Specifically, the confidence intervals for the pairwise differences (HUM-AMZN, MT-AMZN, MT-HUM) all include zero, and the p-values are greater than the adjusted significance level.

Therefore, we do not find significant evidence to support the notion that the average returns of any two stocks among HUM, AMZN, and MT are different from each other at the 1% level of significance. This aligns with the ANOVA results and reinforces the conclusion of overall equality in mean returns for the three stocks.

Part 3: Engaging Chat-GPT

Prompt for Chat-GPT

Ask Chat-GPT to explain the general steps and details involved in conducting an ANOVA test followed by post hoc tests for pairwise comparisons. Inquire about the importance of equal variances assumption and how to interpret the results.

Expected Answer

Chat-GPT would likely provide a general explanation of ANOVA, the need for post hoc tests, and the importance of checking for equal variances. The response might include guidance on interpreting ANOVA results and conducting post hoc tests.

Comparison to Your Answer

The answer is specific to your dataset and involves practical implementation in R. Chat-GPT’s response would be more general and focused on the theoretical aspects of ANOVA and post hoc tests. There might be differences in the level of detail and specificity. The answer is tailored to your data, while Chat-GPT’s response would be applicable to a broad understanding of statistical testing principles.

2.7 Correlations

stocksReturns<-stock_data%>%
drop_na()%>%
select(date, symbol, Returns)%>%
pivot_wider(date, names_from = symbol, values_from = Returns)
glimpse(stock_data$Returns)
##  num [1:18195] NA 0.823 2.429 3.922 7.411 ...
cor(stocksReturns%>%select(-date))%>%
kable(caption="Correlation Matrix", label = "stocks4",digit=3 , align=rep('c', 4))%>%
kable_styling(latex_options = c("hold_position", "striped"), 
              position="center", stripe_color="purple!8")%>% 
  kableExtra::row_spec(0, bold = TRUE)
Correlation Matrix
HUM AMZN MT
HUM 1.000 0.163 0.217
AMZN 0.163 1.000 0.243
MT 0.217 0.243 1.000

HUM and AMZN (0.165)

The correlation between HUM and AMZN is positive but relatively weak (0.165). This suggests a slight tendency for the two stocks to move in the same direction, but the relationship is not very strong.

HUM and MT (0.218)

The correlation between HUM and MT is positive and slightly stronger (0.218) compared to HUM and AMZN. This indicates a somewhat stronger tendency for the two stocks to move together.

AMZN and MT (0.243)

The correlation between AMZN and MT is positive and stronger (0.243) compared to HUM and AMZN but weaker than HUM and MT. This suggests a moderate tendency for AMZN and MT to move in the same direction.

2.8 Testing the significance of correlations

Step 1: Formulate Hypotheses Null Hypothesis \(H_0\):The correlation coefficients between stock returns are not significantly different from zero, indicating independence.

lternative Hypothesis \(H_1\) : At least one correlation coefficient is significantly different from zero, indicating dependence.

Step 2: Choose Significance Level

Significance level\(\alpha = 0.05\)

Step 3: Select Test Statistic

We will use Fisher’s transformation to convert the correlation coefficients to z-scores, making them approximately normally distributed.

Step 4: Calculate Critical Value(s) or P-value

Under the null hypothesis, the test statistic follows a standard normal distribution. We will compare the absolute value of the test statistic with the critical value from the standard normal distribution or calculate a two-tailed p-value.

Step 5: Make a Decision

If the absolute value of the test statistic is greater than the critical value, or if the p-value is less than the significance level, we reject the null hypothesis. Otherwise, we fail to reject the null hypothesis.

# Create a matrix with the given correlation coefficients
correlation_matrix <- matrix(c(1.000, 0.165, 0.218,
                               0.165, 1.000, 0.243,
                               0.218, 0.243, 1.000), 
                             nrow = 3, 
                             byrow = TRUE)

# Convert the matrix to a data frame for better visualization
correlation_df <- as.data.frame(correlation_matrix)

# Set row and column names
rownames(correlation_df) <- colnames(correlation_df) <- c("HUM", "AMZN", "MT")

# Display the correlation matrix
print(correlation_df)
##        HUM  AMZN    MT
## HUM  1.000 0.165 0.218
## AMZN 0.165 1.000 0.243
## MT   0.218 0.243 1.000
# Extract correlation coefficients from the correlation matrix
cor_values <- as.vector(correlation_matrix)

# Fisher's transformation function
fisher_transform <- function(r) {
  0.5 * log((1 + r) / (1 - r))
}

# Apply Fisher's transformation
z_scores <- sapply(cor_values, fisher_transform)

# Perform a two-tailed test for each correlation
p_values <- 2 * (1 - pnorm(abs(z_scores)))

# Compare each p-value with the significance level
alpha <- 0.05
reject_null <- p_values < alpha

# Check if any correlation is statistically significant
if (any(reject_null)) {
  cat("At least one correlation is statistically significant.
      There is evidence of dependence between stock returns.\n")
} else {
  cat("No correlations are statistically significant. 
      No significant evidence of dependence between stock returns.\n")
}
## At least one correlation is statistically significant.
##       There is evidence of dependence between stock returns.

Assumption of independence

The hypothesis test performed on the correlation coefficients indicates that at least one correlation among the stock returns is statistically significant. The evidence suggests that the assumption of independence of stock returns may not be realistic.

Rationale

In this case, the result indicates that at least one correlation is statistically significant (p-value < 0.05), leading to the rejection of the null hypothesis. Therefore, there is evidence of dependence between stock returns. This finding is crucial for understanding the potential relationships and dependencies among the stocks in the dataset, impacting portfolio management and risk assessment strategies.

2.9 Advising an investor

# Define the expected returns for HUM,AMZN and MT
E_r <- c(0.0699459, 0.0580204, -0.0034106)  
# Define the variances for HUM,AMZN and MT
Var_r <- c(5.887240, 9.710527,12.181820)  

# Define the covariance matrix between HUM,AMZN and MT
Cov_r <- matrix(c(5.887243, 1.244174,1.847846,
                  1.244174, 9.710527,2.640371,
                  1.847846, 2.640371, 12.181816), nrow = 3, ncol = 3)  
# Create a sequence of possible weights for w1
weights <- seq(0, 1, by = 0.01)

# Initialize variables to store optimal values
max_happiness <- -Inf
optimal_weights <- numeric(3)

# Loop through all possible weight combinations
for (w1 in weights) {
  for (w2 in weights) {
    w3 <- 1 - w1 - w2  # Ensure that w1 + w2 + w3 = 1
    
    # Calculate portfolio statistics
    portfolio_var <- w1^2 * Var_r[1] + w2^2 * Var_r[2] + w3^2 * Var_r[3] +
                     2 * w1 * w2 * Cov_r[1, 2] + 2 * w1 * w3 * Cov_r[1, 3] +
      2 * w2 * w3 * Cov_r[2, 3]
    portfolio_return <- w1 * E_r[1] + w2 * E_r[2] + w3 * E_r[3]
    happiness <- portfolio_return - portfolio_var
    
    # Check if this combination maximizes happiness
    if (happiness > max_happiness) {
      max_happiness <- happiness
      optimal_weights <- c(w1, w2, w3)
    }
  }
}

# Print the optimal portfolio weights and expected return
cat("Optimal Portfolio Weights:")
## Optimal Portfolio Weights:
cat("HUM weight:", optimal_weights[1], "\n")
## HUM weight: 0.55
cat("AMZN weight:", optimal_weights[2], "\n")
## AMZN weight: 0.28
cat("MT weight:", optimal_weights[3], "\n")
## MT weight: 0.17
cat("Expected Return of Optimal Portfolio:", portfolio_return, "\n")
## Expected Return of Optimal Portfolio: 0.1313769

covariance matrix

# Extract the relevant columns for stocks 1 and 2
returns_data <- stocksReturns[, c("HUM", "AMZN", "MT")]

# Calculate the covariance matrix
covariance_matrix <- cov(returns_data, use = "pairwise.complete.obs")

# Display the covariance matrix
print(covariance_matrix)
##           HUM     AMZN        MT
## HUM  5.911791 1.236293  1.837761
## AMZN 1.236293 9.686651  2.629658
## MT   1.837761 2.629658 12.139455