原始题目(翻译版)
第一部分
编写一个程序"efficient_frontier",它接受两个命令行参数:
- 一个文件名——一个资产列表(直译为资产宇宙)文件。格式为无列名行的csv文件。每一行包含资产名,平均回报率和回报率标准差。
- 一个文件名——文件内容为资产列表文件中资产的相关矩阵。
提供的数据
作为示例数据,资产列表csv文件(universe.csv )包含以下资产及其平均(年化)回报以及这些回报的标准差:
国际股票、
大宗商品、
房地产、
投资-评级公司债券、
与通胀挂钩的中期(7-10年)美国国债和短期(1-3年)美国国债
相关矩阵文件(correlation.csv)包含2009年3月至2015年6月的资产相关性。(这一时期紧随“信贷危机熊市结束”之后。)
有效前沿
有效前沿是一条双曲线,代表所有可能的最优投资组合的边界,由提供的资产数据创建的。
对于这些资产数据,我们需要寻找最优地(风险最低——即波动性最低)投资组合,在每个预期的投资组合回报率水平上。
一个投资组合有一个权重向量,表明投资组合中投资于每项资产的比重。这些权重总和为 1(即 100%)。该程序必须估计最佳权重,即最小波动性,对于回报在 1% 到 26% 之间的每个水平,增量为 1%。
投资组合波动率的公式为:
σ
p
=
∑
i
∑
j
w
i
w
j
c
o
v
i
j
=
∑
i
∑
j
w
i
w
j
σ
i
σ
j
ρ
i
j
\sigma _ {p} = \sqrt { \sum _ {i} \sum _ {j} w_ {i}w_ {j}{cov_ {ij}} }= \sqrt {\sum _ {i} \sum _ {j}w_ {i}w_ {j}\sigma _ {i}\sigma _ {j}{\rho_ {ij}}}
σp=i∑j∑wiwjcovij=i∑j∑wiwjσiσjρij
其中
•
w
i
w_ {i}
wi= 投资组合中第 i 个资产的权重
•
c
o
v
i
j
{cov_ {ij}}
covij = 第 i 个资产和第 j 个资产之间的协方差
•
σ
i
\sigma _ {i}
σi = 第 i 个资产的回报率的标准差
•
ρ
i
j
{\rho_ {ij}}
ρij = 第 i 个和第 j 个资产之间的相关性
对于此步骤,打印以逗号分隔的回报率列表以及该比率的最小波动回报率。在这一部分中,假设允许卖空(权重可以为负)。
例如,1-4%的值为:(预期输出在右侧)
优化这个问题很棘手,因为它是一个有约束的二次优化问题。你可以自由地使用您喜欢的任何方法来实现优化,但在作业文件夹中的文档(“有效前沿的优化方法”)中提供了更多详细信息。此外,该文档演示了如何利用线性方程组来执行优化。
第二部分
在此步骤中,您将为程序添加附加功能。如果选项“-r”作为第一个传递命令行参数(即可执行文件名称之后),您应该实现一个受限制的优化,即使用不允许卖空的附加约束。也就是说,所有的权重都必须为非负数。存在许多不同的方法来检查“-r”,请使用最适合您的方法。
再次打印以逗号分隔的回报率列表以及该回报率的最小波动率。
当不允许卖空时,1-4%的值为:(正确值是0.98%,而不是0.96%)
求解线性方程组
要求解线性方程组,您可以使用 Eigen 包,这是一个文档齐全、经过充分测试的、以及常用的 C++ 线性代数包:http://eigen.tuxfamily.org。
Eigen安装
有关如何安装和/或引用 Eigen 的说明,请参阅矩阵作业内容(我稍后上传到我的资源里)。
PS: 我本人去年发过Eigen安装或引用相关的博客
实现提示
-
如前所述,可执行文件必须命名为“efficient_frontier”。
-
您必须提供Makefile。推荐的 C++ 版本:std=C++17
-
Makefile 必须具有“efficient_frontier”和“clean”目标。
-
如果存在 –r 标志,则它将位于参数的第二个位置 - 第一个(索引 0)是程序名称。然后将指定资产文件,然后指定相关矩阵文件。
-
查看标准差、协方差和相关性之间的关系。
-
如果您打算使用Eigen,请花一些时间来适应它。从“Getting Started”页面:https://eigen.tuxfamily.org/dox/GettingStarted.html
-
考虑数据文件中可能存在哪些错误。您不需要执行任何类型的数据更正。当您发现错误时,将适当的消息打印到标准错误并以状态代码“EXIT_FAILURE”退出。在检查数据错误时,应尽可能在初始解析阶段进行检查。不要依赖于在处理后检查无效数据。
-
关于错误检查的具体提示:
- 您的“-r”选项是否可选?它应该是可选的。
- 您是否检查了两个文件作为命令行参数?
- 您是否验证了每个文件是否存在?
- 您是否验证了每个文件是否具有所有必需的值?例如,如果它是一个 N x N 矩阵,那么 N 行中的每一行是否都有 N 个数值?
- 您是否接受资产名称中的空格?
- 您是否验证了每个应该为数字的输入都是数字?
- 对于此作业,应该为数字但不是数字的值(空值、空格、单词等)可以报告为错误。
-
考虑使用更多面向对象的设计。名词通常指定类/属性,而动词代表潜在的行为。
- 一个资产(Asset)具有名称、平均回报率和标准差。
- 一个投资组合(Portfolio)具有权重列表和资产列表,可以从中计算投资组合的波动率和回报率。您可以添加更多属性和函数。
- 其他类和文件,根据需要支持解析和优化。
不限制功能的实现提示
从作业文件夹中的优化方法笔记中,我们可以找到梯度为0的最优解,因此我们有以下方程:
其中:
𝜎 是协方差矩阵
𝐴 是一个 2 x n 的矩阵(其中 n = 资产数量),形式为:(来自公式 6、7、10)
这会产生以下矩阵
b 是一个列向量,其形式为:
,(来自方程 6、7、10 的右侧)
现在,求解 𝐴𝑥 = 𝑏 形式的线性方程组。
x 包含权重向量和拉格朗日乘子。
Eigen 包,https://eigen.tuxfamily.org/dox/group__TutorialLinearAlgebra.html 提供了示例代码。
受限功能实现提示
虽然优化方法文档提出了使用原始-对偶的投影步骤
梯度法,我们还可以继续利用矩阵方程的方法。一旦我们有了初步的权重向量,我们看看哪里权重是负数。如果存在负权重(例如,对于第 i 个资产),我们向“矩阵”添加一个线性方程,将该变量设置为 0。这意味着一个新行第 i 个位置上的 1 被添加到“矩阵”中。我们还需要向位于等式右侧的列向量添加“0”行。由于“矩阵”中的列数必须等于x 和 b 中的行数,我们还需要将该新行的转置添加到矩阵上。重复此过程,直到不存在负权重或权重在 0 的小值范围内,使得投资组合波动方程中不会有任何因素。每个负权重只能被添加过一次。
方法
计算无限制情况下的 x
虽然 x 具有负数成员(或者,
𝑥
i
𝑥_{i}
xi < −𝜀,其中 𝜀 是一个足够小的数字):
* 为每个负数成员
x
i
x_{i}
xi添加一个线性方程,以将该数字限制为 0
* 通过求解更新的线性方程组重新计算权重。
示例数据:
假设权重 1 和 3 为负。更新后的矩阵和向量变为:(rate = .1)
评分标准
与之前的作业不同,我们不会直接提供测试用例的结果。由于这项作业是您课程最终评估的一部分,因此您需要自己创建测试用例。作业评分者将根据您提交的内容和参考实现运行您的测试用例。
您需要创建一个名为“testcases.txt”的文件,该文件包含两个部分:
- #error: 列出应生成错误消息和退出代码的任何测试用例。
- #success: 列出应正常运行的任何测试用例。将比较两种实现的输出。
您可以创建其他文件(例如包含错误资产数据的文件)作为提交的一部分。
示例 testcases.txt:
#error
universe_err.csv correlation.csv
universe.csv correlation_err1.csv
universe.csv correlation_err2.csv
universe.csv correlation_err3.csv
#success
universe.csv correlation.csv
您的 testcases.txt 不会被评分。评分细分为:95% 由讲师生成的测试用例,5% 代码审查。
提交
将您的 Makefile、所有相关代码文件、testcases.txt 和任何相关数据文件提交到 Gradescope 作业。对于数据文件,如果它们是测试用例的一部分,您需要包含提供的数据文件。