离散时间下的最优执行策略:单资产情形
好,咱们今天来聊聊离散时间下的最优执行策略。说实话,这个模型是我个人在实际交易系统里用得最多的一个。为什么?因为它既保留了数学上的严谨性,又足够简单,能直接落地到代码里。
先说说背景。你想想看,我们做交易执行,本质上是在跟市场博弈。你下单太急,市场冲击成本高;你下单太慢,又面临价格波动的风险。这个平衡怎么找?Almgren-Chriss模型就是干这个的。
问题设定
我们考虑一个简单场景:你手里有 X 股 股票要卖出,需要在 T 个时间步 内完成。每个时间步的长度是 τ(比如1分钟或1小时)。
关键假设就两条:
- 单资产:只操作一只股票,不考虑组合效应
- 无风险资产:现金的利率为0,不考虑资金成本
嗯,这里要注意。无风险资产假设其实是个简化。我在实际项目中遇到过,如果持仓周期很长(比如几天),利率的影响就不能忽略。但短期交易(日内)这么假设完全没问题。
价格动态与成本模型
我们先定义几个变量。设第 k 个时间步的股票价格为 Sk,你在这个时间步的交易量为 vk(正数表示卖出)。
价格变化由两部分组成:
- 随机波动:σ√τ εk,其中 εk 是标准正态随机变量
- 市场冲击:包括瞬时冲击和永久冲击
具体来说,价格动态方程是:
S_{k+1} = S_k + σ√τ ε_k - γ v_k
这里的 γ 是永久冲击系数。你卖得越多,价格被压得越低,而且这个影响是永久性的。
另外还有瞬时冲击,它只影响你当前这笔交易的成交价格:
实际成交价 = S_k - η v_k
η 是瞬时冲击系数。说白了,你下单太急,市场深度不够,就得吃更高的滑点。
目标函数:风险与成本的权衡
我们的目标是什么?不是单纯追求最低成本,而是要在 执行成本 和 风险 之间找个平衡。
总成本包括:
- 永久冲击成本:γ Σ vk(这部分是不可避免的)
- 瞬时冲击成本:η Σ vk²(这部分跟交易速度有关)
- 风险成本:价格波动带来的不确定性
目标函数写成数学形式:
min E[ Σ (η v_k² + γ v_k S_k) + λ Σ (x_k² σ² τ) ]
其中 xk 是第 k 步开始时的持仓量,λ 是风险厌恶系数。λ 越大,你越倾向于早点卖完,减少风险暴露。
动态规划求解
好,问题定义清楚了,怎么求解?动态规划是标准做法。
我们定义价值函数 Vk(x) 为:在时间步 k,持有 x 股股票时,从当前到结束的最小期望成本。
贝尔曼方程长这样:
V_k(x) = min_v [ η v² + γ v S + λ x² σ² τ + E[ V_{k+1}(x - v) ] ]
边界条件是 VT(x) = 0,因为到时间结束时,持仓必须为0。
这个方程怎么解?我个人的习惯是,先猜解的形式,再验证。从边界条件往回推,你会发现价值函数是 x 的二次型:
V_k(x) = A_k x² + B_k x + C_k
代入贝尔曼方程,经过一番代数运算(这里我省略了,代码里会展示),可以得到递推关系:
A_k = A_{k+1} - (A_{k+1}² τ) / (η + A_{k+1} τ)
B_k = B_{k+1} - (A_{k+1} B_{k+1} τ) / (η + A_{k+1} τ)
C_k = C_{k+1} + (B_{k+1}² τ) / (4(η + A_{k+1} τ)) + λ σ² τ x²
最优交易速度的闭式解
有了价值函数,最优交易速度 vk* 可以直接求导得到:
v_k* = (A_{k+1} x_k + B_{k+1}/2) τ / (η + A_{k+1} τ)
这个公式看着有点复杂,但它的含义很直观:
- 分子里的 Ak+1 xk 代表「未来风险的折现」
- 分母里的 η 是瞬时冲击成本
- 整个式子告诉你:当前持仓越多,未来风险越大,就应该卖得越快
更妙的是,当 T 很大时,Ak 会收敛到一个常数:
A = (λ σ² τ) / (1 + √(1 + 4 λ σ² τ / η))
这时候最优策略就变成了一个简单的线性函数:
v_k* = (A / (η + A τ)) x_k
说白了,就是按固定比例减持。这个比例取决于风险厌恶、波动率和冲击成本。
Python实现示例
下面给个简单的实现,方便你理解整个流程:
import numpy as np
def almgren_chriss_optimal(T, X, sigma, tau, eta, lam):
"""
计算Almgren-Chriss最优执行策略
参数:
T: 时间步数
X: 初始持仓
sigma: 波动率
tau: 时间步长
eta: 瞬时冲击系数
lam: 风险厌恶系数
"""
# 从后往前递推
A = np.zeros(T+1)
B = np.zeros(T+1)
v = np.zeros(T)
x = np.zeros(T+1)
x[0] = X
# 边界条件
A[T] = 0
B[T] = 0
# 递推计算A和B
for k in range(T-1, -1, -1):
A[k] = A[k+1] - (A[k+1]**2 * tau) / (eta + A[k+1] * tau)
B[k] = B[k+1] - (A[k+1] * B[k+1] * tau) / (eta + A[k+1] * tau)
# 计算最优交易量
for k in range(T):
v[k] = (A[k+1] * x[k] + B[k+1]/2) * tau / (eta + A[k+1] * tau)
x[k+1] = x[k] - v[k]
return v, x
# 示例参数
T = 10
X = 10000
sigma = 0.02
tau = 1/252 # 日频
eta = 0.001
lam = 0.1
v_opt, x_opt = almgren_chriss_optimal(T, X, sigma, tau, eta, lam)
print("最优交易量:", v_opt)
print("持仓变化:", x_opt)
核心逻辑流程图
下面这张图帮你梳理整个求解过程:
关键参数的影响
最后,我用一个表格总结一下各个参数对策略的影响:
| 参数 | 增大时的影响 | 实际含义 |
|---|---|---|
| λ(风险厌恶) | 前期卖出更多,持仓下降更快 | 你更担心价格波动,宁愿多付冲击成本 |
| η(瞬时冲击) | 交易更均匀,避免集中下单 | 市场深度不足,大单会严重推高成本 |
| σ(波动率) | 类似λ,加速减持 | 市场波动大,持仓风险高 |
| T(时间步数) | 每步交易量减少,执行更分散 | 时间充裕,可以慢慢卖 |
嗯,到这里离散时间下的最优执行策略就讲完了。这个模型虽然简单,但它是很多量化交易系统的基础。我个人建议你先把这段代码跑通,然后试着调调参数,看看策略怎么变化。实践出真知嘛。