量化交易中文教材

第 01 章 优化问题与建模

学习目标

读完本章,你应当能够:

  1. 把一个实际决策问题拆成目标、变量、约束三要素,并写成标准形式 \(\min f(x)\) s.t. \(c_i(x)=0,\ c_i(x)\ge 0\)。
  2. 按连续/离散、有约束/无约束、局部/全局、确定/随机、线性/非线性几个维度给优化问题分类,并知道每一类大致该找什么工具。
  3. 准确说出凸集、凸函数、凹函数、凸规划的定义,理解"凸问题的局部解就是全局解"为什么是实务中最重要的一条性质。
  4. 用稳健性、效率、精确性三条标准评价一个优化算法,理解它们之间的权衡。
  5. 能把均值–方差组合优化写成标准形式,判断它是凸规划,并看清"先解连续问题再取整"在整手约束下会出什么问题。

读前导读

这一章在解决什么问题

先从你熟悉的场景说起。在 CFA 课程或工作里,你多半用过 Excel Solver 做均值–方差优化:在一张表里放好预期收益和协方差矩阵,把"权重"那几格设为可变单元格,把"组合效用"或"组合方差"那一格设为目标单元格,再在"约束"框里加上"权重和 = 1""每个权重 ≥ 0",选好"GRG 非线性",点"求解"。几秒钟后权重就填好了。

这一册要讲的,就是你点下"求解"之后 Solver 在背后做了什么。可变单元格就是本章说的变量,目标单元格就是目标,约束框里那几行就是约束——这三样东西合起来叫"建模"。Solver 拿到模型后,从你表里现有的数字(初始点)出发,反复做一件事:估计"往哪个方向改权重能让目标变好、改多少",然后改一点,再估计,再改,直到改不动为止。GRG 是"广义既约梯度法"的缩写,它用到的梯度、步长、约束处理,正是本册第 2–18 章的内容。

本章本身不讲算法,只做三件准备工作。第一,把问题写成统一的"标准形式",就像把各种债券的现金流都写成"贴现因子乘现金流再求和"一样,统一了写法,后面的理论才能通用。第二,给问题分类,因为不同类型的问题要用不同的求解器(Solver 里"单纯形 LP""GRG 非线性""演化"三个选项,就是按问题类型分的)。第三,引出凸性:它决定了 Solver 报告的"找到一个解"到底是不是真正的最优解。你可能遇到过 Solver 换个初始值就给出不同答案的情况,那就是问题不凸、只找到了局部解。均值–方差问题是凸的,所以你过去用 Solver 得到的答案是可信的;但加上"最多持有 10 只股票"之类的约束,情况就变了。

需要先想起来的数学

  • 向量与 \(\mathbb{R}^n\):\(x\in\mathbb{R}^n\) 读作"\(x\) 是一个由 \(n\) 个实数排成的列向量",例如 8 只股票的权重 \(w=(w_1,\dots,w_8)^T\)。\(w^T\Sigma w\) 是"行向量 × 矩阵 × 列向量",结果是一个数,就是你在 CFA 里用 \(\sum_i\sum_j w_iw_j\sigma_{ij}\) 算的组合方差。见 第 00 册第 06 章 线性代数速成。
  • 集合记号:\(\in\) 表示"属于",\(\subseteq\) 表示"是……的子集",\(\emptyset\) 是空集,\(\forall\) 读作"对所有的",\(\mathbb{Z}\) 是整数集。见 第 00 册第 08 章 读懂数学证明与符号。
  • 二阶导数与凸性(一元):\(f''(x)\ge 0\) 表示斜率在增加,图像"向上弯",像碗。例如 \(f(x)=x^2\),\(f''=2>0\),是凸的。你熟悉的凸度(convexity)就是价格对收益率的二阶导数为正,名字同源。见 第 00 册第 02 章 导数与泰勒展开。
  • 梯度与 Hessian(多元):多元函数对每个变量分别求导,排成向量叫梯度 \(\nabla f\);二阶偏导排成矩阵叫 Hessian \(\nabla^2 f\)。一元的"\(f''\ge0\) 则凸"推广到多元,就是"Hessian 半正定则凸"。见 第 00 册第 05 章 多元微积分与优化。
  • 半正定矩阵:对称矩阵 \(A\) 满足"对任意向量 \(v\),\(v^TAv\ge 0\)"。协方差矩阵天然半正定,因为 \(v^T\Sigma v\) 是某个组合的方差,方差不会是负数。见第 00 册第 06 章。

怎么读这一章

1.2(三要素与标准形式)和 1.5(凸性)是核心,必须读懂,后面每一章都会用到。1.3 的分类和 1.4 的算法三性质读一遍、知道有哪些类别即可。1.6 的量化实战建议认真看输出和解读,它直接回答了"Solver 算出 0.39 手怎么办"这个实盘问题;代码第一次可以只看注释。练习 2、4、5 最能检验你是否真懂了凸性。


1.1 为什么要学数值优化

先说结论:量化交易里几乎每一个"求最好"的步骤,底层都是一个数值优化问题。估计一个 GARCH 模型是在最大化似然函数;拟合收益率曲线是在最小化残差平方和;构建组合是在风险约束下最大化期望收益;把大单拆成小单执行是在冲击成本与时间风险之间求最优权衡;训练一个神经网络因子模型是在最小化损失函数。会调用 scipy.optimize.minimize 不难,难的是在它报 "line search failed"、迭代几千步不收敛、或者给出一个明显荒谬的解时,知道问题出在哪里。这正是本册要解决的问题。

原书(Nocedal & Wright《Numerical Optimization》第 1 版,1999)专讲连续优化(continuous optimization):变量取实数值、函数光滑的问题。作者在前言中列出的典型应用里,就有"在可接受的风险水平下最大化期望收益的投资组合设计"。全书的写法是:先用不严格的讨论和图形建立直觉,再正式给出算法,最后严格陈述并(多数情况下)证明理论结果——证明可以跳读,但结论必须掌握。

原书第 1 版共 18 章:第 2–9 章是无约束优化(基础、线搜索、信赖域、共轭梯度、实用牛顿法、导数计算、拟牛顿法、大规模拟牛顿),第 10–11 章是非线性最小二乘与非线性方程,第 12 章是约束优化理论,第 13–14 章是线性规划(单纯形法与内点法),第 15–18 章是非线性约束优化(二次规划、罚函数与增广拉格朗日、序列二次规划),附录 A 汇总了所需的分析与线性代数背景。原书不涉及网络优化、整数规划、随机规划、非光滑优化和全局优化——这几类问题在量化中也会遇到,本章会说明它们与本书内容的关系。

本章对应原书第 1 章,内容不难,但"建模"和"凸性"这两个概念会贯穿全册。


1.2 优化的三要素与建模

优化问题都由三部分组成:

  • 目标(objective):一个可以用单个数字衡量的性能指标,例如利润、时间、能量、组合的风险调整收益。
  • 变量(variables,也叫 unknowns):目标所依赖的、我们可以选择的量,例如各资产的持仓权重。
  • 约束(constraints):变量必须满足的限制,例如权重和为 1、不允许卖空、单只股票不超过 10%。

找出这三者的过程叫做建模(modeling)。原书强调,建模往往是整个过程中最重要的一步:模型太简单,得不到对实际问题有用的洞见;模型太复杂,又可能根本解不出来。量化研究里这种权衡随处可见——忽略交易成本的组合优化很好解,但结果换手率高得离谱;加入非凸的市场冲击成本更真实,但求解器可能只能给出局部解。

建好模型之后,还要回答两个问题:

  1. 用什么算法? 不存在通用的优化算法,算法要针对问题类型挑选。选得好,几秒钟解完;选得不好,可能永远解不出来。
  2. 怎么知道解对了? 这要靠最优性条件(optimality conditions)。它既用来检验当前点是不是解,没满足时还能提示如何改进(第 2 章、原书第 12 章)。此外还可以做敏感性分析(sensitivity analysis),看解对模型参数和数据的变化有多敏感——对量化来说,这一步往往比求出解本身更重要,因为输入的期望收益和协方差都是带噪声的估计。

1.2.1 标准形式

记 \(x\in\mathbb{R}^n\) 为变量向量,\(f\) 为目标函数,\(c_i\) 为约束函数。原书采用的标准形式是

\[ \min_{x\in\mathbb{R}^n} f(x)\quad \text{s.t.}\quad \begin{cases} c_i(x)=0, & i\in\mathcal{E},\\ c_i(x)\ge 0, & i\in\mathcal{I}, \end{cases} \tag{1.1} \]

其中 \(\mathcal{E}\)、\(\mathcal{I}\) 分别是等式约束和不等式约束的指标集。注意本书约定不等式写成 "\(\ge 0\)" 的形式,这和某些教材(以及 CVXPY 等软件)用 "\(\le 0\)" 的习惯相反,读文献时要留心。

白话解释:(1.1) 逐个符号读一遍。\(\min_{x\in\mathbb{R}^n} f(x)\):在所有 \(n\) 维实向量 \(x\) 里找让 \(f(x)\) 最小的那个;s.t. 是 subject to("满足")的缩写。\(\mathcal{E}\) 和 \(\mathcal{I}\) 只是"编号清单":比如有 3 个约束,第 1 个是等式、第 2、3 个是不等式,就写 \(\mathcal{E}=\{1\}\),\(\mathcal{I}=\{2,3\}\)。这样写的好处是所有约束都变成"某个函数 \(=0\)"或"某个函数 \(\ge 0\)"两种格式。 拿 Excel Solver 对照:\(x\) 是可变单元格,\(f(x)\) 是目标单元格,\(c_i(x)\) 是约束框里每一行"左边减右边"的那个算式。例如约束"\(\sum_i w_i = 1\)"写成 \(c_1(w)=\sum_i w_i-1=0\);约束"\(w_3\le 0.1\)"写成 \(c_2(w)=0.1-w_3\ge 0\)。

把实际问题写成 (1.1) 时常需要几个小变换:

  • 最大化 \(f\) 等价于最小化 \(-f\)。
  • "\(\le\)" 约束两边乘 \(-1\) 变成 "\(\ge\)"。
  • 对变量重新编号,把所有决策量排成一个向量。

好的优化软件会对用户透明地完成这些转换。

例 1.1(原书例 (1.2)) 考虑

\[\min\ (x_1-2)^2+(x_2-1)^2\quad\text{s.t.}\quad x_1^2-x_2\le 0,\quad x_1+x_2\le 2.\]

写成标准形式:\(c_1(x)=-x_1^2+x_2\ge 0\),\(c_2(x)=-x_1-x_2+2\ge 0\),于是 \(\mathcal{I}=\{1,2\}\),\(\mathcal{E}=\emptyset\)。原书图 1.1 画出了目标函数的等高线(contours,即 \(f\) 取常值的点集)、可行域(feasible region,满足全部约束的点集)以及最优点 \(x^*\):最优点落在可行域边界上,恰好是某条等高线与可行域相切的位置。这个几何图像——"最优点是等高线与约束边界相切之处"——就是后面拉格朗日乘子理论的直观来源。

金融直觉:这个"相切"你在 CFA 里见过。画有效前沿时,最优风险组合是资本配置线与有效前沿相切的点;选最终组合时,是投资者的无差异曲线与资本配置线相切的点。无差异曲线就是效用函数的等高线,资本配置线就是可行域的边界。例 1.1 的图是同一件事的一般版本:在可行域里不断把等高线往"更好"的方向推,推到最后一刻还碰着可行域的那一点,就是最优点。此时等高线和边界在这一点方向一致,这就是第 12 章拉格朗日条件"目标梯度与约束梯度平行"的几何含义。

1.2.2 例:运输问题

例 1.2(原书运输问题) 一家化工公司有 2 个工厂 \(F_1,F_2\) 和 12 个零售店 \(R_1,\dots,R_{12}\)。工厂 \(F_i\) 每周产能 \(a_i\) 吨,零售店 \(R_j\) 每周需求 \(b_j\) 吨,从 \(F_i\) 运到 \(R_j\) 每吨运费 \(c_{ij}\)。设 \(x_{ij}\) 为从 \(F_i\) 运往 \(R_j\) 的吨数,问题是

\[ \min \sum_{i,j} c_{ij}x_{ij}\quad\text{s.t.}\quad \sum_{j=1}^{12}x_{ij}\le a_i\ (i=1,2),\quad \sum_{i=1}^{2}x_{ij}\ge b_j\ (j=1,\dots,12),\quad x_{ij}\ge 0. \]

目标和约束都是线性函数,这类问题叫线性规划(linear programming, LP)。原书提醒,真实模型还应包括生产成本和库存成本。量化中的 LP 也很多:最小化 CVaR 的组合优化(Rockafellar–Uryasev 表述)、带 \(\ell_1\) 换手约束的组合调整、指数复制中最小化绝对跟踪误差,都可以写成 LP。线性规划的解法在原书第 13–14 章。


1.3 优化问题的分类

1.3.1 连续优化与离散优化

如果运输问题里工厂生产的是拖拉机,\(x_{ij}\) 就必须是整数,要加上 \(x_{ij}\in\mathbb{Z}\),问题变成整数规划(integer programming)。同时含连续变量和整数变量的叫混合整数规划(mixed integer programming)。

  • 离散优化(discrete optimization)的解取自有限(或可数)集合;连续优化的解取自不可数集合,通常是实向量空间。
  • 连续问题通常更容易。原因是光滑性:在某一点算出的函数值和导数,可以用来推断它附近点的行为。离散问题中"挨得很近"的两个点函数值可能差别很大,而可行解又多到无法穷举。
  • 连续优化算法在离散优化中同样重要:求解整数规划的分支定界(branch-and-bound)法,大部分时间都花在求解线性规划松弛(relaxation,即去掉整数约束后的问题)上。

原书特别指出一个常见误区:先忽略整数约束求出实数解,再四舍五入,并不能保证得到接近最优的整数解。这在交易中非常现实:A 股以 100 股为一手、持仓股票数量有上限(基数约束)、期货合约只能整张交易。资金量小或股价很高时,四舍五入会严重偏离最优,本章的量化实战会给出具体数字。

1.3.2 有约束与无约束

可以按目标与约束的性质(线性、非线性、凸)、变量多少(大规模/小规模)、光滑性(可微/不可微)给问题分类,但最重要的区分是有没有约束,原书正是据此分成前后两大部分。

  • 无约束问题有时直接来自应用,例如极大似然估计(参数可以先做变换使其不受限,如用 \(\log\sigma\) 代替 \(\sigma>0\))。
  • 有时自然约束可以安全忽略,因为它们不影响最优解。
  • 约束问题也可以改写为无约束问题:用罚项(penalization terms)代替约束,这是原书第 17 章的主题。

约束有三种常见形式:简单界约束(如 \(0\le x_1\le 100\))、一般线性约束(如 \(\sum_i x_i\le 1\)——这正是组合权重的预算约束)、非线性不等式(如组合波动率 \(\sqrt{w^T\Sigma w}\le \sigma_{\max}\))。目标与约束全是线性的叫线性规划;至少有一个是非线性的叫非线性规划(nonlinear programming)。

1.3.3 全局优化与局部优化

最快的算法一般只能找到局部解(local solution):在它的某个邻域内目标值最小的可行点。它未必是全局解(global solution)——整个可行域上目标值最小的点。全局解既难识别也难找到。

一个极其重要的特例是凸规划(convex programming):它的每个局部解都是全局解。线性规划是凸规划;标准的均值–方差组合优化也是凸规划。一般非线性问题则可能有许多不是全局解的局部解。原书只顺带讨论全局优化;许多全局优化算法本身就是通过求解一系列局部优化问题来实现的(例如多起点法)。

1.3.4 随机优化与确定性优化

模型可能依赖建模时未知的量:运输问题里的需求 \(b_j\),或者原书特别提到的——金融规划模型依赖未来利率走势和经济表现。建模者可以给出若干情景(scenarios)并赋予概率,随机优化(stochastic optimization)利用这些不确定性信息去优化模型的期望表现。

原书只讨论确定性优化(deterministic optimization),即模型完全给定。但许多随机优化算法正是通过求解一组确定性子问题来实现的。量化中基于情景的组合优化、CVaR 优化、资产负债管理都属于随机规划,它们的子问题多半就是本书讲的 LP 或 QP。


1.4 优化算法应具备的性质

优化算法都是迭代的:从一个初始猜测出发,生成一列逐步改进的估计,直到满足停止条件。不同算法的区别在于"怎样从当前点走到下一点"——用不用函数值、一阶导数、二阶导数,是否累积历史信息。原书提出好算法应具备三个性质:

  • 稳健性(robustness):在它所针对的那类问题上,从任何合理的初始点出发都能表现良好。
  • 效率(efficiency):不需要过多的计算时间和存储。
  • 精确性(accuracy):能精确地找到解,对数据误差和计算机舍入误差不过分敏感。

这三者经常冲突。收敛快的方法(如牛顿法)在大规模问题上可能需要存储过多(\(n\times n\) 的 Hessian 矩阵);最稳健的方法可能最慢。收敛速度与存储、稳健性与速度之间的权衡,是贯穿本册的主线。例如第 3 章会看到,最速下降法几乎总能保证梯度趋于零,但在病态问题上慢得无法接受;牛顿法在解附近极快,但离解较远时可能连下降方向都不是。


1.5 凸性

凸性是本章最重要的数学概念。

定义(凸集) 集合 \(S\subseteq\mathbb{R}^n\) 称为凸集(convex set),如果其中任意两点的连线段都在 \(S\) 内:

\[\forall x,y\in S,\ \forall\alpha\in[0,1]:\quad \alpha x+(1-\alpha)y\in S.\]

定义(凸函数) 函数 \(f\) 称为凸函数(convex function),如果其定义域是凸集,且

\[f(\alpha x+(1-\alpha)y)\le \alpha f(x)+(1-\alpha)f(y),\quad \forall x,y,\ \forall \alpha\in[0,1].\]

几何意义:函数图像位于连接 \((x,f(x))\) 与 \((y,f(y))\) 的弦的下方。光滑凸函数在一维、二维时呈"碗状",等高线围成凸集。原书图 1.3 的例子是 \(f(x)=(x_1-6)^2+\tfrac{1}{25}(x_2-4.5)^4\)。若 \(-f\) 是凸函数,则称 \(f\) 为凹函数(concave function)。

白话解释:两个定义里的 \(\alpha x+(1-\alpha)y\) 就是"按 \(\alpha\) 和 \(1-\alpha\) 的比例把 \(x\) 和 \(y\) 混合"。\(\alpha\) 从 1 走到 0,这个点就从 \(x\) 沿直线走到 \(y\),所以它代表"\(x\) 与 \(y\) 连线上的任意一点"。 用组合来理解最直观:\(x\) 和 \(y\) 是两个组合的权重向量,\(\alpha x+(1-\alpha)y\) 就是"把 \(\alpha\) 的资金按 \(x\) 配、\(1-\alpha\) 按 \(y\) 配"得到的混合组合。凸集说的是:两个可行组合的任何混合仍然可行(例如两个都满足"权重和为 1、不卖空"的组合,混合后仍满足)。凸函数说的是:混合组合的目标值不超过两者目标值的同比例加权平均。组合标准差就是凸函数——这正是分散化:两个组合混合后的波动率 \(\le\) 两者波动率的加权平均,只有相关系数为 1 时才取等号。

为什么凸性重要? 无约束优化算法一般只能保证收敛到驻点(stationary point,梯度为零的点),而驻点可能是极小点、极大点或鞍点。但如果 \(f\) 是凸的,驻点就是全局极小点(第 2 章定理 2.5 给出证明)。

定义(凸规划) 问题 (1.1) 称为凸规划,如果:

  1. 目标函数 \(f\) 是凸函数;
  2. 等式约束函数 \(c_i,\ i\in\mathcal{E}\) 是线性(仿射)函数;
  3. 不等式约束函数 \(c_i,\ i\in\mathcal{I}\) 是凹函数。

第 3 条初看奇怪,原因在于本书约定写成 \(c_i(x)\ge 0\):凹函数的上水平集 \(\{x: c_i(x)\ge 0\}\) 是凸集,于是可行域是一族凸集的交,仍是凸集。等式约束必须是线性的,因为非线性等式约束 \(c(x)=0\) 一般定义的是一个弯曲的曲面,不是凸集。

推导拆解:为什么"\(c\) 凹"能推出"\(\{x: c(x)\ge 0\}\) 是凸集"?只需三步。 第一步,任取集合里两点 \(x,y\),即 \(c(x)\ge 0\),\(c(y)\ge 0\)。 第二步,凹函数的定义是凸函数不等式反过来:\(c(\alpha x+(1-\alpha)y)\ge \alpha c(x)+(1-\alpha)c(y)\)。 第三步,右边是两个非负数的非负加权和,所以 \(\ge 0\)。于是 \(c(\alpha x+(1-\alpha)y)\ge 0\),混合点也在集合里。 再用"多个凸集的交仍是凸集"(练习 3),就得到整个可行域是凸集。换成 "\(\le 0\)" 的软件约定时,要求就变成"\(c\) 凸",本质一样。

判断凸性的实用方法 对二阶可微函数,\(f\) 凸当且仅当其 Hessian 在定义域内处处半正定(这一事实的线性代数背景见第 01 册第 07a 章「正定矩阵的刻画、平方根与 Cholesky 分解」)。例如二次函数 \(f(w)=\frac{\gamma}{2}w^T\Sigma w-\mu^Tw\) 的 Hessian 是 \(\gamma\Sigma\),协方差矩阵 \(\Sigma\) 半正定,所以它是凸函数。约束方面:\(\sum_i w_i=1\) 是线性等式,\(w_i\ge 0\)、\(w_i\le u_i\) 是线性不等式(线性函数既凸又凹),而波动率约束 \(\sigma_{\max}-\sqrt{w^T\Sigma w}\ge 0\) 中 \(\sqrt{w^T\Sigma w}=\|\Sigma^{1/2}w\|\) 是凸函数,取负后为凹,符合凸规划的要求。

推导拆解:\(f(w)=\frac{\gamma}{2}w^T\Sigma w-\mu^Tw\) 的 Hessian 为什么是 \(\gamma\Sigma\)? 先求梯度。\(w^T\Sigma w=\sum_i\sum_j\sigma_{ij}w_iw_j\),对 \(w_k\) 求偏导,含 \(w_k\) 的项有 \(j=k\) 和 \(i=k\) 两组,得 \(\sum_j\sigma_{kj}w_j+\sum_i\sigma_{ik}w_i=2(\Sigma w)_k\)(用了 \(\Sigma\) 对称)。所以 \(\nabla(w^T\Sigma w)=2\Sigma w\),\(\nabla f=\gamma\Sigma w-\mu\)。这和一元的 \((ax^2)'=2ax\) 完全对应。 再求一次导:\(\gamma\Sigma w\) 对 \(w\) 是线性的,导数就是系数矩阵 \(\gamma\Sigma\);\(\mu\) 是常数,导数为 0。所以 \(\nabla^2 f=\gamma\Sigma\)。 半正定的含义也很直观:对任意方向 \(v\),\(v^T(\gamma\Sigma)v=\gamma\cdot\text{Var}(v^Tr)\ge 0\),即沿任何方向调仓,目标函数都"向上弯"。

金融直觉:把 \(f\) 取负,\(-f=\mu^Tw-\frac{\gamma}{2}w^T\Sigma w\),这正是 CFA 里的效用公式 \(U=E(R)-\tfrac12 A\sigma^2\),\(\gamma\) 就是风险厌恶系数 \(A\)。最小化 \(f\) 等于最大化效用,也就是最大化"确定性等价收益"。下面这些在量化中常见的问题不是凸的,要警惕局部解:

  • 带基数约束(最多持有 \(K\) 只股票)或整手约束的组合问题——可行域是离散的;
  • 以夏普比率 \(\mu^Tw/\sqrt{w^T\Sigma w}\) 为目标且允许多空的问题(可以变换为凸问题,但直接优化时不凸);
  • 某些风险平价的表述(例如直接最小化 \(\sum_{i,j}(w_i(\Sigma w)_i-w_j(\Sigma w)_j)^2\));
  • 神经网络因子模型的训练、带非线性冲击成本的执行优化。

白话解释:基数约束为什么破坏凸性?取两个可行组合:\(x\) 只持有股票 1–5,\(y\) 只持有股票 6–10,在"最多持有 5 只"的约束下两者都可行。但它们的 50/50 混合持有 10 只,不可行。连线上的点跑出了可行域,所以可行域不是凸集。 夏普比率的问题在于它是一个比值。分子线性、分母是凸函数,比值一般既不凸也不凹。"变换为凸问题"的常见做法是:固定 \(\mu^Tw=1\) 去最小化 \(w^T\Sigma w\),再把解按比例缩放回权重和为 1——在 \(\mu^Tw>0\) 可达的前提下,这样求出的就是切点组合(最大夏普组合)。


1.6 量化实战:把均值–方差组合写成标准形式

场景 一个 20 万元的账户在 8 只 A 股上做均值–方差配置。我们要:(1) 把问题写成标准形式 (1.1) 并验证它是凸规划;(2) 用 SciPy 求连续最优解;(3) 加上"100 股一手"的整手约束,检验原书"先解连续再取整不可靠"的警告。

设股票权重为 \(w\in\mathbb{R}^8\),剩余资金 \(1-\sum_i w_i\) 放现金(收益率 \(r_f\))。问题为

\[ \min_w\ \frac{\gamma}{2}w^T\Sigma w-\Big[\mu^Tw+r_f\big(1-\textstyle\sum_i w_i\big)\Big] \quad\text{s.t.}\quad 1-\textstyle\sum_i w_i\ge 0,\quad w_i\ge 0,\quad 0.3-w_i\ge 0. \]

目标的 Hessian 是 \(\gamma\Sigma\)(正定),约束全部线性,所以这是凸规划——任何局部算法找到的解都是全局最优。

import numpy as np
from scipy.optimize import minimize
from itertools import product

rng = np.random.default_rng(0)
n, T = 8, 750                                   # 8 只股票,750 个交易日的模拟日收益
F = rng.normal(0, 0.012, (T, 1))                # 市场因子
beta = rng.uniform(0.6, 1.4, n)
R = F @ beta[None, :] + rng.normal(0, 0.015, (T, n))
Sigma = np.cov(R.T) * 252                       # 年化协方差(样本估计)
mu = np.array([0.06, 0.08, 0.05, 0.09, 0.16, 0.07, 0.10, 0.06])  # 假设的年化预期收益
rf, gamma = 0.02, 3.0                           # 现金收益率、风险厌恶系数

# 1) 凸性检查:目标的 Hessian = gamma*Sigma 正定,约束全线性 => 凸规划
print("Sigma 特征值范围: [%.4f, %.4f]" % tuple(np.linalg.eigvalsh(Sigma)[[0, -1]]))

# 2) 标准形式 (1.1):股票权重 w;现金 1 - sum(w) >= 0;0 <= w_i <= 0.3
def f(w):
    return 0.5 * gamma * w @ Sigma @ w - (mu @ w + rf * (1 - w.sum()))
grad = lambda w: gamma * Sigma @ w - (mu - rf)
def solve(ub):
    cons = [{"type": "ineq", "fun": lambda w: 1.0 - w.sum()},
            {"type": "ineq", "fun": lambda w: w},
            {"type": "ineq", "fun": lambda w: ub - w}]
    r = minimize(f, np.full(n, 0.05), jac=grad, constraints=cons, method="SLSQP")
    return np.clip(r.x, 0, None)
w_star = solve(np.full(n, 0.30))
print("连续最优权重:", np.round(w_star, 3), "现金 %.3f  f* = %.5f" % (1 - w_star.sum(), f(w_star)))

# 3) 整手约束:资金 20 万元,A 股 100 股一手;第 5 只股票股价 1520 元,一手 15.2 万
C = 200_000
price = np.array([12.5, 38.0, 8.2, 165.0, 1520.0, 27.3, 64.0, 5.6])
lot_value = 100 * price
def report(name, lots):
    w = lots * lot_value / C
    ok = (w.sum() <= 1) and (w <= 0.30 + 1e-12).all()
    print("%-10s 手数 %s 权重和 %.3f 可行=%s  f = %.5f" % (name, lots.astype(int), w.sum(), ok, f(w)))

lots_cont = w_star * C / lot_value
print("连续解对应手数:", np.round(lots_cont, 2))
report("四舍五入", np.round(lots_cont))
# 第 5 只股票哪怕 1 手也占 76% 资金,违反 30% 上限,只能取 0 手。
# 正确做法:把这一事实作为约束重新求解连续问题,再取整
ub = np.full(n, 0.30); ub[4] = 0.0
w_re = solve(ub)
report("重优化后取整", np.floor(w_re * C / lot_value))

# 4) 在“重优化后取整”解的每只股票 ±2 手邻域内枚举(第 5 只固定 0 手),找可行整数解中的最优者
base = np.floor(w_re * C / lot_value)
idx = [i for i in range(n) if i != 4]
best, best_val = None, np.inf
for d in product(range(-2, 3), repeat=len(idx)):
    lots = base.copy(); lots[idx] += d
    if (lots < 0).any(): continue
    w = lots * lot_value / C
    if w.sum() > 1 or (w > 0.30).any(): continue
    v = f(w)
    if v < best_val: best, best_val = lots, v
report("邻域枚举", best)

运行输出:

Sigma 特征值范围: [0.0468, 0.3250]
连续最优权重: [0.    0.052 0.    0.059 0.3   0.    0.175 0.   ] 现金 0.414  f* = -0.05488
连续解对应手数: [0.   2.71 0.   0.71 0.39 0.   5.48 0.  ]
四舍五入       手数 [0 3 0 1 0 0 5 0] 权重和 0.299 可行=True  f = -0.03547
重优化后取整     手数 [1 6 0 1 0 0 7 0] 权重和 0.427 可行=True  f = -0.03802
邻域枚举       手数 [1 7 0 2 0 0 7 0] 权重和 0.528 可行=True  f = -0.03865

解读

  • 协方差矩阵最小特征值为正,目标严格凸,SLSQP 给出的连续解就是全局最优,目标值 \(-0.0549\)。
  • 连续解要求高价股(第 5 只)持有 0.39 手。四舍五入后它变成 0 手,其余股票也只是机械取整,目标值跌到 \(-0.0355\),损失了约 35%。原因是:高价股"消失"后,原来分给它的 30% 风险预算本应重新分配给其他股票,单纯取整完全没有做这件事。
  • 把"第 5 只股票只能为 0"作为约束重新求解连续问题再取整,目标值改善到 \(-0.0380\);在其邻域内枚举又能找到 \(-0.0387\) 的整数解。真正求解这类问题要用混合整数二次规划(MIQP)求解器,它的核心正是分支定界加上反复求解连续松弛——也就是本书讲的连续优化算法。

实务要点:资金量越小、股价越高、组合越集中,取整误差越大。实盘系统中常见的做法是"连续优化 → 取整 → 对剩余现金做一次小规模的贪心或整数修正",本例说明至少要在取整后检查约束并重新分配。


本章小结

优化 = 目标 + 变量 + 约束,建模的好坏常常比算法更决定成败。本书只处理连续、确定、(大多)光滑的问题,并以求局部解为主;整数、随机、非光滑、全局优化是相邻的领域,它们的算法大量调用连续优化作为子程序。凸性是最重要的结构性质:凸规划的局部解即全局解,因此判断问题是否为凸是动手求解前的第一步。好的算法要在稳健性、效率、精确性之间取得平衡。

概念 要点
标准形式 \(\min f(x)\),s.t. \(c_i(x)=0\ (i\in\mathcal{E})\),\(c_i(x)\ge 0\ (i\in\mathcal{I})\)
线性规划 LP 目标与约束全线性;凸规划的特例
非线性规划 目标或约束中至少一个非线性
整数/混合整数规划 部分变量取整数;"连续解取整"不保证接近最优
凸集 \(\alpha x+(1-\alpha)y\in S\),\(\alpha\in[0,1]\)
凸函数 \(f(\alpha x+(1-\alpha)y)\le\alpha f(x)+(1-\alpha)f(y)\);二阶可微时等价于 Hessian 半正定
凸规划 \(f\) 凸;等式约束线性;不等式约束 \(c_i\ge0\) 中 \(c_i\) 凹
凸性的回报 局部解 = 全局解;可微时驻点 = 全局极小点
算法三性质 稳健性、效率、精确性,三者常需权衡

练习

基础

  1. 把问题"\(\max\ x_1x_2\) s.t. \(x_1+2x_2\le 4\),\(x_1\ge 0\),\(x_2\ge 0\)"写成标准形式 (1.1),写出 \(\mathcal{E}\)、\(\mathcal{I}\) 和每个 \(c_i\)。 提示:目标取 \(-x_1x_2\);\(c_1=4-x_1-2x_2\),\(c_2=x_1\),\(c_3=x_2\),\(\mathcal{E}=\emptyset\)。
  2. 判断下列函数是否为凸函数:(a) \(f(x)=e^x\);(b) \(f(x)=x^3\)(在 \(\mathbb{R}\) 上);(c) \(f(w)=w^T\Sigma w\),\(\Sigma\) 为协方差矩阵;(d) \(f(x)=\|x\|_1\)。 提示:(a) 凸,\(f''>0\);(b) 不凸,\(x<0\) 时 \(f''<0\);(c) 凸,Hessian \(2\Sigma\) 半正定;(d) 凸(范数都是凸函数,由三角不等式证明),但不可微。
  3. 证明两个凸集的交仍是凸集。由此说明:由线性等式和凹函数不等式 \(c_i\ge 0\) 定义的可行域是凸集。
  4. 说明为什么非线性等式约束 \(x_1^2+x_2^2=1\) 定义的集合不是凸集。如果把它换成 \(x_1^2+x_2^2\le 1\) 呢? 提示:单位圆周上两点的中点不在圆周上;单位圆盘是凸集,对应 \(c(x)=1-x_1^2-x_2^2\ge0\),\(c\) 是凹函数。

进阶

  1. 均值–方差问题加上"组合年化波动率不超过 15%"的约束 \(\sqrt{w^T\Sigma w}\le 0.15\)。证明加约束后仍是凸规划。如果改为"组合波动率不低于 10%",还是凸规划吗? 提示:\(\|\Sigma^{1/2}w\|\) 是凸函数;"不低于"对应 \(\sqrt{w^T\Sigma w}-0.10\ge 0\),左边是凸函数而不是凹函数,可行域是一个凸集的补集,不是凸规划。
  2. 证明:若 \(f\) 是凸函数,则任意水平集 \(\{x: f(x)\le a\}\) 是凸集。反之不成立,请举一个水平集都是凸集但函数不凸的一维例子。 提示:反例 \(f(x)=\sqrt{|x|}\),水平集是区间,但函数不凸。
  3. 在本章量化实战中把资金改为 200 万元,重新运行,比较"四舍五入"与连续解的差距,并解释资金规模的影响。 提示:资金越大,每手占资金比例越小,取整误差越小;但高价股一手 15.2 万元仍占 7.6%,仍有可见误差。
  4. 指数复制问题:用 \(n\) 只股票复制一个指数,最小化跟踪误差的绝对值之和 \(\sum_t|r_t^Tw-r_t^{\text{idx}}|\)。说明如何引入辅助变量把它写成线性规划。 提示:令 \(u_t\ge r_t^Tw-r_t^{\text{idx}}\),\(u_t\ge -(r_t^Tw-r_t^{\text{idx}})\),最小化 \(\sum_t u_t\)。

原书推荐习题:原书第 1 章没有习题。


原书对照

本章内容 原书位置 PDF 页码
前言:全书目标、覆盖范围、未覆盖内容 Preface PDF p.7–10
全书目录 Contents PDF p.11–20
1.2 三要素与建模、标准形式、例 1.1 §1 引言,Mathematical Formulation,式 (1.1)(1.2),图 1.1 PDF p.22–24(原书 p.1–3)
1.2.2 运输问题 Example: A Transportation Problem,式 (1.3)(1.4) PDF p.25–26
1.3 分类:连续/离散、有/无约束、全局/局部、随机/确定 Continuous versus Discrete … Stochastic and Deterministic Optimization PDF p.25–28
1.4 算法的三个性质 Optimization Algorithms PDF p.28–29
1.5 凸性 Convexity,图 1.3 PDF p.29–30
历史注释("数学规划"一词的来历等) Notes and References PDF p.30

页码换算:原书正文页码约等于 PDF 页码减 21。