Mean-Variance Optimization 2-优化过程

论坛 期权论坛 期权     
期权匿名问答   2022-1-27 20:36   10915   14
复习完矩阵微分和求导的知识[1],我们继续第二讲。如何给定投资组合的目标,在约束条件下,求出最佳的配置?
主要参考了MIT的均值方差模型[2]。
符号说明


  • 一共有m个风险资产,
  • m个资产的历史均值收益率向量为
  • 收益率期望 ,收益率的协方差矩阵为
  • 我们想要利用这m个资产,配置“理想”的权重,得到投资组合;其中,权重向量为 ,且 ,即为权重和等于1。
  • 投资组合的情况:投资组合的收益率 ,注意,R_w是一个标量;投资组合收益率的方差 ,这也是一个标量。
  • 投资组合的期望收益率:
  • 实际操作中,我们会把期望收益率=历史收益率的均值。
组合1:投资组合最小波动率


  • 给定投资组合的预期收益率为 ,如何选择权重向量,使得投资组合的波动率最小?
  • 数学表达式



  • 拉格朗日表达式:


首先,这里较为困难的就是标量L对向量w的求导,用到第一讲的内容。


另外对 的求导很简单,就是标量的导数:


三个偏导数都是等于0;



  • 程序
  • 数据:
链接:https://pan.baidu.com/s/1GUVyCMXBzFjIcuKeY5c18w
提取码:le24
如果你用自己的数据,数据在excel中得按这种格式,避免格式的麻烦(毕竟主要目标是计算权重,而不是清洗数据)。



图1:月度收益率,每一列是一个股票的收益率时间序列

在使用程序计算的时候,需要小心时间频率。我们的目标都是对投资组合的年化数据进行处理。例如,样本数据是资产收益率的月度序列,在计算样本平均收益率的时候,记得将每个均值*12,化成年化收益率。
问题来了:收益率协方差矩阵要不要*12进行年化?首先,假设不乘以12,协方差矩阵(1,1)位置是资产1的收益率的方差,该方差是月度数据计算出来的,因此是月度方差;那么应该*12,使其等于年化的方差才行。因此协方差矩阵也要乘以12,进行年化。
import pandas as pd
import numpy as np


def get_ret_and_cov(df, frequency):
    """输入:股票时间序列
       输出:股票年画平均收益,股票收益的年化标准差,股票收益率的年化协方差矩阵。
       frequency控制了数据频率:如果是日度数据,frequency=252;
       如果是周度数据,frequency=52;如果是月度数据,frequency=12。本例中是月度数据
    """
    ret_ave = pd.DataFrame(df.mean()).reset_index()
    ret_ave.columns = ['Stkcd', 'ret_ave']
    # 年化收益率
    ret_ave['ret_ave'] = ret_ave['ret_ave'] * frequency
    ret_std = pd.DataFrame(df.std()).reset_index()
    ret_std.columns = ['Stkcd', 'ret_std']
    ret_std['ret_std'] = ret_std['ret_std'] * np.sqrt(frequency)
    # 年化协方差矩阵
    ret_cov = df.cov() * frequency
    return ret_ave, ret_std, ret_cov

def mini_vol(number, ret_ave_vector, ret_cov_matrix, target_ret):
    """number是股票个数;ret_ave_vector是股票的收益率向量,注意是列向量;
       ret_cov_matrix是股票收益率的协方差矩阵;
       target_ret是目标收益率
    """
    # 协方差矩阵的逆矩阵
    ret_cov_matrix_I = ret_cov_matrix.I
    # 全1向量e
    e = np.matrix([1]*number).reshape((-1,1))
    # 4*4的系数矩阵
    a = float(np.dot(np.dot(ret_ave_vector.T, ret_cov_matrix_I), ret_ave_vector))
    b = float(np.dot(np.dot(e.T, ret_cov_matrix_I), ret_ave_vector))
    c = float(np.dot(np.dot(e.T, ret_cov_matrix_I), e))
    # 得到系数矩阵
    coeff_matrix = np.matrix([a,b,b,c]).reshape((2,2))
    coeff_matrix_I = coeff_matrix.I
    # 解方程
    y1 = np.matrix([target_ret, 1]).reshape((-1,1))
    lambda_result = np.dot(coeff_matrix_I, y1)
    lambda1 = float(lambda_result[0])
    lambda2 = float(lambda_result[1])
    # 得到权重
    weights = lambda1 * np.dot(ret_cov_matrix_I, ret_ave_vector) + lambda2 * np.dot(
                ret_cov_matrix_I, e)
    return weights

def port_info(weights, ret_ave_vector, ret_cov_matrix):
    """计算投资组合的年化收益率,以及年化波动率"""
    port_return =  float(np.dot(weights.T, ret_ave_vector))
    port_var = float(np.dot(np.dot(weights.T, ret_cov_matrix),weights))
    port_std = np.sqrt(port_var)
    return port_return, port_std

monthly_data = pd.read_csv(r'...\return.csv', engine='python')
ret_ave, ret_std, ret_cov = get_ret_and_cov(m_data, 12)
# 生成收益率的列向量+协方差矩阵
ret_ave1 = np.matrix(ret_ave['ret_ave']).reshape((-1,1))
ret_cov1 = np.matrix(ret_cov)   
# 计算权重:假设我的目标收益率是0
weights = mini_vol(4, ret_ave1, ret_cov1, 0)
# 计算投资组合的信息
port_return, port_std = port_info(weights, ret_ave1, ret_cov1)组合2:投资组合最大收益率


  • 给定投资组合的预期波动率为 ,如何选择权重向量,使得投资组合的收益率最大?
  • 数学表达式



  • 拉格朗日表达式:


首先对w求偏导:


另外对 的求导很简单,就是标量的导数:


三个偏导数都是等于0;


在运行程序前,注意点:
先找出所有资产中,最低的一个波动率( )。这是能够达到的极限,也就是只有这个资产权重为1,其他全是0。如果设置波动率比它还小,那么是无法达到的。这个前提条件,也是上面方程组有解的前提条件。
程序:
def get_smallest_vol(ret_cov_matrix):
    """找出所有资产中最小的波动率;注意是返回σ,要开根号"""
    diags = np.diag(ret_cov_matrix)
    return np.sqrt(np.min(diags))

def max_ret(number, ret_ave_vector, ret_cov_matrix, target_vol):
    """
       number是股票个数;ret_ave_vector是股票的收益率向量,注意是列向量;
       ret_cov_matrix是股票收益率的协方差矩阵;
       target_vol是目标波动率,注意是σ。
    """
    ret_cov_matrix_I = ret_cov_matrix.I
    e = np.matrix([1]*number).reshape((-1,1))
   
    a = float(np.dot(np.dot(ret_ave_vector.T, ret_cov_matrix_I), ret_ave_vector))
    b = float(np.dot(np.dot(ret_ave_vector.T, ret_cov_matrix_I), e))
    c = float(np.dot(np.dot(e.T, ret_cov_matrix_I), e))
    A = (target_vol * c) ** 2 - c
    B = 2 * b * (1 - c * target_vol ** 2)
    C = (target_vol * b) ** 2 - a
    delta = B ** 2 - 4 * A * C

    lambda21 = 0.5 / A * (- B + np.sqrt(delta))
    lambda22 = 0.5 / A * (- B - np.sqrt(delta))
    lambda11 =  (b - c * lambda21) / 2
    lambda12 =  (b - c * lambda22) / 2
    weights1 = np.dot(ret_cov_matrix_I, (ret_ave_vector - lambda21 * e))/(2*lambda11)
    weights2 = np.dot(ret_cov_matrix_I, (ret_ave_vector - lambda22 * e))/(2*lambda12)
    return weights1, weights2其他程序和例1相同。
# 首先判断所能够达到的最小波动率σ,下面穿进去的target_vol绝对不能够比它小:
print(get_smallest_vol(ret_cov1))
# 计算权重:假设我的目标波动率是40%
weights1, weights2 = max_ret(4, ret_ave1, ret_cov1, 0.4)
# 计算投资组合的信息
port_return1, port_std1 = port_info(weights1, ret_ave1, ret_cov1)
port_return2, port_std2 = port_info(weights2, ret_ave1, ret_cov1)有效前沿

事实上,利用例子1,我们能够把有效前沿找出来。
import matplotlib.pyplot as plt

port_ret = []
port_std = []
# 收益率从0到1,步长为0.00001,一共10万个收益率样本
ranges = np.arange(0,1, 0.00001)
for i in ranges:
    weight = mini_vol(4, ret_ave1, ret_cov1, i)
    port_ret1, port_std1 = port_info(weight, ret_ave1, ret_cov1)
    port_ret.append(port_ret1)
    port_std.append(port_std1)

port_std = np.array(port_std)
port_ret = np.array(port_ret)
plt.figure(figsize = (16,9))
plt.scatter(port_std,port_ret,c = port_ret/port_std, marker = 'o')
plt.grid(True)
plt.xlabel('excepted volatility')
plt.ylabel('expected return')
plt.colorbar(label = 'Sharpe ratio')        


图2:有效前沿

怎么样?感觉美不美?是不是比大批量采样更加简洁?
结语

这次主要把矩阵微分和求导复习了一下。这里特别感谢雷敬华老师,把我们的计量经济学教得很扎实;感谢魏丽老师,教给我们很棒的规划求解知识。回想当时,自己还不会任何编程知识,一直都是纸上谈兵;现在才发现,老师们给我们这么多宝贵的知识。编程只是工具,而有趣的思想才是首要目标。如果硬核模拟撒点求有效前沿,程序较为复杂;但是通过规划求解,很简单就把权重求了出来。
欢迎正在阅读这篇文章的你,来人大读书。它真的是个好学校。
参考


  • ^https://zhuanlan.zhihu.com/p/137761052
  • ^https://ocw.mit.edu/courses/mathematics/18-s096-topics-in-mathematics-with-applications-in-finance-fall-2013/lecture-notes/MIT18_S096F13_lecnote14.pdf
分享到 :
0 人收藏

14 个回复

倒序浏览
2#
期权匿名回答  16级独孤 | 2022-1-27 20:36:21 发帖IP地址来自 北京
美!
3#
期权匿名回答  16级独孤 | 2022-1-27 20:37:17 发帖IP地址来自 广东广州
这不是三天就会爬虫的大佬吗[拜托]
4#
期权匿名回答  16级独孤 | 2022-1-27 20:38:03 发帖IP地址来自 北京
想请教一下大神有卖空限制情形下MVO最优解怎么得到
5#
期权匿名回答  16级独孤 | 2022-1-27 20:38:52 发帖IP地址来自 中国
资产的权重再设置限制条件,比较复杂,需要用到松弛变量。。
6#
期权匿名回答  16级独孤 | 2022-1-27 20:39:07 发帖IP地址来自 首都经贸大学
w - (a)nx1 = 0

(a)nx1>0

这样?但是如果手动设置a(nx1)的话,跟随机模拟权重的值有啥区别呢
7#
期权匿名回答  16级独孤 | 2022-1-27 20:39:14 发帖IP地址来自 陕西西安
直接画出有效前沿,避免狂撒点还不一定能模拟到极端情况。
8#
期权匿名回答  16级独孤 | 2022-1-27 20:39:51 发帖IP地址来自 北京
额,请问大神,卖空约束下,mvo最优权重无解析解的情况下有效前沿仍然可以确定么
9#
期权匿名回答  16级独孤 | 2022-1-27 20:40:02 发帖IP地址来自 北京
亲,我没做过。。
10#
期权匿名回答  16级独孤 | 2022-1-27 20:40:41 发帖IP地址来自 北京
额[红心][红心][红心]多谢指点
11#
期权匿名回答  16级独孤 | 2022-1-27 20:41:23 发帖IP地址来自 中国
没帮上忙。。。以后更新了KKT再和你交流。。。
12#
期权匿名回答  16级独孤 | 2022-1-27 20:42:11 发帖IP地址来自 广东湛江
感谢!数学系的看起来如沐春风!目前看到的阅读最舒适的均值方差模型,没有一句废话,逻辑通畅连续,感谢感谢!
13#
期权匿名回答  16级独孤 | 2022-1-27 20:42:16 发帖IP地址来自 中国
客气啦,很开心可以提供有趣的知识。
14#
期权匿名回答  16级独孤 | 2022-1-27 20:43:08 发帖IP地址来自 北京
请问协方差矩阵为什么是*12来进行年化的呀?因为按照方差的性质Var(ax)=a^2Var(x),为什么不是乘以12^2呢?还有如果目标是最大化夏普比率的话,约束条件应该是什么呢?
15#
期权匿名回答  16级独孤 | 2022-1-27 20:44:05 发帖IP地址来自 北京
问题1:我使用的是月度数据,因此cov(x1,x2)是月度协方差,需要乘以12转化为年度的协方差(特例:cov(x1,x1)=Var(x1),月度的方差*12=年度方差)。问题2:在我的能力范围内,我没法以最大化夏普比率作为目标函数,因为分子分母都有关于权重的表达式,而且权重变量的次级还不同,不是线性的。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:400157
帖子:80032
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP