# Long-Short Momentum Portfolio Construction with 3-month lookback window
# This script creates a portfolio that:
# - Goes LONG in stocks with positive returns over the last 3 months
# - Goes SHORT in stocks with negative returns over the last 3 months
# - Rebalanced monthly with equal weighting
# ---- PACKAGE INSTALLATION AND LOADING ----
# Install and load required packages
if (!require("pacman")) install.packages("pacman")
## Cargando paquete requerido: pacman
pacman::p_load(
tidyverse, # Data manipulation and visualization
quantmod, # Financial data retrieval and analysis
PerformanceAnalytics, # Performance and risk analysis
zoo, # Time series analysis
roll, # Rolling window calculations
xts, # Extensible time series
lubridate, # Date handling
readxl, # Excel file reading
knitr, # For tables
grid, # For graphics
gridExtra # For arranging multiple plots
)
# ---- FILE PATH CONFIGURATION ----
# Create file paths using file.path() to handle spaces and special characters better
base_dir <- file.path("C:", "Users", "lcyep", "OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey",
"Tec", "Semestre 6", "Risk", "R, project")
# Use forward slashes instead of backslashes
stock_file_path <- file.path(base_dir, "data.xlsx")
market_file_path <- file.path(base_dir, "data2.xlsx")
# Print the paths for verification
cat("Stock file path:", stock_file_path, "\n")
## Stock file path: C:/Users/lcyep/OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey/Tec/Semestre 6/Risk/R, project/data.xlsx
cat("Market file path:", market_file_path, "\n")
## Market file path: C:/Users/lcyep/OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey/Tec/Semestre 6/Risk/R, project/data2.xlsx
# Check if files exist
if (!file.exists(stock_file_path)) {
stop("Stock file not found. Please check the path and filename.")
}
if (!file.exists(market_file_path)) {
stop("Market file not found. Please check the path and filename.")
}
# ---- DATA IMPORT FUNCTION ----
# Function to import Excel data
import_excel_data <- function(stock_file_path, market_file_path) {
tryCatch({
# Read stock price data
cat("Reading stock data from:", stock_file_path, "\n")
stock_data <- read_excel(stock_file_path)
# Read benchmark and risk-free rate data
cat("Reading market data from:", market_file_path, "\n")
market_data <- read_excel(market_file_path)
# Convert the first column to dates
dates <- as.Date(stock_data[[1]])
# Create xts objects for stock prices
stock_prices <- as.matrix(stock_data[, -1]) # Remove the date column
rownames(stock_prices) <- NULL
stock_prices_xts <- xts(stock_prices, order.by = dates)
colnames(stock_prices_xts) <- colnames(stock_data)[-1] # Preserve stock names
# Extract S&P 500 price and T-bill data
sp500_prices <- as.numeric(market_data[[2]]) # S&P 500 Price Index
tbill_rates <- as.numeric(market_data[[4]]) / 100 / 12 # Convert annual rate to monthly
market_dates <- as.Date(market_data[[1]])
sp500_prices_xts <- xts(sp500_prices, order.by = market_dates)
tbill_rates_xts <- xts(tbill_rates, order.by = market_dates)
# Calculate returns for stocks
stock_returns_xts <- ROC(stock_prices_xts, type = "discrete", n = 1)
stock_returns_xts <- stock_returns_xts[-1, ] # Remove first NA row
# Calculate returns for S&P 500
sp500_returns_xts <- ROC(sp500_prices_xts, type = "discrete", n = 1)
sp500_returns_xts <- sp500_returns_xts[-1, ] # Remove first NA row
# Remove first value from tbill rates to align with returns
tbill_rates_xts <- tbill_rates_xts[-1, ]
return(list(
stock_returns = stock_returns_xts,
sp500_returns = sp500_returns_xts,
risk_free_rate = tbill_rates_xts
))
}, error = function(e) {
stop(paste("Error reading files:", e$message))
})
}
# ---- MOMENTUM ANALYSIS FUNCTIONS ----
# Function to calculate N-month cumulative returns
calculate_momentum <- function(returns, lookback_period = 3) {
# Calculate cumulative returns over the lookback period
# For 3-month lookback, we calculate (1+r1)*(1+r2)*(1+r3) - 1
momentum <- rep(NA, length(returns))
if (length(returns) >= lookback_period) {
# Calculate cumulative returns using rolling product
for (i in lookback_period:length(returns)) {
momentum[i] <- prod(1 + returns[(i - lookback_period + 1):i]) - 1
}
}
return(momentum)
}
# Function to construct long-short momentum portfolio based on trailing returns
construct_long_short_momentum_portfolio <- function(asset_returns, lookback_period = 3,
start_after_months = 36) {
dates <- index(asset_returns)
n_stocks <- ncol(asset_returns)
n_periods <- length(dates) - start_after_months
portfolio_returns <- numeric(n_periods)
selected_long_assets <- list()
selected_short_assets <- list()
momentum_scores <- list()
cat("Starting long-short momentum portfolio construction with", n_periods, "rebalancing periods\n")
for (i in 1:n_periods) {
# Define the current position in the time series
current_idx <- i + start_after_months - 1
# Calculate momentum for each asset using data up to the current month
asset_momentums <- numeric(n_stocks)
for (j in 1:n_stocks) {
# Get returns for the current asset
asset_data <- asset_returns[1:current_idx, j]
# Calculate momentum (trailing return over lookback period)
if (current_idx >= lookback_period) {
# Get the last lookback_period months of returns
recent_returns <- asset_data[(current_idx - lookback_period + 1):current_idx]
# Calculate cumulative return over the lookback period
if (all(!is.na(recent_returns))) {
asset_momentums[j] <- prod(1 + recent_returns) - 1
} else {
asset_momentums[j] <- NA
}
} else {
asset_momentums[j] <- NA
}
}
# Create data frame of stocks and their momentum scores
asset_names <- colnames(asset_returns)
momentum_df <- data.frame(
asset = asset_names,
momentum = asset_momentums
)
# Store momentum scores for this period
momentum_scores[[i]] <- momentum_df
# Select assets with positive momentum for LONG positions
selected_long_df <- momentum_df %>%
filter(!is.na(momentum) & momentum > 0) %>%
arrange(desc(momentum))
# Select assets with negative momentum for SHORT positions
selected_short_df <- momentum_df %>%
filter(!is.na(momentum) & momentum < 0) %>%
arrange(momentum) # Arrange in ascending order (most negative first)
selected_long_assets_names <- selected_long_df$asset
selected_short_assets_names <- selected_short_df$asset
selected_long_assets[[i]] <- selected_long_assets_names
selected_short_assets[[i]] <- selected_short_assets_names
# Find indices of selected stocks
selected_long_idx <- match(selected_long_assets_names, asset_names)
selected_short_idx <- match(selected_short_assets_names, asset_names)
# Calculate portfolio return for the next month
next_month_return <- 0
# Determine the capital allocation (50% to long, 50% to short)
long_allocation <- 0.5
short_allocation <- 0.5
# Calculate long component return (if any long positions)
long_return <- 0
if (length(selected_long_idx) > 0) {
# Equal weighting for all selected long stocks
long_weights <- rep(1/length(selected_long_idx), length(selected_long_idx))
# Get the returns for the next month
long_next_month_returns <- as.numeric(asset_returns[current_idx + 1, selected_long_idx])
# Calculate weighted return for long positions
long_return <- sum(long_weights * long_next_month_returns, na.rm = TRUE)
}
# Calculate short component return (if any short positions)
short_return <- 0
if (length(selected_short_idx) > 0) {
# Equal weighting for all selected short stocks
short_weights <- rep(1/length(selected_short_idx), length(selected_short_idx))
# Get the returns for the next month (returns are negative for successful shorts)
short_next_month_returns <- as.numeric(asset_returns[current_idx + 1, selected_short_idx])
# Calculate weighted return for short positions (negative of the asset returns)
short_return <- -sum(short_weights * short_next_month_returns, na.rm = TRUE)
}
# Combine long and short returns with proper allocation
if (length(selected_long_idx) > 0 && length(selected_short_idx) > 0) {
# Both long and short positions
next_month_return <- (long_allocation * long_return) + (short_allocation * short_return)
} else if (length(selected_long_idx) > 0) {
# Only long positions
next_month_return <- long_return
} else if (length(selected_short_idx) > 0) {
# Only short positions
next_month_return <- short_return
} else {
# If no assets meet criteria, return 0 (cash position)
next_month_return <- 0
}
portfolio_returns[i] <- next_month_return
# Print progress
if (i %% 5 == 0 || i == 1 || i == n_periods) {
cat("Processing period", i, "of", n_periods,
"- Date:", as.character(dates[current_idx + 1]), "\n")
cat("LONG positions count:", length(selected_long_assets_names), "\n")
if (length(selected_long_assets_names) > 0) {
cat("Top 5 long momentum assets:", paste(head(selected_long_assets_names, 5), collapse=", "),
ifelse(length(selected_long_assets_names) > 5, "...", ""), "\n")
cat("Top 5 long momentum scores:", paste(sprintf("%.2f%%", head(selected_long_df$momentum, 5) * 100), collapse=", "),
ifelse(length(selected_long_assets_names) > 5, "...", ""), "\n")
} else {
cat("No assets with positive momentum found this period\n")
}
cat("SHORT positions count:", length(selected_short_assets_names), "\n")
if (length(selected_short_assets_names) > 0) {
cat("Top 5 short momentum assets:", paste(head(selected_short_assets_names, 5), collapse=", "),
ifelse(length(selected_short_assets_names) > 5, "...", ""), "\n")
cat("Top 5 short momentum scores:", paste(sprintf("%.2f%%", head(selected_short_df$momentum, 5) * 100), collapse=", "),
ifelse(length(selected_short_assets_names) > 5, "...", ""), "\n")
} else {
cat("No assets with negative momentum found this period\n")
}
}
}
# Create a time series of portfolio returns
portfolio_returns_ts <- xts(portfolio_returns, order.by = dates[(start_after_months + 1):length(dates)])
# Save all momentum scores to a file for analysis
all_momentum_df <- do.call(rbind, lapply(1:length(momentum_scores), function(i) {
df <- momentum_scores[[i]]
df$period <- i
df$date <- as.character(dates[i + start_after_months])
return(df)
}))
output_file <- file.path(base_dir, "long_short_momentum_scores.csv")
write.csv(all_momentum_df, output_file, row.names = FALSE)
cat("Saved all momentum scores to:", output_file, "\n")
return(list(
returns = portfolio_returns_ts,
selected_long_assets = selected_long_assets,
selected_short_assets = selected_short_assets,
all_momentum = all_momentum_df
))
}
# ---- PERFORMANCE ANALYSIS FUNCTION ----
# Function to analyze portfolio performance
analyze_long_short_momentum_portfolio <- function(portfolio_result, risk_free_rate, sp500_returns, start_after_months = 36) {
portfolio_returns <- portfolio_result$returns
# Calculate cumulative returns
cumulative_returns <- cumprod(1 + portfolio_returns) - 1
# Plot results
plot(cumulative_returns, main = "Cumulative Long-Short Momentum Portfolio Returns",
ylab = "Return", xlab = "Date")
# Calculate performance metrics
portfolio_avg_return <- mean(portfolio_returns) * 12 * 100 # Annualized and as percentage
portfolio_sd <- sd(portfolio_returns) * sqrt(12) * 100 # Annualized and as percentage
portfolio_sharpe <- mean(portfolio_returns - risk_free_rate[(start_after_months + 1):length(risk_free_rate)]) /
sd(portfolio_returns)
# Calculate benchmark metrics for the same period
benchmark_returns <- sp500_returns[(start_after_months + 1):length(sp500_returns)]
benchmark_avg_return <- mean(benchmark_returns) * 12 * 100 # Annualized and as percentage
benchmark_sd <- sd(benchmark_returns) * sqrt(12) * 100 # Annualized and as percentage
benchmark_sharpe <- mean(benchmark_returns - risk_free_rate[(start_after_months + 1):length(risk_free_rate)]) /
sd(benchmark_returns)
# Calculate Upside-Potential Ratio for both
target_return <- mean(risk_free_rate[(start_after_months + 1):length(risk_free_rate)])
portfolio_upside <- mean(pmax(portfolio_returns - target_return, 0)) /
sqrt(mean((portfolio_returns - mean(portfolio_returns))^2))
benchmark_upside <- mean(pmax(benchmark_returns - target_return, 0)) /
sqrt(mean((benchmark_returns - mean(benchmark_returns))^2))
# Create performance comparison table
performance_table <- data.frame(
Metric = c("Average Return", "Standard Deviation", "Sharpe Ratio", "Upside-Potential Ratio"),
`Long-Short Portfolio` = c(sprintf("%.2f%%", portfolio_avg_return),
sprintf("%.2f%%", portfolio_sd),
sprintf("%.3f", portfolio_sharpe),
sprintf("%.3f", portfolio_upside)),
`S&P 500 Benchmark` = c(sprintf("%.2f%%", benchmark_avg_return),
sprintf("%.2f%%", benchmark_sd),
sprintf("%.3f", benchmark_sharpe),
sprintf("%.3f", benchmark_upside))
)
cat("\n----- Long-Short Momentum Portfolio Performance Metrics -----\n")
print(performance_table)
# Save the performance table
output_file <- file.path(base_dir, "long_short_momentum_performance_comparison.csv")
write.csv(performance_table, output_file, row.names = FALSE)
cat("Saved performance comparison to:", output_file, "\n")
# Create a data frame of portfolio composition over time
composition <- data.frame(
Date = index(portfolio_returns),
stringsAsFactors = FALSE
)
composition$Long_Assets <- sapply(portfolio_result$selected_long_assets, function(assets) {
paste(assets, collapse = ", ")
})
composition$Short_Assets <- sapply(portfolio_result$selected_short_assets, function(assets) {
paste(assets, collapse = ", ")
})
composition$Long_Asset_Count <- sapply(portfolio_result$selected_long_assets, length)
composition$Short_Asset_Count <- sapply(portfolio_result$selected_short_assets, length)
# Save portfolio composition to CSV
output_file <- file.path(base_dir, "long_short_momentum_portfolio_composition.csv")
write.csv(composition, output_file, row.names = FALSE)
cat("Saved portfolio composition to:", output_file, "\n")
# Save portfolio returns to CSV
returns_df <- data.frame(
Date = index(portfolio_returns),
Return = as.numeric(portfolio_returns)
)
output_file <- file.path(base_dir, "long_short_momentum_portfolio_returns.csv")
write.csv(returns_df, output_file, row.names = FALSE)
cat("Saved portfolio returns to:", output_file, "\n")
# Count frequency of asset selection for long positions
all_selected_long <- unlist(portfolio_result$selected_long_assets)
long_selection_freq <- sort(table(all_selected_long), decreasing = TRUE)
# Count frequency of asset selection for short positions
all_selected_short <- unlist(portfolio_result$selected_short_assets)
short_selection_freq <- sort(table(all_selected_short), decreasing = TRUE)
cat("\n----- Most Frequently Selected Long Assets -----\n")
print(head(long_selection_freq, 10))
cat("\n----- Most Frequently Selected Short Assets -----\n")
print(head(short_selection_freq, 10))
# Save selection frequency to CSV for long positions
long_selection_freq_df <- data.frame(
Asset = names(long_selection_freq),
Frequency = as.numeric(long_selection_freq),
Percentage = as.numeric(long_selection_freq) / length(portfolio_result$selected_long_assets) * 100
)
output_file <- file.path(base_dir, "long_short_momentum_long_asset_selection_frequency.csv")
write.csv(long_selection_freq_df, output_file, row.names = FALSE)
cat("Saved long asset selection frequency to:", output_file, "\n")
# Save selection frequency to CSV for short positions
short_selection_freq_df <- data.frame(
Asset = names(short_selection_freq),
Frequency = as.numeric(short_selection_freq),
Percentage = as.numeric(short_selection_freq) / length(portfolio_result$selected_short_assets) * 100
)
output_file <- file.path(base_dir, "long_short_momentum_short_asset_selection_frequency.csv")
write.csv(short_selection_freq_df, output_file, row.names = FALSE)
cat("Saved short asset selection frequency to:", output_file, "\n")
return(list(
cumulative_returns = cumulative_returns,
performance_table = performance_table,
composition = composition,
long_selection_frequency = long_selection_freq_df,
short_selection_frequency = short_selection_freq_df
))
}
# ---- MAIN EXECUTION ----
# Run the complete analysis
run_long_short_momentum_analysis <- function() {
# Start timer
start_time <- Sys.time()
cat("Starting long-short momentum portfolio analysis at", as.character(start_time), "\n")
# Import data
cat("Importing data from Excel files...\n")
data <- import_excel_data(stock_file_path, market_file_path)
# Basic data exploration
cat("\nData summary:\n")
cat("- Number of stocks:", ncol(data$stock_returns), "\n")
cat("- Date range:", as.character(first(index(data$stock_returns))),
"to", as.character(last(index(data$stock_returns))), "\n")
cat("- Number of observations:", nrow(data$stock_returns), "\n\n")
# Run the portfolio construction
cat("Constructing long-short momentum portfolio...\n")
portfolio_result <- construct_long_short_momentum_portfolio(
asset_returns = data$stock_returns,
lookback_period = 3, # 3 months lookback for momentum
start_after_months = 36 # Start after 36 months of data
)
# Analyze performance
cat("\nAnalyzing long-short momentum portfolio performance...\n")
analysis <- analyze_long_short_momentum_portfolio(
portfolio_result = portfolio_result,
risk_free_rate = data$risk_free_rate,
sp500_returns = data$sp500_returns,
start_after_months = 36
)
# End timer
end_time <- Sys.time()
cat("\nAnalysis completed in", round(difftime(end_time, start_time, units = "mins"), 2), "minutes\n")
# Return results
return(list(
portfolio = portfolio_result,
analysis = analysis,
data = data
))
}
# Execute the analysis and store the results
long_short_momentum_result <- run_long_short_momentum_analysis()
## Starting long-short momentum portfolio analysis at 2025-05-03 15:36:45.884326
## Importing data from Excel files...
## Reading stock data from: C:/Users/lcyep/OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey/Tec/Semestre 6/Risk/R, project/data.xlsx
## New names:
## • `` -> `...1`
## Reading market data from: C:/Users/lcyep/OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey/Tec/Semestre 6/Risk/R, project/data2.xlsx
## New names:
## • `` -> `...1`
##
## Data summary:
## - Number of stocks: 50
## - Date range: 2005-01-31 to 2024-02-29
## - Number of observations: 230
##
## Constructing long-short momentum portfolio...
## Starting long-short momentum portfolio construction with 194 rebalancing periods
## Processing period 1 of 194 - Date: 2008-01-31
## LONG positions count: 23
## Top 5 long momentum assets: APPLE, NETFLIX, SALESFORCE, ALPHABET A, MICROSOFT ...
## Top 5 long momentum scores: 29.07%, 28.29%, 22.16%, 21.90%, 20.84% ...
## SHORT positions count: 27
## Top 5 short momentum assets: CITIGROUP, COMCAST A, STARBUCKS, LOWE'S COMPANIES, CISCO SYSTEMS ...
## Top 5 short momentum scores: -36.92%, -24.48%, -21.87%, -19.27%, -18.29% ...
## Processing period 5 of 194 - Date: 2008-05-30
## LONG positions count: 31
## Top 5 long momentum assets: SALESFORCE, APPLE, NETFLIX, UNION PACIFIC, AMERICAN TOWER ...
## Top 5 long momentum scores: 28.55%, 28.51%, 27.16%, 16.38%, 16.00% ...
## SHORT positions count: 19
## Top 5 short momentum assets: UNITEDHEALTH GROUP, MERCK & COMPANY, NVIDIA, BANK OF AMERICA, STARBUCKS ...
## Top 5 short momentum scores: -35.82%, -17.48%, -16.43%, -14.97%, -14.17% ...
## Processing period 10 of 194 - Date: 2008-10-31
## LONG positions count: 21
## Top 5 long momentum assets: WELLS FARGO & CO, BANK OF AMERICA, JP MORGAN CHASE & CO., AMGEN, CITIGROUP ...
## Top 5 long momentum scores: 58.02%, 46.63%, 36.11%, 25.68%, 22.37% ...
## SHORT positions count: 29
## Top 5 short momentum assets: NVIDIA, APPLE, SALESFORCE, ALPHABET A, TEXAS INSTRUMENTS ...
## Top 5 short momentum scores: -42.79%, -32.12%, -29.06%, -23.92%, -23.65% ...
## Processing period 15 of 194 - Date: 2009-03-31
## LONG positions count: 9
## Top 5 long momentum assets: NETFLIX, AMAZON.COM, ALPHABET A, INTERNATIONAL BUS.MCHS., NVIDIA ...
## Top 5 long momentum scores: 57.70%, 51.73%, 15.37%, 12.78%, 10.84% ...
## SHORT positions count: 41
## Top 5 short momentum assets: CITIGROUP, BANK OF AMERICA, WELLS FARGO & CO, ADOBE (NAS), JP MORGAN CHASE & CO. ...
## Top 5 short momentum scores: -81.91%, -75.69%, -58.12%, -27.89%, -27.83% ...
## Processing period 20 of 194 - Date: 2009-08-31
## LONG positions count: 45
## Top 5 long momentum assets: BANK OF AMERICA, TEXAS INSTRUMENTS, APPLE, THERMO FISHER SCIENTIFIC, AMGEN ...
## Top 5 long momentum scores: 65.62%, 33.17%, 29.85%, 29.08%, 28.55% ...
## SHORT positions count: 5
## Top 5 short momentum assets: LOCKHEED MARTIN, COMCAST A, NETFLIX, HOME DEPOT, WALMART
## Top 5 short momentum scores: -4.80%, -3.88%, -3.02%, -1.44%, -1.03%
## Processing period 25 of 194 - Date: 2010-01-29
## LONG positions count: 40
## Top 5 long momentum assets: AMAZON.COM, SALESFORCE, ALPHABET A, NVIDIA, UNITEDHEALTH GROUP ...
## Top 5 long momentum scores: 44.09%, 29.58%, 25.03%, 24.28%, 21.73% ...
## SHORT positions count: 10
## Top 5 short momentum assets: CITIGROUP, BANK OF AMERICA, GILEAD SCIENCES, AMGEN, JP MORGAN CHASE & CO. ...
## Top 5 short momentum scores: -31.61%, -10.99%, -6.95%, -6.08%, -4.91% ...
## Processing period 30 of 194 - Date: 2010-06-30
## LONG positions count: 22
## Top 5 long momentum assets: NETFLIX, SALESFORCE, APPLE, CITIGROUP, STARBUCKS ...
## Top 5 long momentum scores: 68.28%, 27.34%, 25.54%, 16.47%, 13.01% ...
## SHORT positions count: 28
## Top 5 short momentum assets: GILEAD SCIENCES, NVIDIA, UNITEDHEALTH GROUP, PFIZER, ABBOTT LABORATORIES ...
## Top 5 short momentum scores: -24.55%, -18.89%, -14.15%, -13.22%, -12.38% ...
## Processing period 35 of 194 - Date: 2010-11-30
## LONG positions count: 41
## Top 5 long momentum assets: NETFLIX, AMAZON.COM, NVIDIA, ALPHABET A, ORACLE ...
## Top 5 long momentum scores: 69.25%, 40.16%, 30.80%, 26.58%, 24.28% ...
## SHORT positions count: 9
## Top 5 short momentum assets: BANK OF AMERICA, JP MORGAN CHASE & CO., WELLS FARGO & CO, LOCKHEED MARTIN, MEDTRONIC ...
## Top 5 short momentum scores: -18.45%, -6.58%, -6.02%, -5.14%, -4.71% ...
## Processing period 40 of 194 - Date: 2011-04-29
## LONG positions count: 35
## Top 5 long momentum assets: NETFLIX, UNITEDHEALTH GROUP, NVIDIA, CHEVRON, GILEAD SCIENCES ...
## Top 5 long momentum scores: 35.33%, 25.17%, 19.87%, 17.80%, 17.19% ...
## SHORT positions count: 15
## Top 5 short momentum assets: CISCO SYSTEMS, NIKE 'B', MICROSOFT, MERCK & COMPANY, CITIGROUP ...
## Top 5 short momentum scores: -15.22%, -11.38%, -9.03%, -8.41%, -6.55% ...
## Processing period 45 of 194 - Date: 2011-09-30
## LONG positions count: 11
## Top 5 long momentum assets: MCDONALDS, APPLE, AMAZON.COM, MICROSOFT, COCA COLA ...
## Top 5 long momentum scores: 10.88%, 10.64%, 9.43%, 6.36%, 5.45% ...
## SHORT positions count: 39
## Top 5 short momentum assets: NVIDIA, BANK OF AMERICA, ADOBE (NAS), TEXAS INSTRUMENTS, CITIGROUP ...
## Top 5 short momentum scores: -33.58%, -30.47%, -27.12%, -25.75%, -24.54% ...
## Processing period 50 of 194 - Date: 2012-02-29
## LONG positions count: 39
## Top 5 long momentum assets: NETFLIX, LOWE'S COMPANIES, HOME DEPOT, AMGEN, GILEAD SCIENCES ...
## Top 5 long momentum scores: 46.44%, 27.64%, 23.99%, 18.61%, 17.28% ...
## SHORT positions count: 11
## Top 5 short momentum assets: ORACLE, SALESFORCE, AMAZON.COM, ACCENTURE CLASS A, CITIGROUP ...
## Top 5 short momentum scores: -13.92%, -12.29%, -8.93%, -4.85%, -2.75% ...
## Processing period 55 of 194 - Date: 2012-07-31
## LONG positions count: 22
## Top 5 long momentum assets: VERIZON COMMUNICATIONS, AT&T, WALMART, AMAZON.COM, NEXTERA ENERGY ...
## Top 5 long momentum scores: 16.24%, 14.19%, 13.92%, 12.76%, 12.66% ...
## SHORT positions count: 28
## Top 5 short momentum assets: NETFLIX, CITIGROUP, JP MORGAN CHASE & CO., NIKE 'B', CISCO SYSTEMS ...
## Top 5 short momentum scores: -40.47%, -25.01%, -22.29%, -19.05%, -18.82% ...
## Processing period 60 of 194 - Date: 2012-12-31
## LONG positions count: 36
## Top 5 long momentum assets: NETFLIX, GILEAD SCIENCES, LOWE'S COMPANIES, BANK OF AMERICA, CITIGROUP ...
## Top 5 long momentum scores: 36.82%, 30.01%, 26.72%, 23.40%, 16.36% ...
## SHORT positions count: 14
## Top 5 short momentum assets: INTEL, NVIDIA, MICROSOFT, APPLE, AT&T ...
## Top 5 short momentum scores: -21.20%, -14.68%, -13.64%, -12.02%, -6.85% ...
## Processing period 65 of 194 - Date: 2013-05-31
## LONG positions count: 44
## Top 5 long momentum assets: NETFLIX, GILEAD SCIENCES, VERIZON COMMUNICATIONS, AMGEN, MICROSOFT ...
## Top 5 long momentum scores: 30.76%, 28.37%, 23.62%, 21.94%, 20.58% ...
## SHORT positions count: 6
## Top 5 short momentum assets: ORACLE, SALESFORCE, AMAZON.COM, APPLE, EXXON MOBIL ...
## Top 5 short momentum scores: -7.69%, -4.47%, -4.40%, -2.79%, -1.09% ...
## Processing period 70 of 194 - Date: 2013-10-31
## LONG positions count: 33
## Top 5 long momentum assets: NETFLIX, SALESFORCE, GILEAD SCIENCES, APPLE, LOCKHEED MARTIN ...
## Top 5 long momentum scores: 46.48%, 35.96%, 22.63%, 20.23%, 17.60% ...
## SHORT positions count: 17
## Top 5 short momentum assets: VERIZON COMMUNICATIONS, COCA COLA, INTEL, ABBOTT LABORATORIES, EXXON MOBIL ...
## Top 5 short momentum scores: -7.28%, -5.56%, -5.40%, -4.85%, -4.77% ...
## Processing period 75 of 194 - Date: 2014-03-31
## LONG positions count: 34
## Top 5 long momentum assets: THERMO FISHER SCIENTIFIC, NETFLIX, ADOBE (NAS), SALESFORCE, ELI LILLY ...
## Top 5 long momentum scores: 23.49%, 21.82%, 20.87%, 19.74%, 18.70% ...
## SHORT positions count: 16
## Top 5 short momentum assets: STARBUCKS, AT&T, CITIGROUP, AMAZON.COM, WALMART ...
## Top 5 short momentum scores: -12.89%, -9.32%, -8.11%, -8.01%, -7.79% ...
## Processing period 80 of 194 - Date: 2014-08-29
## LONG positions count: 36
## Top 5 long momentum assets: NETFLIX, INTEL, GILEAD SCIENCES, AMGEN, APPLE ...
## Top 5 long momentum scores: 31.26%, 26.98%, 16.64%, 14.00%, 13.41% ...
## SHORT positions count: 14
## Top 5 short momentum assets: PFIZER, WALMART, MCDONALDS, PROCTER & GAMBLE, NEXTERA ENERGY ...
## Top 5 short momentum scores: -8.25%, -7.69%, -6.73%, -6.34%, -5.97% ...
## Processing period 85 of 194 - Date: 2015-01-30
## LONG positions count: 37
## Top 5 long momentum assets: LOWE'S COMPANIES, ORACLE, UNITEDHEALTH GROUP, MEDTRONIC, BRISTOL MYERS SQUIBB ...
## Top 5 long momentum scores: 30.01%, 17.48%, 17.21%, 16.55%, 15.34% ...
## SHORT positions count: 13
## Top 5 short momentum assets: NETFLIX, INTERNATIONAL BUS.MCHS., GILEAD SCIENCES, ALPHABET A, VERIZON COMMUNICATIONS ...
## Top 5 short momentum scores: -24.29%, -15.48%, -11.45%, -9.81%, -6.42% ...
## Processing period 90 of 194 - Date: 2015-06-30
## LONG positions count: 23
## Top 5 long momentum assets: NETFLIX, AMAZON.COM, ELI LILLY, STARBUCKS, GILEAD SCIENCES ...
## Top 5 long momentum scores: 31.41%, 12.91%, 12.44%, 11.16%, 8.44% ...
## SHORT positions count: 27
## Top 5 short momentum assets: UNION PACIFIC, WALMART, PROCTER & GAMBLE, AMERICAN TOWER, LOCKHEED MARTIN ...
## Top 5 short momentum scores: -16.09%, -11.51%, -7.92%, -6.41%, -5.92% ...
## Processing period 95 of 194 - Date: 2015-11-30
## LONG positions count: 27
## Top 5 long momentum assets: NVIDIA, INTEL, AMAZON.COM, NIKE 'B', TEXAS INSTRUMENTS ...
## Top 5 long momentum scores: 42.21%, 16.96%, 16.74%, 13.72%, 13.49% ...
## SHORT positions count: 23
## Top 5 short momentum assets: WALMART, INTERNATIONAL BUS.MCHS., ABBOTT LABORATORIES, AMGEN, CITIGROUP ...
## Top 5 short momentum scores: -20.48%, -13.53%, -11.62%, -10.43%, -9.05% ...
## Processing period 100 of 194 - Date: 2016-04-29
## LONG positions count: 26
## Top 5 long momentum assets: VERIZON COMMUNICATIONS, NEXTERA ENERGY, AT&T, ORACLE, WALMART ...
## Top 5 long momentum scores: 17.01%, 13.91%, 13.83%, 11.99%, 11.73% ...
## SHORT positions count: 24
## Top 5 short momentum assets: BANK OF AMERICA, CITIGROUP, ELI LILLY, AMAZON.COM, WELLS FARGO & CO ...
## Top 5 short momentum scores: -19.67%, -19.32%, -14.54%, -12.17%, -11.04% ...
## Processing period 105 of 194 - Date: 2016-09-30
## LONG positions count: 39
## Top 5 long momentum assets: NVIDIA, TEXAS INSTRUMENTS, INTEL, UNION PACIFIC, MERCK & COMPANY ...
## Top 5 long momentum scores: 31.29%, 14.75%, 13.61%, 13.47%, 11.61% ...
## SHORT positions count: 11
## Top 5 short momentum assets: BRISTOL MYERS SQUIBB, GILEAD SCIENCES, MCDONALDS, SALESFORCE, NETFLIX ...
## Top 5 short momentum scores: -19.96%, -9.97%, -5.24%, -5.12%, -4.99% ...
## Processing period 110 of 194 - Date: 2017-02-28
## LONG positions count: 40
## Top 5 long momentum assets: NVIDIA, BANK OF AMERICA, WELLS FARGO & CO, JP MORGAN CHASE & CO., COMCAST A ...
## Top 5 long momentum scores: 53.43%, 37.21%, 22.43%, 22.19%, 22.00% ...
## SHORT positions count: 10
## Top 5 short momentum assets: AMERICAN TOWER, MEDTRONIC, WALMART, BRISTOL MYERS SQUIBB, NEXTERA ENERGY ...
## Top 5 short momentum scores: -11.68%, -7.32%, -4.68%, -3.44%, -3.34% ...
## Processing period 115 of 194 - Date: 2017-07-31
## LONG positions count: 33
## Top 5 long momentum assets: NVIDIA, MCDONALDS, THERMO FISHER SCIENTIFIC, UNITEDHEALTH GROUP, ORACLE ...
## Top 5 long momentum scores: 32.71%, 18.17%, 13.59%, 13.05%, 12.40% ...
## SHORT positions count: 17
## Top 5 short momentum assets: INTERNATIONAL BUS.MCHS., AT&T, VERIZON COMMUNICATIONS, CISCO SYSTEMS, INTEL ...
## Top 5 short momentum scores: -11.66%, -9.19%, -8.39%, -7.40%, -6.46% ...
## Processing period 120 of 194 - Date: 2017-12-29
## LONG positions count: 42
## Top 5 long momentum assets: INTEL, WALMART, UNION PACIFIC, AMAZON.COM, HOME DEPOT ...
## Top 5 long momentum scores: 27.86%, 24.54%, 20.13%, 20.00%, 19.98% ...
## SHORT positions count: 8
## Top 5 short momentum assets: MERCK & COMPANY, GILEAD SCIENCES, COMCAST A, AT&T, AMERICAN TOWER ...
## Top 5 short momentum scores: -13.45%, -10.67%, -7.56%, -2.88%, -2.78% ...
## Processing period 125 of 194 - Date: 2018-05-31
## LONG positions count: 11
## Top 5 long momentum assets: NETFLIX, ADOBE (NAS), AMAZON.COM, INTEL, CISCO SYSTEMS ...
## Top 5 long momentum scores: 15.60%, 10.93%, 7.94%, 7.23%, 6.62% ...
## SHORT positions count: 39
## Top 5 short momentum assets: COMCAST A, LOWE'S COMPANIES, WELLS FARGO & CO, WALMART, BRISTOL MYERS SQUIBB ...
## Top 5 short momentum scores: -26.19%, -21.29%, -21.01%, -17.02%, -16.73% ...
## Processing period 130 of 194 - Date: 2018-10-31
## LONG positions count: 45
## Top 5 long momentum assets: ELI LILLY, APPLE, PFIZER, ABBOTT LABORATORIES, LOWE'S COMPANIES ...
## Top 5 long momentum scores: 25.76%, 21.95%, 21.47%, 20.28%, 20.14% ...
## SHORT positions count: 5
## Top 5 short momentum assets: WELLS FARGO & CO, INTEL, NETFLIX, CHEVRON, TEXAS INSTRUMENTS
## Top 5 short momentum scores: -5.19%, -4.87%, -4.42%, -3.28%, -2.68%
## Processing period 135 of 194 - Date: 2019-03-29
## LONG positions count: 27
## Top 5 long momentum assets: NETFLIX, DANAHER, SALESFORCE, NIKE 'B', LOWE'S COMPANIES ...
## Top 5 long momentum scores: 25.15%, 15.96%, 14.63%, 14.12%, 11.36% ...
## SHORT positions count: 23
## Top 5 short momentum assets: UNITEDHEALTH GROUP, COCA COLA, GILEAD SCIENCES, AMGEN, WELLS FARGO & CO ...
## Top 5 short momentum scores: -13.91%, -10.04%, -9.62%, -8.73%, -8.09% ...
## Processing period 140 of 194 - Date: 2019-08-30
## LONG positions count: 32
## Top 5 long momentum assets: STARBUCKS, MEDTRONIC, COSTCO WHOLESALE, PROCTER & GAMBLE, AT&T ...
## Top 5 long momentum scores: 21.90%, 14.78%, 12.26%, 10.86%, 9.98% ...
## SHORT positions count: 17
## Top 5 short momentum assets: NETFLIX, LOWE'S COMPANIES, JOHNSON & JOHNSON, EXXON MOBIL, ELI LILLY ...
## Top 5 short momentum scores: -12.83%, -10.38%, -7.78%, -7.37%, -6.91% ...
## Processing period 145 of 194 - Date: 2020-01-31
## LONG positions count: 39
## Top 5 long momentum assets: UNITEDHEALTH GROUP, NVIDIA, APPLE, BRISTOL MYERS SQUIBB, AMGEN ...
## Top 5 long momentum scores: 35.28%, 35.18%, 31.11%, 26.58%, 24.58% ...
## SHORT positions count: 11
## Top 5 short momentum assets: MCDONALDS, INTERNATIONAL BUS.MCHS., HOME DEPOT, ORACLE, CISCO SYSTEMS ...
## Top 5 short momentum scores: -7.96%, -7.83%, -5.88%, -3.73%, -2.93% ...
## Processing period 150 of 194 - Date: 2020-06-30
## LONG positions count: 35
## Top 5 long momentum assets: NVIDIA, AMAZON.COM, ABBOTT LABORATORIES, LOWE'S COMPANIES, ELI LILLY ...
## Top 5 long momentum scores: 31.45%, 29.65%, 23.22%, 22.31%, 21.26% ...
## SHORT positions count: 15
## Top 5 short momentum assets: WELLS FARGO & CO, CITIGROUP, JP MORGAN CHASE & CO., BANK OF AMERICA, COCA COLA ...
## Top 5 short momentum scores: -35.20%, -24.50%, -16.19%, -15.37%, -12.73% ...
## Processing period 155 of 194 - Date: 2020-11-30
## LONG positions count: 25
## Top 5 long momentum assets: NIKE 'B', SALESFORCE, NVIDIA, THERMO FISHER SCIENTIFIC, STARBUCKS ...
## Top 5 long momentum scores: 23.02%, 19.20%, 18.08%, 14.29%, 13.63% ...
## SHORT positions count: 25
## Top 5 short momentum assets: CISCO SYSTEMS, EXXON MOBIL, CHEVRON, CITIGROUP, GILEAD SCIENCES ...
## Top 5 short momentum scores: -23.78%, -22.48%, -17.20%, -17.18%, -16.37% ...
## Processing period 160 of 194 - Date: 2021-04-30
## LONG positions count: 34
## Top 5 long momentum assets: EXXON MOBIL, WELLS FARGO & CO, INTEL, BANK OF AMERICA, CHEVRON ...
## Top 5 long momentum scores: 35.44%, 29.46%, 28.46%, 27.65%, 24.09% ...
## SHORT positions count: 16
## Top 5 short momentum assets: APPLE, COSTCO WHOLESALE, NIKE 'B', WALMART, MERCK & COMPANY ...
## Top 5 short momentum scores: -7.94%, -6.45%, -6.06%, -5.77%, -5.76% ...
## Processing period 165 of 194 - Date: 2021-09-30
## LONG positions count: 37
## Top 5 long momentum assets: NVIDIA, ADOBE (NAS), ELI LILLY, DANAHER, ALPHABET A ...
## Top 5 long momentum scores: 37.80%, 31.54%, 29.31%, 26.56%, 22.79% ...
## SHORT positions count: 13
## Top 5 short momentum assets: CITIGROUP, AT&T, CHEVRON, EXXON MOBIL, LOCKHEED MARTIN ...
## Top 5 short momentum scores: -8.64%, -6.83%, -6.76%, -6.60%, -5.86% ...
## Processing period 170 of 194 - Date: 2022-02-28
## LONG positions count: 21
## Top 5 long momentum assets: PFIZER, EXXON MOBIL, LOCKHEED MARTIN, APPLE, CHEVRON ...
## Top 5 long momentum scores: 20.46%, 17.82%, 17.09%, 16.68%, 14.71% ...
## SHORT positions count: 29
## Top 5 short momentum assets: NETFLIX, SALESFORCE, ADOBE (NAS), WALT DISNEY, ORACLE ...
## Top 5 short momentum scores: -38.12%, -22.38%, -17.85%, -15.44%, -15.41% ...
## Processing period 175 of 194 - Date: 2022-07-29
## LONG positions count: 13
## Top 5 long momentum assets: AT&T, ELI LILLY, MERCK & COMPANY, INTERNATIONAL BUS.MCHS., BRISTOL MYERS SQUIBB ...
## Top 5 long momentum scores: 17.22%, 13.22%, 11.12%, 8.59%, 5.44% ...
## SHORT positions count: 37
## Top 5 short momentum assets: NETFLIX, NVIDIA, AMAZON.COM, WALT DISNEY, INTEL ...
## Top 5 short momentum scores: -53.32%, -44.44%, -34.84%, -31.18%, -24.52% ...
## Processing period 180 of 194 - Date: 2022-12-30
## LONG positions count: 37
## Top 5 long momentum assets: GILEAD SCIENCES, NETFLIX, MERCK & COMPANY, ELI LILLY, STARBUCKS ...
## Top 5 long momentum scores: 38.38%, 36.67%, 29.01%, 23.19%, 21.57% ...
## SHORT positions count: 13
## Top 5 short momentum assets: AMAZON.COM, AMERICAN TOWER, WALT DISNEY, MEDTRONIC, ADOBE (NAS) ...
## Top 5 short momentum scores: -23.85%, -12.91%, -12.68%, -10.10%, -7.63% ...
## Processing period 185 of 194 - Date: 2023-05-31
## LONG positions count: 24
## Top 5 long momentum assets: NVIDIA, MICROSOFT, SALESFORCE, APPLE, ELI LILLY ...
## Top 5 long momentum scores: 42.03%, 23.99%, 18.10%, 17.60%, 15.03% ...
## SHORT positions count: 26
## Top 5 short momentum assets: BANK OF AMERICA, WELLS FARGO & CO, AT&T, PFIZER, DANAHER ...
## Top 5 short momentum scores: -17.47%, -15.19%, -13.25%, -11.93%, -10.39% ...
## Processing period 190 of 194 - Date: 2023-10-31
## LONG positions count: 15
## Top 5 long momentum assets: AMGEN, ELI LILLY, EXXON MOBIL, ALPHABET A, CHEVRON ...
## Top 5 long momentum scores: 21.05%, 14.53%, 9.63%, 9.32%, 7.16% ...
## SHORT positions count: 35
## Top 5 short momentum assets: NEXTERA ENERGY, AMERICAN TOWER, NETFLIX, NIKE 'B', VERIZON COMMUNICATIONS ...
## Top 5 short momentum scores: -22.79%, -15.21%, -14.28%, -13.36%, -12.85% ...
## Processing period 194 of 194 - Date: 2024-02-29
## LONG positions count: 42
## Top 5 long momentum assets: NVIDIA, CITIGROUP, SALESFORCE, NETFLIX, BANK OF AMERICA ...
## Top 5 long momentum scores: 50.88%, 42.24%, 39.96%, 37.02%, 29.12% ...
## SHORT positions count: 8
## Top 5 short momentum assets: PFIZER, LOCKHEED MARTIN, BRISTOL MYERS SQUIBB, UNITEDHEALTH GROUP, CISCO SYSTEMS ...
## Top 5 short momentum scores: -11.39%, -5.55%, -5.16%, -4.45%, -3.74% ...
## Saved all momentum scores to: C:/Users/lcyep/OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey/Tec/Semestre 6/Risk/R, project/long_short_momentum_scores.csv
##
## Analyzing long-short momentum portfolio performance...
##
## ----- Long-Short Momentum Portfolio Performance Metrics -----
## Metric Long.Short.Portfolio S.P.500.Benchmark
## 1 Average Return -0.00% 9.04%
## 2 Standard Deviation 5.96% 16.18%
## 3 Sharpe Ratio -0.047 0.144
## 4 Upside-Potential Ratio 0.329 0.465
## Saved performance comparison to: C:/Users/lcyep/OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey/Tec/Semestre 6/Risk/R, project/long_short_momentum_performance_comparison.csv
## Saved portfolio composition to: C:/Users/lcyep/OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey/Tec/Semestre 6/Risk/R, project/long_short_momentum_portfolio_composition.csv
## Saved portfolio returns to: C:/Users/lcyep/OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey/Tec/Semestre 6/Risk/R, project/long_short_momentum_portfolio_returns.csv
##
## ----- Most Frequently Selected Long Assets -----
## all_selected_long
## ADOBE (NAS) NETFLIX UNITEDHEALTH GROUP
## 139 137 136
## COSTCO WHOLESALE APPLE DANAHER
## 135 133 133
## UNION PACIFIC SALESFORCE THERMO FISHER SCIENTIFIC
## 132 131 131
## ACCENTURE CLASS A
## 130
##
## ----- Most Frequently Selected Short Assets -----
## all_selected_short
## AT&T EXXON MOBIL VERIZON COMMUNICATIONS
## 104 101 98
## INTEL CITIGROUP CHEVRON
## 94 93 92
## CISCO SYSTEMS GILEAD SCIENCES PFIZER
## 86 86 86
## INTERNATIONAL BUS.MCHS.
## 85
## Saved long asset selection frequency to: C:/Users/lcyep/OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey/Tec/Semestre 6/Risk/R, project/long_short_momentum_long_asset_selection_frequency.csv
## Saved short asset selection frequency to: C:/Users/lcyep/OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey/Tec/Semestre 6/Risk/R, project/long_short_momentum_short_asset_selection_frequency.csv
##
## Analysis completed in 0.03 minutes
# ---- ADDITIONAL ANALYSIS ----
# 1. Plot the portfolio returns alongside the benchmark
portfolio_vs_benchmark <- merge(
`Long-Short` = cumprod(1 + long_short_momentum_result$portfolio$returns) - 1,
Benchmark = cumprod(1 + long_short_momentum_result$data$sp500_returns[(36+1):length(long_short_momentum_result$data$sp500_returns)]) - 1
)
# Create a plot with different colors and a legend
plot(portfolio_vs_benchmark,
main = "Long-Short Momentum Portfolio vs. S&P 500",
col = c("blue", "red"),
lwd = c(2, 2),
legend.loc = "topleft")

# Save the plot
output_file <- file.path(base_dir, "long_short_momentum_portfolio_vs_benchmark.png")
png(output_file, width = 800, height = 500)
plot(portfolio_vs_benchmark,
main = "Long-Short Momentum Portfolio vs. S&P 500",
col = c("blue", "red"),
lwd = c(2, 2),
legend.loc = "topleft")
dev.off()
## png
## 2
cat("Saved portfolio vs benchmark plot to:", output_file, "\n")
## Saved portfolio vs benchmark plot to: C:/Users/lcyep/OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey/Tec/Semestre 6/Risk/R, project/long_short_momentum_portfolio_vs_benchmark.png
# 2. Calculate annual returns
annual_returns <- apply.yearly(long_short_momentum_result$portfolio$returns, Return.cumulative)
print(annual_returns)
## [,1]
## 2008-12-31 -0.0707925166
## 2009-12-31 -0.0242900337
## 2010-12-31 0.0281704396
## 2011-12-30 0.0802211329
## 2012-12-31 -0.1076291865
## 2013-12-31 0.0138861492
## 2014-12-31 -0.0204361646
## 2015-12-31 -0.0003605381
## 2016-12-30 -0.0320946763
## 2017-12-29 -0.0123021490
## 2018-12-31 0.0114466335
## 2019-12-31 -0.0021798030
## 2020-12-31 0.0915335408
## 2021-12-31 0.0224574350
## 2022-12-30 0.0126632810
## 2023-12-29 -0.0316552711
## 2024-02-29 0.0308158468
# 3. Monthly returns statistics
monthly_stats <- data.frame(
Statistic = c("Min", "1st Quartile", "Median", "Mean", "3rd Quartile", "Max", "Standard Deviation"),
Value = c(
min(long_short_momentum_result$portfolio$returns),
quantile(long_short_momentum_result$portfolio$returns, 0.25),
median(long_short_momentum_result$portfolio$returns),
mean(long_short_momentum_result$portfolio$returns),
quantile(long_short_momentum_result$portfolio$returns, 0.75),
max(long_short_momentum_result$portfolio$returns),
sd(long_short_momentum_result$portfolio$returns)
)
)
# Print monthly statistics
cat("\n----- Monthly Return Statistics -----\n")
##
## ----- Monthly Return Statistics -----
print(monthly_stats)
## Statistic Value
## 1 Min -1.121605e-01
## 2 1st Quartile -9.546434e-03
## 3 Median 3.418900e-04
## 4 Mean -1.527840e-06
## 5 3rd Quartile 1.009043e-02
## 6 Max 4.661465e-02
## 7 Standard Deviation 1.720165e-02
# Save statistics to CSV
output_file <- file.path(base_dir, "long_short_momentum_monthly_statistics.csv")
write.csv(monthly_stats, output_file, row.names = FALSE)
cat("Saved monthly return statistics to:", output_file, "\n")
## Saved monthly return statistics to: C:/Users/lcyep/OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey/Tec/Semestre 6/Risk/R, project/long_short_momentum_monthly_statistics.csv
# Save all output files in one directory for easy access
save(long_short_momentum_result, file = file.path(base_dir, "long_short_momentum_portfolio_results.RData"))
cat("All analysis results saved to:", file.path(base_dir, "long_short_momentum_portfolio_results.RData"), "\n")
## All analysis results saved to: C:/Users/lcyep/OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey/Tec/Semestre 6/Risk/R, project/long_short_momentum_portfolio_results.RData
# 4. Additional visualization: Histogram of returns
png(file.path(base_dir, "long_short_momentum_returns_histogram.png"), width = 800, height = 500)
hist(long_short_momentum_result$portfolio$returns,
breaks = 30,
main = "Long-Short Momentum Portfolio Monthly Returns Distribution",
xlab = "Monthly Return",
col = "skyblue")
abline(v = mean(long_short_momentum_result$portfolio$returns), col = "red", lwd = 2)
dev.off()
## png
## 2
# 5. Drawdown analysis
drawdown_portfolio <- PerformanceAnalytics::Drawdowns(long_short_momentum_result$portfolio$returns)
drawdown_benchmark <- PerformanceAnalytics::Drawdowns(
long_short_momentum_result$data$sp500_returns[(36+1):length(long_short_momentum_result$data$sp500_returns)]
)
drawdowns <- merge(
`Long-Short` = drawdown_portfolio,
Benchmark = drawdown_benchmark
)
png(file.path(base_dir, "long_short_momentum_drawdowns.png"), width = 800, height = 500)
plot(drawdowns,
main = "Drawdowns: Long-Short Momentum Portfolio vs S&P 500",
col = c("blue", "red"),
lwd = c(2, 2),
legend.loc = "bottomleft")
dev.off()
## png
## 2
# 6. Count the average number of stocks in the portfolio
avg_long_stocks <- mean(sapply(long_short_momentum_result$portfolio$selected_long_assets, length))
avg_short_stocks <- mean(sapply(long_short_momentum_result$portfolio$selected_short_assets, length))
cat("\nAverage number of long stocks in the portfolio:", round(avg_long_stocks, 2), "\n")
##
## Average number of long stocks in the portfolio: 30.68
cat("Average number of short stocks in the portfolio:", round(avg_short_stocks, 2), "\n")
## Average number of short stocks in the portfolio: 19.32
# 7. Calculate the turnover rate for long positions
long_turnover <- numeric(length(long_short_momentum_result$portfolio$selected_long_assets) - 1)
for (i in 2:length(long_short_momentum_result$portfolio$selected_long_assets)) {
prev_stocks <- long_short_momentum_result$portfolio$selected_long_assets[[i-1]]
curr_stocks <- long_short_momentum_result$portfolio$selected_long_assets[[i]]
# Calculate how many stocks were changed
stocks_removed <- setdiff(prev_stocks, curr_stocks)
stocks_added <- setdiff(curr_stocks, prev_stocks)
# Turnover is the number of stocks changed divided by the average number of stocks
total_changed <- length(stocks_removed) + length(stocks_added)
avg_portfolio_size <- (length(prev_stocks) + length(curr_stocks)) / 2
if (avg_portfolio_size > 0) {
long_turnover[i-1] <- total_changed / (2 * avg_portfolio_size)
} else {
long_turnover[i-1] <- 0
}
}
# Calculate the turnover rate for short positions
short_turnover <- numeric(length(long_short_momentum_result$portfolio$selected_short_assets) - 1)
for (i in 2:length(long_short_momentum_result$portfolio$selected_short_assets)) {
prev_stocks <- long_short_momentum_result$portfolio$selected_short_assets[[i-1]]
curr_stocks <- long_short_momentum_result$portfolio$selected_short_assets[[i]]
# Calculate how many stocks were changed
stocks_removed <- setdiff(prev_stocks, curr_stocks)
stocks_added <- setdiff(curr_stocks, prev_stocks)
# Turnover is the number of stocks changed divided by the average number of stocks
total_changed <- length(stocks_removed) + length(stocks_added)
avg_portfolio_size <- (length(prev_stocks) + length(curr_stocks)) / 2
if (avg_portfolio_size > 0) {
short_turnover[i-1] <- total_changed / (2 * avg_portfolio_size)
} else {
short_turnover[i-1] <- 0
}
}
cat("Average monthly turnover rate for long positions:", round(mean(long_turnover, na.rm = TRUE) * 100, 2), "%\n")
## Average monthly turnover rate for long positions: 25.49 %
cat("Average monthly turnover rate for short positions:", round(mean(short_turnover, na.rm = TRUE) * 100, 2), "%\n")
## Average monthly turnover rate for short positions: 40.58 %