JoaoJungblut / Mean-CVaR_Portfolio_with_Mixture-Copulas

Repository for final course project at Universidade Federal do Rio Grande do Sul (UFRGS) in economic science.
MIT License
4 stars 3 forks source link

Have error when running the code of main.R #1

Open amazinginging opened 7 months ago

amazinginging commented 7 months ago

Hello, recently I was running your code package to # Construct portfolio and benchmarks mixture_portfolio_1y <- RollingWindowEstimation(returns = returns, We = 252, Wt = nrow(returns), K = 1000, When Mixture = TRUE) here, you'll get an error, I changed line 48 of portfolio.analysis.R to association_measure < -OptMixtureCopulas (unif_dist = unif_dist, K = K,combination = c("Clayton", "Gumbel", "t", "Normal", "Frank", "Joe")) but I still get an error and I find 75 lines zsim < -ComputeZSim (copula_mixture = association_measure, garch_coef = fit_garch$garch_coef) The zsim generated here contains a lot of NA but here I don't know how to modify it

JoaoJungblut commented 7 months ago

Hello, I've made a few changes in both functions because I was studying new combinations of Copulas and portfolio restrictions. Although, I kept the old version on the files. Please, try to use them instead of the new ones. Furthermore, if you provide me the error messages I can check what is going on and give you a better answer.

This repository was build for my conclusion project. You can access the whole paper here: https://lume.ufrgs.br/handle/10183/26434/browse?type=author&value=Jungblut%2C+Jo%C3%A3o+Ramos

amazinginging commented 7 months ago

Thank you very much for your reply, your code is very excellent, but the following problems have occurred during my operation, and I have also made some modifications, but I don't know whether these modifications are correct. I can't find the old code under the current codebase, so I just run the R file main.R. Hope to get in touch with you in this way. My email address is 2105564065@qq.com. If it is convenient for you, we can also contact you by email.I have four questions as followings:

  1. When I run main.R on line 51: mixture_portfolio_1y <- RollingWindowEstimation(returns = returns, We = 252, Wt = nrow(returns), K = 1000, Mixture = TRUE),Its results are as follows: 1 of 2440 Error in purrr::map() at portfolio_analysis.R:101:2: ℹ In index: 1. Caused by error in association_measure_with_error_handling(): ! object 'association_measure' not found Run rlang::last_trace() to see where the error occurred. Warning message: In value[3L] : An error occurred while computing the association measure: An error occurred evaluating the 'table' parameter while selecting a method for the '%in%' function: argument "combination" is missing, with no default I tried to modify 48 lines of code in the portfolio.analysis.R file, The original code is: association_measure <- OptMixtureCopulas(unif_dist = unif_dist, K = K), I modify it as follows: association_measure <- OptMixtureCopulas(unif_dist = unif_dist, K = K,combination = c("Clayton","Gumbel","t"))
  2. When I'm done with the above changes, run line 51 of main.R: mixture_portfolio_1y <- RollingWindowEstimation(returns = returns, We = 252, Wt = nrow(returns), K = 1000, Mixture = TRUE),Its results are as follows: 1 of 2440

solnp-->The linearized problem has no feasible solnp-->solution. The problem may not be feasible.

Iter: 1 fn: -1490.7666 Pars: 1.18545 1.00000 1.59273 1.00000 0.52227 10.10246 1.00000 solnp--> Solution not reliable....Problem Inverting Hessian. Error in purrr::map() at portfolio_analysis.R:101:2: ℹ In index: 1. Caused by error in CVaROptimization(): ! unused argument (Turnover = 3e-04) Run rlang::last_trace() to see where the error occurred. There were 36 warnings (use warnings() to see them), Therefore, I deleted the first CVaROptimization function and the third one, and only saved the following CVaROptimization function code: CVaROptimization <- function(returns, Alpha = 0.975, TargetReturn = 0, Turnover = 0.0003, NumAssets = 8) {

cvar_objective <- function(r_mat, alpha, probs = NULL) { x.names <- colnames(r_mat) N <- NCOL(r_mat) S <- NROW(r_mat) mu <- colMeans(r_mat) if (is.null(probs)) probs <- rep(1/S, S) if (alpha < 0.5) alpha <- 1 - alpha

Amat <- cbind(as.matrix(r_mat),  diag(S), 1)
var.names <- c(x.names, paste0("z_cvar_aux", seq_len(S)), "gamma")

bnds <- ROI::V_bound(li = c(N + S + 1), lb = c( -Inf),
                     ui = c(N + S + 1), ub = c(  Inf))

constraint <- L_constraint(L = Amat, dir = rep(">=", S), 
                           rhs = rep(0, S), 
                           names = var.names)

objective <- L_objective(c(rep(0, N), probs/(1 - alpha), 1))

list(objective = objective, constraint = constraint, bounds = bnds)

}

budget_constraint <- function(r_mat, dir = "==", rhs = 1) { x.names <- colnames(r_mat) L_constraint(L = rep(1, NCOL(r_mat)), dir = dir, rhs = rhs, names = x.names) }

reward_constraint <- function(r_mat, dir = ">=", rhs = TargetReturn) { x.names <- colnames(r_mat) L_constraint(L = colMeans(r_mat), dir = dir,
rhs = rhs, names = x.names) }

turnover_constraint <- function(r_mat, x0 = NULL, dir = "<=", rhs = Turnover) { x.names <- colnames(r_mat) N <- NCOL(r_mat) S <- NROW(r_mat) if (is.null(x0)) x0 <- rep(1/N, N) Amat <- cbind(diag(N), - diag(N), diag(N)) var.names <- c(x.names,
paste0("y_plus_aux", seq_len(N)), paste0("y_minus_aux", seq_len(N)))

rbind(L_constraint(L = Amat, dir = rep("==", N), rhs = x0, 
                   names = var.names),
      L_constraint(c(rep(0, N), rep(1, N), rep(1, N) ), 
                   dir = dir, rhs = rhs, names = var.names))

}

cardinality_constraint <- function(r_mat, dir = "<=", rhs = NumAssets) { x.names <- colnames(r_mat) N <- NCOL(r_mat) Amat <- cbind(diag(N), -diag(N)) var.names <- c(x.names, paste0("z_card_aux", seq_len(N))) cat("Variable types for z_card_aux must be set to binary.\n") rbind(L_constraint(L = Amat, dir = rep("<=", N), rhs = rep(0, N), names = var.names), L_constraint(L = c(rep(0, N), rep(1, N)), dir = dir, rhs = rhs, names = var.names)) }

tmp <- cvar_objective(returns, 0.975) lp <- OP()

constraints(lp) <- rbind( tmp$constraint, budget_constraint(returns), reward_constraint(returns),

turnover_constraint(returns),

cardinality_constraint(returns, dir = "<=", rhs = NumAssets),
use.names = TRUE

)

obj <- c((tmp$objective)$L) objective(lp) <- c(obj, double(NCOL(constraints(lp)) - length(obj))) types(lp) <- rep("C", NCOL(constraints(lp))) types(lp)[grep("z_card_aux", constraints(lp)$names)] <- "B" (sol <- ROI_solve(lp, solver = "glpk")) weights <- round(solution(sol)[1:ncol(returns)], 4)[1:ncol(returns)]

return(weights) }

  1. After I've made the above changes, continue running line 51 of main.R,: mixture_portfolio_1y <- RollingWindowEstimation(returns = returns, We = 252, Wt = nrow(returns), K = 1000, Mixture = TRUE), No error is reported, but the calculated mixture_portfolio_1y$portfolio_return is all NA. Its results are as follows: 1 of 8

solnp-->The linearized problem has no feasible solnp-->solution. The problem may not be feasible.

Iter: 1 fn: -1490.7666 Pars: 1.18545 1.00000 1.59273 1.00000 0.52227 10.10246 1.00000 solnp--> Solution not reliable....Problem Inverting Hessian. Variable types for z_card_aux must be set to binary. For this problem, I tried to modify 123 lines of copula_estimate.R. The original code is: if(is.null(pi) == TRUE){ pi = c(Clayton = 1, Gumbel = 1, t = 1, Normal = 1, Frank = 1, Joe = 1) }, I modify it as follows: if(is.null(pi) == TRUE){ pi = c(Clayton = 1/6, Gumbel = 1/6, t =1/6, Normal = 1/6, Frank =1/6 1, Joe = 1/6) } After the modification, Its results are as follows: 1 of 8

Iter: 1 fn: -1349.3177 Pars: 1.185451489 0.000000078 1.884782512 0.054868385 0.517355370 9.338307771 0.945131537 Iter: 2 fn: -1349.3177 Pars: 1.1854514890 0.0000000183 1.8848063293 0.0548664868 0.5173557482 9.3384527559 0.9451334949 Iter: 3 fn: -1349.3177 Pars: 1.18545148897 0.00000001068 1.88476221200 0.05486982385 0.51735509669 9.33816085686 0.94513016548 solnp--> Completed in 3 iterations Variable types for z_card_aux must be set to binary. At this point, the result I ran was different from your portfolio_return data in excel in the result folder. 4.After making the above changes, I try to run your code with my own data set, and sometimes the following two problems occur: 1: In .local(copula, tau, ...) : For the Gumbel copula, tau must be >= 0. Replacing negative values by 0.

JoaoJungblut commented 7 months ago

When I have time to test the code again, I'll come back with a solution for your doubts.

amazinginging commented 7 months ago

Okay,thank you very much. And I also have a question,do these files contain the old version?I cannot find the old version.I'm a little worried.

JoaoJungblut commented 7 months ago

I checked the files again and found that I had removed the old version of the OptMixtureCopulas function. If you try to run main.R, you'll encounter an error because it was designed for my conclusion project. Instead, please run test.R, which has been updated with new functionalities.

amazinginging commented 7 months ago

Thanks for your answer, I re-downloaded your codebase, I ran test.R, but something went wrong, I was running 63 lines of test.R: MarketComposition <- read_excel("data_directory/MarketComposition.xlsx") %>% mutate(date = as.Date(Data), # convert to date format m = month(date, label = TRUE)) %>% # convert to numeric format dplyr::filter(m == "dez") %>% # update factors select(date, everything(),-c(Data, m)) %>% # select date, month and tickers gather("Ticker", "Composition", -date, na.rm=TRUE) %>% # adjust to panel data group_by(date) %>% # Select tickers by last date of the month reframe(Tickers = Ticker) MarketComposition The resulting MarketComposition is empty, 0 obs. of 2 variables. I don't know how to solve this problem. In addition, I would like to ask you about the problems that occur when running the main.R file. Can you show me the latest portfolio_optimization.R and portfolio_analysis.R files that I need to run the main.R file. In view of the problems caused by running main.R, I made some code modifications last time, and I also told you my modification scheme, but I am not sure whether the modification method is correct.

JoaoJungblut commented 7 months ago

It's all good with MarketComposition; it might be a misidentification of a function. Try declaring the library first in all tidyverse functions as in "dplyr::filter()".

MarketComposition <- read_excel("data_directory/MarketComposition.xlsx") %>%

  • mutate(date = as.Date(Data), # convert to date format
  • m = month(date, label = TRUE)) %>% # convert to numeric format
  • dplyr::filter(m == "dez") %>% # update factors
  • select(date, everything(), -c(Data, m)) %>% # select date, month, and tickers
  • gather("Ticker", "Composition", -date, na.rm=TRUE) %>% # adjust to panel data
  • group_by(date) %>% # Select tickers by last date of the month
  • reframe(Tickers = Ticker) MarketComposition

    A tibble: 1,557 × 2

    date Tickers

    1 1997-12-31 ITUB4 2 1997-12-31 PETR4 3 1997-12-31 BBDC4 4 1997-12-31 ELET3 5 1997-12-31 BBAS3 6 1997-12-31 ITSA4 7 1997-12-31 CMIG4 8 1997-12-31 VIVT3 9 1997-12-31 ELET6 10 1997-12-31 CSNA3 # ℹ 1,547 more rows # ℹ Use `print(n = ...)` to see more rows

On the other hand, I will reorganize this repository and include the old version.

amazinginging commented 7 months ago

Thanks for your patient answer. I tried the method you suggested again, but the result of MarketComposition is still MarketComposition

A tibble: 0 × 2

ℹ 2 variables: date , Tickers

Now I guess there is a problem with MarketComposition.xlsx. The first column of my MarketComposition.xlsx file is Data, and the data format is "1997/12/31". MarketComposition.xlsx has 301 rows and 214 columns, but some columns are all NA Also, thank you very much for reorganizing your code base and uploading code files containing older versions.

amazinginging commented 7 months ago

Hello, thank you for uploading the old version of the code. There's nothing wrong with him But I have also been running your new version of the code recently and have a new question to ask you. When the mean-CVAR model is used to calculate portfolio weights, if the turnover limit is applied in addition, the code is expressed as follows:

CVaROptimization_turnover <- function(returns, Alpha = 0.95, TargetReturn = 0, Turnover = 0.2, NumAssets = 8) {

CVaROptimization: Function to perform CVaR optimization for portfolio weights.

Inputs:

returns: A data frame of asset returns.

Alpha: CVaR alpha level (default = 0.025).

TargetReturn: Daily target return constraint (default = 0).

Turnover: Daily turnover measure constraint (default = 0.0003) equal to transaction costs.

NumAssets: Maximum number of assets in the portfolio (default = 8).

Output:

A matrix containing the optimized portfolio weights using CVaR optimization.

cvar_objective <- function(r_mat, alpha, probs = NULL) { x.names <- colnames(r_mat) N <- NCOL(r_mat) S <- NROW(r_mat) mu <- colMeans(r_mat) if (is.null(probs)) probs <- rep(1/S, S) if (alpha < 0.5) alpha= 1 - alpha

Amat <- cbind(as.matrix(r_mat),  diag(S), 1)
var.names <- c(x.names, paste0("z_cvar_aux", seq_len(S)), "gamma")

## set bounds for gamma (-Inf, Inf)
bnds <- ROI::V_bound(li = c(N + S + 1), lb = c( -Inf),
                     ui = c(N + S + 1), ub = c(  Inf))

constraint <- L_constraint(L = Amat, dir = rep(">=", S),
                           rhs = rep(0, S),
                           names = var.names)

objective <- L_objective(c(rep(0, N), probs/(1 - alpha), 1))

list(objective = objective, constraint = constraint, bounds = bnds)

}

budget_constraint <- function(r_mat, dir = "==", rhs = 1) { x.names <- colnames(r_mat) L_constraint(L = rep(1, NCOL(r_mat)), dir = dir, rhs = rhs, names = x.names) }

reward_constraint <- function(r_mat, dir = ">=", rhs = TargetReturn) { x.names <- colnames(r_mat) L_constraint(L = colMeans(r_mat), dir = dir, rhs = rhs, names = x.names) }

turnover_constraint <- function(r_mat, x0 = NULL, dir = "<=", rhs = Turnover) { x.names <- colnames(r_mat) N <- NCOL(r_mat) S <- NROW(r_mat) if (is.null(x0)) x0 <- rep(1/N, N) Amat <- cbind(diag(N), - diag(N), diag(N)) var.names <- c(x.names, paste0("y_plus_aux", seq_len(N)), paste0("y_minus_aux", seq_len(N)))

rbind(L_constraint(L = Amat, dir = rep("==", N), rhs = x0,
                   names = var.names),
      L_constraint(c(rep(0, N), rep(1, N), rep(1, N) ),
                   dir = dir, rhs = rhs, names = var.names))

}

cardinality_constraint <- function(r_mat, dir = "<=", rhs = NumAssets) {

x.names <- colnames(r_mat)

N <- NCOL(r_mat)

Amat <- cbind(diag(N), -diag(N))

var.names <- c(x.names, paste0("z_card_aux", seq_len(N)))

cat("Variable types for z_card_aux must be set to binary.\n")

Define the variable types

var_types <- rep("C", N) # Assume continuous by default

var_types[grep("z_card_aux", var.names)] <- "B" # Set z_card_aux variables to binary

#

rbind(L_constraint(L = Amat, dir = rep("<=", N),

rhs = rep(0, N), names = var.names),

L_constraint(L = c(rep(0, N), rep(1, N)), dir = dir,

rhs = rhs, names = var.names))

}

tmp <- cvar_objective(returns, 0.95)

lp <- OP()

lp <- ROI::OP()

constraints(lp) <- rbind( tmp$constraint, budget_constraint(returns), reward_constraint(returns,dir = ">=", rhs = TargetReturn), turnover_constraint(returns),

cardinality_constraint(returns, dir = "<=", rhs = NumAssets),

use.names = TRUE

)

Variable types for z_card_aux must be set to binary.

obj <- c((tmp$objective)$L) objective(lp) <- c(obj, double(NCOL(constraints(lp)) - length(obj)))

Error in (function (classes, fdef, mtable) : unable to find an inherited method for function 'constraints' for signature '"OP"'

types(lp) <- rep("C", NCOL(constraints(lp)))

Error in (function (classes, fdef, mtable) : unable to find an inherited method for function 'constraints' for signature '"OP"'

types(lp)[grep("z_card_aux", constraints(lp)$names)] <- "B"

Error in (function (classes, fdef, mtable) : unable to find an inherited method for function 'constraints' for signature '"OP"'

(sol <- ROI_solve(lp, solver = "glpk"))

Error in ROI_solve(lp, solver = "glpk"): objective is missing, with no default

weights <- round(solution(sol)[1:ncol(returns)], 4)[1:ncol(returns)] print(weights)

return(weights) }

If the copula type does not use the mixture type, and only a single copula model, such as GUASS, or t, is used to calculate, the resulting weight will sometimes yield NA: 85 of 171 [1] NA NA NA NA NA NA NA NA NA NA