我正在尝试在R中实现CVaR投资组合优化。基本上是尝试复制本文中使用的Matlab方法:
为此,我需要在非线性约束下执行非线性优化。
我曾尝试使用nloptr包,但发现了超出我的矩阵的梯度的导数计算。
相反,我选择了NlcOptim软件包,该软件包以与本文中使用的Matlab函数相同的方式来表示约束。
library(NlcOptim)
# ====================================================================
# Just generate arbitrary returns data and bootstrap -----------------
asset_returns <- rbind(c(0.1, 0.05, 0.05, 0.01, 0.06),
c(0.05, 0.05, 0.06, -0.01, 0.09),
c(0.025, 0.05, 0.07, 0.02, -0.1),
c(0.01, 0.05, 0.08, -0.02, -0.01),
c(0.01, 0.05, 0.08, 0.00, 0.2),
c(0.005, 0.05, 0.09, 0.005, -0.15),
c(0.01, 0.05, 0.08, 0.01, -0.01),
c(0.012, 0.05, 0.00, -0.01, -0.01),
c(0.015, 0.05, 0.00, 0.03, 0.05),
c(0.02, 0.05, -0.01, 0.04, 0.03))
# Returns for 5 assets over 10 trading periods
nAssets <- ncol(asset_returns)
nReturns <- nrow(asset_returns)
nPeriods <- 4
nSims <- 10
# BOOTSTRAP ---------------------------------------------------------
sim_period_returns <- matrix(nrow = nSims, ncol = nAssets)
for (k in 1:nSims) {# run nSims simulations
sim_returns <- matrix(nrow = nPeriods, ncol = nAssets)
sample_order <- sample(nReturns, nPeriods)
for (i in 1:nPeriods) {
sim_returns[i,] <- asset_returns[sample_order[i],]
}
sim_prices <- rbind(rep(1, nAssets), 1 + sim_returns)
for (j in 1:nAssets) {
sim_period_returns[k, j] <- prod(sim_prices[, j]) - 1
}
}
# ------------------------------------------------------------------------
# ========================================================================
# The important stuff ====================================================
returns <- sim_period_returns
alpha <- 0.95
CVaR_limit <- 0.025
UB <- 0.75
LB <- 0.05
# Inequality constraints
A <- rbind(c(rep(0, nAssets), 1, 1/((1-alpha)*nSims) * rep(1, nSims)),
cbind(- returns, -1, diag(nSims)))
b <- as.matrix(c(-CVaR_limit, rep(0, nSims)), nrow = nSims, ncol = 1)
# Equality constraints
Aeq <- c(rep(1, nAssets), 0, rep(0, nSims))
beq <- 1
# Upper and lower bounds
UB <- c(rep(UB, nAssets), Inf, rep(Inf, nSims))
LB <- c(rep(LB, nAssets), 0, rep(0, nSims))
# Initial portfolio weights
w0 <- rep(1/nAssets, nAssets)
VaR0 <- quantile(returns %*% w0, alpha, names = F)
w0 <- c(w0, VaR0, rep(0, nSims))
objective_function <- function(x) {
# objective function to minimise
return (-colMeans(returns) %*% x[1:nAssets])
}
# **********************************************
# The solnl function giving the error based on the above inputs
solnl(X = w0,
objfun = objective_function,
A = A,
B = b,
Aeq = Aeq,
Beq = beq,
lb = LB,
ub = UB)
# **********************************************
# ===================================================================
我收到以下错误:
Error in if (eq > 0 & ineq > 0) { : argument is of length zero
我已经阅读了程序包的源代码,并试图找出导致此错误的原因,但仍然不知所措。
[检查源代码和输入数据,当以下代码被调用nLineareq = nrow(Aeq);
时,我认为错误始于NlcOptim的第319行:通过以您定义的nrow(Aeq)
方式调用Aeq
,将导致NULL
几行后,对表达式if (eq > 0 & ineq > 0)
求值导致错误。关于错误,您可以在这里R - argument is of length zero in if statement
快速解决方法是使用]更改Aeq
上的形状>
Aeq <- t(array(c(rep(1, nAssets), 0, rep(0, nSims))))
但是通过更改,当我尝试运行代码时,我得到了另一个错误
Error: objetc 'lambda' not found
我不确定r的实现是否需要不同的初始条件或该方法是否收敛,因为在本文中,用于优化的方法是内部点而不是
NlcOptim
中实现的SQP。希望对您有所帮助