
2.4 线性最优化
假设套利定价理论模型和资本资产定价模型都是线性的,利用Python的回归分析求得资产期望价值。
随着投资组合资产数量增加,限制条件也会增加,投资经理会在此限制下达到投资者的目标。
线性最优化通过求解目标函数最小值或最大值解决投资组合分配问题。这些投资目标通常有一定限制条件,例如,不许卖空、限制投资证券数量等。
但Python没有支持此方法的单一官方软件包,可以借助开源线性规划库——Pulp来解决这个线性规划问题。
2.4.1 安装Pulp
你可以访问https://github.com/coin-or/pulp
安装Pulp,这个网站的综合文档列表中有最优化问题的相关介绍。
你也可以使用pip
命令来安装这个包[1]:

2.4.2 一个用线性规划求最大值的实例
假设我们考虑投资两种证券X和Y。若投资X证券的数量为x,投资Y证券的数量为y,试求3x + 2y的最大值。限制条件如下:
1)投资2倍的X证券数量与投资Y证券数量之和不超过100。
2)投资X证券数量与投资Y证券数量之和不超过80。
3)投资X证券的数量不超过40。
4)不许卖空(short selling)。
该最大化问题的数学表示如下:
最大化:f(x, y) = 3x + 2y
限制条件:
2x + y≤100
x + y≤80
x≤40
x≥0, y≥0
绘制函数图,如图2-4所示,阴影区域代表该问题可行域。

图 2-4
该问题可在Python的pulp
包中通过如下代码表示:

LpVariable
函数声明一个要求解的变量。LpProblem
函数通过问题的一段文本描述和最优化的类型来初始化问题,本例使用求最大值的最优化方法。代码中“+=
”允许加入任意数量的限制条件及其描述文本。最后,调用.solve()
函数执行线性优化,通过.variables()
函数输出每个变量的最优解。
运行代码输出结果如下:

满足限制条件下,当x等于20,y等于60时,3x + 2y取得最大值180。
2.4.3 线性规划的结果
线性优化通常有如下三个结果:
1)线性规划问题的局部最优解是最接近目标函数的最优解,虽然不是全局最优解(global optimal solution),但优于其他所有可行解。
2)若找不到最优解,则线性规划无可行解(infeasible)。
3)若最优解无界或有无限个,则线性规划无有界解(unbounded)。
2.4.4 整数规划
前述求最大值的线性规划问题,变量可以是连续值或分数。但在无法使用分数时该如何处理?这类变量被限制为整数的问题称作整数线性规划(linear integer programming)问题。整数规划的一种特殊情况是二进制的0或1变量。二进制变量对处理多项选择的决策模型非常有帮助。
整数规划模型经常用于实际问题建模。采用线性或二元方法解决非线性问题时,往往需要“艺术处理”而非“科学方法”。
1. 使用整数规划求解最小值的例子
假设我们可以从三位经纪人手中购买150份特定外国证券的场外合同。经纪人X的报价为每份合同500美元,外加4 000美元手续费。经纪人Y的报价为每份合同450美元,外加2 000美元手续费。经纪人Z的报价为每份合同450美元,外加6 000美元手续费。另外经纪人X最多出售100份合同,经纪人Y最多出售90份合同,经纪人Z最多出售70份合同,且每位经纪人都是30份合同起售。请计算购买这150份合同所需最低成本为多少。
利用pulp
包设置下列变量:

dealers
变量包含字典的标识符,字典的标识符稍后用于进行列表与字典的引用。variable_costs
和fixed_costs
变量为字典类型,包含各自经纪人所需的合约成本和手续费。Pulp求解器可求解LpVariable
函数定义的quantities
和is_orders
变量的值。dicts
函数使Pulp将赋值变量作为字典对象,将dealers
变量作为字典对象的引用。注意quantities
变量的下界为0,表示不允许卖空。is_orders
值为二进制对象,表示我们是否与某位经纪人交易。
这个整数规划问题的模型可由以下方程式直观地表述:

其中

其中,variable costi为每份合同的变动成本,quantityi为合同的数量,fixed costi为固定成本。如果购买合同i,则IsOrderi = 1;如果不购买合同i,则IsOrderi = 0。
上述方程用二进制变量IsOrderi表示最小化总成本,从而决定与哪个经销商合作。
让我们用Python实现这个模型:

运行求解器会发生什么?检查出来:

结果,当我们对quantities
和is_order
这两个未知变量进行乘法计算时,会执行非线性规划。这就是执行整数规划时遇到的陷阱。那么我们该如何解决这个问题呢?如下一节所示,我们将使用二进制变量。
2. 二进制条件下的整数规划
制定最小化规划的另一种方法是将所有未知变量以线性方式递增:

与前述方程相比,我们得到的固定费用相同,但变量quantityi位于等式第一项,所以它将作为IsOrderi的函数求解。本例限制条件如下:
isOrderi×30≤quantityx≤isOrderi×100
isOrderi×30≤quantityy≤isOrderi×90
isOrderi×30≤quantityz≤isOrderi×70
用Python运行此模型:

运行求解器会发生什么呢?让我们来看一下结果:

结果显示,满足所有限制条件时,我们从经纪人Y处购买90份合同并从经纪人Z处购买60份合同,花费的成本最低为66 500美元。
综上所述,整数规划模型在决策中发挥作用需要精心设计模型,以获得准确结果。
[1]建议使用此方法,大多数Python库用pip命令安装是最方便的。——译者注