library(readxl)
library(ggplot2)
library(tidyr)
## Warning: package 'tidyr' was built under R version 4.3.3
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.3.3
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(zoo)
## Warning: package 'zoo' was built under R version 4.3.3
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
library(TTR)
## Warning: package 'TTR' was built under R version 4.3.3
library(e1071)
## Warning: package 'e1071' was built under R version 4.3.3
library(sn)
## Warning: package 'sn' was built under R version 4.3.3
## Loading required package: stats4
## 
## Attaching package: 'sn'
## The following object is masked from 'package:stats':
## 
##     sd
library(moments)
## 
## Attaching package: 'moments'
## The following objects are masked from 'package:e1071':
## 
##     kurtosis, moment, skewness
library(PearsonDS)
## Warning: package 'PearsonDS' was built under R version 4.3.3
library(openxlsx)
## Warning: package 'openxlsx' was built under R version 4.3.3
FINM_8100_DATA_1_ <- read_excel("C:/Users/thech/Downloads/FINM 8100 DATA (1).xlsx")
## New names:
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...11`
## • `` -> `...13`
## • `` -> `...15`
## • `` -> `...17`
## • `` -> `...19`
## • `` -> `...21`
## • `` -> `...23`
## • `` -> `...25`
## • `` -> `...27`
## • `` -> `...29`
## • `` -> `...31`
## • `` -> `...32`
#################Commonwealth Bank#########################
commonwealth<-FINM_8100_DATA_1_[,2:3]
commonwealth[1,1]<-"year"

colnames(commonwealth) <- as.character(unlist(commonwealth[1, ]))
cm<-commonwealth[-1, ] 

cmdotcom<-cm%>%filter(year>=20000301 & year <=20030331)

cmm <- mean(as.numeric(cmdotcom$Change.cm), na.rm = TRUE)
cms <- sd(as.numeric(cmdotcom$Change.cm), na.rm = TRUE)

hist(as.numeric(cmdotcom$Change.cm), breaks = 100, freq = FALSE, main = " Distribution of Commonwealth in Dotcom", xlab = " Daily return")

# Add normal distribution curve
curve(
  dnorm(x, mean = cmm, sd = cms),
  col = "lightblue", lwd = 2,
  add = TRUE
)

# Add true distribution curve
dens <- density(as.numeric(cmdotcom$Change.cm), bw = 0.1, na.rm = TRUE)
lines(dens, col = "blue", lwd = 2)

##################Variance-Covariance Approach


cmchange <- as.numeric(cmdotcom$Change.cm)

##50 days
#----------EQUALLY WEIGHTED
win50   <- 50
alpha <- 0.01              
z     <- qnorm(alpha)     

cmmu_roll50 <- rollapply(cmchange, width = win50, FUN = mean, align = "right", fill = NA, na.rm = TRUE)
cmsd_roll50 <- rollapply(cmchange, width = win50, FUN = sd,   align = "right", fill = NA, na.rm = TRUE)

cmVaR50d_99 <- (cmmu_roll50 + z * cmsd_roll50)  


##120 days
win120   <- 120
alpha <- 0.01              
z     <- qnorm(alpha)     

cmmu_roll120 <- rollapply(cmchange, width = win120, FUN = mean, align = "right", fill = NA, na.rm = TRUE)
cmsd_roll120 <- rollapply(cmchange, width = win120, FUN = sd,   align = "right", fill = NA, na.rm = TRUE)

cmVaR120d_99 <- (cmmu_roll120 + z * cmsd_roll120)


##250 days
win250   <- 250
alpha <- 0.01              
z     <- qnorm(alpha)     

cmmu_roll250 <- rollapply(cmchange, width = win250, FUN = mean, align = "right", fill = NA, na.rm = TRUE)
cmsd_roll250 <- rollapply(cmchange, width = win250, FUN = sd,   align = "right", fill = NA, na.rm = TRUE)


cmVaR250d_99 <- (cmmu_roll250 + z * cmsd_roll250)


#plot cm
# Make sure you have a Date column
dates <- as.Date(as.character(cmdotcom$year), format = "%Y%m%d")

# Base plot with dates on x-axis
plot(dates, cmchange, type = "l", col = "grey",
     main = "Commonwealth Bank Daily Returns with 99% VaR, equally weighted",
     xlab = "Date", ylab = "Return & VaR")

# Overlay the VaR lines
lines(dates, cmVaR50d_99, col = "black")
lines(dates, cmVaR120d_99, col = "blue")
lines(dates, cmVaR250d_99, col = "purple")

# Format x-axis: tick every 6 months
ticks <- as.Date(c("2001-01-01", "2002-01-01", "2003-01-01"))

# Draw axis
axis.Date(1, at = ticks, format = "%Y")

#--------------exponentially weighted



library(TTR)

lam50  <- 49/51
lam120 <- 119/121
lam250 <- 249/251
# Returns
rcm <- as.numeric(cmchange)
alpha <- 0.01
z <- qnorm(alpha)

# choose lambda (decay) directly, e.g. 0.94 is common
lambda <- 0.94

# Step 1: de-mean returns (you can also just use r if mean≈0)
eps <- rcm - mean(rcm, na.rm = TRUE)

# Step 2: compute EWMA variance with EMA() on squared eps

ewma_var50 <- EMA(eps^2, ratio = 1 - lam50)
ewma_var120 <- EMA(eps^2, ratio = 1 - lam120)
ewma_var250 <- EMA(eps^2, ratio = 1 - lam250)

cmmu_roll50 <- rollapply(cmchange, width = win50, FUN = mean, align = "right", fill = NA, na.rm = TRUE)
cmmu_roll120 <- rollapply(cmchange, width = win120, FUN = mean, align = "right", fill = NA, na.rm = TRUE)
cmmu_roll250 <- rollapply(cmchange, width = win250, FUN = mean, align = "right", fill = NA, na.rm = TRUE)

# Step 3: EWMA volatility
ewma_sd50 <- sqrt(ewma_var50)
ewma_sd120 <- sqrt(ewma_var120)
ewma_sd250 <- sqrt(ewma_var250)
# Step 4: VaR series
VaR_ewma50 <- cmmu_roll50 + z * ewma_sd50
VaR_ewma120 <- cmmu_roll120 + z * ewma_sd120
VaR_ewma250 <- cmmu_roll250 + z * ewma_sd250
# Plot
dates <- as.Date(as.character(cmdotcom$year), format = "%Y%m%d")

# Base plot with dates on x-axis
plot(dates, cmchange, type = "l", col = "grey",
     main = "Commonwealth Bank Daily Returns with 99% VaR,exponentially weighted",
     xlab = "Date", ylab = "Return & VaR")
lines(dates,VaR_ewma50, col = "black")
lines(dates, VaR_ewma120, col = "blue")
lines(dates, VaR_ewma250, col = "purple")
# Format x-axis: tick every 6 months
#plot cm
# Make sure you have a Date column
ticks <- as.Date(c("2001-01-01", "2002-01-01", "2003-01-01"))
axis.Date(1, at = ticks, format = "%Y")

################## Historical Approach

#50days
win50   <- 50
alpha <- 0.01              

cmVaR50h_99 <- rollapply(cmchange, width = win50, FUN = function(cmchange) quantile(cmchange, probs = alpha, na.rm = TRUE), align = "right", fill = NA)


#120 days
win120   <- 120
alpha <- 0.01              

cmVaR120h_99 <- rollapply(cmchange, width = win120, FUN = function(cmchange) quantile(cmchange, probs = alpha, na.rm = TRUE), align = "right", fill = NA)

#250 days
win250   <- 250
alpha <- 0.01              

cmVaR250h_99 <- rollapply(cmchange, width = win250, FUN = function(cmchange) quantile(cmchange, probs = alpha, na.rm = TRUE), align = "right", fill = NA)

dates <- as.Date(as.character(cmdotcom$year), format = "%Y%m%d")

# Base plot with dates on x-axis
plot(dates, cmchange, type = "l", col = "grey",
     main = "Commonwealth Bank Daily Returns with 99% VaR, historical",
     xlab = "Date", ylab = "Return & VaR")
lines(dates, cmVaR50h_99, col = "black")
lines(dates, cmVaR120h_99,col = "blue")
lines(dates, cmVaR250h_99, col = "purple")

# Format x-axis: tick every 6 months

ticks <- as.Date(c("2001-01-01", "2002-01-01", "2003-01-01"))

# Draw axis
axis.Date(1, at = ticks, format = "%Y")

####################Monte Carlo Approach

stackr<-FINM_8100_DATA_1_[,2:9]
stackr[1,1]<-"year"

colnames(stackr) <- as.character(unlist(stackr[1, ]))
stackr<-stackr[-1, ] 

dotcom<-stackr%>%filter(year>=20000301 & year <=20030331)
coldotcom <- as.numeric(c(as.matrix(dotcom[2:8])))


skewness(coldotcom, na.rm = TRUE)
## [1] -1.379403
stackr <- as.numeric(stackr$Change.cm)
stackr <- stackr[is.finite(stackr)] 

coldotcom <- as.numeric(coldotcom)
coldotcom <- coldotcom[is.finite(coldotcom)]

cmm<- mean(rcm,na.rm = TRUE)
cms<- sd(rcm, na.rm = TRUE)
cmsk<- skewness(coldotcom, na.rm = TRUE)
cmk<- kurtosis(coldotcom, na.rm = TRUE)


# install.packages("PearsonDS")  # run once

## --- your inputs (clean vectors) ---
# bank returns (for mean & sd)
bank <- as.numeric(stackr)           # e.g., stackr <- as.numeric(stackr$Change.cm)
bank <- bank[is.finite(bank)]

# industry pooled returns (for skew & kurt)
ind <- as.numeric(coldotcom)
ind <- ind[is.finite(ind)]

## --- target moments -----------------
mu  <- mean(cmchange, na.rm = TRUE)               # mean
sdv <- stats::sd(rcm, na.rm = TRUE)          # sd  (use stats::sd to avoid masking)
sk  <- skewness(ind, na.rm = TRUE)            # skewness
ku  <- kurtosis(ind, na.rm = TRUE)  # **regular** kurtosis (not excess)

# (optional) tiny nudge to satisfy Pearson existence condition: beta2 > beta1 + 1
if (ku <= sk^2 + 1) ku <- sk^2 + 1 + 1e-6

## --- fit Pearson distribution from moments ---
fitPRS<- pearsonFitM(moments = list(mean = mu, variance = sdv^2,
                                  skewness = sk, kurtosis = ku))

## --- Monte Carlo sampling (choose N) ---
set.seed(123)
N <- nrow(dotcom)
x_sim <- rpearson(N, params = fitPRS)

## quick check
c(mean = mean(x_sim), sd = sd(x_sim),
  skew = skewness(x_sim), kurt = kurtosis(x_sim))
##          mean            sd          skew          kurt 
## -0.0008058715  0.1103552042 -1.5876367207 11.7074746594
## example plot
hist(x_sim, breaks = 80, freq = FALSE, col = "lightblue",
     main = "PearsonDS Monte Carlo")
lines(density(x_sim, bw = 1, na.rm = TRUE), lwd = 2)

#50days
win50   <- 50
alpha <- 0.01              

cmVaR50m_99 <- rollapply(x_sim, width = win50, FUN = function(x_sim) quantile(x_sim, probs = alpha, na.rm = TRUE), align = "right", fill = NA)


#120 days
win120   <- 120
alpha <- 0.01              

cmVaR120m_99 <- rollapply(x_sim, width = win120, FUN = function(x_sim) quantile(x_sim, probs = alpha, na.rm = TRUE), align = "right", fill = NA)

#250 days

win250   <- 250
alpha <- 0.01              

cmVaR250m_99 <- rollapply(x_sim, width = win250, FUN = function(x_sim) quantile(x_sim, probs = alpha, na.rm = TRUE), align = "right", fill = NA)


dates <- as.Date(as.character(cmdotcom$year), format = "%Y%m%d")

# Base plot with dates on x-axis
plot(dates, x_sim, type = "l", col = "grey",
     main = "Commonwealth Bank Daily Returns with 99% VaR, monte-carlo",
     xlab = "Date", ylab = "Return & VaR")
lines(dates, cmVaR50m_99, col = "black")
lines(dates, cmVaR120m_99,col = "blue")
lines(dates, cmVaR250m_99, col = "purple")

ticks <- as.Date(c("2001-01-01", "2002-01-01", "2003-01-01"))

# Draw axis
axis.Date(1, at = ticks, format = "%Y")

# install.packages("writexl")   # run once
library(writexl)
## Warning: package 'writexl' was built under R version 4.3.3
# 1) Dates (from your yyyymmdd column)
dates <- as.Date(as.character(cmdotcom$year), format = "%Y%m%d")

# 2) Map "pretty column name" -> "object name in R"
var_map <- c(
  VarCov_50  = "cmVaR50d_99",
  VarCov_120 = "cmVaR120d_99",
  VarCov_250 = "cmVaR250d_99",
  EWMA_50    = "VaR_ewma50",
  EWMA_120   = "VaR_ewma120",
  EWMA_250   = "VaR_ewma250",
  Hist_50    = "cmVaR50h_99",
  Hist_120   = "cmVaR120h_99",
  Hist_250   = "cmVaR250h_99",
  MC_50      = "cmVaR50m_99",
  MC_120     = "cmVaR120m_99",
  MC_250     = "cmVaR250m_99"
)

# 3) Start with Date + Return
cols <- list(
  Date   = dates,
  Return = as.numeric(cmchange)
)

# 4) Add each VaR column if it exists
for (pretty_name in names(var_map)) {
  obj_name <- var_map[[pretty_name]]
  if (exists(obj_name, inherits = FALSE)) {
    cols[[pretty_name]] <- get(obj_name)
  }
}

# 5) Build data frame & (optionally) drop all-NA columns
VaR_export <- as.data.frame(cols)
VaR_export <- VaR_export[ , !sapply(VaR_export, function(v) all(!is.finite(v) | is.na(v))), drop = FALSE]

# 6) Write to Excel (single sheet)
#write_xlsx(VaR_export, path = "Commonwealth_VaR_Export.xlsx")

# Where is it saved?
#getwd()   # prints the folder; that's where the file is


#--------------------------------------Test----------------------------------------------#

#####count
valid <- is.finite(cmVaR50d_99) & is.finite(cmchange)
exceptionse50 <- (cmchange < cmVaR50d_99)  & valid       
ce50<-sum(exceptionse50, na.rm = TRUE)
pe50<-ce50/sum(valid)
# z-Test at 99%
thres99<- 0.01
z<- (pe50-thres99)/sqrt(thres99*(1-thres99)/sum(valid))
cn<-qnorm(1-thres99)
z
## [1] 2.359221
cn
## [1] 2.326348
#--> reject null: more than 0.01 -> more bleached than expected or underestimate risks but not much

#####magnitude
exceptionse50 <-cmchange < cmVaR50d_99  
loss_exc <- cmchange[exceptionse50]
var_exc  <- cmVaR50d_99[exceptionse50]
ok <- is.finite(loss_exc) & is.finite(var_exc)
d <- var_exc[ok] - loss_exc[ok]   # differences
n  <- length(d)
mean_d <- mean(d, na.rm = TRUE)
sd_d   <- sd(d, na.rm = TRUE)

t <- mean_d / (sd_d / sqrt(n))   # test statistic
ct<-qt(1-thres99,n-1)

t
## [1] 3.17601
ct
## [1] 2.650309
#--> rejest null: the difference is not 0 -> exceeded by large


#####loss function
y <- as.numeric(cmchange)       
q <- cmVaR50d_99                  
thres99 <- 0.01                     

# Loss function
s <- ((1-thres99) - (y < q)) * (y - q)
loss<-sum(s,na.rm = TRUE)
loss
## [1] 184.8002
alpha <- 0.01

# 1) Backtest helper for ONE VaR series
backtest_var <- function(y, q, alpha = 0.01) {
  valid <- is.finite(y) & is.finite(q)
  yv <- y[valid]; qv <- q[valid]
  n  <- length(yv)
  if (n == 0) return(data.frame(n=0, exceptions=NA, p_exc=NA, z=NA, zcrit=NA,
                                t_short=NA, tcrit=NA,
                                sum_sf=NA, total_loss=NA, mean_loss=NA))
  
  # exceptions (Kupiec-style z)
  exc <- (yv < qv)
  ce  <- sum(exc)
  pe  <- ce / n
  z   <- (pe - alpha) / sqrt(alpha*(1-alpha)/n)
  zc  <- qnorm(1 - alpha)

  # shortfall (how far below VaR)
  sf <- qv[exc] - yv[exc]            # positive = exceedance magnitude
  if (length(sf) >= 3) {
    tstat <- mean(sf) / (sd(sf) / sqrt(length(sf)))
    tcrit <- qt(1 - alpha, df = length(sf) - 1)
    sumsf <- sum(sf, na.rm = TRUE)
  } else {
    tstat <- NA; tcrit <- NA; sumsf <- NA
  }

  # quantile loss
  loss_vec   <- (alpha - (yv < qv)) * (yv - qv)
  total_loss <- sum(loss_vec, na.rm = TRUE)
  mean_loss  <- mean(loss_vec, na.rm = TRUE)

  data.frame(
    n = n,
    exceptions = ce,
    p_exc = pe,
    z = z, zcrit = zc,
    t_short = tstat, tcrit = tcrit,
    sum_sf = sumsf,
    total_loss = total_loss,
    mean_loss = mean_loss
  )
}

# 2) Collect VaR series you have
var_names <- c(
  "VarCov_50"  = "cmVaR50d_99",
  "VarCov_120" = "cmVaR120d_99",
  "VarCov_250" = "cmVaR250d_99",
    "EWMA_50"    = "VaR_ewma50",
  "EWMA_120"   = "VaR_ewma120",
  "EWMA_250"   = "VaR_ewma250",
  "Hist_50"    = "cmVaR50h_99",
  "Hist_120"   = "cmVaR120h_99",
  "Hist_250"   = "cmVaR250h_99",
  "MC_50"      = "cmVaR50m_99",
  "MC_120"     = "cmVaR120m_99",
  "MC_250"     = "cmVaR250m_99"
)

var_list <- lapply(var_names, function(obj) if (exists(obj, inherits = TRUE)) get(obj) else NULL)
var_list <- var_list[!sapply(var_list, is.null)]  # drop missing

# 3) Run backtests for ALL VaR series
results <- do.call(
  rbind,
  lapply(names(var_list), function(nm) {
    cbind(model = nm, backtest_var(y = as.numeric(cmchange), q = var_list[[nm]], alpha = alpha))
  })
)
row.names(results) <- NULL
print(results)
##         model   n exceptions       p_exc          z    zcrit  t_short    tcrit
## 1   VarCov_50 755         14 0.018543046  2.3592211 2.326348 3.176010 2.650309
## 2  VarCov_120 685         11 0.016058394  1.5936216 2.326348 2.658118 2.763769
## 3  VarCov_250 555          7 0.012612613  0.6185915 2.326348 2.594303 3.142668
## 4     EWMA_50 755          8 0.010596026  0.1645968 2.326348 2.652299 2.997952
## 5    EWMA_120 685          8 0.011678832  0.4416060 2.326348 2.484191 2.997952
## 6    EWMA_250 555         10 0.018018018  1.8984358 2.326348 2.178316 2.821438
## 7     Hist_50 755         18 0.023841060  3.8223039 2.326348 3.730660 2.566934
## 8    Hist_120 685         13 0.018978102  2.3616320 2.326348 2.330366 2.680998
## 9    Hist_250 555          6 0.010810811  0.1919767 2.326348 2.164940 3.364930
## 10      MC_50 755         12 0.015894040  1.6276797 2.326348 3.305582 2.718079
## 11     MC_120 685          6 0.008759124 -0.3264044 2.326348 1.988431 3.364930
## 12     MC_250 555          4 0.007207207 -0.6612529 2.326348 1.872184 4.540703
##       sum_sf total_loss   mean_loss
## 1  0.7123264   2.571800 0.003406357
## 2  0.6267987   2.347286 0.003426696
## 3  0.6338765   2.045312 0.003685247
## 4  0.3849883   2.250383 0.002980640
## 5  0.4945944   2.230696 0.003256490
## 6  0.5373925   1.960110 0.003531729
## 7  0.5591988   2.329849 0.003085893
## 8  0.6492843   2.313772 0.003377769
## 9  0.5353620   1.990325 0.003586172
## 10 0.6791893   3.020245 0.004000324
## 11 0.3732375   2.582347 0.003769850
## 12 0.2118250   2.099235 0.003782405
# 4) Export to Excel
#write_xlsx(as.data.frame(results), "VaR_backtests.xlsx")

























#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library(readxl)
library(dplyr)
library(tidyr)
library(zoo)
library(TTR)
library(PearsonDS)
library(moments)
library(purrr)
## Warning: package 'purrr' was built under R version 4.3.3
#----------------------- load & tidy -----------------------
raw <- read_excel("C:/Users/thech/Downloads/FINM 8100 DATA (1).xlsx")
## New names:
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...11`
## • `` -> `...13`
## • `` -> `...15`
## • `` -> `...17`
## • `` -> `...19`
## • `` -> `...21`
## • `` -> `...23`
## • `` -> `...25`
## • `` -> `...27`
## • `` -> `...29`
## • `` -> `...31`
## • `` -> `...32`
# Make first row the header, like you did, but for the whole sheet
names(raw) <- as.character(unlist(raw[1, ]))
## Warning: The `value` argument of `names<-()` can't be empty as of tibble 3.0.0.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
df <- raw[-1, ]

# Make first row the header, then drop it
names(raw) <- as.character(unlist(raw[1, ]))
df <- raw[-1, ]

# ---- FIX BAD COLUMN NAMES ----
nm <- names(df)
nm <- trimws(nm)
nm[is.na(nm) | nm == ""] <- paste0("col_", which(is.na(nm) | nm == ""))
nm <- make.names(nm, unique = TRUE)   # also fixes duplicates, spaces, etc.
names(df) <- nm
# --------------------------------

# Ensure the yyyymmdd column is called 'year' (your sheet has it in the 2nd col)
if (!"year" %in% names(df)) names(df)[2] <- "year"

# Now this will work
df <- df %>% mutate(year = as.numeric(year))


# Ensure the yyyymmdd column is named 'year' and is numeric
if (!"year" %in% names(df)) {
  # If your second column is the yyyymmdd, rename it
  names(df)[2] <- "year"
}
df <- df %>% mutate(year = as.numeric(year))

# Grab all bank columns automatically
bank_cols <- grep("^Change\\.", names(df), value = TRUE)

# Numeric returns
df <- df %>%
  mutate(across(all_of(bank_cols), ~ suppressWarnings(as.numeric(.x))))

# Focus on dot-com window
dot <- df %>% filter(year >= 20000301 & year <= 20030331)

# For MC skew/kurt we’ll use the pooled industry (all banks stacked)
industry_pool <- dot %>% select(all_of(bank_cols)) %>% as.matrix() %>% as.numeric()
industry_pool <- industry_pool[is.finite(industry_pool)]
sk_ind <- skewness(industry_pool, na.rm = TRUE)
ku_ind <- kurtosis(industry_pool, na.rm = TRUE)
if (ku_ind <= sk_ind^2 + 1) ku_ind <- sk_ind^2 + 1 + 1e-6  # Pearson existence tweak

alpha <- 0.05
z_q <- qnorm(alpha)
wins <- c(50, 120, 250)
lam_from_win <- function(w) (w - 1) / (w + 1)  # your choice earlier
names(wins) <- paste0(wins, "d")

dates <- as.Date(as.character(dot$year), format = "%Y%m%d")

#---------------------- helpers ---------------------------
roll_mean  <- function(x, w) rollapply(x, w, mean, align = "right", fill = NA, na.rm = TRUE)
roll_sd    <- function(x, w) rollapply(x, w, sd,   align = "right", fill = NA, na.rm = TRUE)
roll_qtl   <- function(x, w, p) rollapply(x, w, function(y) quantile(y, probs = p, na.rm = TRUE),
                                          align = "right", fill = NA)

backtest_var <- function(y, q, alpha = 0.05) {
  valid <- is.finite(y) & is.finite(q)
  yv <- y[valid]; qv <- q[valid]; n <- length(yv)
  if (n == 0) return(tibble(n=0, exceptions=NA, p_exc=NA, z=NA, zcrit=NA,
                            t_short=NA, tcrit=NA, sum_sf=NA, total_loss=NA, mean_loss=NA))
  exc <- (yv < qv)
  ce  <- sum(exc); pe <- ce/n
  z   <- (pe - alpha)/sqrt(alpha*(1-alpha)/n); zc <- qnorm(1 - alpha)
  sf <- qv[exc] - yv[exc]
  if (length(sf) >= 3) {
    tstat <- mean(sf) / (sd(sf)/sqrt(length(sf)))
    tcrit <- qt(1 - alpha, df = length(sf) - 1)
    sumsf <- sum(sf)
  } else {
    tstat <- NA; tcrit <- NA; sumsf <- NA
  }
  loss_vec   <- (alpha - (yv < qv)) * (yv - qv)
  tibble(
    n = n, exceptions = ce, p_exc = pe, z = z, zcrit = zc,
    t_short = tstat, tcrit = tcrit, sum_sf = sumsf,
    total_loss = sum(loss_vec, na.rm = TRUE),
    mean_loss  = mean(loss_vec, na.rm = TRUE)
  )
}

compute_bank <- function(ret_vec) {
  r <- as.numeric(ret_vec)
  # Var-Cov (equal weights)
  vc <- map(wins, ~ roll_mean(r, .x) + z_q * roll_sd(r, .x))
  names(vc) <- paste0("VarCov_", names(vc))

  # EWMA (lambda from window, like your code)
  ewma_list <- imap(wins, function(w, nm) {
    lam <- lam_from_win(w)
    eps <- r - mean(r, na.rm = TRUE)
    sd_ewma <- sqrt(EMA(eps^2, ratio = 1 - lam))
    mu_roll <- roll_mean(r, w)
    mu_roll + z_q * sd_ewma
  })
  names(ewma_list) <- paste0("EWMA_", names(ewma_list))

  # Historical
  hist_list <- map(wins, ~ roll_qtl(r, .x, alpha))
  names(hist_list) <- paste0("Hist_", names(hist_list))

  # PearsonDS Monte Carlo (match sample length N, then roll quantiles)
  N <- length(r)
  mu <- mean(r, na.rm = TRUE)
  sdv <- sd(r, na.rm = TRUE)
  fit <- pearsonFitM(moments = list(mean = mu, variance = sdv^2,
                                    skewness = sk_ind, kurtosis = ku_ind))
  set.seed(123)
  x_sim <- rpearson(N, params = fit)

  mc_list <- map(wins, ~ roll_qtl(x_sim, .x, alpha))
  names(mc_list) <- paste0("MC_", names(mc_list))

  # Assemble tidy export table
  export_df <- tibble(
    Date   = dates,
    Return = r
  ) %>% bind_cols(as_tibble(vc),
                  as_tibble(ewma_list),
                  as_tibble(hist_list),
                  as_tibble(mc_list))

  # Backtests for all series
  bt <- bind_rows(lapply(names(export_df)[-(1:2)], function(colnm) {
    res <- backtest_var(y = export_df$Return, q = export_df[[colnm]], alpha = alpha)
    mutate(res, model = colnm)
  }))

  list(export = export_df, backtests = bt)
}

#------------------- run for ALL banks --------------------
# long form for clarity, then split by bank and map
long <- dot %>%
  select(year, all_of(bank_cols)) %>%
  pivot_longer(-year, names_to = "bank", values_to = "ret")

by_bank <- split(long, long$bank)

results_per_bank <- imap(by_bank, function(df_bank, bank_name) {
  out <- compute_bank(df_bank$ret)
  out$backtests <- mutate(out$backtests, bank = bank_name, .before = 1)
  out
})

# 1) One big backtest table across banks & models
backtests_all <- bind_rows(lapply(results_per_bank, `[[`, "backtests"))

# 2) (Optional) write one Excel per bank
# library(writexl)
# iwalk(results_per_bank, function(x, nm) {
#   write_xlsx(x$export, paste0(gsub("^Change\\.", "", nm), "_VaR_Export.xlsx"))
# })

# 3) (Optional) plot function for any bank + model set
plot_bank <- function(bank = "Change.cm") {
  ex <- results_per_bank[[bank]]$export
  matplot(ex$Date, ex[, -c(1,2)], type = "l", lty = 1,
          main = paste0(bank, " — 95% VaR (all methods)"),
          xlab = "Date", ylab = "Return / VaR")
  lines(ex$Date, ex$Return, col = "grey")
}

# Quick peek:
# head(backtests_all)
# plot_bank("Change.cm")

library(writexl)

# Combine all VaR export tables (add bank column)
VaR_all <- dplyr::bind_rows(
  lapply(names(results_per_bank), function(bk) {
    df <- results_per_bank[[bk]]$export
    df$bank <- bk
    df
  }),
  .id = NULL
)

# Backtests already combined earlier
Backtests_all <- backtests_all

# Save as one Excel with 2 sheets
write_xlsx(
  list(
    "VaR_Exports" = VaR_all,
    "Backtests"   = Backtests_all
  ),
  path = "AllBanks_VaR_and_Backtestsdot95.xlsx"
)

getwd()
## [1] "C:/Users/thech/OneDrive/Documents/ANU/SEM 4/applied project/VaR"