GetECBHistoricalExchangeRateData <- function() { # 1. Setup temporary files and download the data temp_zip <- tempfile(fileext = ".zip") url <- "https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.zip" message("Downloading data from ECB...") download.file(url, temp_zip, quiet = TRUE) # 2. Unzip and identify the CSV file unzipped_files <- unzip(temp_zip, exdir = tempdir()) csv_file <- unzipped_files[grep("\\.csv$", unzipped_files)] # 3. Load the data into R message("Loading data...") df <- read.csv(csv_file, na.strings = c("N/A", "NA", ""), stringsAsFactors = FALSE) # Clean up temp files unlink(temp_zip) unlink(csv_file) return(df) } PreProcessData <- function(df, target_currencies, last_n_days = NULL) { # Preprocess Dates and Time df$Date <- as.Date(df$Date) df <- df[order(df$Date), ] # Filter by the last N days if specified if (!is.null(last_n_days)) { cutoff_date <- max(df$Date, na.rm = TRUE) - last_n_days df <- df[df$Date >= cutoff_date, ] message(sprintf("Filtered data to the last %d days (since %s).", last_n_days, cutoff_date)) } # Create a Time Index for the regression df$TimeIndex <- as.numeric(df$Date - min(df$Date)) # Ensure targets actually exist in the dataframe to prevent errors valid_targets <- intersect(target_currencies, names(df)) # Filter the data frame down to Date, TimeIndex, and those specific targets df <- df[, c("Date", "TimeIndex", valid_targets)] # Create the new cross pairs dynamically # combn(valid_targets, 2) creates all unique 2-pair combinations if (length(valid_targets) >= 2) { pair_combos <- combn(valid_targets, 2) for (i in 1:ncol(pair_combos)) { base_curr <- pair_combos[1, i] quote_curr <- pair_combos[2, i] # Create column name, e.g., "USD_JPY" pair_name <- paste0(base_curr, "_", quote_curr) # Math: To get Base/Quote, divide the ECB Quote column by the ECB Base column df[[pair_name]] <- df[[quote_curr]] / df[[base_curr]] } } # Update the 'currencies' vector so the loop analyzes original and new columns currencies <- setdiff(names(df), c("Date", "TimeIndex")) return(list(currencies = currencies, df = df)) } CalculateMetrics <- function(df,currencies) { # 5. Loop through each currency, run regression, and calculate metrics results_list <- list() message("Running regressions...") for (curr in currencies) { valid_data <- df[!is.na(df[[curr]]), ] if (nrow(valid_data) > 2) { # Simple linear regression: Exchange Rate ~ Time model <- lm(valid_data[[curr]] ~ valid_data$TimeIndex) # Extract Beta (slope) and Residual Standard Error (RSE) beta <- coef(model)[2] rse <- summary(model)$sigma # Calculate Signal-to-Noise Ratio: |Beta| / RSE if (!is.na(rse) && rse > 0) { signal_to_noise <- abs(beta) / rse } else { signal_to_noise <- NA } # Store results results_list[[curr]] <- data.frame( Currency = curr, Beta = beta, AbsBeta = abs(beta), RSE = rse, SignalToNoise = signal_to_noise, stringsAsFactors = FALSE, row.names = NULL ) } } # Combine all results results_df <- do.call(rbind, results_list) return (results_df) } OrderBySignalToNoiseRatio <- function(results_df) { # 6. Order by the Signal-to-Noise ratio and get the top 3 top_3_currencies <- results_df[order(results_df$SignalToNoise, decreasing = TRUE), ] top_3_currencies <- head(top_3_currencies, 3) return (top_3_currencies) } # # 10. RUNTIME # df <- GetECBHistoricalExchangeRateData() res <- PreProcessData(df,c("USD", "JPY", "GBP","CAD","NOK"),720) results_df <- CalculateMetrics(res$df,res$currencies) top_3_currencies <- OrderBySignalToNoiseRatio(results_df) # Print the final output message("\nTop 3 currencies by Trend Predictability (|Beta| / RSE):") print(top_3_currencies)