# Momentum Portfolio Construction with 3-month lookback window
# This script creates a portfolio that invests in stocks with positive 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 momentum portfolio based on trailing returns
construct_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_assets <- list()
  momentum_scores <- list()
  
  cat("Starting 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
    selected_momentum_df <- momentum_df %>%
      filter(!is.na(momentum) & momentum > 0) %>%
      arrange(desc(momentum))
    
    selected_assets_names <- selected_momentum_df$asset
    selected_assets[[i]] <- selected_assets_names
    
    # Find indices of selected stocks
    selected_idx <- match(selected_assets_names, asset_names)
    
    # Calculate portfolio return for the next month
    next_month_return <- 0
    
    if (length(selected_idx) > 0) {
      # Equal weighting for all selected stocks
      weights <- rep(1/length(selected_idx), length(selected_idx))
      
      # Get the returns for the next month
      next_month_returns <- as.numeric(asset_returns[current_idx + 1, selected_idx])
      
      # Calculate weighted return
      next_month_return <- sum(weights * next_month_returns, na.rm = TRUE)
    } 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")
      
      if (length(selected_assets_names) > 0) {
        cat("Selected assets count:", length(selected_assets_names), "\n")
        cat("Top 5 momentum assets:", paste(head(selected_assets_names, 5), collapse=", "), 
            ifelse(length(selected_assets_names) > 5, "...", ""), "\n")
        cat("Top 5 momentum scores:", paste(sprintf("%.2f%%", head(selected_momentum_df$momentum, 5) * 100), collapse=", "),
            ifelse(length(selected_assets_names) > 5, "...", ""), "\n")
      } else {
        cat("No assets with positive 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, "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_assets = selected_assets,
    all_momentum = all_momentum_df
  ))
}

# ---- PERFORMANCE ANALYSIS FUNCTION ----

# Function to analyze portfolio performance
analyze_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 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"),
    `Momentum 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----- Momentum Portfolio Performance Metrics -----\n")
  print(performance_table)
  
  # Save the performance table
  output_file <- file.path(base_dir, "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$Assets <- sapply(portfolio_result$selected_assets, function(assets) {
    paste(assets, collapse = ", ")
  })
  
  composition$Asset_Count <- sapply(portfolio_result$selected_assets, length)
  
  # Save portfolio composition to CSV
  output_file <- file.path(base_dir, "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, "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
  all_selected <- unlist(portfolio_result$selected_assets)
  selection_freq <- sort(table(all_selected), decreasing = TRUE)
  
  cat("\n----- Most Frequently Selected Assets -----\n")
  print(head(selection_freq, 10))
  
  # Save selection frequency to CSV
  selection_freq_df <- data.frame(
    Asset = names(selection_freq),
    Frequency = as.numeric(selection_freq),
    Percentage = as.numeric(selection_freq) / length(portfolio_result$selected_assets) * 100
  )
  output_file <- file.path(base_dir, "momentum_asset_selection_frequency.csv")
  write.csv(selection_freq_df, output_file, row.names = FALSE)
  cat("Saved asset selection frequency to:", output_file, "\n")
  
  return(list(
    cumulative_returns = cumulative_returns,
    performance_table = performance_table,
    composition = composition,
    selection_frequency = selection_freq_df
  ))
}

# ---- MAIN EXECUTION ----

# Run the complete analysis
run_momentum_analysis <- function() {
  # Start timer
  start_time <- Sys.time()
  cat("Starting 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 momentum portfolio...\n")
  portfolio_result <- construct_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 momentum portfolio performance...\n")
  analysis <- analyze_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
momentum_result <- run_momentum_analysis()
## Starting momentum portfolio analysis at 2025-05-03 15:27:56.704972 
## 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 momentum portfolio...
## Starting momentum portfolio construction with 194 rebalancing periods
## Processing period 1 of 194 - Date: 2008-01-31 
## Selected assets count: 23 
## Top 5 momentum assets: APPLE, NETFLIX, SALESFORCE, ALPHABET A, MICROSOFT ... 
## Top 5 momentum scores: 29.07%, 28.29%, 22.16%, 21.90%, 20.84% ... 
## Processing period 5 of 194 - Date: 2008-05-30 
## Selected assets count: 31 
## Top 5 momentum assets: SALESFORCE, APPLE, NETFLIX, UNION PACIFIC, AMERICAN TOWER ... 
## Top 5 momentum scores: 28.55%, 28.51%, 27.16%, 16.38%, 16.00% ... 
## Processing period 10 of 194 - Date: 2008-10-31 
## Selected assets count: 21 
## Top 5 momentum assets: WELLS FARGO & CO, BANK OF AMERICA, JP MORGAN CHASE & CO., AMGEN, CITIGROUP ... 
## Top 5 momentum scores: 58.02%, 46.63%, 36.11%, 25.68%, 22.37% ... 
## Processing period 15 of 194 - Date: 2009-03-31 
## Selected assets count: 9 
## Top 5 momentum assets: NETFLIX, AMAZON.COM, ALPHABET A, INTERNATIONAL BUS.MCHS., NVIDIA ... 
## Top 5 momentum scores: 57.70%, 51.73%, 15.37%, 12.78%, 10.84% ... 
## Processing period 20 of 194 - Date: 2009-08-31 
## Selected assets count: 45 
## Top 5 momentum assets: BANK OF AMERICA, TEXAS INSTRUMENTS, APPLE, THERMO FISHER SCIENTIFIC, AMGEN ... 
## Top 5 momentum scores: 65.62%, 33.17%, 29.85%, 29.08%, 28.55% ... 
## Processing period 25 of 194 - Date: 2010-01-29 
## Selected assets count: 40 
## Top 5 momentum assets: AMAZON.COM, SALESFORCE, ALPHABET A, NVIDIA, UNITEDHEALTH GROUP ... 
## Top 5 momentum scores: 44.09%, 29.58%, 25.03%, 24.28%, 21.73% ... 
## Processing period 30 of 194 - Date: 2010-06-30 
## Selected assets count: 22 
## Top 5 momentum assets: NETFLIX, SALESFORCE, APPLE, CITIGROUP, STARBUCKS ... 
## Top 5 momentum scores: 68.28%, 27.34%, 25.54%, 16.47%, 13.01% ... 
## Processing period 35 of 194 - Date: 2010-11-30 
## Selected assets count: 41 
## Top 5 momentum assets: NETFLIX, AMAZON.COM, NVIDIA, ALPHABET A, ORACLE ... 
## Top 5 momentum scores: 69.25%, 40.16%, 30.80%, 26.58%, 24.28% ... 
## Processing period 40 of 194 - Date: 2011-04-29 
## Selected assets count: 35 
## Top 5 momentum assets: NETFLIX, UNITEDHEALTH GROUP, NVIDIA, CHEVRON, GILEAD SCIENCES ... 
## Top 5 momentum scores: 35.33%, 25.17%, 19.87%, 17.80%, 17.19% ... 
## Processing period 45 of 194 - Date: 2011-09-30 
## Selected assets count: 11 
## Top 5 momentum assets: MCDONALDS, APPLE, AMAZON.COM, MICROSOFT, COCA COLA ... 
## Top 5 momentum scores: 10.88%, 10.64%, 9.43%, 6.36%, 5.45% ... 
## Processing period 50 of 194 - Date: 2012-02-29 
## Selected assets count: 39 
## Top 5 momentum assets: NETFLIX, LOWE'S COMPANIES, HOME DEPOT, AMGEN, GILEAD SCIENCES ... 
## Top 5 momentum scores: 46.44%, 27.64%, 23.99%, 18.61%, 17.28% ... 
## Processing period 55 of 194 - Date: 2012-07-31 
## Selected assets count: 22 
## Top 5 momentum assets: VERIZON COMMUNICATIONS, AT&T, WALMART, AMAZON.COM, NEXTERA ENERGY ... 
## Top 5 momentum scores: 16.24%, 14.19%, 13.92%, 12.76%, 12.66% ... 
## Processing period 60 of 194 - Date: 2012-12-31 
## Selected assets count: 36 
## Top 5 momentum assets: NETFLIX, GILEAD SCIENCES, LOWE'S COMPANIES, BANK OF AMERICA, CITIGROUP ... 
## Top 5 momentum scores: 36.82%, 30.01%, 26.72%, 23.40%, 16.36% ... 
## Processing period 65 of 194 - Date: 2013-05-31 
## Selected assets count: 44 
## Top 5 momentum assets: NETFLIX, GILEAD SCIENCES, VERIZON COMMUNICATIONS, AMGEN, MICROSOFT ... 
## Top 5 momentum scores: 30.76%, 28.37%, 23.62%, 21.94%, 20.58% ... 
## Processing period 70 of 194 - Date: 2013-10-31 
## Selected assets count: 33 
## Top 5 momentum assets: NETFLIX, SALESFORCE, GILEAD SCIENCES, APPLE, LOCKHEED MARTIN ... 
## Top 5 momentum scores: 46.48%, 35.96%, 22.63%, 20.23%, 17.60% ... 
## Processing period 75 of 194 - Date: 2014-03-31 
## Selected assets count: 34 
## Top 5 momentum assets: THERMO FISHER SCIENTIFIC, NETFLIX, ADOBE (NAS), SALESFORCE, ELI LILLY ... 
## Top 5 momentum scores: 23.49%, 21.82%, 20.87%, 19.74%, 18.70% ... 
## Processing period 80 of 194 - Date: 2014-08-29 
## Selected assets count: 36 
## Top 5 momentum assets: NETFLIX, INTEL, GILEAD SCIENCES, AMGEN, APPLE ... 
## Top 5 momentum scores: 31.26%, 26.98%, 16.64%, 14.00%, 13.41% ... 
## Processing period 85 of 194 - Date: 2015-01-30 
## Selected assets count: 37 
## Top 5 momentum assets: LOWE'S COMPANIES, ORACLE, UNITEDHEALTH GROUP, MEDTRONIC, BRISTOL MYERS SQUIBB ... 
## Top 5 momentum scores: 30.01%, 17.48%, 17.21%, 16.55%, 15.34% ... 
## Processing period 90 of 194 - Date: 2015-06-30 
## Selected assets count: 23 
## Top 5 momentum assets: NETFLIX, AMAZON.COM, ELI LILLY, STARBUCKS, GILEAD SCIENCES ... 
## Top 5 momentum scores: 31.41%, 12.91%, 12.44%, 11.16%, 8.44% ... 
## Processing period 95 of 194 - Date: 2015-11-30 
## Selected assets count: 27 
## Top 5 momentum assets: NVIDIA, INTEL, AMAZON.COM, NIKE 'B', TEXAS INSTRUMENTS ... 
## Top 5 momentum scores: 42.21%, 16.96%, 16.74%, 13.72%, 13.49% ... 
## Processing period 100 of 194 - Date: 2016-04-29 
## Selected assets count: 26 
## Top 5 momentum assets: VERIZON COMMUNICATIONS, NEXTERA ENERGY, AT&T, ORACLE, WALMART ... 
## Top 5 momentum scores: 17.01%, 13.91%, 13.83%, 11.99%, 11.73% ... 
## Processing period 105 of 194 - Date: 2016-09-30 
## Selected assets count: 39 
## Top 5 momentum assets: NVIDIA, TEXAS INSTRUMENTS, INTEL, UNION PACIFIC, MERCK & COMPANY ... 
## Top 5 momentum scores: 31.29%, 14.75%, 13.61%, 13.47%, 11.61% ... 
## Processing period 110 of 194 - Date: 2017-02-28 
## Selected assets count: 40 
## Top 5 momentum assets: NVIDIA, BANK OF AMERICA, WELLS FARGO & CO, JP MORGAN CHASE & CO., COMCAST A ... 
## Top 5 momentum scores: 53.43%, 37.21%, 22.43%, 22.19%, 22.00% ... 
## Processing period 115 of 194 - Date: 2017-07-31 
## Selected assets count: 33 
## Top 5 momentum assets: NVIDIA, MCDONALDS, THERMO FISHER SCIENTIFIC, UNITEDHEALTH GROUP, ORACLE ... 
## Top 5 momentum scores: 32.71%, 18.17%, 13.59%, 13.05%, 12.40% ... 
## Processing period 120 of 194 - Date: 2017-12-29 
## Selected assets count: 42 
## Top 5 momentum assets: INTEL, WALMART, UNION PACIFIC, AMAZON.COM, HOME DEPOT ... 
## Top 5 momentum scores: 27.86%, 24.54%, 20.13%, 20.00%, 19.98% ... 
## Processing period 125 of 194 - Date: 2018-05-31 
## Selected assets count: 11 
## Top 5 momentum assets: NETFLIX, ADOBE (NAS), AMAZON.COM, INTEL, CISCO SYSTEMS ... 
## Top 5 momentum scores: 15.60%, 10.93%, 7.94%, 7.23%, 6.62% ... 
## Processing period 130 of 194 - Date: 2018-10-31 
## Selected assets count: 45 
## Top 5 momentum assets: ELI LILLY, APPLE, PFIZER, ABBOTT LABORATORIES, LOWE'S COMPANIES ... 
## Top 5 momentum scores: 25.76%, 21.95%, 21.47%, 20.28%, 20.14% ... 
## Processing period 135 of 194 - Date: 2019-03-29 
## Selected assets count: 27 
## Top 5 momentum assets: NETFLIX, DANAHER, SALESFORCE, NIKE 'B', LOWE'S COMPANIES ... 
## Top 5 momentum scores: 25.15%, 15.96%, 14.63%, 14.12%, 11.36% ... 
## Processing period 140 of 194 - Date: 2019-08-30 
## Selected assets count: 32 
## Top 5 momentum assets: STARBUCKS, MEDTRONIC, COSTCO WHOLESALE, PROCTER & GAMBLE, AT&T ... 
## Top 5 momentum scores: 21.90%, 14.78%, 12.26%, 10.86%, 9.98% ... 
## Processing period 145 of 194 - Date: 2020-01-31 
## Selected assets count: 39 
## Top 5 momentum assets: UNITEDHEALTH GROUP, NVIDIA, APPLE, BRISTOL MYERS SQUIBB, AMGEN ... 
## Top 5 momentum scores: 35.28%, 35.18%, 31.11%, 26.58%, 24.58% ... 
## Processing period 150 of 194 - Date: 2020-06-30 
## Selected assets count: 35 
## Top 5 momentum assets: NVIDIA, AMAZON.COM, ABBOTT LABORATORIES, LOWE'S COMPANIES, ELI LILLY ... 
## Top 5 momentum scores: 31.45%, 29.65%, 23.22%, 22.31%, 21.26% ... 
## Processing period 155 of 194 - Date: 2020-11-30 
## Selected assets count: 25 
## Top 5 momentum assets: NIKE 'B', SALESFORCE, NVIDIA, THERMO FISHER SCIENTIFIC, STARBUCKS ... 
## Top 5 momentum scores: 23.02%, 19.20%, 18.08%, 14.29%, 13.63% ... 
## Processing period 160 of 194 - Date: 2021-04-30 
## Selected assets count: 34 
## Top 5 momentum assets: EXXON MOBIL, WELLS FARGO & CO, INTEL, BANK OF AMERICA, CHEVRON ... 
## Top 5 momentum scores: 35.44%, 29.46%, 28.46%, 27.65%, 24.09% ... 
## Processing period 165 of 194 - Date: 2021-09-30 
## Selected assets count: 37 
## Top 5 momentum assets: NVIDIA, ADOBE (NAS), ELI LILLY, DANAHER, ALPHABET A ... 
## Top 5 momentum scores: 37.80%, 31.54%, 29.31%, 26.56%, 22.79% ... 
## Processing period 170 of 194 - Date: 2022-02-28 
## Selected assets count: 21 
## Top 5 momentum assets: PFIZER, EXXON MOBIL, LOCKHEED MARTIN, APPLE, CHEVRON ... 
## Top 5 momentum scores: 20.46%, 17.82%, 17.09%, 16.68%, 14.71% ... 
## Processing period 175 of 194 - Date: 2022-07-29 
## Selected assets count: 13 
## Top 5 momentum assets: AT&T, ELI LILLY, MERCK & COMPANY, INTERNATIONAL BUS.MCHS., BRISTOL MYERS SQUIBB ... 
## Top 5 momentum scores: 17.22%, 13.22%, 11.12%, 8.59%, 5.44% ... 
## Processing period 180 of 194 - Date: 2022-12-30 
## Selected assets count: 37 
## Top 5 momentum assets: GILEAD SCIENCES, NETFLIX, MERCK & COMPANY, ELI LILLY, STARBUCKS ... 
## Top 5 momentum scores: 38.38%, 36.67%, 29.01%, 23.19%, 21.57% ... 
## Processing period 185 of 194 - Date: 2023-05-31 
## Selected assets count: 24 
## Top 5 momentum assets: NVIDIA, MICROSOFT, SALESFORCE, APPLE, ELI LILLY ... 
## Top 5 momentum scores: 42.03%, 23.99%, 18.10%, 17.60%, 15.03% ... 
## Processing period 190 of 194 - Date: 2023-10-31 
## Selected assets count: 15 
## Top 5 momentum assets: AMGEN, ELI LILLY, EXXON MOBIL, ALPHABET A, CHEVRON ... 
## Top 5 momentum scores: 21.05%, 14.53%, 9.63%, 9.32%, 7.16% ... 
## Processing period 194 of 194 - Date: 2024-02-29 
## Selected assets count: 42 
## Top 5 momentum assets: NVIDIA, CITIGROUP, SALESFORCE, NETFLIX, BANK OF AMERICA ... 
## Top 5 momentum scores: 50.88%, 42.24%, 39.96%, 37.02%, 29.12% ... 
## Saved all momentum scores to: C:/Users/lcyep/OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey/Tec/Semestre 6/Risk/R, project/momentum_scores.csv 
## 
## Analyzing momentum portfolio performance...
## 
## ----- Momentum Portfolio Performance Metrics -----
##                   Metric Momentum.Portfolio S.P.500.Benchmark
## 1         Average Return             13.18%             9.04%
## 2     Standard Deviation             14.72%            16.18%
## 3           Sharpe Ratio              0.240             0.144
## 4 Upside-Potential Ratio              0.525             0.465
## Saved performance comparison to: C:/Users/lcyep/OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey/Tec/Semestre 6/Risk/R, project/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/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/momentum_portfolio_returns.csv 
## 
## ----- Most Frequently Selected Assets -----
## all_selected
##              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 
## Saved asset selection frequency to: C:/Users/lcyep/OneDrive - Instituto Tecnologico y de Estudios Superiores de Monterrey/Tec/Semestre 6/Risk/R, project/momentum_asset_selection_frequency.csv 
## 
## Analysis completed in 0.02 minutes
# ---- ADDITIONAL ANALYSIS ----

# 1. Plot the portfolio returns alongside the benchmark
portfolio_vs_benchmark <- merge(
  Momentum = cumprod(1 + momentum_result$portfolio$returns) - 1, 
  Benchmark = cumprod(1 + momentum_result$data$sp500_returns[(36+1):length(momentum_result$data$sp500_returns)]) - 1
)

# Create a plot with different colors and a legend
plot(portfolio_vs_benchmark, 
     main = "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, "momentum_portfolio_vs_benchmark.png")
png(output_file, width = 800, height = 500)
plot(portfolio_vs_benchmark, 
     main = "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/momentum_portfolio_vs_benchmark.png
# 2. Calculate annual returns
annual_returns <- apply.yearly(momentum_result$portfolio$returns, Return.cumulative)
print(annual_returns)
##                   [,1]
## 2008-12-31 -0.38409577
## 2009-12-31  0.34457890
## 2010-12-31  0.20131138
## 2011-12-30  0.09319881
## 2012-12-31  0.20209548
## 2013-12-31  0.38559110
## 2014-12-31  0.13052739
## 2015-12-31  0.13211614
## 2016-12-30  0.08836382
## 2017-12-29  0.22573375
## 2018-12-31  0.05158242
## 2019-12-31  0.25945290
## 2020-12-31  0.24029191
## 2021-12-31  0.26586930
## 2022-12-30 -0.11713523
## 2023-12-29  0.16232314
## 2024-02-29  0.05943164
# 3. Monthly returns statistics
monthly_stats <- data.frame(
  Statistic = c("Min", "1st Quartile", "Median", "Mean", "3rd Quartile", "Max", "Standard Deviation"),
  Value = c(
    min(momentum_result$portfolio$returns),
    quantile(momentum_result$portfolio$returns, 0.25),
    median(momentum_result$portfolio$returns),
    mean(momentum_result$portfolio$returns),
    quantile(momentum_result$portfolio$returns, 0.75),
    max(momentum_result$portfolio$returns),
    sd(momentum_result$portfolio$returns)
  )
)

# Print monthly statistics
cat("\n----- Monthly Return Statistics -----\n")
## 
## ----- Monthly Return Statistics -----
print(monthly_stats)
##            Statistic       Value
## 1                Min -0.14398432
## 2       1st Quartile -0.01112703
## 3             Median  0.01696985
## 4               Mean  0.01098095
## 5       3rd Quartile  0.03648318
## 6                Max  0.14508267
## 7 Standard Deviation  0.04248239
# Save statistics to CSV
output_file <- file.path(base_dir, "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/momentum_monthly_statistics.csv
# Save all output files in one directory for easy access
save(momentum_result, file = file.path(base_dir, "momentum_portfolio_results.RData"))
cat("All analysis results saved to:", file.path(base_dir, "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/momentum_portfolio_results.RData
# 4. Additional visualization: Histogram of returns
png(file.path(base_dir, "momentum_returns_histogram.png"), width = 800, height = 500)
hist(momentum_result$portfolio$returns, 
     breaks = 30, 
     main = "Momentum Portfolio Monthly Returns Distribution", 
     xlab = "Monthly Return", 
     col = "skyblue")
abline(v = mean(momentum_result$portfolio$returns), col = "red", lwd = 2)
dev.off()
## png 
##   2
# 5. Drawdown analysis
drawdown_portfolio <- PerformanceAnalytics::Drawdowns(momentum_result$portfolio$returns)
drawdown_benchmark <- PerformanceAnalytics::Drawdowns(
  momentum_result$data$sp500_returns[(36+1):length(momentum_result$data$sp500_returns)]
)

drawdowns <- merge(
  Momentum = drawdown_portfolio,
  Benchmark = drawdown_benchmark
)

png(file.path(base_dir, "momentum_drawdowns.png"), width = 800, height = 500)
plot(drawdowns, 
     main = "Drawdowns: 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_stocks <- mean(sapply(momentum_result$portfolio$selected_assets, length))
cat("\nAverage number of stocks in the momentum portfolio:", round(avg_stocks, 2), "\n")
## 
## Average number of stocks in the momentum portfolio: 30.68
# 7. Calculate the turnover rate
turnover <- numeric(length(momentum_result$portfolio$selected_assets) - 1)

for (i in 2:length(momentum_result$portfolio$selected_assets)) {
  prev_stocks <- momentum_result$portfolio$selected_assets[[i-1]]
  curr_stocks <- momentum_result$portfolio$selected_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) {
    turnover[i-1] <- total_changed / (2 * avg_portfolio_size)
  } else {
    turnover[i-1] <- 0
  }
}

cat("Average monthly turnover rate:", round(mean(turnover, na.rm = TRUE) * 100, 2), "%\n")
## Average monthly turnover rate: 25.49 %
# 8. Compare performance with the long-short Jensen's alpha portfolio (if available)
if (exists("long_short_result")) {
  # Create a comparison of cumulative returns
  combined_returns <- merge(
    Momentum = cumprod(1 + momentum_result$portfolio$returns) - 1,
    `Long-Short` = cumprod(1 + long_short_result$portfolio$returns) - 1,
    Benchmark = cumprod(1 + momentum_result$data$sp500_returns[(36+1):length(momentum_result$data$sp500_returns)]) - 1
  )
  
  # Plot the comparison
  png(file.path(base_dir, "momentum_vs_longshort_vs_benchmark.png"), width = 800, height = 500)
  plot(combined_returns, 
       main = "Momentum vs Long-Short vs S&P 500", 
       col = c("blue", "green", "red"),
       lwd = c(2, 2, 2),
       legend.loc = "topleft")
  dev.off()
  
  # Compare performance metrics
  if (exists("long_short_result$analysis$performance_table")) {
    # Create a combined performance table
    momentum_metrics <- momentum_result$analysis$performance_table
    long_short_metrics <- long_short_result$analysis$performance_table
    
    # Merge the tables (this assumes they have the same structure)
    combined_metrics <- data.frame(
      Metric = momentum_metrics$Metric,
      `Momentum Portfolio` = momentum_metrics$`Momentum Portfolio`,
      `Long-Short Portfolio` = long_short_metrics$`Long-Short Portfolio`,
      `S&P 500 Benchmark` = momentum_metrics$`S&P 500 Benchmark`
    )
    
    cat("\n----- Comparative Performance Metrics -----\n")
    print(combined_metrics)
    
    # Save to CSV
    output_file <- file.path(base_dir, "momentum_vs_longshort_performance.csv")
    write.csv(combined_metrics, output_file, row.names = FALSE)
    cat("Saved comparative performance metrics to:", output_file, "\n")
  }
}

# Display a final message with key findings
cat("\n===== MOMENTUM PORTFOLIO ANALYSIS SUMMARY =====\n")
## 
## ===== MOMENTUM PORTFOLIO ANALYSIS SUMMARY =====
cat("Portfolio Strategy: Long positions in stocks with positive returns over the past 3 months\n")
## Portfolio Strategy: Long positions in stocks with positive returns over the past 3 months
cat("Rebalancing: Monthly, based on 3-month lookback period\n")
## Rebalancing: Monthly, based on 3-month lookback period
cat("Equal weighting across all selected assets\n\n")
## Equal weighting across all selected assets
# Performance metrics will be filled in after running the script
cat("Key Performance Metrics will be displayed after running the script.\n\n")
## Key Performance Metrics will be displayed after running the script.