后处理权重 ¶
作者:Robert Andrew Martin
译者:片刻小哥哥
项目地址:https://www.dafeiyang.cn/finance/stock/tools/PyPortfolioOpt/Postprocessing
原始地址:https://pyportfolioopt.readthedocs.io/en/latest/Postprocessing.html
生成最佳权重后,通常需要进行一些后处理才能实际使用。 特别是,您可能会使用投资组合优化技术来生成投资组合分配 —— 您可以在经纪人处购买的股票代码和相应整数数量的列表。
然而,将连续权重(由我们的任何优化方法输出)转换为可操作的分配并非易事。 例如,假设我们想要分配 10,000 美元。 如果我们将权重乘以投资组合总价值,结果将是每项资产的美元金额。 因此,如果苹果的最佳权重是 0.15,我们需要价值 1500 美元的苹果股票。 然而,Apple 股票是离散单位的(撰写本文时为 190 美元),因此我们无法购买正好 1500 美元的股票。 我们能做的最好的事情就是购买最接近所需美元价值的股票数量。
PyPortfolioOpt 提供了两种解决此问题的方法:一种使用简单的贪心算法,另一种使用整数规划。
贪心算法 ¶
DiscreteAllocation.greedy_portfolio()
分两轮进行。 在第一轮中,我们为每种资产购买尽可能多的股票,但不超过所需的权重。 在苹果的例子中,\(1500/190 \approx 7.89\),所以我们以 1330 美元的价格购买 7 股。 迭代完所有资产后,我们将剩下很多钱(因为我们总是向下舍入)。
在第二轮中,我们计算每个资产的当前权重与现有权重的偏差程度。 我们希望苹果占投资组合的 15%(总价值 10,000 美元),但我们只购买了价值 1330 美元的苹果股票,因此偏差为 \(0.15 - 0.133\)。 有些资产与理想的偏差会比较大,所以我们会先购买这些资产的股票。 然后我们重复这个过程,总是购买当前权重与理想权重最远的资产股票。 虽然这个算法不能保证最优解决方案,但我发现它允许我们用很少的剩余资金生成离散分配(例如,10,000 美元的投资组合中还剩下 12 美元)。
话虽这么说,我们可以看到,在测试数据集上(对于标准 max_sharpe
投资组合),分配方法可能与所需权重有相当大的偏差,特别是对于股价较高的公司(例如 AMZN)。
Funds remaining: 12.15
MA: allocated 0.242, desired 0.246
FB: allocated 0.200, desired 0.199
PFE: allocated 0.183, desired 0.184
BABA: allocated 0.088, desired 0.096
AAPL: allocated 0.086, desired 0.092
AMZN: allocated 0.000, desired 0.072
BBY: allocated 0.064, desired 0.061
SBUX: allocated 0.036, desired 0.038
GOOG: allocated 0.102, desired 0.013
Allocation has RMSE: 0.038
整数规划 ¶
该方法(首次实现归功于 Dingyuan Wang)将离散分配视为整数规划问题。 实际上,整数规划方法搜索可能的分配空间,以找到最接近我们所需权重的分配空间。 我们将使用以下符号:
- \(T \in \mathbb{R}\) 是要分配的总美元价值
- \(p \in \mathbb{R}^n\) 是最新价格的数组
- \(w \in \mathbb{R}^n\) 是目标权重的集合
- \(x \in \mathbb{Z}^n\) 是整数分配(即结果)
- \(r \in \mathbb{R}\) 是剩余的未分配价值,即 \(r = T - x \cdot p\) 。
优化问题由下式给出:
这很容易翻译成 cvxpy
。
警告
PyPortfolioOpt 使用 ECOS_BB
作为整数规划的默认求解器。 ECOS_BB
存在已知的正确性问题(请参阅 此处 进行讨论)。 另一种方法是使用 GLPK_MI
,它与 cvxopt
一起打包。
处理空头 ¶
从 v0.4 开始,DiscreteAllocation
通过为 仅多头部分 和 仅空头部分 找到单独的离散分配来自动处理空头。 如果您的投资组合有空头,您应该通过空头比率。 默认值为 0.30,对应于 130/30 多空平衡。 实际上,这意味着您可以做多 10,000 美元的某些股票,做空 3000 美元的其他股票,然后使用空头收益再做多 3000 美元。 因此,最终投资组合的总价值将为 13,000 美元。
文档参考 ¶
crete_allocation
模块包含 DiscreteAllocation
类,该类提供多种方法从连续权重生成离散投资组合分配。
class pypfopt.discrete_allocation.DiscreteAllocation(weights, latest_prices, total_portfolio_value=10000, short_ratio=None)
[来源] ¶
从连续权重生成离散投资组合分配
实例变量:
- 输入:
weights
- dictlatest_prices
- pd.Series 或 dicttotal_portfolio_value
- int/float 型short_ratio
- float
- 输出:
分配
- dict
公共方法:
greedy_portfolio()
- 使用贪心算法lp_portfolio()
- 使用线性规划
__init__(weights, latest_prices, total_portfolio_value=10000, short_ratio=None)
[来源] ¶
Parameters:
- weights ( dict ) – 生成的连续权重
efficient_frontier
模块 - latest_prices ( pd.Series ) – 每项资产的最新价格
- total_portfolio_value ( 整数/float , optional ) – 投资组合所需的总价值,默认为 10000
- short_ratio ( float, 默认为无。 ) – 空头比率,例如 0.3 对应于 130/30。如果没有, 默认为输入权重。
Raises:
- TypeError - 如果
weights
不是一个字典 - TypeError - 如果
latest_prices
不是一个 series - ValueError - 如果
short_ratio < 0
用于计算和打印离散化之间的 RMSE 误差的实用函数 权重和连续权重。使用 RMSE 代替 MAE 因为我们 想要惩罚大的变化。
Parameters: verbose ( bool ) – 打印权重差异?
Returns: 均方根误差
Return type: float
删除零头寸的效用函数(即没有购买股票)
将连续权重转换为离散投资组合分配 使用贪心迭代方法。
Parameters:
- reinvest ( bool, 默认为 False ) – 是否将做空所得现金进行再投资
- verbose ( bool, 默认为 False ) – 打印错误分析?
Returns: 应购买的每个股票的股票数量,以及剩余资金金额。
Return type: (dict, float)
lp_portfolio(reinvest=False, verbose=False, solver='ECOS_BB')
[来源] ¶
将连续权重转换为离散投资组合分配 使用整数规划。
Parameters:
- reinvest ( bool, 默认为 False ) – 是否将做空所得现金进行再投资
- verbose ( bool ) – 打印错误分析?
- solver ( str, 默认为“ECOS_BB” ) – 要使用的 CVXPY 求解器(必须支持混合整数程序)
Returns: 应购买的每个股票的股票数量以及剩余资金金额。
Return type: (dict, float)