Install the necessary packages

library(quantmod)
library(zoo)

Let’s compare the S&P 500 and Singapore Exchange Index.

#Download historical data for S&P 500 and Singapore Exchange Index
getSymbols("^GSPC", src = "yahoo")  # S&P 500
## [1] "GSPC"
getSymbols("^STI", src = "yahoo")    # Straits Times Index (SGX)
## Warning: ^STI contains missing values. Some functions will not work if objects
## contain missing values in the middle of the series. Consider using na.omit(),
## na.approx(), na.fill(), etc to remove or replace them.
## [1] "STI"

The data from 1 January 2010 to 1 January 2023 will be trimmed and cleaned.

# Fill in NA with an approximation data
STI <- na.approx(STI)
# Trim data for the comparison period
start_date <- "2010-01-01"
end_date <- "2023-01-01"
GSPC <- subset(GSPC, index(GSPC) >= start_date & index(GSPC) <= end_date)
STI <- subset(STI, index(STI) >= start_date & index(STI) <= end_date)
# Check if the data is well trimmed
print(GSPC[rownames(GSPC) >= "2010-01-01" & rownames(GSPC) <= "2010-01-02", ])
##      GSPC.Open GSPC.High GSPC.Low GSPC.Close GSPC.Volume GSPC.Adjusted
print(STI[rownames(STI) >= "2010-01-01" & rownames(STI) <= "2010-01-02", ])
##      STI.Open STI.High STI.Low STI.Close STI.Volume STI.Adjusted
# Merge the datasets
aligned_data <- merge(GSPC, STI)
# Remove missing values 
cleaned_data <- na.omit(aligned_data)

After data is cleanned and trimmed, we can now compare the correlation and statistics between the S&P 500 and Singapore Exchange Index

# Calculate correlation
correlation <- cor(cleaned_data[, 1], cleaned_data[, 7])  # Adjust column index if needed

# Print the correlation coefficient
print(round(correlation, 2))
##           STI.Open
## GSPC.Open     0.17
# Compare the statistics
nasdaq_stats <- c(mean(GSPC[, 4], na.rm = TRUE), median(GSPC[, 4], na.rm = TRUE), sd(GSPC[, 4], na.rm = TRUE))  # Adjust column for Close prices
lond_stats <- c(mean(STI[, 4], na.rm = TRUE), median(STI[, 4], na.rm = TRUE), sd(STI[, 4], na.rm = TRUE))  # Adjust column for Close prices

# Combine statistics into a single data frame
stats_comparison <- rbind(nasdaq_stats, lond_stats)
colnames(stats_comparison) <- c("Mean", "Median", "Standard Deviation")
rownames(stats_comparison) <- c("S&P 500", "Singapore Exchange (STI)")
print(round(stats_comparison, 2))
##                             Mean  Median Standard Deviation
## S&P 500                  2401.49 2125.03             988.94
## Singapore Exchange (STI) 3093.40 3139.98             236.20

Let us compare the Value at Risk for the S&P 500 and Singapore Exchange Index.

# Calculate daily returns
GSPC_returns <- dailyReturn(Cl(GSPC))
STI_returns <- dailyReturn(Cl(STI))
# Remove any NA values in returns
GSPC_returns <- na.omit(GSPC_returns)
STI_returns <- na.omit(STI_returns)
# Calculate Value at Risk (VaR)
# Using 95% confidence level
VaR_GSPC <- quantile(GSPC_returns, probs = 0.05)  # 5th percentile
VaR_STI <- quantile(STI_returns, probs = 0.05)    # 5th percentile

# Print VaR results
cat("Value at Risk (VaR) at 95% confidence level:\n")
## Value at Risk (VaR) at 95% confidence level:
cat("S&P 500 VaR:", round(VaR_GSPC * 100, 2), "%\n")
## S&P 500 VaR: -1.72 %
cat("Singapore Exchange (STI) VaR:", round(VaR_STI * 100, 2), "%\n")
## Singapore Exchange (STI) VaR: -1.3 %

Let us compare the volatility for the S&P 500 and Singapore Exchange Index

# Calculate the standard deviation (volatility) of returns for each index
volatility_GSPC <- sd(GSPC_returns)  # Daily volatility for S&P 500
volatility_STI <- sd(STI_returns)    # Daily volatility for SGX
# Annualize the volatility 
annualized_volatility_GSPC <- volatility_GSPC * sqrt(365)
annualized_volatility_STI <- volatility_STI * sqrt(365)
# Print the volatility comparison
cat("Daily Volatility for S&P 500 (GSPC):", round(volatility_GSPC, 4), "\n")
## Daily Volatility for S&P 500 (GSPC): 0.0112
cat("Daily Volatility for SGX (STI):", round(volatility_STI, 4), "\n")
## Daily Volatility for SGX (STI): 0.0084
cat("Annualized Volatility for S&P 500 (GSPC):", round(annualized_volatility_GSPC, 4), "\n")
## Annualized Volatility for S&P 500 (GSPC): 0.2143
cat("Annualized Volatility for SGX (STI):", round(annualized_volatility_STI, 4), "\n")
## Annualized Volatility for SGX (STI): 0.1613

Let us compare the Sharpe ratio of the S&P 500 and Singapore Exchange Index.

First, we calculate the mean and standard deviation of the S&P 500 and Singapore Exchange Index.

# Calculate the mean return for both indices
mean_GSPC <- mean(GSPC_returns)
mean_STI <- mean(STI_returns)
# Calculate the standard deviation (volatility) of returns for both indices
volatility_GSPC <- sd(GSPC_returns)  # Daily volatility for S&P 500
volatility_STI <- sd(STI_returns)    # Daily volatility for SGX

We will annualise the mean and standard deviation

# Annualize the mean return (assuming 365 trading days in a year)
annualized_mean_GSPC <- mean_GSPC * 365
annualized_mean_STI <- mean_STI * 365
# Annualize the volatility (assuming 365 trading days in a year)
annualized_volatility_GSPC <- volatility_GSPC * sqrt(365)
annualized_volatility_STI <- volatility_STI * sqrt(365)

Finally, we can calculate the Sharpe ratio for the S&P 500 and Singapore Exchange index

# Calculate the Sharpe Ratio for both indices (assuming 0% risk-free rate)
sharpe_ratio_GSPC <- (annualized_mean_GSPC - 0) / annualized_volatility_GSPC
sharpe_ratio_STI <- (annualized_mean_STI - 0) / annualized_volatility_STI

# Print the Sharpe Ratio comparison
cat("Sharpe Ratio for S&P 500 (GSPC):", round(sharpe_ratio_GSPC, 4), "\n")
## Sharpe Ratio for S&P 500 (GSPC): 0.743
cat("Sharpe Ratio for SGX (STI):", round(sharpe_ratio_STI, 4), "\n")
## Sharpe Ratio for SGX (STI): 0.1614

Let us compare the cumulative returns between the S&P 500 and SGX from 2010 to 2023.

# Check the first few rows to verify data
head(GSPC)
##            GSPC.Open GSPC.High GSPC.Low GSPC.Close GSPC.Volume GSPC.Adjusted
## 2010-01-04   1116.56   1133.87  1116.56    1132.99  3991400000       1132.99
## 2010-01-05   1132.66   1136.63  1129.66    1136.52  2491020000       1136.52
## 2010-01-06   1135.71   1139.19  1133.95    1137.14  4972660000       1137.14
## 2010-01-07   1136.27   1142.46  1131.32    1141.69  5270680000       1141.69
## 2010-01-08   1140.52   1145.39  1136.22    1144.98  4389590000       1144.98
## 2010-01-11   1145.96   1149.74  1142.02    1146.98  4255780000       1146.98
head(STI)
##            STI.Open STI.High STI.Low STI.Close STI.Volume STI.Adjusted
## 2010-01-04  2897.62  2897.62 2886.43   2894.55          0      2894.55
## 2010-01-05  2894.55  2923.91 2894.55   2920.28          0      2920.28
## 2010-01-06  2920.28  2937.98 2919.74   2930.49          0      2930.49
## 2010-01-07  2930.49  2945.06 2901.24   2913.25          0      2913.25
## 2010-01-08  2913.25  2932.72 2909.41   2922.76          0      2922.76
## 2010-01-11  2922.76  2947.08 2922.76   2933.53          0      2933.53

First, we calculate the daily returns of S&P500 and SGX.

# Calculate daily returns for both indices
GSPC_returns <- dailyReturn(GSPC)
STI_returns <- dailyReturn(STI)

Next, we calculate the cumulative returns of S&P500 and SGX.

# Calculate cumulative returns 
GSPC_cumulative_returns <- cumsum(GSPC_returns)
STI_cumulative_returns <- cumsum(STI_returns)

Finally, we can compare them with a line graph.

# Plot Cumulative Returns
plot(index(GSPC_cumulative_returns), GSPC_cumulative_returns, type = "l", col = "blue", 
     xlab = "Date", ylab = "Cumulative Returns", main = "Cumulative Returns: S&P 500 vs SGX (2010-2023)")
lines(index(STI_cumulative_returns), STI_cumulative_returns, col = "red")
legend("topleft", legend = c("S&P 500", "SGX"), col = c("blue", "red"), lty = 1)

As shown on the graph, the S&P 500 has drastically higher cumulative returns over the years from 2010 to 2023 as compared to the SGX.