Equally Weighted Portfolio
# Data reading and manipulation
library(readxl)
library(dplyr)
##
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(tibble)
library(lubridate)
##
## Adjuntando el paquete: 'lubridate'
## The following objects are masked from 'package:base':
##
## date, intersect, setdiff, union
# Financial analysis
library(PerformanceAnalytics)
## Cargando paquete requerido: xts
## Cargando paquete requerido: zoo
##
## Adjuntando el paquete: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
##
## ######################### Warning from 'xts' package ##########################
## # #
## # The dplyr lag() function breaks how base R's lag() function is supposed to #
## # work, which breaks lag(my_xts). Calls to lag(my_xts) that you type or #
## # source() into this session won't work correctly. #
## # #
## # Use stats::lag() to make sure you're not using dplyr::lag(), or you can add #
## # conflictRules('dplyr', exclude = 'lag') to your .Rprofile to stop #
## # dplyr from breaking base R's lag() function. #
## # #
## # Code in packages is not affected. It's protected by R's namespace mechanism #
## # Set `options(xts.warn_dplyr_breaks_lag = FALSE)` to suppress this warning. #
## # #
## ###############################################################################
##
## Adjuntando el paquete: 'xts'
## The following objects are masked from 'package:dplyr':
##
## first, last
##
## Adjuntando el paquete: 'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
##
## legend
library(xts)
# Read Excel files
data_prices <- read_excel("data.xlsx")
## New names:
## • `` -> `...1`
data_market <- read_excel("Data2.xlsx")
## New names:
## • `` -> `...1`
# Format the date columns
data_prices[[1]] <- as.Date(data_prices[[1]])
data_market[[1]] <- as.Date(data_market[[1]])
# Rename market data columns for easier access
colnames(data_market)[2:4] <- c("SP500_Price", "SP500_TotalReturn", "RiskFree")
# Calculate log returns for asset prices
returns_assets <- data_prices %>%
arrange(data_prices[[1]]) %>%
mutate(across(-1, ~ log(. / lag(.)))) %>%
slice(-1) # Remove the first row with NA
# Calculate log returns for market and risk-free rate (monthly)
returns_market <- data_market %>%
arrange(data_market[[1]]) %>%
mutate(
MarketReturn = log(SP500_TotalReturn / lag(SP500_TotalReturn)),
RiskFreeRate = log(1 + RiskFree / 100 / 12)
) %>%
select(Date = 1, MarketReturn, RiskFreeRate) %>%
slice(-1)
# Rename the date column in asset returns
colnames(returns_assets)[1] <- "Date"
# Join both datasets by date
full_data <- inner_join(returns_assets, returns_market, by = "Date")
# Select only the asset columns (exclude Date, MarketReturn, and RiskFreeRate)
asset_names <- colnames(full_data)[!(colnames(full_data) %in% c("Date", "MarketReturn", "RiskFreeRate"))]
# Calculate the equally weighted portfolio return (1/N strategy)
portfolio_1N <- full_data %>%
select(all_of(asset_names)) %>%
rowMeans(na.rm = TRUE)
# Add the 1/N portfolio returns to the dataset
full_data$Portfolio_1N <- portfolio_1N
# Convert to xts for plotting
portfolio_xts <- xts(full_data$Portfolio_1N, order.by = full_data$Date)
# Set month labels to English
Sys.setlocale("LC_TIME", "C")
## [1] "C"
# Plot cumulative return
chart.CumReturns(portfolio_xts,
main = "Cumulative Return of the 1/N Portfolio",
ylab = "Growth of $1",
wealth.index = TRUE)

# Convert benchmark returns to xts
benchmark_xts <- xts(full_data$MarketReturn, order.by = full_data$Date)
# Merge both time series
comparison_xts <- merge(portfolio_xts, benchmark_xts)
colnames(comparison_xts) <- c("1/N Portfolio", "Market Benchmark")
# Plot cumulative returns comparison
chart.CumReturns(comparison_xts,
legend.loc = "topleft",
main = "1/N Portfolio vs Market Benchmark",
ylab = "Growth of $1",
wealth.index = TRUE)

# Calculate excess returns
excess_portfolio <- full_data$Portfolio_1N - full_data$RiskFreeRate
excess_market <- full_data$MarketReturn - full_data$RiskFreeRate
# Run linear regression to get alpha and beta
model <- lm(excess_portfolio ~ excess_market)
# Extract Jensen’s Alpha
jensen_alpha <- coef(model)[1]
# Print result
cat("Jensen's Alpha of the 1/N Portfolio:", round(jensen_alpha, 6), "\n")
## Jensen's Alpha of the 1/N Portfolio: 0.000822
# Calculate average and standard deviation of returns
average_return <- mean(full_data$Portfolio_1N, na.rm = TRUE)
std_deviation <- sd(full_data$Portfolio_1N, na.rm = TRUE)
# Print results
cat("Average monthly return:", round(average_return, 6), "\n")
## Average monthly return: 0.008135
cat("Monthly standard deviation:", round(std_deviation, 6), "\n")
## Monthly standard deviation: 0.041426
# Annualize average return
annual_return <- (1 + average_return)^12 - 1
# Annualize standard deviation
annual_std_deviation <- std_deviation * sqrt(12)
# Print results
cat("Annualized return:", round(annual_return, 6), "\n")
## Annualized return: 0.102111
cat("Annualized standard deviation:", round(annual_std_deviation, 6), "\n")
## Annualized standard deviation: 0.143503
# Calculate average risk-free rate
average_riskfree <- mean(full_data$RiskFreeRate, na.rm = TRUE)
# Calculate Sharpe Ratio
sharpe_ratio <- (average_return - average_riskfree) / std_deviation
# Print result
cat("Sharpe Ratio of the 1/N Portfolio:", round(sharpe_ratio, 4), "\n")
## Sharpe Ratio of the 1/N Portfolio: 0.1672
# Annualize the average risk-free rate
annual_riskfree <- (1 + average_riskfree)^12 - 1
# Calculate annual Sharpe Ratio
annual_sharpe_ratio <- (annual_return - annual_riskfree) / annual_std_deviation
# Print result
cat("Annualized Sharpe Ratio:", round(annual_sharpe_ratio, 4), "\n")
## Annualized Sharpe Ratio: 0.6098
# Convert portfolio returns to xts object
portfolio_xts <- xts(full_data$Portfolio_1N, order.by = full_data$Date)
# Use average risk-free rate as the minimum acceptable return (MAR)
average_riskfree <- mean(full_data$RiskFreeRate, na.rm = TRUE)
# Calculate U-P Ratio
up_ratio <- UpsidePotentialRatio(portfolio_xts, MAR = average_riskfree)
# Print result
cat("Upside-Potential Ratio of the 1/N Portfolio:", round(up_ratio[1,1], 4), "\n")
## Upside-Potential Ratio of the 1/N Portfolio: 0.6384
# === Final Comparison Table: 1/N Portfolio vs S&P 500 (All Time) ===
# Benchmark metrics
avg_return_benchmark <- mean(full_data$MarketReturn, na.rm = TRUE)
sd_benchmark <- sd(full_data$MarketReturn, na.rm = TRUE)
sharpe_benchmark <- (average_return - average_riskfree) / std_deviation
annual_return_benchmark <- (1 + avg_return_benchmark)^12 - 1
annual_sd_benchmark <- sd_benchmark * sqrt(12)
annual_sharpe_benchmark <- (annual_return_benchmark - annual_riskfree) / annual_sd_benchmark
up_benchmark <- UpsidePotentialRatio(xts(full_data$MarketReturn, order.by = full_data$Date), MAR = average_riskfree)[1, 1]
# Create summary table
comparison_table <- data.frame(
Metric = c("Average Monthly Return", "Standard Deviation (Monthly)", "Sharpe Ratio (Monthly)",
"Upside-Potential Ratio", "Annual Return", "Annual Std Dev", "Annual Sharpe Ratio"),
`1/N Portfolio` = c(round(average_return, 6), round(std_deviation, 6), round(sharpe_ratio, 4),
round(up_ratio[1,1], 4), round(annual_return, 6), round(annual_std_deviation, 6),
round(annual_sharpe_ratio, 4)),
`S&P 500 Benchmark` = c(round(avg_return_benchmark, 6), round(sd_benchmark, 6), round(sharpe_benchmark, 4),
round(up_benchmark, 4), round(annual_return_benchmark, 6), round(annual_sd_benchmark, 6),
round(annual_sharpe_benchmark, 4))
)
# Show table
knitr::kable(comparison_table,
caption = "Performance Metrics: 1/N Portfolio vs S&P 500 (All Time)")
Performance Metrics: 1/N Portfolio vs S&P 500 (All
Time)
| Average Monthly Return |
0.008135 |
0.007896 |
| Standard Deviation (Monthly) |
0.041426 |
0.044081 |
| Sharpe Ratio (Monthly) |
0.167200 |
0.167200 |
| Upside-Potential Ratio |
0.638400 |
0.594800 |
| Annual Return |
0.102111 |
0.098972 |
| Annual Std Dev |
0.143503 |
0.152702 |
| Annual Sharpe Ratio |
0.609800 |
0.552500 |
1/N Portfolio Backtest (Last 36 Months)
# Filtrar solo los últimos 36 meses (desde marzo 2021)
start_date <- as.Date("2021-03-01")
full_data_3y <- full_data %>% filter(Date >= start_date)
# Seleccionar columnas de activos
asset_names <- colnames(full_data_3y)[!(colnames(full_data_3y) %in% c("Date", "MarketReturn", "RiskFreeRate"))]
# Calcular portafolio 1/N solo para los últimos 36 meses
portfolio_1N_3y <- full_data_3y %>%
select(all_of(asset_names)) %>%
rowMeans(na.rm = TRUE)
# Agregarlo al data frame
full_data_3y$Portfolio_1N <- portfolio_1N_3y
# Convertir a xts
portfolio_xts_3y <- xts(full_data_3y$Portfolio_1N, order.by = full_data_3y$Date)
# Graficar
chart.CumReturns(portfolio_xts_3y,
main = "Cumulative Return of the 1/N Portfolio (Last 36 Months)",
ylab = "Growth of $1",
wealth.index = TRUE)

# Benchmark en mismo periodo
benchmark_xts_3y <- xts(full_data_3y$MarketReturn, order.by = full_data_3y$Date)
# Merge
comparison_xts <- merge(portfolio_xts_3y, benchmark_xts_3y)
colnames(comparison_xts) <- c("1/N Portfolio", "Market Benchmark")
# Gráfico comparativo
chart.CumReturns(comparison_xts,
legend.loc = "topleft",
main = "1/N Portfolio vs Market Benchmark (Last 36 Months)",
ylab = "Growth of $1",
wealth.index = TRUE)

# Calcular alpha
excess_portfolio <- full_data_3y$Portfolio_1N - full_data_3y$RiskFreeRate
excess_market <- full_data_3y$MarketReturn - full_data_3y$RiskFreeRate
model <- lm(excess_portfolio ~ excess_market)
jensen_alpha <- coef(model)[1]
cat("Jensen's Alpha:", round(jensen_alpha, 6), "\n")
## Jensen's Alpha: -0.002852
# Retorno promedio y desviación estándar
average_return <- mean(full_data_3y$Portfolio_1N, na.rm = TRUE)
std_deviation <- sd(full_data_3y$Portfolio_1N, na.rm = TRUE)
# Anualización
annual_return <- (1 + average_return)^12 - 1
annual_std_dev <- std_deviation * sqrt(12)
cat("Annualized Return:", round(annual_return, 6), "\n")
## Annualized Return: 0.071176
cat("Annualized Std Dev:", round(annual_std_dev, 6), "\n")
## Annualized Std Dev: 0.161457
# Sharpe Ratio
avg_rf <- mean(full_data_3y$RiskFreeRate)
annual_rf <- (1 + avg_rf)^12 - 1
sharpe <- (annual_return - annual_rf) / annual_std_dev
cat("Annual Sharpe Ratio:", round(sharpe, 4), "\n")
## Annual Sharpe Ratio: 0.2709
# U-P Ratio
portfolio_xts_3y <- xts(full_data_3y$Portfolio_1N, order.by = full_data_3y$Date)
up_ratio <- UpsidePotentialRatio(portfolio_xts_3y, MAR = avg_rf)
cat("Upside-Potential Ratio:", round(up_ratio[1,1], 4), "\n")
## Upside-Potential Ratio: 0.6733
# === Performance Metrics: Last 36 Months ===
# Risk-free rate for last 36 months
rf_3y <- mean(full_data_3y$RiskFreeRate, na.rm = TRUE)
# 1/N Portfolio metrics (36 months)
avg_return_1n_3y <- mean(full_data_3y$Portfolio_1N, na.rm = TRUE)
sd_1n_3y <- sd(full_data_3y$Portfolio_1N, na.rm = TRUE)
sharpe_1n_3y <- (avg_return_1n_3y - rf_3y) / sd_1n_3y
xts_1n_3y <- xts(full_data_3y$Portfolio_1N, order.by = full_data_3y$Date)
up_1n_3y <- UpsidePotentialRatio(xts_1n_3y, MAR = rf_3y)[1, 1]
# Benchmark metrics (36 months)
avg_return_benchmark_3y <- mean(full_data_3y$MarketReturn, na.rm = TRUE)
sd_benchmark_3y <- sd(full_data_3y$MarketReturn, na.rm = TRUE)
sharpe_benchmark_3y <- (avg_return_benchmark_3y - rf_3y) / sd_benchmark_3y
xts_benchmark_3y <- xts(full_data_3y$MarketReturn, order.by = full_data_3y$Date)
up_benchmark_3y <- UpsidePotentialRatio(xts_benchmark_3y, MAR = rf_3y)[1, 1]
# Annualized metrics
annual_return_1n_3y <- (1 + avg_return_1n_3y)^12 - 1
annual_sd_1n_3y <- sd_1n_3y * sqrt(12)
annual_rf_3y <- (1 + rf_3y)^12 - 1
annual_sharpe_1n_3y <- (annual_return_1n_3y - annual_rf_3y) / annual_sd_1n_3y
annual_return_benchmark_3y <- (1 + avg_return_benchmark_3y)^12 - 1
annual_sd_benchmark_3y <- sd_benchmark_3y * sqrt(12)
annual_sharpe_benchmark_3y <- (annual_return_benchmark_3y - annual_rf_3y) / annual_sd_benchmark_3y
# Create updated summary table with annualized metrics
comparison_table_3y <- data.frame(
Metric = c("Average Monthly Return", "Standard Deviation (Monthly)", "Sharpe Ratio (Monthly)", "Upside-Potential Ratio",
"Annual Return", "Annual Standard Deviation", "Sharpe Ratio (Annual)"),
`1/N Portfolio (36M)` = c(round(avg_return_1n_3y, 6), round(sd_1n_3y, 6), round(sharpe_1n_3y, 4), round(up_1n_3y, 4),
round(annual_return_1n_3y, 6), round(annual_sd_1n_3y, 6), round(annual_sharpe_1n_3y, 4)),
`S&P 500 Benchmark (36M)` = c(round(avg_return_benchmark_3y, 6), round(sd_benchmark_3y, 6), round(sharpe_benchmark_3y, 4), round(up_benchmark_3y, 4),
round(annual_return_benchmark_3y, 6), round(annual_sd_benchmark_3y, 6), round(annual_sharpe_benchmark_3y, 4))
)
# Display the updated table
knitr::kable(comparison_table_3y, caption = "Performance Metrics (Last 36 Months): 1/N Portfolio vs S&P 500")
Performance Metrics (Last 36 Months): 1/N Portfolio vs S&P
500
| Average Monthly Return |
0.005746 |
0.009377 |
| Standard Deviation (Monthly) |
0.046609 |
0.051021 |
| Sharpe Ratio (Monthly) |
0.074800 |
0.139500 |
| Upside-Potential Ratio |
0.673300 |
0.746500 |
| Annual Return |
0.071176 |
0.118513 |
| Annual Standard Deviation |
0.161457 |
0.176741 |
| Sharpe Ratio (Annual) |
0.270900 |
0.515300 |
“Port 2 Eq.Weight Jensenn Alpha”
library(readxl)
library(dplyr)
library(tibble)
library(PerformanceAnalytics)
data_prices <- read_excel("data.xlsx")
## New names:
## • `` -> `...1`
data_market <- read_excel("Data2.xlsx")
## New names:
## • `` -> `...1`
# Asegurar formato de fecha
data_prices[[1]] <- as.Date(data_prices[[1]])
data_market[[1]] <- as.Date(data_market[[1]])
# Renombrar columnas para facilitar el uso
colnames(data_market)[2:4] <- c("SP500_Price", "SP500_TotalReturn", "RiskFree")
# Calcular retornos logarítmicos
returns_assets <- data_prices %>%
arrange(data_prices[[1]]) %>%
mutate(across(-1, ~ log(. / lag(.)))) %>%
slice(-1) # eliminar el primer NA
returns_market <- data_market %>%
arrange(data_market[[1]]) %>%
mutate(
MarketReturn = log(SP500_TotalReturn / lag(SP500_TotalReturn)),
RiskFreeRate = log(1 + RiskFree / 100 / 12) # aproximando mensual
) %>%
select(Date = 1, MarketReturn, RiskFreeRate) %>%
slice(-1)
# Combinar fechas con retornos de activos
returns_assets <- rename(returns_assets, Date = 1)
# Unir datasets
full_data <- inner_join(returns_assets, returns_market, by = "Date")
# Crear una función para calcular Jensen's alpha
calcular_alpha <- function(retorno_activo, retorno_mercado, riesgo_libre) {
exceso_retorno_activo <- retorno_activo - riesgo_libre
exceso_retorno_mercado <- retorno_mercado - riesgo_libre
modelo <- lm(exceso_retorno_activo ~ exceso_retorno_mercado)
alpha <- coef(modelo)[1]
return(alpha)
}
# Aplicar a cada activo (excepto las columnas de fecha, MarketReturn y RiskFreeRate)
nombres_activos <- colnames(full_data)[!(colnames(full_data) %in% c("Date", "MarketReturn", "RiskFreeRate"))]
alphas <- sapply(nombres_activos, function(nombre_activo) {
calcular_alpha(
retorno_activo = full_data[[nombre_activo]],
retorno_mercado = full_data$MarketReturn,
riesgo_libre = full_data$RiskFreeRate
)
})
# Convertir a data frame para ordenarlo
tabla_alphas <- data.frame(Asset = nombres_activos, JensenAlpha = alphas)
tabla_alphas <- tabla_alphas %>%
filter(JensenAlpha > 0) %>%
arrange(desc(JensenAlpha))
# Mostrar los 10 mejores
top_10 <- head(tabla_alphas, 10)
print(top_10)
## Asset JensenAlpha
## NETFLIX.(Intercept) NETFLIX 0.017002618
## NVIDIA.(Intercept) NVIDIA 0.013335182
## APPLE.(Intercept) APPLE 0.012637688
## AMAZON.COM.(Intercept) AMAZON.COM 0.009879615
## SALESFORCE.(Intercept) SALESFORCE 0.007986925
## ELI LILLY.(Intercept) ELI LILLY 0.006481438
## ALPHABET A.(Intercept) ALPHABET A 0.006320645
## COSTCO WHOLESALE.(Intercept) COSTCO WHOLESALE 0.005679584
## THERMO FISHER SCIENTIFIC.(Intercept) THERMO FISHER SCIENTIFIC 0.005536472
## AMERICAN TOWER.(Intercept) AMERICAN TOWER 0.004911322
# Extraer solo los nombres de los top 10 activos
top_10_nombres <- top_10$Asset
# Filtrar las columnas de esos activos en el full_data
retornos_top10 <- full_data %>%
select(all_of(top_10_nombres))
# Calcular el rendimiento promedio (igualmente ponderado) en cada periodo
portafolio_igual <- rowMeans(retornos_top10, na.rm = TRUE)
# Agregar columna al full_data
full_data$EqualWeightedPortfolio <- portafolio_igual
# Ver primeros valores
head(full_data[, c("Date", "EqualWeightedPortfolio")])
## # A tibble: 6 × 2
## Date EqualWeightedPortfolio
## <date> <dbl>
## 1 2005-01-31 -0.0235
## 2 2005-02-28 0.0173
## 3 2005-03-31 -0.0608
## 4 2005-04-29 -0.00969
## 5 2005-05-31 0.139
## 6 2005-06-30 0.0161
# Crear xts del portafolio para usar funciones de PerformanceAnalytics
portafolio_xts <- xts(full_data$EqualWeightedPortfolio, order.by = full_data$Date)
# Rendimiento acumulado
chart.CumReturns(portafolio_xts, main = "Cumulative Return of the Portfolio", wealth.index = TRUE, ylab = "Growth of $1")

# Crear xts para benchmark también
benchmark_xts <- xts(full_data$MarketReturn, order.by = full_data$Date)
# Juntar ambos en un solo objeto
compare_xts <- merge(portafolio_xts, benchmark_xts)
colnames(compare_xts) <- c("Portafolio", "Benchmark")
# Gráfica de rendimientos acumulados
chart.CumReturns(compare_xts, legend.loc = "topleft", main = "Portfolio vs Benchmark Compariso", wealth.index = TRUE, ylab = "Growth of $1")

# Calcular Jensen's alpha del portafolio frente al benchmark
exceso_portafolio <- full_data$EqualWeightedPortfolio - full_data$RiskFreeRate
exceso_mercado <- full_data$MarketReturn - full_data$RiskFreeRate
modelo_portafolio <- lm(exceso_portafolio ~ exceso_mercado)
alpha_portafolio <- coef(modelo_portafolio)[1]
cat("Jensen's alpha of the equally weighted portfolio:", round(alpha_portafolio, 6), "\n")
## Jensen's alpha of the equally weighted portfolio: 0.008977
# Promedio y desviación estándar mensual del portafolio
avg_return <- mean(full_data$EqualWeightedPortfolio, na.rm = TRUE)
std_dev <- sd(full_data$EqualWeightedPortfolio, na.rm = TRUE)
cat("Average monthly return:", round(avg_return, 6), "\n")
## Average monthly return: 0.017198
cat("Monthly standard deviation:", round(std_dev, 6), "\n")
## Monthly standard deviation: 0.058469
# Promedio del risk-free rate
avg_riskfree <- mean(full_data$RiskFreeRate, na.rm = TRUE)
# Sharpe ratio
sharpe_ratio <- (avg_return - avg_riskfree) / std_dev
cat("Sharpe Ratio:", round(sharpe_ratio, 4), "\n")
## Sharpe Ratio: 0.2735
# Crear xts del portafolio para usar UpsidePotentialRatio
portafolio_xts <- # Convertir el portafolio en objeto xts si no lo hiciste aún
portafolio_xts <- xts(full_data$EqualWeightedPortfolio, order.by = full_data$Date)
# Calcular la tasa libre de riesgo promedio mensual
avg_riskfree <- mean(full_data$RiskFreeRate, na.rm = TRUE)
# Calcular el Upside-Potential Ratio
up_ratio <- UpsidePotentialRatio(portafolio_xts, MAR = avg_riskfree)
# Mostrar resultado
cat("Upside-Potential Ratio:", round(up_ratio[1,1], 4), "\n")
## Upside-Potential Ratio: 0.7181
# Metrics for Equal Weighted Top 10 Jensen Alpha Portfolio
avg_return_eqw <- mean(full_data$EqualWeightedPortfolio, na.rm = TRUE)
sd_eqw <- sd(full_data$EqualWeightedPortfolio, na.rm = TRUE)
rf_total <- mean(full_data$RiskFreeRate, na.rm = TRUE)
sharpe_eqw <- (avg_return_eqw - rf_total) / sd_eqw
xts_eqw <- xts(full_data$EqualWeightedPortfolio, order.by = full_data$Date)
up_eqw <- UpsidePotentialRatio(xts_eqw, MAR = rf_total)[1, 1]
# Metrics for Market Benchmark
avg_return_bench <- mean(full_data$MarketReturn, na.rm = TRUE)
sd_bench <- sd(full_data$MarketReturn, na.rm = TRUE)
sharpe_bench <- (avg_return_bench - rf_total) / sd_bench
xts_bench <- xts(full_data$MarketReturn, order.by = full_data$Date)
up_bench <- UpsidePotentialRatio(xts_bench, MAR = rf_total)[1, 1]
# Annualized metrics
annual_return_eqw <- (1 + avg_return_eqw)^12 - 1
annual_sd_eqw <- sd_eqw * sqrt(12)
annual_sharpe_eqw <- (annual_return_eqw - ((1 + rf_total)^12 - 1)) / annual_sd_eqw
annual_return_bench <- (1 + avg_return_bench)^12 - 1
annual_sd_bench <- sd_bench * sqrt(12)
annual_sharpe_bench <- (annual_return_bench - ((1 + rf_total)^12 - 1)) / annual_sd_bench
# Extended summary table
performance_summary <- data.frame(
Metric = c("Average Monthly Return", "Standard Deviation (Monthly)", "Sharpe Ratio (Monthly)", "Upside-Potential Ratio",
"Annualized Return", "Annualized Std Dev", "Sharpe Ratio (Annual)"),
`Top 10 Jensen Alpha` = c(round(avg_return_eqw, 6), round(sd_eqw, 6), round(sharpe_eqw, 4), round(up_eqw, 4),
round(annual_return_eqw, 6), round(annual_sd_eqw, 6), round(annual_sharpe_eqw, 4)),
`S&P 500 Benchmark` = c(round(avg_return_bench, 6), round(sd_bench, 6), round(sharpe_bench, 4), round(up_bench, 4),
round(annual_return_bench, 6), round(annual_sd_bench, 6), round(annual_sharpe_bench, 4))
)
# Display table
knitr::kable(performance_summary, caption = "Performance Metrics: Jensen Alpha Portfolio vs S&P 500 (Full Sample)")
Performance Metrics: Jensen Alpha Portfolio vs S&P 500
(Full Sample)
| Average Monthly Return |
0.017198 |
0.007896 |
| Standard Deviation (Monthly) |
0.058469 |
0.044081 |
| Sharpe Ratio (Monthly) |
0.273500 |
0.151700 |
| Upside-Potential Ratio |
0.718100 |
0.594800 |
| Annualized Return |
0.227058 |
0.098972 |
| Annualized Std Dev |
0.202544 |
0.152702 |
| Sharpe Ratio (Annual) |
1.048900 |
0.552500 |
“2: Last 36 Months - Eq.Weight Jensenn Alpha Last 36 Months”
# Filter last 36 months
start_date <- max(full_data$Date) %m-% months(36)
full_data_36m <- full_data %>% filter(Date >= start_date)
# Recalculate Jensen's alpha using only last 36 months
alphas_36m <- sapply(nombres_activos, function(asset) {
calcular_alpha(
retorno_activo = full_data_36m[[asset]],
retorno_mercado = full_data_36m$MarketReturn,
riesgo_libre = full_data_36m$RiskFreeRate
)
})
# Create and sort alpha table
alpha_table_36m <- data.frame(Asset = nombres_activos, JensenAlpha = alphas_36m) %>%
filter(JensenAlpha > 0) %>%
arrange(desc(JensenAlpha))
# Select top 10
top_10_36m <- head(alpha_table_36m, 10)
top_10_names_36m <- top_10_36m$Asset
# Calculate equally weighted portfolio using top 10
returns_top10_36m <- full_data_36m %>% select(all_of(top_10_names_36m))
equal_weighted_36m <- rowMeans(returns_top10_36m, na.rm = TRUE)
full_data_36m$EqualWeightedPortfolio <- equal_weighted_36m
# Create xts objects
portfolio_xts_36m <- xts(full_data_36m$EqualWeightedPortfolio, order.by = full_data_36m$Date)
benchmark_xts_36m <- xts(full_data_36m$MarketReturn, order.by = full_data_36m$Date)
# Plot cumulative return of the portfolio
chart.CumReturns(portfolio_xts_36m,
main = "Cumulative Return: Top 10 Jensen Alpha Portfolio (Last 36 Months)",
ylab = "Growth of $1",
wealth.index = TRUE)

# Compare with benchmark
compare_36m <- merge(portfolio_xts_36m, benchmark_xts_36m)
colnames(compare_36m) <- c("Equal Weighted Top 10", "Market Benchmark")
chart.CumReturns(compare_36m,
legend.loc = "topleft",
main = "Top 10 Jensen Alpha Portfolio vs Market (Last 36 Months)",
ylab = "Growth of $1",
wealth.index = TRUE)

# Calculate metrics for Top 10 Jensen Alpha portfolio
avg_return_top10 <- mean(full_data_36m$EqualWeightedPortfolio, na.rm = TRUE)
sd_top10 <- sd(full_data_36m$EqualWeightedPortfolio, na.rm = TRUE)
rf_36m <- mean(full_data_36m$RiskFreeRate, na.rm = TRUE)
sharpe_top10 <- (avg_return_top10 - rf_36m) / sd_top10
up_top10 <- UpsidePotentialRatio(portfolio_xts_36m, MAR = rf_36m)[1,1]
# Calculate metrics for S&P 500
avg_return_sp500 <- mean(full_data_36m$MarketReturn, na.rm = TRUE)
sd_sp500 <- sd(full_data_36m$MarketReturn, na.rm = TRUE)
sharpe_sp500 <- (avg_return_sp500 - rf_36m) / sd_sp500
benchmark_xts_36m <- xts(full_data_36m$MarketReturn, order.by = full_data_36m$Date)
up_sp500 <- UpsidePotentialRatio(benchmark_xts_36m, MAR = rf_36m)[1,1]
# Annualized metrics for Top 10 Jensen Alpha Portfolio
annual_return_top10 <- (1 + avg_return_top10)^12 - 1
annual_sd_top10 <- sd_top10 * sqrt(12)
annual_sharpe_top10 <- (annual_return_top10 - ((1 + rf_36m)^12 - 1)) / annual_sd_top10
# Annualized metrics for S&P 500
annual_return_sp500 <- (1 + avg_return_sp500)^12 - 1
annual_sd_sp500 <- sd_sp500 * sqrt(12)
annual_sharpe_sp500 <- (annual_return_sp500 - ((1 + rf_36m)^12 - 1)) / annual_sd_sp500
# Updated summary table
performance_comparison <- data.frame(
Metric = c("Average Monthly Return", "Standard Deviation (Monthly)", "Sharpe Ratio (Monthly)", "Upside-Potential Ratio",
"Annualized Return", "Annualized Std Dev", "Sharpe Ratio (Annual)"),
`Top 10 Jensen Alpha` = c(round(avg_return_top10, 6), round(sd_top10, 6), round(sharpe_top10, 4), round(up_top10, 4),
round(annual_return_top10, 6), round(annual_sd_top10, 6), round(annual_sharpe_top10, 4)),
`S&P 500 Benchmark` = c(round(avg_return_sp500, 6), round(sd_sp500, 6), round(sharpe_sp500, 4), round(up_sp500, 4),
round(annual_return_sp500, 6), round(annual_sd_sp500, 6), round(annual_sharpe_sp500, 4))
)
# Display the table
knitr::kable(performance_comparison, caption = "Performance Comparison: Top 10 Jensen Alpha Portfolio vs S&P 500 (Last 36 Months)")
Performance Comparison: Top 10 Jensen Alpha Portfolio vs
S&P 500 (Last 36 Months)
| Average Monthly Return |
0.020983 |
0.009377 |
| Standard Deviation (Monthly) |
0.049665 |
0.051021 |
| Sharpe Ratio (Monthly) |
0.377000 |
0.139500 |
| Upside-Potential Ratio |
1.058700 |
0.746500 |
| Annualized Return |
0.282990 |
0.118513 |
| Annualized Std Dev |
0.172044 |
0.176741 |
| Sharpe Ratio (Annual) |
1.485400 |
0.515300 |
3: “Long-Short Portfolio Based on Jensen’s Alpha Ranking”
# Data handling
library(readxl)
library(dplyr)
library(tibble)
# Financial performance and time series
library(PerformanceAnalytics)
library(xts)
# Define a function to calculate Jensen’s alpha
calculate_alpha <- function(asset_return, market_return, risk_free) {
excess_asset <- asset_return - risk_free
excess_market <- market_return - risk_free
model <- lm(excess_asset ~ excess_market)
return(coef(model)[1]) # Alpha
}
# Get stock column names
stock_names <- colnames(full_data)[!(colnames(full_data) %in% c("Date", "MarketReturn", "RiskFreeRate", "Portfolio_1N"))]
# Calculate alpha for each stock
alphas <- sapply(stock_names, function(name) {
calculate_alpha(full_data[[name]], full_data$MarketReturn, full_data$RiskFreeRate)
})
# Create data frame with results
alpha_table <- data.frame(Stock = stock_names, Alpha = alphas)
# Sort and filter
alpha_table <- alpha_table %>%
arrange(desc(Alpha))
# Preview
head(alpha_table)
## Stock Alpha
## NETFLIX.(Intercept) NETFLIX 0.017002618
## NVIDIA.(Intercept) NVIDIA 0.013335182
## APPLE.(Intercept) APPLE 0.012637688
## AMAZON.COM.(Intercept) AMAZON.COM 0.009879615
## EqualWeightedPortfolio.(Intercept) EqualWeightedPortfolio 0.008977149
## SALESFORCE.(Intercept) SALESFORCE 0.007986925
# Filter top 5 positive alpha stocks (long positions)
long_stocks <- alpha_table %>%
filter(Alpha > 0) %>%
slice_max(order_by = Alpha, n = 5)
# Filter bottom 5 negative alpha stocks (short positions)
short_stocks <- alpha_table %>%
filter(Alpha < 0) %>%
slice_min(order_by = Alpha, n = 5)
# Get return series for long and short groups
returns_long <- full_data %>%
select(all_of(long_stocks$Stock))
returns_short <- full_data %>%
select(all_of(short_stocks$Stock))
# Calculate average return per period
long_avg <- rowMeans(returns_long, na.rm = TRUE)
short_avg <- rowMeans(returns_short, na.rm = TRUE)
# Long-short portfolio return
long_short_return <- long_avg - short_avg
# Add to dataset
full_data$LongShort_Portfolio <- long_short_return
# Convert to xts
longshort_xts <- xts(full_data$LongShort_Portfolio, order.by = full_data$Date)
# Set months in English
Sys.setlocale("LC_TIME", "C")
## [1] "C"
# Plot
chart.CumReturns(longshort_xts,
main = "Cumulative Return of Long-Short Portfolio",
ylab = "Growth of $1",
wealth.index = TRUE)

# Convert market returns to xts
benchmark_xts <- xts(full_data$MarketReturn, order.by = full_data$Date)
# Combine long-short and benchmark into one xts object
compare_ls_vs_benchmark <- merge(longshort_xts, benchmark_xts)
colnames(compare_ls_vs_benchmark) <- c("Long-Short Portfolio", "Market Benchmark")
# Plot cumulative performance
chart.CumReturns(compare_ls_vs_benchmark,
legend.loc = "topleft",
main = "Long-Short Portfolio vs Market Benchmark",
ylab = "Growth of $1",
wealth.index = TRUE)

# Excess returns
excess_longshort <- full_data$LongShort_Portfolio - full_data$RiskFreeRate
excess_market <- full_data$MarketReturn - full_data$RiskFreeRate
# Linear regression
model_ls <- lm(excess_longshort ~ excess_market)
alpha_ls <- coef(model_ls)[1]
cat("Jensen's Alpha (Long-Short):", round(alpha_ls, 6), "\n")
## Jensen's Alpha (Long-Short): 0.022659
avg_return_ls <- mean(full_data$LongShort_Portfolio, na.rm = TRUE)
sd_return_ls <- sd(full_data$LongShort_Portfolio, na.rm = TRUE)
annual_return_ls <- (1 + avg_return_ls)^12 - 1
annual_sd_ls <- sd_return_ls * sqrt(12)
cat("Annualized Return (Long-Short):", round(annual_return_ls, 6), "\n")
## Annualized Return (Long-Short): 0.324029
cat("Annualized Std Dev (Long-Short):", round(annual_sd_ls, 6), "\n")
## Annualized Std Dev (Long-Short): 0.313351
avg_rf <- mean(full_data$RiskFreeRate, na.rm = TRUE)
annual_rf <- (1 + avg_rf)^12 - 1
sharpe_ls <- (annual_return_ls - annual_rf) / annual_sd_ls
cat("Annualized Sharpe Ratio (Long-Short):", round(sharpe_ls, 4), "\n")
## Annualized Sharpe Ratio (Long-Short): 0.9875
up_ratio_ls <- UpsidePotentialRatio(longshort_xts, MAR = avg_rf)
cat("Upside-Potential Ratio (Long-Short):", round(up_ratio_ls[1,1], 4), "\n")
## Upside-Potential Ratio (Long-Short): 0.8322
# Metrics for S&P 500 Benchmark (full sample)
benchmark_xts <- xts(full_data$MarketReturn, order.by = full_data$Date)
avg_return_benchmark <- mean(full_data$MarketReturn, na.rm = TRUE)
sd_benchmark <- sd(full_data$MarketReturn, na.rm = TRUE)
annual_return_benchmark <- (1 + avg_return_benchmark)^12 - 1
annual_sd_benchmark <- sd_benchmark * sqrt(12)
sharpe_benchmark <- (annual_return_benchmark - annual_rf) / annual_sd_benchmark
up_benchmark <- UpsidePotentialRatio(benchmark_xts, MAR = avg_rf)[1, 1]
# Create summary table
performance_table_ls <- data.frame(
Metric = c("Average Monthly Return", "Standard Deviation (Monthly)", "Sharpe Ratio (Monthly)", "Upside-Potential Ratio",
"Annualized Return", "Annualized Std Dev", "Sharpe Ratio (Annual)"),
`Long-Short Portfolio` = c(round(avg_return_ls, 6), round(sd_return_ls, 6),
round((avg_return_ls - avg_rf) / sd_return_ls, 4),
round(up_ratio_ls[1,1], 4),
round(annual_return_ls, 6), round(annual_sd_ls, 6), round(sharpe_ls, 4)),
`S&P 500 Benchmark` = c(round(avg_return_benchmark, 6), round(sd_benchmark, 6),
round((avg_return_benchmark - avg_rf) / sd_benchmark, 4),
round(up_benchmark, 4),
round(annual_return_benchmark, 6), round(annual_sd_benchmark, 6), round(sharpe_benchmark, 4))
)
# Display table
knitr::kable(performance_table_ls, caption = "Performance Metrics: Long-Short Jensen Alpha Portfolio vs S&P 500 (Full Sample)")
Performance Metrics: Long-Short Jensen Alpha Portfolio vs
S&P 500 (Full Sample)
| Average Monthly Return |
0.023666 |
0.007896 |
| Standard Deviation (Monthly) |
0.090457 |
0.044081 |
| Sharpe Ratio (Monthly) |
0.248300 |
0.151700 |
| Upside-Potential Ratio |
0.832200 |
0.594800 |
| Annualized Return |
0.324029 |
0.098972 |
| Annualized Std Dev |
0.313351 |
0.152702 |
| Sharpe Ratio (Annual) |
0.987500 |
0.552500 |
3: Last 36 Months - “Long-Short Portfolio Based on Jensen’s Alpha
Ranking”
# Filtrar los últimos 36 meses
start_date <- as.Date("2021-03-01")
full_data_3y <- full_data %>% filter(Date >= start_date)
# Obtener nombres de las acciones
stock_names <- colnames(full_data_3y)[!(colnames(full_data_3y) %in% c("Date", "MarketReturn", "RiskFreeRate", "Portfolio_1N", "LongShort_Portfolio"))]
# Calcular alpha para cada acción
alphas <- sapply(stock_names, function(name) {
calculate_alpha(full_data_3y[[name]], full_data_3y$MarketReturn, full_data_3y$RiskFreeRate)
})
# Crear tabla ordenada
alpha_table <- data.frame(Stock = stock_names, Alpha = alphas) %>%
arrange(desc(Alpha))
# Top 5 alpha positivo (long)
long_stocks <- alpha_table %>%
filter(Alpha > 0) %>%
slice_max(order_by = Alpha, n = 5)
# Bottom 5 alpha negativo (short)
short_stocks <- alpha_table %>%
filter(Alpha < 0) %>%
slice_min(order_by = Alpha, n = 5)
# Seleccionar retornos
returns_long <- full_data_3y %>% select(all_of(long_stocks$Stock))
returns_short <- full_data_3y %>% select(all_of(short_stocks$Stock))
# Calcular retornos promedio y retorno Long-Short
long_avg <- rowMeans(returns_long, na.rm = TRUE)
short_avg <- rowMeans(returns_short, na.rm = TRUE)
long_short_return <- long_avg - short_avg
# Agregar columna al dataset
full_data_3y$LongShort_Portfolio <- long_short_return
longshort_xts <- xts(full_data_3y$LongShort_Portfolio, order.by = full_data_3y$Date)
chart.CumReturns(longshort_xts,
main = "Cumulative Return: Long-Short Portfolio (Last 36 Months)",
ylab = "Growth of $1",
wealth.index = TRUE)

benchmark_xts_3y <- xts(full_data_3y$MarketReturn, order.by = full_data_3y$Date)
compare_ls_vs_benchmark <- merge(longshort_xts, benchmark_xts_3y)
colnames(compare_ls_vs_benchmark) <- c("Long-Short Portfolio", "Market Benchmark")
chart.CumReturns(compare_ls_vs_benchmark,
legend.loc = "topleft",
main = "Long-Short Portfolio vs Market Benchmark (Last 36 Months)",
ylab = "Growth of $1",
wealth.index = TRUE)

# Jensen's Alpha
excess_longshort <- full_data_3y$LongShort_Portfolio - full_data_3y$RiskFreeRate
excess_market <- full_data_3y$MarketReturn - full_data_3y$RiskFreeRate
model_ls <- lm(excess_longshort ~ excess_market)
alpha_ls <- coef(model_ls)[1]
cat("Jensen's Alpha (Long-Short):", round(alpha_ls, 6), "\n")
## Jensen's Alpha (Long-Short): 0.036915
# Retorno y riesgo
avg_return_ls <- mean(full_data_3y$LongShort_Portfolio, na.rm = TRUE)
sd_return_ls <- sd(full_data_3y$LongShort_Portfolio, na.rm = TRUE)
annual_return_ls <- (1 + avg_return_ls)^12 - 1
annual_sd_ls <- sd_return_ls * sqrt(12)
cat("Annualized Return:", round(annual_return_ls, 6), "\n")
## Annualized Return: 0.568798
cat("Annualized Std Dev:", round(annual_sd_ls, 6), "\n")
## Annualized Std Dev: 0.171143
# Sharpe Ratio
avg_rf <- mean(full_data_3y$RiskFreeRate, na.rm = TRUE)
annual_rf <- (1 + avg_rf)^12 - 1
sharpe_ls <- (annual_return_ls - annual_rf) / annual_sd_ls
cat("Annualized Sharpe Ratio:", round(sharpe_ls, 4), "\n")
## Annualized Sharpe Ratio: 3.1632
# U-P Ratio
up_ratio_ls <- UpsidePotentialRatio(longshort_xts, MAR = avg_rf)
cat("Upside-Potential Ratio:", round(up_ratio_ls[1,1], 4), "\n")
## Upside-Potential Ratio: 1.8604
# Recalculate annualized benchmark metrics for 36 months
annual_return_benchmark_3y <- (1 + avg_return_benchmark_3y)^12 - 1
annual_sd_benchmark_3y <- sd_benchmark_3y * sqrt(12)
annual_sharpe_benchmark_3y <- (annual_return_benchmark_3y - annual_rf) / annual_sd_benchmark_3y
# Build summary table with monthly and annual metrics
comparison_table_ls_3y_extended <- data.frame(
Metric = c("Average Monthly Return", "Standard Deviation (Monthly)", "Sharpe Ratio (Monthly)", "Upside-Potential Ratio",
"Annualized Return", "Annualized Std Dev", "Sharpe Ratio (Annual)"),
`Long-Short Portfolio (36M)` = c(round(avg_return_ls, 6), round(sd_return_ls, 6),
round((avg_return_ls - avg_rf) / sd_return_ls, 4),
round(up_ratio_ls[1,1], 4),
round(annual_return_ls, 6), round(annual_sd_ls, 6), round(sharpe_ls, 4)),
`S&P 500 Benchmark (36M)` = c(round(avg_return_benchmark_3y, 6), round(sd_benchmark_3y, 6),
round((avg_return_benchmark_3y - avg_rf) / sd_benchmark_3y, 4),
round(up_benchmark_3y, 4),
round(annual_return_benchmark_3y, 6), round(annual_sd_benchmark_3y, 6), round(annual_sharpe_benchmark_3y, 4))
)
# Display table
knitr::kable(comparison_table_ls_3y_extended,
caption = "Performance Metrics (Last 36 Months): Long-Short Portfolio vs S&P 500 (Monthly & Annualized)")
Performance Metrics (Last 36 Months): Long-Short Portfolio vs
S&P 500 (Monthly & Annualized)
| Average Monthly Return |
0.038239 |
0.009377 |
| Standard Deviation (Monthly) |
0.049405 |
0.051021 |
| Sharpe Ratio (Monthly) |
0.728300 |
0.139500 |
| Upside-Potential Ratio |
1.860400 |
0.746500 |
| Annualized Return |
0.568798 |
0.118513 |
| Annualized Std Dev |
0.171143 |
0.176741 |
| Sharpe Ratio (Annual) |
3.163200 |
0.515300 |
4: “Momentum Portfolio Based on 3-Month Positive Returns”
library(readxl)
library(dplyr)
library(tibble)
library(lubridate) # For working with dates
# Financial analysis
library(PerformanceAnalytics)
library(xts)
# Set the date of the last observation
end_date <- max(full_data$Date)
# Define the start date (3 months before)
start_date <- end_date %m-% months(3)
# Filter only the last 3 months of data
last_3_months_data <- full_data %>%
filter(Date >= start_date & Date <= end_date)
# Select only stock columns
stock_columns <- colnames(full_data)[!(colnames(full_data) %in% c("Date", "MarketReturn", "RiskFreeRate", "Portfolio_1N", "LongShort_Portfolio"))]
# Calculate cumulative return for each stock over the 3-month window
three_month_returns <- colSums(last_3_months_data[, stock_columns], na.rm = TRUE)
# Convert to data frame
momentum_table <- data.frame(Stock = names(three_month_returns),
CumReturn3M = three_month_returns)
# Filter stocks with positive 3-month return
momentum_stocks <- momentum_table %>%
filter(CumReturn3M > 0)
# View top momentum stocks
head(momentum_stocks)
## Stock CumReturn3M
## APPLE APPLE 0.05679724
## MICROSOFT MICROSOFT 0.20162421
## AMAZON.COM AMAZON.COM 0.28376729
## ALPHABET A ALPHABET A 0.10965496
## JOHNSON & JOHNSON JOHNSON & JOHNSON 0.08425490
## WALMART WALMART 0.07325524
# Get names of momentum stocks
momentum_names <- momentum_stocks$Stock
# Extract their return columns from the full dataset
momentum_returns <- full_data %>%
select(all_of(momentum_names))
# Calculate the average return across those stocks (equal weight)
momentum_portfolio_return <- rowMeans(momentum_returns, na.rm = TRUE)
# Add the momentum portfolio to the dataset
full_data$Momentum_Portfolio <- momentum_portfolio_return
# Convert to xts
momentum_xts <- xts(full_data$Momentum_Portfolio, order.by = full_data$Date)
# Set locale to English for month labels
Sys.setlocale("LC_TIME", "C")
## [1] "C"
# Plot cumulative performance
chart.CumReturns(momentum_xts,
main = "Cumulative Return of Momentum Portfolio",
ylab = "Growth of $1",
wealth.index = TRUE)

# Convert market returns to xts
benchmark_xts <- xts(full_data$MarketReturn, order.by = full_data$Date)
# Combine momentum and benchmark returns
compare_momentum_benchmark <- merge(momentum_xts, benchmark_xts)
colnames(compare_momentum_benchmark) <- c("Momentum Portfolio", "Market Benchmark")
# Plot cumulative returns
chart.CumReturns(compare_momentum_benchmark,
legend.loc = "topleft",
main = "Momentum Portfolio vs Market Benchmark",
ylab = "Growth of $1",
wealth.index = TRUE)

# Excess returns
excess_momentum <- full_data$Momentum_Portfolio - full_data$RiskFreeRate
excess_market <- full_data$MarketReturn - full_data$RiskFreeRate
# Linear regression
model_momentum <- lm(excess_momentum ~ excess_market)
alpha_momentum <- coef(model_momentum)[1]
cat("Jensen's Alpha (Momentum Portfolio):", round(alpha_momentum, 6), "\n")
## Jensen's Alpha (Momentum Portfolio): 0.001176
# Monthly metrics
avg_mom <- mean(full_data$Momentum_Portfolio, na.rm = TRUE)
sd_mom <- sd(full_data$Momentum_Portfolio, na.rm = TRUE)
# Annualize
annual_return_mom <- (1 + avg_mom)^12 - 1
annual_sd_mom <- sd_mom * sqrt(12)
cat("Annualized Return:", round(annual_return_mom, 6), "\n")
## Annualized Return: 0.110568
cat("Annualized Std Dev:", round(annual_sd_mom, 6), "\n")
## Annualized Std Dev: 0.150594
avg_rf <- mean(full_data$RiskFreeRate, na.rm = TRUE)
annual_rf <- (1 + avg_rf)^12 - 1
sharpe_momentum <- (annual_return_mom - annual_rf) / annual_sd_mom
cat("Annualized Sharpe Ratio:", round(sharpe_momentum, 4), "\n")
## Annualized Sharpe Ratio: 0.6372
up_ratio_momentum <- UpsidePotentialRatio(momentum_xts, MAR = avg_rf)
cat("Upside-Potential Ratio:", round(up_ratio_momentum[1,1], 4), "\n")
## Upside-Potential Ratio: 0.6812
# === Performance Metrics Table: Momentum Portfolio vs S&P 500 ===
# Benchmark metrics (all time)
avg_return_benchmark <- mean(full_data$MarketReturn, na.rm = TRUE)
sd_benchmark <- sd(full_data$MarketReturn, na.rm = TRUE)
sharpe_benchmark <- (avg_return_benchmark - avg_rf) / sd_benchmark
xts_benchmark <- xts(full_data$MarketReturn, order.by = full_data$Date)
up_benchmark <- UpsidePotentialRatio(xts_benchmark, MAR = avg_rf)[1, 1]
# Recalculate annualized benchmark metrics
annual_return_benchmark <- (1 + avg_return_benchmark)^12 - 1
annual_sd_benchmark <- sd_benchmark * sqrt(12)
annual_sharpe_benchmark <- (annual_return_benchmark - annual_rf) / annual_sd_benchmark
# Extended summary table with annualized metrics
comparison_table_momentum_all_extended <- data.frame(
Metric = c("Average Monthly Return", "Standard Deviation (Monthly)", "Sharpe Ratio (Monthly)", "Upside-Potential Ratio",
"Annualized Return", "Annualized Std Dev", "Sharpe Ratio (Annual)"),
`Momentum Portfolio` = c(round(avg_mom, 6), round(sd_mom, 6),
round((avg_mom - avg_rf) / sd_mom, 4),
round(up_ratio_momentum[1,1], 4),
round(annual_return_mom, 6), round(annual_sd_mom, 6), round(sharpe_momentum, 4)),
`S&P 500 Benchmark` = c(round(avg_return_benchmark, 6), round(sd_benchmark, 6),
round((avg_return_benchmark - avg_rf) / sd_benchmark, 4),
round(up_benchmark, 4),
round(annual_return_benchmark, 6), round(annual_sd_benchmark, 6), round(annual_sharpe_benchmark, 4))
)
# Show the extended table
knitr::kable(comparison_table_momentum_all_extended,
caption = "Performance Metrics: Momentum Portfolio vs S&P 500 (All Time, Monthly & Annualized)")
Performance Metrics: Momentum Portfolio vs S&P 500 (All
Time, Monthly & Annualized)
| Average Monthly Return |
0.008778 |
0.007896 |
| Standard Deviation (Monthly) |
0.043473 |
0.044081 |
| Sharpe Ratio (Monthly) |
0.174100 |
0.151700 |
| Upside-Potential Ratio |
0.681200 |
0.594800 |
| Annualized Return |
0.110568 |
0.098972 |
| Annualized Std Dev |
0.150594 |
0.152702 |
| Sharpe Ratio (Annual) |
0.637200 |
0.552500 |
4: Last 36 Months - “Momentum Portfolio Based on 3-Month Positive
Returns”
start_date <- as.Date("2021-03-01")
full_data_3y <- full_data %>% filter(Date >= start_date)
# Fechas e índices
dates <- full_data_3y$Date
stock_columns <- colnames(full_data_3y)[!(colnames(full_data_3y) %in% c("Date", "MarketReturn", "RiskFreeRate", "Portfolio_1N", "LongShort_Portfolio", "Momentum_Portfolio"))]
n <- nrow(full_data_3y)
# Inicializar vector para guardar retornos del portafolio momentum
momentum_returns <- rep(NA, n)
# Aplicar rolling (cada mes desde el mes 4)
for (i in 4:n) {
# Datos de los 3 meses previos
past_3_months <- full_data_3y[(i - 3):(i - 1), stock_columns]
cum_returns <- colSums(past_3_months, na.rm = TRUE)
# Seleccionar acciones con retorno acumulado positivo
selected <- names(cum_returns[cum_returns > 0])
# Si hay acciones, calcular retorno promedio del siguiente mes
if (length(selected) > 0) {
next_month <- full_data_3y[i, selected]
momentum_returns[i] <- mean(unlist(next_month), na.rm = TRUE)
}
}
# Convertir a xts
momentum_xts_3y <- xts(momentum_returns, order.by = dates)
momentum_xts_3y <- na.omit(momentum_xts_3y)
chart.CumReturns(momentum_xts_3y,
main = "Cumulative Return: 3-Month Momentum Portfolio (Last 36 Months)",
ylab = "Growth of $1",
wealth.index = TRUE)

benchmark_xts_3y <- xts(full_data_3y$MarketReturn, order.by = full_data_3y$Date)
benchmark_xts_3y <- benchmark_xts_3y[index(momentum_xts_3y)]
compare_momentum_benchmark <- merge(momentum_xts_3y, benchmark_xts_3y)
colnames(compare_momentum_benchmark) <- c("Momentum Portfolio", "Market Benchmark")
chart.CumReturns(compare_momentum_benchmark,
legend.loc = "topleft",
main = "Momentum Portfolio vs Market Benchmark (Last 36 Months)",
ylab = "Growth of $1",
wealth.index = TRUE)

# Calcular tasa libre de riesgo alineada
rf_3y <- xts(full_data_3y$RiskFreeRate, order.by = full_data_3y$Date)[index(momentum_xts_3y)]
avg_rf <- mean(rf_3y)
annual_rf <- (1 + avg_rf)^12 - 1
# Jensen's Alpha
excess_mom <- momentum_xts_3y - rf_3y
excess_mkt <- benchmark_xts_3y - rf_3y
alpha_mom <- coef(lm(excess_mom ~ excess_mkt))[1]
# Retorno y desviación estándar
mean_mom <- mean(momentum_xts_3y)
sd_mom <- sd(momentum_xts_3y)
annual_return_mom <- (1 + mean_mom)^12 - 1
annual_sd_mom <- sd_mom * sqrt(12)
# Sharpe Ratio
sharpe_mom <- (annual_return_mom - annual_rf) / annual_sd_mom
# U-P Ratio
up_mom <- UpsidePotentialRatio(momentum_xts_3y, MAR = avg_rf)[1,1]
# Mostrar métricas
cat("Jensen's Alpha:", round(alpha_mom, 6), "\n")
## Jensen's Alpha: -0.000892
cat("Annualized Return:", round(annual_return_mom, 6), "\n")
## Annualized Return: 0.057548
cat("Annualized Std Dev:", round(annual_sd_mom, 6), "\n")
## Annualized Std Dev: 0.138501
cat("Sharpe Ratio:", round(sharpe_mom, 4), "\n")
## Sharpe Ratio: 0.1993
cat("Upside-Potential Ratio:", round(up_mom, 4), "\n")
## Upside-Potential Ratio: 0.7974
# === Performance Metrics Table: Momentum Portfolio vs S&P 500 (Last 36 Months) ===
# Calculate benchmark metrics over same dates
benchmark_returns_mom <- benchmark_xts_3y
rf_total <- mean(rf_3y)
avg_return_benchmark_mom <- mean(benchmark_returns_mom)
sd_benchmark_mom <- sd(benchmark_returns_mom)
sharpe_benchmark_mom <- (avg_return_benchmark_mom - rf_total) / sd_benchmark_mom
up_benchmark_mom <- UpsidePotentialRatio(benchmark_returns_mom, MAR = rf_total)[1, 1]
# Annualized benchmark metrics
annual_return_benchmark_mom <- (1 + avg_return_benchmark_mom)^12 - 1
annual_sd_benchmark_mom <- sd_benchmark_mom * sqrt(12)
annual_sharpe_benchmark_mom <- (annual_return_benchmark_mom - annual_rf) / annual_sd_benchmark_mom
# Extended summary table
comparison_table_mom_3y_extended <- data.frame(
Metric = c("Average Monthly Return", "Standard Deviation (Monthly)", "Sharpe Ratio (Monthly)", "Upside-Potential Ratio",
"Annualized Return", "Annualized Std Dev", "Sharpe Ratio (Annual)"),
`Momentum Portfolio (36M)` = c(round(mean_mom, 6), round(sd_mom, 6),
round((mean_mom - avg_rf) / sd_mom, 4),
round(up_mom, 4),
round(annual_return_mom, 6), round(annual_sd_mom, 6), round(sharpe_mom, 4)),
`S&P 500 Benchmark (36M)` = c(round(avg_return_benchmark_mom, 6), round(sd_benchmark_mom, 6),
round((avg_return_benchmark_mom - avg_rf) / sd_benchmark_mom, 4),
round(up_benchmark_mom, 4),
round(annual_return_benchmark_mom, 6), round(annual_sd_benchmark_mom, 6), round(annual_sharpe_benchmark_mom, 4))
)
# Show table
knitr::kable(comparison_table_mom_3y_extended, caption = "Performance Metrics (Last 36 Months): Momentum Portfolio vs S&P 500 (Monthly and Annualized)")
Performance Metrics (Last 36 Months): Momentum Portfolio vs
S&P 500 (Monthly and Annualized)
| Average Monthly Return |
0.004674 |
0.007144 |
| Standard Deviation (Monthly) |
0.039982 |
0.052441 |
| Sharpe Ratio (Monthly) |
0.055300 |
0.089300 |
| Upside-Potential Ratio |
0.797400 |
0.768000 |
| Annualized Return |
0.057548 |
0.089180 |
| Annualized Std Dev |
0.138501 |
0.181661 |
| Sharpe Ratio (Annual) |
0.199300 |
0.326100 |
5: “Long-Short Momentum Portfolio Based on 3-Month Returns”
# Data reading and manipulation
library(readxl)
library(dplyr)
library(tibble)
library(lubridate)
# Financial performance analysis
library(PerformanceAnalytics)
library(xts)
# Define the end and start dates for the 3-month window
end_date <- max(full_data$Date)
start_date <- end_date %m-% months(3)
# Filter last 3 months of data
last_3_months_data <- full_data %>%
filter(Date >= start_date & Date <= end_date)
# Get stock column names (exclude benchmark and portfolio columns)
stock_cols <- colnames(full_data)[!(colnames(full_data) %in% c("Date", "MarketReturn", "RiskFreeRate",
"Portfolio_1N", "LongShort_Portfolio", "Momentum_Portfolio"))]
# Calculate cumulative return for each stock over 3 months
cum_returns_3m <- colSums(last_3_months_data[, stock_cols], na.rm = TRUE)
# Create a table
momentum_signal <- data.frame(Stock = names(cum_returns_3m),
Return3M = cum_returns_3m)
# Split into long (positive) and short (negative) groups
long_stocks <- momentum_signal %>% filter(Return3M > 0)
short_stocks <- momentum_signal %>% filter(Return3M < 0)
# Extract returns for long and short stocks
returns_long <- full_data %>%
select(all_of(long_stocks$Stock))
returns_short <- full_data %>%
select(all_of(short_stocks$Stock))
# Calculate average return per group
long_avg <- rowMeans(returns_long, na.rm = TRUE)
short_avg <- rowMeans(returns_short, na.rm = TRUE)
# Long-Short Momentum Portfolio return
momentum_ls_return <- long_avg - short_avg
# Add to dataset
full_data$Momentum_LongShort <- momentum_ls_return
# Convert to xts
momentum_ls_xts <- xts(full_data$Momentum_LongShort, order.by = full_data$Date)
# Set English month labels
Sys.setlocale("LC_TIME", "C")
## [1] "C"
# Plot cumulative returns
chart.CumReturns(momentum_ls_xts,
main = "Cumulative Return: Long-Short Momentum Portfolio",
ylab = "Growth of $1",
wealth.index = TRUE)

# Create xts for benchmark
benchmark_xts <- xts(full_data$MarketReturn, order.by = full_data$Date)
# Merge both
compare_momentum_ls <- merge(momentum_ls_xts, benchmark_xts)
colnames(compare_momentum_ls) <- c("Long-Short Momentum", "Market Benchmark")
# Plot
chart.CumReturns(compare_momentum_ls,
legend.loc = "topleft",
main = "Long-Short Momentum vs Market Benchmark",
ylab = "Growth of $1",
wealth.index = TRUE)

# Calculate excess returns
excess_momentum_ls <- full_data$Momentum_LongShort - full_data$RiskFreeRate
excess_market <- full_data$MarketReturn - full_data$RiskFreeRate
# Linear regression
model_mom_ls <- lm(excess_momentum_ls ~ excess_market)
alpha_mom_ls <- coef(model_mom_ls)[1]
cat("Jensen's Alpha (Long-Short Momentum):", round(alpha_mom_ls, 6), "\n")
## Jensen's Alpha (Long-Short Momentum): 1.6e-05
# Monthly metrics
avg_return_mom_ls <- mean(full_data$Momentum_LongShort, na.rm = TRUE)
sd_return_mom_ls <- sd(full_data$Momentum_LongShort, na.rm = TRUE)
# Annualize
annual_return_mom_ls <- (1 + avg_return_mom_ls)^12 - 1
annual_sd_mom_ls <- sd_return_mom_ls * sqrt(12)
cat("Annualized Return:", round(annual_return_mom_ls, 6), "\n")
## Annualized Return: 0.036135
cat("Annualized Std Dev:", round(annual_sd_mom_ls, 6), "\n")
## Annualized Std Dev: 0.101879
# Risk-free rate (already calculated earlier)
avg_rf <- mean(full_data$RiskFreeRate, na.rm = TRUE)
annual_rf <- (1 + avg_rf)^12 - 1
# Sharpe Ratio
sharpe_mom_ls <- (annual_return_mom_ls - annual_rf) / annual_sd_mom_ls
cat("Annualized Sharpe Ratio:", round(sharpe_mom_ls, 4), "\n")
## Annualized Sharpe Ratio: 0.2113
up_ratio_mom_ls <- UpsidePotentialRatio(momentum_ls_xts, MAR = avg_rf)
cat("Upside-Potential Ratio:", round(up_ratio_mom_ls[1,1], 4), "\n")
## Upside-Potential Ratio: 0.801
# === Performance Metrics Table: Long-Short Momentum vs S&P 500 ===
# Métricas del benchmark en el mismo periodo
avg_return_benchmark <- mean(full_data$MarketReturn, na.rm = TRUE)
sd_benchmark <- sd(full_data$MarketReturn, na.rm = TRUE)
sharpe_benchmark <- (avg_return_benchmark - avg_rf) / sd_benchmark
xts_benchmark <- xts(full_data$MarketReturn, order.by = full_data$Date)
up_benchmark <- UpsidePotentialRatio(xts_benchmark, MAR = avg_rf)[1, 1]
# Annualized metrics for S&P 500
annual_return_benchmark <- (1 + avg_return_benchmark)^12 - 1
annual_sd_benchmark <- sd_benchmark * sqrt(12)
annual_sharpe_benchmark <- (annual_return_benchmark - annual_rf) / annual_sd_benchmark
# Tabla extendida
comparison_table_ls_mom_extended <- data.frame(
Metric = c("Average Monthly Return", "Standard Deviation (Monthly)", "Sharpe Ratio (Monthly)", "Upside-Potential Ratio",
"Annualized Return", "Annualized Std Dev", "Sharpe Ratio (Annual)"),
`Long-Short Momentum` = c(round(avg_return_mom_ls, 6), round(sd_return_mom_ls, 6),
round((avg_return_mom_ls - avg_rf) / sd_return_mom_ls, 4),
round(up_ratio_mom_ls[1,1], 4),
round(annual_return_mom_ls, 6), round(annual_sd_mom_ls, 6), round(sharpe_mom_ls, 4)),
`S&P 500 Benchmark` = c(round(avg_return_benchmark, 6), round(sd_benchmark, 6),
round((avg_return_benchmark - avg_rf) / sd_benchmark, 4),
round(up_benchmark, 4),
round(annual_return_benchmark, 6), round(annual_sd_benchmark, 6), round(annual_sharpe_benchmark, 4))
)
# Mostrar tabla extendida
knitr::kable(comparison_table_ls_mom_extended, caption = "Performance Metrics (All Time): Long-Short Momentum Portfolio vs S&P 500 (Monthly and Annualized)")
Performance Metrics (All Time): Long-Short Momentum Portfolio
vs S&P 500 (Monthly and Annualized)
| Average Monthly Return |
0.002963 |
0.007896 |
| Standard Deviation (Monthly) |
0.029410 |
0.044081 |
| Sharpe Ratio (Monthly) |
0.059600 |
0.151700 |
| Upside-Potential Ratio |
0.801000 |
0.594800 |
| Annualized Return |
0.036135 |
0.098972 |
| Annualized Std Dev |
0.101879 |
0.152702 |
| Sharpe Ratio (Annual) |
0.211300 |
0.552500 |
5: Last 36 Months - “Long-Short Momentum Portfolio Based on 3-Month
Returns”
start_date <- as.Date("2021-03-01")
full_data_3y <- full_data %>% filter(Date >= start_date)
# Fechas e índices
dates <- full_data_3y$Date
stock_cols <- colnames(full_data_3y)[!(colnames(full_data_3y) %in% c("Date", "MarketReturn", "RiskFreeRate",
"Portfolio_1N", "LongShort_Portfolio",
"Momentum_Portfolio", "Momentum_LongShort"))]
n <- nrow(full_data_3y)
# Inicializar vector
momentum_ls_returns <- rep(NA, n)
# Rolling window: cada mes, mirar 3 meses atrás y calcular retorno para el mes siguiente
for (i in 4:n) {
past_3m <- full_data_3y[(i - 3):(i - 1), stock_cols]
cum_returns <- colSums(past_3m, na.rm = TRUE)
# Clasificar en long y short
long_assets <- names(cum_returns[cum_returns > 0])
short_assets <- names(cum_returns[cum_returns < 0])
# Si hay activos suficientes
if (length(long_assets) > 0 & length(short_assets) > 0) {
next_returns <- full_data_3y[i, ]
long_avg <- mean(unlist(next_returns[, long_assets]), na.rm = TRUE)
short_avg <- mean(unlist(next_returns[, short_assets]), na.rm = TRUE)
# Long - Short
momentum_ls_returns[i] <- long_avg - short_avg
}
}
# Convertir a xts
momentum_ls_xts_3y <- xts(momentum_ls_returns, order.by = dates)
momentum_ls_xts_3y <- na.omit(momentum_ls_xts_3y)
chart.CumReturns(momentum_ls_xts_3y,
main = "Cumulative Return: Long-Short Momentum (36 Months)",
ylab = "Growth of $1",
wealth.index = TRUE)

# Benchmark
benchmark_xts_3y <- xts(full_data_3y$MarketReturn, order.by = full_data_3y$Date)
benchmark_xts_3y <- benchmark_xts_3y[index(momentum_ls_xts_3y)]
compare_mom_ls <- merge(momentum_ls_xts_3y, benchmark_xts_3y)
colnames(compare_mom_ls) <- c("Long-Short Momentum", "Market Benchmark")
chart.CumReturns(compare_mom_ls,
legend.loc = "topleft",
main = "Long-Short Momentum vs Market (36 Months)",
ylab = "Growth of $1",
wealth.index = TRUE)

# Tasa libre de riesgo alineada
rf_3y <- xts(full_data_3y$RiskFreeRate, order.by = full_data_3y$Date)[index(momentum_ls_xts_3y)]
avg_rf <- mean(rf_3y)
annual_rf <- (1 + avg_rf)^12 - 1
# Jensen's Alpha
excess_mom_ls <- momentum_ls_xts_3y - rf_3y
excess_mkt <- benchmark_xts_3y - rf_3y
alpha_mom_ls <- coef(lm(excess_mom_ls ~ excess_mkt))[1]
# Retorno y desviación
mean_ls <- mean(momentum_ls_xts_3y)
sd_ls <- sd(momentum_ls_xts_3y)
annual_return_ls <- (1 + mean_ls)^12 - 1
annual_sd_ls <- sd_ls * sqrt(12)
# Sharpe
sharpe_ls <- (annual_return_ls - annual_rf) / annual_sd_ls
# U-P Ratio
up_ls <- UpsidePotentialRatio(momentum_ls_xts_3y, MAR = avg_rf)[1, 1]
# Mostrar
cat("Jensen's Alpha:", round(alpha_mom_ls, 6), "\n")
## Jensen's Alpha: 0.002184
cat("Annualized Return:", round(annual_return_ls, 6), "\n")
## Annualized Return: 0.036668
cat("Annualized Std Dev:", round(annual_sd_ls, 6), "\n")
## Annualized Std Dev: 0.144329
cat("Sharpe Ratio:", round(sharpe_ls, 4), "\n")
## Sharpe Ratio: 0.0466
cat("Upside-Potential Ratio:", round(up_ls, 4), "\n")
## Upside-Potential Ratio: 0.6191
# === Metrics for Market Benchmark over same dates as Long-Short Momentum ===
# Benchmark metrics aligned to the same dates as the momentum long-short portfolio
benchmark_xts_3y <- xts(full_data_3y$MarketReturn, order.by = full_data_3y$Date)
benchmark_xts_3y <- benchmark_xts_3y[index(momentum_ls_xts_3y)]
avg_return_benchmark <- mean(benchmark_xts_3y, na.rm = TRUE)
sd_benchmark <- sd(benchmark_xts_3y, na.rm = TRUE)
sharpe_benchmark <- (avg_return_benchmark - avg_rf) / sd_benchmark
up_benchmark <- UpsidePotentialRatio(benchmark_xts_3y, MAR = avg_rf)[1, 1]
# Calcular métricas anualizadas del benchmark
annual_return_benchmark <- (1 + avg_return_benchmark)^12 - 1
annual_sd_benchmark <- sd_benchmark * sqrt(12)
annual_sharpe_benchmark <- (annual_return_benchmark - annual_rf) / annual_sd_benchmark
# Tabla extendida con métricas mensualizadas y anualizadas
comparison_table_ls_mom_36m_ext <- data.frame(
Metric = c("Average Monthly Return", "Standard Deviation (Monthly)", "Sharpe Ratio (Monthly)", "Upside-Potential Ratio",
"Annualized Return", "Annualized Std Dev", "Sharpe Ratio (Annual)"),
`Long-Short Momentum (36M)` = c(
round(mean_ls, 6), round(sd_ls, 6),
round((mean_ls - avg_rf) / sd_ls, 4),
round(up_ls, 4),
round(annual_return_ls, 6), round(annual_sd_ls, 6),
round(sharpe_ls, 4)
),
`S&P 500 Benchmark (36M)` = c(
round(avg_return_benchmark, 6), round(sd_benchmark, 6),
round((avg_return_benchmark - avg_rf) / sd_benchmark, 4),
round(up_benchmark, 4),
round(annual_return_benchmark, 6), round(annual_sd_benchmark, 6),
round(annual_sharpe_benchmark, 4)
)
)
# Mostrar tabla
knitr::kable(comparison_table_ls_mom_36m_ext,
caption = "Performance Metrics (Last 36 Months): Long-Short Momentum Portfolio vs S&P 500 (Monthly and Annualized)")
Performance Metrics (Last 36 Months): Long-Short Momentum
Portfolio vs S&P 500 (Monthly and Annualized)
| Average Monthly Return |
0.003005 |
0.007144 |
| Standard Deviation (Monthly) |
0.041664 |
0.052441 |
| Sharpe Ratio (Monthly) |
0.013000 |
0.089300 |
| Upside-Potential Ratio |
0.619100 |
0.768000 |
| Annualized Return |
0.036668 |
0.089180 |
| Annualized Std Dev |
0.144329 |
0.181661 |
| Sharpe Ratio (Annual) |
0.046600 |
0.326100 |
6: “Equally Weighted Portfolio of the 10 Lowest Beta Stocks”
# Data manipulation and time handling
library(readxl)
library(dplyr)
library(tibble)
# Time series and financial metrics
library(PerformanceAnalytics)
library(xts)
# Get stock column names (excluding non-asset columns)
stock_names <- colnames(full_data)[!(colnames(full_data) %in% c("Date", "MarketReturn", "RiskFreeRate",
"Portfolio_1N", "LongShort_Portfolio",
"Momentum_Portfolio", "Momentum_LongShort"))]
# Function to calculate beta
calculate_beta <- function(stock_return, market_return, riskfree_rate) {
excess_stock <- stock_return - riskfree_rate
excess_market <- market_return - riskfree_rate
model <- lm(excess_stock ~ excess_market)
return(coef(model)[2]) # Beta is the slope
}
# Calculate beta for each stock
betas <- sapply(stock_names, function(stock) {
calculate_beta(full_data[[stock]], full_data$MarketReturn, full_data$RiskFreeRate)
})
# Create table with results
beta_table <- data.frame(Stock = stock_names, Beta = betas)
# Sort by lowest beta
beta_table <- beta_table %>% arrange(Beta)
# Preview lowest beta stocks
head(beta_table, 10)
## Stock Beta
## WALMART.excess_market WALMART 0.3889799
## PROCTER & GAMBLE.excess_market PROCTER & GAMBLE 0.4567104
## VERIZON COMMUNICATIONS.excess_market VERIZON COMMUNICATIONS 0.4729684
## NEXTERA ENERGY.excess_market NEXTERA ENERGY 0.4927911
## GILEAD SCIENCES.excess_market GILEAD SCIENCES 0.4940299
## PEPSICO.excess_market PEPSICO 0.5247904
## BRISTOL MYERS SQUIBB.excess_market BRISTOL MYERS SQUIBB 0.5293171
## ELI LILLY.excess_market ELI LILLY 0.5315469
## MERCK & COMPANY.excess_market MERCK & COMPANY 0.5534168
## COCA COLA.excess_market COCA COLA 0.5589442
# Get the names of the 10 stocks with the lowest beta
low_beta_stocks <- head(beta_table, 10)$Stock
# Extract their returns
low_beta_returns <- full_data %>%
select(all_of(low_beta_stocks))
# Calculate equal-weighted return per period
low_beta_portfolio_return <- rowMeans(low_beta_returns, na.rm = TRUE)
# Add to the main dataset
full_data$LowBeta_Portfolio <- low_beta_portfolio_return
# Convert to xts
lowbeta_xts <- xts(full_data$LowBeta_Portfolio, order.by = full_data$Date)
# Set English for date labels
Sys.setlocale("LC_TIME", "C")
## [1] "C"
# Plot cumulative return
chart.CumReturns(lowbeta_xts,
main = "Cumulative Return: Low-Beta Portfolio",
ylab = "Growth of $1",
wealth.index = TRUE)

# Convert benchmark returns to xts
benchmark_xts <- xts(full_data$MarketReturn, order.by = full_data$Date)
# Merge for comparison
compare_lowbeta <- merge(lowbeta_xts, benchmark_xts)
colnames(compare_lowbeta) <- c("Low-Beta Portfolio", "Market Benchmark")
# Plot comparison
chart.CumReturns(compare_lowbeta,
legend.loc = "topleft",
main = "Low-Beta Portfolio vs Market Benchmark",
ylab = "Growth of $1",
wealth.index = TRUE)

# Excess returns
excess_lowbeta <- full_data$LowBeta_Portfolio - full_data$RiskFreeRate
excess_market <- full_data$MarketReturn - full_data$RiskFreeRate
# Regression
model_lowbeta <- lm(excess_lowbeta ~ excess_market)
alpha_lowbeta <- coef(model_lowbeta)[1]
cat("Jensen's Alpha (Low-Beta Portfolio):", round(alpha_lowbeta, 6), "\n")
## Jensen's Alpha (Low-Beta Portfolio): 0.001162
# Monthly averages
avg_return_lowbeta <- mean(full_data$LowBeta_Portfolio, na.rm = TRUE)
sd_return_lowbeta <- sd(full_data$LowBeta_Portfolio, na.rm = TRUE)
# Annualized
annual_return_lowbeta <- (1 + avg_return_lowbeta)^12 - 1
annual_sd_lowbeta <- sd_return_lowbeta * sqrt(12)
cat("Annualized Return:", round(annual_return_lowbeta, 6), "\n")
## Annualized Return: 0.070806
cat("Annualized Std Dev:", round(annual_sd_lowbeta, 6), "\n")
## Annualized Std Dev: 0.112861
# Use average risk-free rate
avg_rf <- mean(full_data$RiskFreeRate, na.rm = TRUE)
annual_rf <- (1 + avg_rf)^12 - 1
# Sharpe Ratio
sharpe_lowbeta <- (annual_return_lowbeta - annual_rf) / annual_sd_lowbeta
cat("Annualized Sharpe Ratio:", round(sharpe_lowbeta, 4), "\n")
## Annualized Sharpe Ratio: 0.4979
# Create xts object
lowbeta_xts <- xts(full_data$LowBeta_Portfolio, order.by = full_data$Date)
# Calculate U-P ratio
up_ratio_lowbeta <- UpsidePotentialRatio(lowbeta_xts, MAR = avg_rf)
cat("Upside-Potential Ratio:", round(up_ratio_lowbeta[1,1], 4), "\n")
## Upside-Potential Ratio: 0.765
# === Metrics for Market Benchmark (aligned with Low-Beta Portfolio dates) ===
benchmark_xts <- xts(full_data$MarketReturn, order.by = full_data$Date)
avg_return_benchmark <- mean(full_data$MarketReturn, na.rm = TRUE)
sd_benchmark <- sd(full_data$MarketReturn, na.rm = TRUE)
sharpe_benchmark <- (avg_return_benchmark - avg_rf) / sd_benchmark
up_benchmark <- UpsidePotentialRatio(benchmark_xts, MAR = avg_rf)[1, 1]
# Cálculos anualizados del benchmark
annual_return_benchmark <- (1 + avg_return_benchmark)^12 - 1
annual_sd_benchmark <- sd_benchmark * sqrt(12)
annual_sharpe_benchmark <- (annual_return_benchmark - annual_rf) / annual_sd_benchmark
# Tabla completa con métricas mensuales y anualizadas
comparison_table_lowbeta_ext <- data.frame(
Metric = c("Average Monthly Return", "Standard Deviation (Monthly)", "Sharpe Ratio (Monthly)", "Upside-Potential Ratio",
"Annualized Return", "Annualized Std Dev", "Sharpe Ratio (Annual)"),
`Low-Beta Portfolio` = c(
round(avg_return_lowbeta, 6), round(sd_return_lowbeta, 6),
round((avg_return_lowbeta - avg_rf) / sd_return_lowbeta, 4),
round(up_ratio_lowbeta[1, 1], 4),
round(annual_return_lowbeta, 6), round(annual_sd_lowbeta, 6),
round(sharpe_lowbeta, 4)
),
`S&P 500 Benchmark` = c(
round(avg_return_benchmark, 6), round(sd_benchmark, 6),
round((avg_return_benchmark - avg_rf) / sd_benchmark, 4),
round(up_benchmark, 4),
round(annual_return_benchmark, 6), round(annual_sd_benchmark, 6),
round(annual_sharpe_benchmark, 4)
)
)
# Mostrar la tabla
knitr::kable(comparison_table_lowbeta_ext,
caption = "Performance Metrics: Low-Beta Portfolio vs S&P 500 (Monthly and Annualized)")
Performance Metrics: Low-Beta Portfolio vs S&P 500 (Monthly
and Annualized)
| Average Monthly Return |
0.005717 |
0.007896 |
| Standard Deviation (Monthly) |
0.032580 |
0.044081 |
| Sharpe Ratio (Monthly) |
0.138400 |
0.151700 |
| Upside-Potential Ratio |
0.765000 |
0.594800 |
| Annualized Return |
0.070806 |
0.098972 |
| Annualized Std Dev |
0.112861 |
0.152702 |
| Sharpe Ratio (Annual) |
0.497900 |
0.552500 |
6: Last 36 Months - “Equally Weighted Portfolio of the 10 Lowest
Beta Stocks”
start_date <- as.Date("2021-03-01")
full_data_3y <- full_data %>% filter(Date >= start_date)
# Columnas de acciones
stock_names <- colnames(full_data_3y)[!(colnames(full_data_3y) %in% c("Date", "MarketReturn", "RiskFreeRate",
"Portfolio_1N", "LongShort_Portfolio",
"Momentum_Portfolio", "Momentum_LongShort",
"LowBeta_Portfolio"))]
# Función para calcular beta
calculate_beta <- function(stock_return, market_return, riskfree_rate) {
excess_stock <- stock_return - riskfree_rate
excess_market <- market_return - riskfree_rate
model <- lm(excess_stock ~ excess_market)
return(coef(model)[2])
}
# Betas con datos 3y
betas <- sapply(stock_names, function(stock) {
calculate_beta(full_data_3y[[stock]], full_data_3y$MarketReturn, full_data_3y$RiskFreeRate)
})
# Tabla ordenada por beta
beta_table <- data.frame(Stock = stock_names, Beta = betas) %>% arrange(Beta)
# Top 10 de beta más baja
low_beta_stocks <- head(beta_table, 10)$Stock
# Retornos de las acciones seleccionadas
low_beta_returns <- full_data_3y %>% select(all_of(low_beta_stocks))
# Promedio (igual ponderación)
low_beta_portfolio_return <- rowMeans(low_beta_returns, na.rm = TRUE)
# Agregar al dataset 3y
full_data_3y$LowBeta_Portfolio <- low_beta_portfolio_return
# Convertir a xts
lowbeta_xts_3y <- xts(full_data_3y$LowBeta_Portfolio, order.by = full_data_3y$Date)
# Benchmark alineado
benchmark_xts_3y <- xts(full_data_3y$MarketReturn, order.by = full_data_3y$Date)
# Comparar
compare_lowbeta <- merge(lowbeta_xts_3y, benchmark_xts_3y)
colnames(compare_lowbeta) <- c("Low-Beta Portfolio", "Market Benchmark")
chart.CumReturns(compare_lowbeta,
legend.loc = "topleft",
main = "Low-Beta Portfolio vs Market (Last 36 Months)",
ylab = "Growth of $1",
wealth.index = TRUE)

# Tasa libre de riesgo alineada
rf_3y <- xts(full_data_3y$RiskFreeRate, order.by = full_data_3y$Date)[index(lowbeta_xts_3y)]
avg_rf <- mean(rf_3y)
annual_rf <- (1 + avg_rf)^12 - 1
# Jensen's Alpha
excess_lb <- lowbeta_xts_3y - rf_3y
excess_mkt <- benchmark_xts_3y - rf_3y
alpha_lb <- coef(lm(excess_lb ~ excess_mkt))[1]
# Retornos y riesgo
mean_lb <- mean(lowbeta_xts_3y)
sd_lb <- sd(lowbeta_xts_3y)
annual_return_lb <- (1 + mean_lb)^12 - 1
annual_sd_lb <- sd_lb * sqrt(12)
# Sharpe
sharpe_lb <- (annual_return_lb - annual_rf) / annual_sd_lb
# U-P Ratio
up_lb <- UpsidePotentialRatio(lowbeta_xts_3y, MAR = avg_rf)[1,1]
# Resultados
cat("Jensen's Alpha:", round(alpha_lb, 6), "\n")
## Jensen's Alpha: -0.000258
cat("Annualized Return:", round(annual_return_lb, 6), "\n")
## Annualized Return: 0.055175
cat("Annualized Std Dev:", round(annual_sd_lb, 6), "\n")
## Annualized Std Dev: 0.133586
cat("Sharpe Ratio:", round(sharpe_lb, 4), "\n")
## Sharpe Ratio: 0.2077
cat("Upside-Potential Ratio:", round(up_lb, 4), "\n")
## Upside-Potential Ratio: 0.8709
# === Metrics for S&P 500 Benchmark (aligned with Low-Beta Portfolio over last 36 months) ===
benchmark_xts_3y <- xts(full_data_3y$MarketReturn, order.by = full_data_3y$Date)
avg_return_benchmark <- mean(benchmark_xts_3y, na.rm = TRUE)
sd_benchmark <- sd(benchmark_xts_3y, na.rm = TRUE)
sharpe_benchmark <- (avg_return_benchmark - avg_rf) / sd_benchmark
up_benchmark <- UpsidePotentialRatio(benchmark_xts_3y, MAR = avg_rf)[1, 1]
# Cálculos anualizados del benchmark
annual_return_benchmark <- (1 + avg_return_benchmark)^12 - 1
annual_sd_benchmark <- sd_benchmark * sqrt(12)
annual_sharpe_benchmark <- (annual_return_benchmark - annual_rf) / annual_sd_benchmark
# Tabla extendida con métricas mensuales y anualizadas
comparison_table_lowbeta_3y_ext <- data.frame(
Metric = c(
"Average Monthly Return", "Standard Deviation (Monthly)", "Sharpe Ratio (Monthly)", "Upside-Potential Ratio",
"Annualized Return", "Annualized Std Dev", "Sharpe Ratio (Annual)"
),
`Low-Beta Portfolio (36M)` = c(
round(mean_lb, 6), round(sd_lb, 6),
round((mean_lb - avg_rf) / sd_lb, 4),
round(up_lb, 4),
round(annual_return_lb, 6), round(annual_sd_lb, 6),
round(sharpe_lb, 4)
),
`S&P 500 Benchmark (36M)` = c(
round(avg_return_benchmark, 6), round(sd_benchmark, 6),
round((avg_return_benchmark - avg_rf) / sd_benchmark, 4),
round(up_benchmark, 4),
round(annual_return_benchmark, 6), round(annual_sd_benchmark, 6),
round(annual_sharpe_benchmark, 4)
)
)
# Mostrar tabla
knitr::kable(comparison_table_lowbeta_3y_ext,
caption = "Performance Metrics: Low-Beta Portfolio vs S&P 500 (Last 36 Months, Monthly and Annualized)")
Performance Metrics: Low-Beta Portfolio vs S&P 500 (Last 36
Months, Monthly and Annualized)
| Average Monthly Return |
0.004486 |
0.009377 |
| Standard Deviation (Monthly) |
0.038563 |
0.051021 |
| Sharpe Ratio (Monthly) |
0.057800 |
0.139500 |
| Upside-Potential Ratio |
0.870900 |
0.746500 |
| Annualized Return |
0.055175 |
0.118513 |
| Annualized Std Dev |
0.133586 |
0.176741 |
| Sharpe Ratio (Annual) |
0.207700 |
0.515300 |
7: Long-Short Portfolio Based on Beta: Long Low-Beta, Short
High-Beta Stocks
library(readxl)
library(dplyr)
library(tibble)
library(PerformanceAnalytics)
library(xts)
# Define stock columns (excluding non-stock columns)
stock_cols <- colnames(full_data)[!(colnames(full_data) %in% c("Date", "MarketReturn", "RiskFreeRate",
"Portfolio_1N", "LongShort_Portfolio",
"Momentum_Portfolio", "Momentum_LongShort",
"LowBeta_Portfolio"))]
# Function to calculate beta
calculate_beta <- function(stock_return, market_return, risk_free_rate) {
excess_stock <- stock_return - risk_free_rate
excess_market <- market_return - risk_free_rate
model <- lm(excess_stock ~ excess_market)
return(coef(model)[2]) # Beta
}
# Calculate beta for each stock
betas <- sapply(stock_cols, function(stock) {
calculate_beta(full_data[[stock]], full_data$MarketReturn, full_data$RiskFreeRate)
})
# Create and sort beta table
beta_table <- data.frame(Stock = stock_cols, Beta = betas) %>%
arrange(Beta)
# Select long (lowest 5 beta) and short (highest 5 beta) stocks
long_beta <- head(beta_table, 5)$Stock
short_beta <- tail(beta_table, 5)$Stock
# Define stock columns (excluding non-stock columns)
stock_cols <- colnames(full_data)[!(colnames(full_data) %in% c("Date", "MarketReturn", "RiskFreeRate",
"Portfolio_1N", "LongShort_Portfolio",
"Momentum_Portfolio", "Momentum_LongShort",
"LowBeta_Portfolio"))]
# Function to calculate beta
calculate_beta <- function(stock_return, market_return, risk_free_rate) {
excess_stock <- stock_return - risk_free_rate
excess_market <- market_return - risk_free_rate
model <- lm(excess_stock ~ excess_market)
return(coef(model)[2]) # Beta
}
# Calculate beta for each stock
betas <- sapply(stock_cols, function(stock) {
calculate_beta(full_data[[stock]], full_data$MarketReturn, full_data$RiskFreeRate)
})
# Create and sort beta table
beta_table <- data.frame(Stock = stock_cols, Beta = betas) %>%
arrange(Beta)
# Select long (lowest 5 beta) and short (highest 5 beta) stocks
long_beta <- head(beta_table, 5)$Stock
short_beta <- tail(beta_table, 5)$Stock
# Get return series for long and short groups
returns_long_beta <- full_data %>% select(all_of(long_beta))
returns_short_beta <- full_data %>% select(all_of(short_beta))
# Calculate average return per group
long_avg_beta <- rowMeans(returns_long_beta, na.rm = TRUE)
short_avg_beta <- rowMeans(returns_short_beta, na.rm = TRUE)
# Long-Short Beta Portfolio return
longshort_beta_return <- long_avg_beta - short_avg_beta
# Add to full_data
full_data$Beta_LongShort <- longshort_beta_return
# Convert to xts
beta_ls_xts <- xts(full_data$Beta_LongShort, order.by = full_data$Date)
# Set English locale for dates
Sys.setlocale("LC_TIME", "C")
## [1] "C"
# Plot cumulative return
chart.CumReturns(beta_ls_xts,
main = "Cumulative Return: Long-Short Beta Portfolio",
ylab = "Growth of $1",
wealth.index = TRUE)

# Create xts for benchmark
benchmark_xts <- xts(full_data$MarketReturn, order.by = full_data$Date)
# Merge series
compare_beta_ls <- merge(beta_ls_xts, benchmark_xts)
colnames(compare_beta_ls) <- c("Beta Long-Short", "Market Benchmark")
# Plot comparison
chart.CumReturns(compare_beta_ls,
legend.loc = "topleft",
main = "Long-Short Beta Portfolio vs Market Benchmark",
ylab = "Growth of $1",
wealth.index = TRUE)

# Excess returns
excess_beta_ls <- full_data$Beta_LongShort - full_data$RiskFreeRate
excess_market <- full_data$MarketReturn - full_data$RiskFreeRate
# Regression
model_beta_ls <- lm(excess_beta_ls ~ excess_market)
alpha_beta_ls <- coef(model_beta_ls)[1]
cat("Jensen's Alpha (Long-Short Beta):", round(alpha_beta_ls, 6), "\n")
## Jensen's Alpha (Long-Short Beta): 0.003171
# Monthly values
avg_return_beta_ls <- mean(full_data$Beta_LongShort, na.rm = TRUE)
sd_return_beta_ls <- sd(full_data$Beta_LongShort, na.rm = TRUE)
# Annualized
annual_return_beta_ls <- (1 + avg_return_beta_ls)^12 - 1
annual_sd_beta_ls <- sd_return_beta_ls * sqrt(12)
cat("Annualized Return:", round(annual_return_beta_ls, 6), "\n")
## Annualized Return: -0.045518
cat("Annualized Std Dev:", round(annual_sd_beta_ls, 6), "\n")
## Annualized Std Dev: 0.279352
# Risk-free rate (monthly and annual)
avg_rf <- mean(full_data$RiskFreeRate, na.rm = TRUE)
annual_rf <- (1 + avg_rf)^12 - 1
# Sharpe Ratio
sharpe_beta_ls <- (annual_return_beta_ls - annual_rf) / annual_sd_beta_ls
cat("Annualized Sharpe Ratio:", round(sharpe_beta_ls, 4), "\n")
## Annualized Sharpe Ratio: -0.2152
# Create xts object
beta_ls_xts <- xts(full_data$Beta_LongShort, order.by = full_data$Date)
# U-P Ratio
up_ratio_beta_ls <- UpsidePotentialRatio(beta_ls_xts, MAR = avg_rf)
cat("Upside-Potential Ratio:", round(up_ratio_beta_ls[1,1], 4), "\n")
## Upside-Potential Ratio: 0.8541
# Metrics for S&P 500 Benchmark
benchmark_xts <- xts(full_data$MarketReturn, order.by = full_data$Date)
avg_return_benchmark <- mean(benchmark_xts, na.rm = TRUE)
sd_benchmark <- sd(benchmark_xts, na.rm = TRUE)
sharpe_benchmark <- (avg_return_benchmark - avg_rf) / sd_benchmark
up_benchmark <- UpsidePotentialRatio(benchmark_xts, MAR = avg_rf)[1, 1]
# Anualización de métricas del benchmark
annual_return_benchmark <- (1 + avg_return_benchmark)^12 - 1
annual_sd_benchmark <- sd_benchmark * sqrt(12)
annual_sharpe_benchmark <- (annual_return_benchmark - annual_rf) / annual_sd_benchmark
# Tabla extendida
comparison_table_beta_ls_extended <- data.frame(
Metric = c(
"Average Monthly Return", "Standard Deviation (Monthly)", "Sharpe Ratio (Monthly)", "Upside-Potential Ratio",
"Annualized Return", "Annualized Std Dev", "Sharpe Ratio (Annual)"
),
`Long-Short Beta Portfolio` = c(
round(avg_return_beta_ls, 6), round(sd_return_beta_ls, 6),
round((avg_return_beta_ls - avg_rf) / sd_return_beta_ls, 4),
round(up_ratio_beta_ls[1,1], 4),
round(annual_return_beta_ls, 6), round(annual_sd_beta_ls, 6),
round(sharpe_beta_ls, 4)
),
`S&P 500 Benchmark` = c(
round(avg_return_benchmark, 6), round(sd_benchmark, 6),
round((avg_return_benchmark - avg_rf) / sd_benchmark, 4),
round(up_benchmark, 4),
round(annual_return_benchmark, 6), round(annual_sd_benchmark, 6),
round(annual_sharpe_benchmark, 4)
)
)
# Mostrar tabla
knitr::kable(comparison_table_beta_ls_extended,
caption = "Performance Metrics: Long-Short Beta Portfolio vs S&P 500 (Monthly and Annualized)")
Performance Metrics: Long-Short Beta Portfolio vs S&P 500
(Monthly and Annualized)
| Average Monthly Return |
-0.003875 |
0.007896 |
| Standard Deviation (Monthly) |
0.080642 |
0.044081 |
| Sharpe Ratio (Monthly) |
-0.063000 |
0.151700 |
| Upside-Potential Ratio |
0.854100 |
0.594800 |
| Annualized Return |
-0.045518 |
0.098972 |
| Annualized Std Dev |
0.279352 |
0.152702 |
| Sharpe Ratio (Annual) |
-0.215200 |
0.552500 |
7: Last 36 Months - Long-Short Portfolio Based on Beta: Long
Low-Beta, Short High-Beta Stocks
start_date <- as.Date("2021-03-01")
full_data_3y <- full_data %>% filter(Date >= start_date)
# Filtrar solo columnas de acciones
stock_cols <- colnames(full_data_3y)[!(colnames(full_data_3y) %in% c("Date", "MarketReturn", "RiskFreeRate",
"Portfolio_1N", "LongShort_Portfolio",
"Momentum_Portfolio", "Momentum_LongShort",
"LowBeta_Portfolio", "Beta_LongShort"))]
# Función para beta
calculate_beta <- function(stock_return, market_return, risk_free_rate) {
excess_stock <- stock_return - risk_free_rate
excess_market <- market_return - risk_free_rate
model <- lm(excess_stock ~ excess_market)
return(coef(model)[2])
}
# Calcular betas con datos 3y
betas <- sapply(stock_cols, function(stock) {
calculate_beta(full_data_3y[[stock]], full_data_3y$MarketReturn, full_data_3y$RiskFreeRate)
})
# Tabla ordenada
beta_table <- data.frame(Stock = stock_cols, Beta = betas) %>% arrange(Beta)
# Elegir 5 acciones para long (beta baja) y 5 para short (beta alta)
long_beta <- head(beta_table, 5)$Stock
short_beta <- tail(beta_table, 5)$Stock
# Seleccionar retornos
returns_long <- full_data_3y %>% select(all_of(long_beta))
returns_short <- full_data_3y %>% select(all_of(short_beta))
# Calcular promedios
long_avg <- rowMeans(returns_long, na.rm = TRUE)
short_avg <- rowMeans(returns_short, na.rm = TRUE)
# Retorno del portafolio
longshort_beta_return <- long_avg - short_avg
# Agregar a los datos
full_data_3y$Beta_LongShort <- longshort_beta_return
# Convertir a xts
beta_ls_xts_3y <- xts(full_data_3y$Beta_LongShort, order.by = full_data_3y$Date)
chart.CumReturns(beta_ls_xts_3y,
main = "Cumulative Return: Long-Short Beta Portfolio (36 Months)",
ylab = "Growth of $1",
wealth.index = TRUE)

benchmark_xts_3y <- xts(full_data_3y$MarketReturn, order.by = full_data_3y$Date)
compare_beta_ls <- merge(beta_ls_xts_3y, benchmark_xts_3y)
colnames(compare_beta_ls) <- c("Beta Long-Short", "Market Benchmark")
chart.CumReturns(compare_beta_ls,
legend.loc = "topleft",
main = "Long-Short Beta vs Market (36 Months)",
ylab = "Growth of $1",
wealth.index = TRUE)

# Tasa libre de riesgo alineada
rf_3y <- xts(full_data_3y$RiskFreeRate, order.by = full_data_3y$Date)[index(beta_ls_xts_3y)]
avg_rf <- mean(rf_3y)
annual_rf <- (1 + avg_rf)^12 - 1
# Jensen's Alpha
excess_ls <- beta_ls_xts_3y - rf_3y
excess_mkt <- benchmark_xts_3y - rf_3y
alpha_ls <- coef(lm(excess_ls ~ excess_mkt))[1]
# Retorno y desviación estándar
mean_ls <- mean(beta_ls_xts_3y)
sd_ls <- sd(beta_ls_xts_3y)
annual_return_ls <- (1 + mean_ls)^12 - 1
annual_sd_ls <- sd_ls * sqrt(12)
# Sharpe Ratio
sharpe_ls <- (annual_return_ls - annual_rf) / annual_sd_ls
# U-P Ratio
up_ls <- UpsidePotentialRatio(beta_ls_xts_3y, MAR = avg_rf)[1, 1]
# Resultados
cat("Jensen's Alpha:", round(alpha_ls, 6), "\n")
## Jensen's Alpha: -0.003287
cat("Annualized Return:", round(annual_return_ls, 6), "\n")
## Annualized Return: -0.127603
cat("Annualized Std Dev:", round(annual_sd_ls, 6), "\n")
## Annualized Std Dev: 0.402034
cat("Sharpe Ratio:", round(sharpe_ls, 4), "\n")
## Sharpe Ratio: -0.3856
cat("Upside-Potential Ratio:", round(up_ls, 4), "\n")
## Upside-Potential Ratio: 0.7109
# Metrics for S&P 500 Benchmark (aligned with 36-month period)
benchmark_xts_3y <- xts(full_data_3y$MarketReturn, order.by = full_data_3y$Date)
benchmark_xts_3y <- benchmark_xts_3y[index(beta_ls_xts_3y)]
avg_return_benchmark <- mean(benchmark_xts_3y, na.rm = TRUE)
sd_benchmark <- sd(benchmark_xts_3y, na.rm = TRUE)
sharpe_benchmark <- (avg_return_benchmark - avg_rf) / sd_benchmark
up_benchmark <- UpsidePotentialRatio(benchmark_xts_3y, MAR = avg_rf)[1, 1]
# Calcular métricas anualizadas para el benchmark
annual_return_benchmark <- (1 + avg_return_benchmark)^12 - 1
annual_sd_benchmark <- sd_benchmark * sqrt(12)
annual_sharpe_benchmark <- (annual_return_benchmark - annual_rf) / annual_sd_benchmark
# Crear tabla extendida
comparison_table_beta_ls_3y_ext <- data.frame(
Metric = c("Average Monthly Return", "Standard Deviation (Monthly)", "Sharpe Ratio (Monthly)", "Upside-Potential Ratio",
"Annualized Return", "Annualized Std Dev", "Sharpe Ratio (Annual)"),
`Beta Long-Short (36M)` = c(round(mean_ls, 6), round(sd_ls, 6), round((mean_ls - avg_rf) / sd_ls, 4), round(up_ls, 4),
round(annual_return_ls, 6), round(annual_sd_ls, 6), round(sharpe_ls, 4)),
`S&P 500 Benchmark (36M)` = c(round(avg_return_benchmark, 6), round(sd_benchmark, 6), round((avg_return_benchmark - avg_rf) / sd_benchmark, 4), round(up_benchmark, 4),
round(annual_return_benchmark, 6), round(annual_sd_benchmark, 6), round(annual_sharpe_benchmark, 4))
)
# Mostrar tabla
knitr::kable(comparison_table_beta_ls_3y_ext,
caption = "Extended Performance Metrics: Long-Short Beta Portfolio vs S&P 500 (Last 36 Months)")
Extended Performance Metrics: Long-Short Beta Portfolio vs
S&P 500 (Last 36 Months)
| Average Monthly Return |
-0.011311 |
0.009377 |
| Standard Deviation (Monthly) |
0.116057 |
0.051021 |
| Sharpe Ratio (Monthly) |
-0.116900 |
0.139500 |
| Upside-Potential Ratio |
0.710900 |
0.746500 |
| Annualized Return |
-0.127603 |
0.118513 |
| Annualized Std Dev |
0.402034 |
0.176741 |
| Sharpe Ratio (Annual) |
-0.385600 |
0.515300 |