美文网首页投资理财
[译]量化投资教程:投资组合优化与R实践

[译]量化投资教程:投资组合优化与R实践

作者: FinanceR | 来源:发表于2016-03-12 11:01 被阅读990次

    概述

    最近,我在研究投资组合优化的问题,主要针对的是股票持仓的组合优化,我们会在这个分析过程中发现一些有意思的现象,并一步一步优化、检验我们的风控模型。本文将有四个部分分别阐述具体步骤。

    • 第一部分(原文)中,我将解释什么是杠铃策略,并初步建立风控模型,比较持仓策略和风险收益的关系。
    • 第二部分(原文)中,我将解释什么是无风险利率假定,讨论多项式拟合的情形。
    • 第三部分(原文)中,我将解释如何通过放松约束最优化求解过程以避免非凹的情形,并做了实例演示。
    • 第四部分(原文)中,我将对比大盘策略、等权策略以及之前的优化策略之间的优劣。

    请注意,本文不应该被作为投资建议。本文数据是基于之前观察到的收益来模拟的,和历史上的数据并不太一致。这些技术可以帮助了解如何更好地分配一个投资组合。它不应该被用作唯一的投资决策,如果你正在寻找的建议应该找到一个合格的专业机构。

    第一部分

    数字特征计算

    当看到三个政府 ETF 债券(TLT、IEF、SHY)调整后的股息回报率,我注意到中间到期债券(IEF)风险收益情况比长期债券(TLT)更好。我以表格形式显示结果。在本文中,我们将重新分析和图形化展示我们的结果:

    首先,用如下函数来获取ETF的回报序列

    require(fImport)
    require(PerformanceAnalytics)
    
    # 将股票数据加载到一个时间序列对象的函数
    importSeries = function (symbol,from,to) {
    
        # 从雅虎读取金融数据
        input = yahooSeries(symbol,from=from,to=to)
    
        # 列名
        adjClose = paste(symbol,".Adj.Close",sep="")
        inputReturn = paste(symbol,".Return",sep="")
        CReturn = paste(symbol,".CReturn",sep="")
    
        # 计算收益率并生成时间序列
        input.Return = returns(input[,adjClose])
        colnames(input.Return)[1] = inputReturn
        input = merge(input,input.Return)
    
        # 计算累积收益率并生成时间序列
        input.first = input[,adjClose][1]
        input.CReturn = fapply(input[,adjClose],FUN=function(x) log(x) - log(input.first))
        colnames(input.CReturn)[1] = CReturn
        input = merge(input,input.CReturn)
    
        # 删掉一些没用的东西,如果你不知道就不用删除
        rm(input.first,input.Return,input.CReturn,adjClose,inputReturn,CReturn)
    
        # 返回时间序列
        return(input)
    }
    

    计算年化收益、标准差和夏普率。

    # 获取短中期和长期政府债券的收益率序列
    from = “2001-01-01″
    to = “2011-12-16″
    tlt = importSeries(“tlt”,from,to)
    shy = importSeries(“shy”,from,to)
    ief = importSeries(“ief”,from,to)
    merged = merge(tlt,shy)
    merged = merge(merged,ief)
    vars = c(“tlt.Return”,“shy.Return”,“ief.Return”)
    # 计算年回报率
    t = table.AnnualizedReturns(merged[,vars],Rf=mean(merged[,“shy.Return”],na.rm=TRUE))
    t
    

    结果如下:

    标的 年化收益率 年化波动率 年化夏普率 (Rf=2.81%)
    tlt.Return 0.0772 0.0283 0.0645
    shy.Return 0.1404 0.0173 0.0740
    ief.Return 0.3378 -0.0086 0.4729

    杠铃策略

    如果你经常看娱乐投资电视台,你最终会听到“杠铃策略”这个术语。这是指一个极端的投资组合分配方案。所有的权重都是极端情况,你可以想象这是一个杠铃。在政府债券的投资组合,这将意味着购买期限长或短而不是持有中间。那么什么样的风险收益情况下你会采用这个策略?

    首先,我们将风险定义为投资组合的方差。有各种各样的理由不使用方差,但它是从最古老的50年代开始这种类型的分析都是全新的。我们将定义收益为预期收益。在上面的表中,年回报率表示持有资产的预期收益为1年,标准差的平方表示风险。

    假设投资组合只包括持有长期和短期债券,我们便需要计算投资组合的预期收益和风险。收益的计算是很容易的,这是两种持仓的加权平均收益,权重就是每个资产的投入资本百分比。

    RP = WTLT* RTLT + WSHY * RSHY
    Where: WTLT + WSHY= 1
    

    显然这两种资产具有相关性(在马科维茨于1952年的博士论文发表之前,投资经理不了解相关性并且默认假设为1 -马科维茨因此获得了诺贝尔奖)。假设回报是正态分布的,那么投资组合方差将是:

    Vp = WTLT 2*σ2TLT+ WSHY 2* σ2SHY + WTLT* WSHY * σTLT * σSHY *CorrTLT,SHY
    Where:  WTLT+ WSHY = 1
    

    风控模型

    我们可以根据这两个部分的知识改变持仓权重并为我们的杠铃策略建立风险收益模型。

    # 检查相关性
    corr = cor(merged[,vars],use=‘complete.obs’)
    c = corr[‘tlt.Return’,‘shy.Return’]
    # 假设一个杠铃策略是持有长期和短期资产
    # 定义风险、收益
    ws = NULL
    wt = NULL
    mu = NULL
    sigma = NULL
    # 50个观察
    n=50
    # 遍历杠铃策略的权重
    for (i in 0:n){
          wsi = i/n;
          wti = 1–wsi;
         
          mui = wsi * rSHY + wti * rTLT
          sigmai = wsi*wsi*sSHY*sSHY + wti*wti*sTLT*sTLT + wsi*wti*sSHY*sTLT*c
         
         
          ws = c(ws,wsi)
          wt = c(wt,wti)
          mu = c(mu,mui)
          sigma = c(sigma,sigmai)
    }
    # 风险收益的数据集
    rrProfile = data.frame(ws=ws,wt=wt,mu=mu,sigma=sigma)
    # 绘图
    plot(rrProfile$sigma,
         rrProfile$mu,
           xlim=c(0,.022),
           ylim=c(0,.08),
           ylab=“Expected Yearly Return”,
           xlab=“Expected Yearly Variance”,
           main=“Efficient Frontier for Government Bond Portfolios”)
    

    注意,上面的方程是二次的。我们可以配合我们刚刚创建的点画出抛物线。注意,而习惯上把风险放在X轴上,而把拟合方差(风险)作为因变量放在Y轴。

    # 为模型拟合一个二次函数
    fit = lm(rrProfile$sigma ~ rrProfile$mu + I(rrProfile$mu^2))
    

    接下来,我们图上添加拟合线。

    # 得到回归系数
    coe = fit$coefficients
    # 得到每个回归预测的风险值
    muf = NULL
    sfit = NULL
    for (i in seq(0,.08,by=.001)){
          muf = c(muf,i)
         
          s = coe[1] + coe[2]*i + coe[3]*i^2
          sfit = c(sfit,s)
    }
    # 画出预测边值
    lines(sfit,muf,col=‘red’)
    

    tseries包中的portfolio.optim也许是一个更好的选择。我们只需要输入预期收益率,它会直接返回出来最优组合权重。我们可以在最低预期回报率(比如 100% 持有 SHY)到最高预期回报率(比如 100% 持有 TLT)之间修改输入的收益。注意,portfolio.optim使用日回报率做计算,因此代码将不得不做一些处理。我们假设一年255个交易日。

    # 现在让我们添加第三个标的。
    # 除非我们想做一个格点搜索,否则我们需要对每个级别的回报减少风险来优化投资组合。
    # portfolio.optim 在时间序列中不能有 NA 值。
    
    m2 = removeNA(merged[,vars])
    wSHY = NULL
    wIEF = NULL
    wTLT = NULL
    er = NULL
    eStd = NULL
    
    # 在回报水平之间不断循环搜索找到最优的投资组合,包括最小值(rSHY)和最大值(rTLT)
    # portfolio.optim 使用日回报数据,因此我们不得不做出相应的调整
    
    for (i in seq((rSHY+.001),(rTLT–.001),length.out=100)){
          pm = 1+i
          pm = log(pm)/255
          opt = portfolio.optim(m2,pm=pm)
          er = c(er,exp(pm*255)–1)
          eStd = c(eStd,opt$ps*sqrt(255))
          wTLT = c(wTLT,opt$pw[1])
          wSHY = c(wSHY,opt$pw[2])
          wIEF = c(wIEF,opt$pw[3])
    }
    
    # 画出三个标的的有效边界。
    
    lines(eStd^2,er,col=‘blue’)
    legend(.014,0.015,c(“‘Barbell’ Strategy”,“All Assets”),
                col=c(“red”,“blue”),
                lty=c(1,1))
    solution = data.frame(wTLT,wSHY,wIEF,er,eStd)
    

    结论

    如下图:

    我们已经创建了一个和大盘权重策略非常相关的策略,但是还是不如等权策略。等权策略和大盘权重策略的关联度是非常有趣的。

    这是收益绘制的时间序列:


    有趣的是,可以看到在图中绿色的部分显示我们的投资组合在2009年3月份的市场底部开始有一个快速反弹。这大大跑赢了大盘权重组合。

    作为分享主义者(sharism),本人所有互联网发布的图文均遵从CC版权,转载请保留作者信息并注明作者 Harry Zhu 的 FinanceR专栏:https://segmentfault.com/blog/harryprince,如果涉及源代码请注明GitHub地址:https://github.com/harryprince。微信号: harryzhustudio
    商业使用请联系作者。

    相关文章

      网友评论

        本文标题:[译]量化投资教程:投资组合优化与R实践

        本文链接:https://www.haomeiwen.com/subject/xtwtlttx.html