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)
Metric X1.N.Portfolio S.P.500.Benchmark
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
Metric X1.N.Portfolio..36M. S.P.500.Benchmark..36M.
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)
Metric Top.10.Jensen.Alpha S.P.500.Benchmark
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)
Metric Top.10.Jensen.Alpha S.P.500.Benchmark
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)
Metric Long.Short.Portfolio S.P.500.Benchmark
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)
Metric Long.Short.Portfolio..36M. S.P.500.Benchmark..36M.
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)
Metric Momentum.Portfolio S.P.500.Benchmark
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)
Metric Momentum.Portfolio..36M. S.P.500.Benchmark..36M.
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)
Metric Long.Short.Momentum S.P.500.Benchmark
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)
Metric Long.Short.Momentum..36M. S.P.500.Benchmark..36M.
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)
Metric Low.Beta.Portfolio S.P.500.Benchmark
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)
Metric Low.Beta.Portfolio..36M. S.P.500.Benchmark..36M.
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)
Metric Long.Short.Beta.Portfolio S.P.500.Benchmark
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)
Metric Beta.Long.Short..36M. S.P.500.Benchmark..36M.
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