跳转至

后处理权重

作者: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\)

优化问题由下式给出:

\[ \begin{split}\begin{equation*} \begin{aligned} & \underset{x \in \mathbb{Z}^n}{\text{minimise}} & & r + \lVert wT - x \odot p \rVert_1 \\ & \text{subject to} & & r + x \cdot p = T\\ \end{aligned} \end{equation*}\end{split} \]

这很容易翻译成 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 - dict
    • latest_prices - pd.Series 或 dict
    • total_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

_allocation_rmse_error(verbose=True) [来源]

用于计算和打印离散化之间的 RMSE 误差的实用函数 权重和连续权重。使用 RMSE 代替 MAE 因为我们 想要惩罚大的变化。

Parameters: verbose ( bool ) – 打印权重差异?

Returns: 均方根误差

Return type: float

static _remove_zero_positions(allocation) [来源]

删除零头寸的效用函数(即没有购买股票)

greedy_portfolio(reinvest=False, verbose=False) [来源]

将连续权重转换为离散投资组合分配 使用贪心迭代方法。

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)



回到顶部