基于已知预期收益的R语言Markowitz投资组合优化问题
解决方案:自定义预期收益/协方差的Markowitz投资组合优化(R实现)
核心逻辑
完全可以通过R的二次规划求解器手动实现,不需要依赖那些直接绑定历史收益的工具包——这种方式反而更灵活,能完美适配你自己计算的预期收益、协方差矩阵。Markowitz方差优化的本质是带约束的二次规划问题,直接套公式就能落地。
步骤1:明确优化目标与约束
以最基础的两类场景为例:
场景1:最小方差组合(无目标收益要求)
目标函数:
minimize w^T * Σ * w
约束条件:
- 权重和为1:
sum(w) = 1 - 权重非负(禁止做空,可选):
w_i ≥ 0
场景2:目标收益下的最小方差组合
在上述约束基础上,新增:
- 组合预期收益达标:
sum(w * μ) = target_return
步骤2:用quadprog包实现(推荐)
quadprog是专门解决二次规划问题的R包,完全支持自定义输入的协方差矩阵和预期收益,不需要历史原始数据。以下是具体代码示例:
前置准备
假设你已经有:
mu:自定义的资产预期收益向量(长度为n)Sigma:自定义的n×n协方差矩阵
例1:求解最小方差组合
# 安装并加载包 install.packages("quadprog") library(quadprog) # 适配quadprog的目标函数格式(要求为(1/2)w^T D w,所以乘2抵消系数) Dmat <- 2 * Sigma dvec <- rep(0, length(mu)) # 构造约束矩阵:第一列是权重和为1的等式约束,后续列是非负约束 Amat <- cbind(rep(1, length(mu)), diag(length(mu))) bvec <- c(1, rep(0, length(mu))) # 求解:meq=1表示第一个约束是等式,其余为不等式(≥) result <- solve.QP(Dmat = Dmat, dvec = dvec, Amat = Amat, bvec = bvec, meq = 1) # 提取最优权重 optimal_weights <- result$solution
例2:求解目标收益下的最小方差组合
target_return <- 0.06 # 自定义目标收益 # 更新约束矩阵:新增预期收益达标等式 Amat <- cbind(rep(1, length(mu)), mu, diag(length(mu))) bvec <- c(1, target_return, rep(0, length(mu))) # 求解:meq=2表示前两个约束是等式 result <- solve.QP(Dmat = Dmat, dvec = dvec, Amat = Amat, bvec = bvec, meq = 2) optimal_weights <- result$solution
步骤3:批量处理多周期
把优化逻辑封装成函数,用循环或purrr批量处理各周期的mu和Sigma:
# 定义通用优化函数 optimize_portfolio <- function(mu, Sigma, target_return = NULL, allow_short = FALSE) { Dmat <- 2 * Sigma dvec <- rep(0, length(mu)) # 基础约束:权重和为1 base_constraint <- cbind(rep(1, length(mu))) base_bvec <- c(1) # 添加目标收益约束(如果需要) if (!is.null(target_return)) { base_constraint <- cbind(base_constraint, mu) base_bvec <- c(base_bvec, target_return) } # 添加非负约束(如果禁止做空) if (!allow_short) { base_constraint <- cbind(base_constraint, diag(length(mu))) base_bvec <- c(base_bvec, rep(0, length(mu))) } # 等式约束的数量 meq <- 1 + ifelse(is.null(target_return), 0, 1) result <- solve.QP(Dmat = Dmat, dvec = dvec, Amat = base_constraint, bvec = base_bvec, meq = meq) return(result$solution) } # 模拟多周期数据 periods_data <- list( period1 = list(mu = c(0.05, 0.08), Sigma = matrix(c(0.01, 0.002, 0.002, 0.02), nrow=2)), period2 = list(mu = c(0.06, 0.07), Sigma = matrix(c(0.012, 0.001, 0.001, 0.018), nrow=2)) ) # 批量求解各周期权重 library(purrr) all_weights <- map(periods_data, ~optimize_portfolio(.x$mu, .x$Sigma))
步骤4:回测实现
用得到的权重与实际历史收益计算组合收益:
# 模拟实际历史收益矩阵(每行对应一个周期,每列对应资产) actual_returns <- matrix(c(0.04, 0.09, 0.07, 0.06), nrow=2) # 计算组合回测收益 portfolio_returns <- map2_dbl(all_weights, split(actual_returns, 1:nrow(actual_returns)), ~sum(.x * .y))
关于手动实现的疑问
不需要从零编写求解逻辑,quadprog这类成熟包已经封装了高效的二次规划求解器,完全能满足你的自定义输入需求,效率远高于Excel。那些直接用历史收益的工具包本质也是类似逻辑,你手动调用底层求解器反而能完全掌控输入,适配自己的计算结果。
内容的提问来源于stack exchange,提问作者Theo
相关产品推荐
相关产品推荐

