第十五章:冲击成本优化:凸优化方法、动态规划、强化学习入门

冲击成本优化,说白了就是解决一个核心矛盾:我想快点成交,但又不想多付钱

这就像你赶时间打车,但又不想被司机绕路。在量化交易里,这个矛盾更尖锐——你动用的资金越大,市场越容易察觉你的意图,冲击成本就越高。

我个人习惯把优化方法分成三个层次:凸优化(数学上最优雅)、动态规划(工程上最实用)、强化学习(未来最有潜力)。今天咱们一个一个聊。

15.1 凸优化:把问题变成“好解”的样子

凸优化为什么受欢迎?因为它有唯一的最优解,而且求解速度快。你想想看,如果一个问题有多个局部最优解,你很难保证找到的是最好的那个。凸优化就不一样了——只要你能把问题表述成凸形式,剩下的交给求解器就行。

冲击成本优化怎么变成凸问题?核心思路是:把交易成本建模成凸函数

举个例子,假设我们要在T个时间段内买入Q股股票。每个时间段的交易量是x_t,市场冲击成本是c(x_t)。如果c(x_t)是凸函数(比如二次函数),那么整个优化问题就是凸的。

# 凸优化求解冲击成本最小化
import cvxpy as cp
import numpy as np

# 参数设置
T = 10  # 交易时段数
Q = 100000  # 总交易量
sigma = 0.02  # 波动率
eta = 1e-6  # 冲击成本系数

# 决策变量:每个时段的交易量
x = cp.Variable(T)

# 目标函数:最小化冲击成本 + 风险惩罚
objective = cp.Minimize(
    cp.sum_squares(x) * eta +  # 冲击成本(凸函数)
    sigma * cp.sum(cp.square(cp.sum(x[:i+1]) - Q * (i+1)/T) for i in range(T))  # 跟踪误差
)

# 约束条件
constraints = [
    cp.sum(x) == Q,  # 必须完成交易
    x >= 0,  # 不能卖空
    x <= Q * 0.3  # 单时段交易量上限
]

# 求解
problem = cp.Problem(objective, constraints)
problem.solve()

print(f"最优交易计划: {x.value}")
print(f"最小冲击成本: {objective.value}")

关键点:凸优化的前提是你能把冲击成本函数写成凸形式。我在项目中遇到过用线性冲击成本模型的情况,结果优化出来的交易计划全是极端值——要么不交易,要么一次性全干完。后来改成二次冲击成本,结果就合理多了。

我的经验:实际中,冲击成本往往不是完美的凸函数。比如大单交易时,冲击成本会突然跳升。这时候可以用分段线性函数来近似,只要保证每段都是凸的就行。

15.2 动态规划:把大问题拆成小问题

动态规划的思路很朴素:你不需要一次性决定所有时段的交易量,而是每个时段根据当前状态做最优决策

为什么会这样?因为市场是动态变化的。你早上9:30的冲击成本模型,到了10:00可能就不准了。动态规划允许你边走边看,实时调整。

动态规划的核心是贝尔曼方程

V(s_t) = min_{a_t} [ c(s_t, a_t) + γ * E[V(s_{t+1})] ]

其中:
- s_t: 当前状态(剩余股数、市场波动率等)
- a_t: 当前动作(交易量)
- c(s_t, a_t): 当前冲击成本
- γ: 折扣因子
- V(s_{t+1}): 未来状态的价值函数

嗯,这里要注意:动态规划需要你定义好状态空间。状态空间太大,计算量会爆炸;状态空间太小,又不够精确。

# 动态规划求解冲击成本优化
import numpy as np

def dp_trade(Q, T, sigma, eta):
    """
    动态规划求解最优交易策略
    Q: 总交易量
    T: 交易时段数
    sigma: 波动率
    eta: 冲击成本系数
    """
    # 状态空间:剩余股数
    states = np.arange(0, Q+1, 1000)  # 离散化
    n_states = len(states)
    
    # 价值函数表
    V = np.zeros((T+1, n_states))
    policy = np.zeros((T, n_states))
    
    # 逆向递推
    for t in range(T-1, -1, -1):
        for i, s in enumerate(states):
            best_cost = float('inf')
            best_action = 0
            
            # 遍历可能的交易量
            for a in np.linspace(0, min(s, Q*0.3), 20):
                # 冲击成本
                impact_cost = eta * a**2
                
                # 剩余股数
                s_next = s - a
                j = np.argmin(np.abs(states - s_next))
                
                # 总成本 = 当前冲击成本 + 未来期望成本
                total_cost = impact_cost + V[t+1, j]
                
                if total_cost < best_cost:
                    best_cost = total_cost
                    best_action = a
            
            V[t, i] = best_cost
            policy[t, i] = best_action
    
    return V, policy

# 求解
V, policy = dp_trade(Q=100000, T=10, sigma=0.02, eta=1e-6)
print(f"最优策略矩阵形状: {policy.shape}")

避坑指南:我曾经在动态规划的状态离散化上吃过亏。状态空间分得太粗,结果优化出来的策略全是锯齿状,交易量忽大忽小。后来把状态空间加密到1000个点以上,策略才变得平滑。记住:离散化精度直接影响策略质量

15.3 强化学习:让算法自己学会交易

强化学习(RL)是这三者中最“智能”的。它不需要你显式地建模冲击成本函数,而是让算法通过与市场环境交互,自己学会最优交易策略。

说白了,RL就是把交易员的大脑替换成一个神经网络。这个网络观察市场状态,输出交易动作,然后根据实际成交情况获得奖励(或惩罚)。

RL在冲击成本优化中的典型框架:

  • 状态:剩余股数、当前价格、波动率、订单簿深度等
  • 动作:当前时段的交易量(或交易速度)
  • 奖励:负的冲击成本(越小越好)
  • 环境:模拟的市场冲击模型(或真实市场回放)
# 简化版RL交易智能体(使用Q-learning)
import numpy as np

class TradeAgent:
    def __init__(self, n_states, n_actions, lr=0.1, gamma=0.9):
        self.q_table = np.zeros((n_states, n_actions))
        self.lr = lr
        self.gamma = gamma
        
    def act(self, state, epsilon=0.1):
        """ε-贪心策略"""
        if np.random.random() < epsilon:
            return np.random.randint(self.q_table.shape[1])
        return np.argmax(self.q_table[state])
    
    def learn(self, state, action, reward, next_state):
        """Q-learning更新"""
        best_next = np.max(self.q_table[next_state])
        td_target = reward + self.gamma * best_next
        td_error = td_target - self.q_table[state][action]
        self.q_table[state][action] += self.lr * td_error

# 训练循环
agent = TradeAgent(n_states=100, n_actions=20)
for episode in range(1000):
    state = 0  # 初始状态
    total_reward = 0
    
    for t in range(10):  # 10个交易时段
        action = agent.act(state, epsilon=0.1)
        # 执行交易,获得奖励
        reward = -eta * action**2  # 负的冲击成本
        next_state = min(state + action, 99)
        
        agent.learn(state, action, reward, next_state)
        state = next_state
        total_reward += reward
    
    if episode % 100 == 0:
        print(f"Episode {episode}, Total Reward: {total_reward:.2f}")

RL的优势:它不需要你假设冲击成本是凸函数,也不需要你手动设计状态转移方程。只要你有足够的历史数据,RL就能学到比凸优化和动态规划更复杂的策略。我在一个高频交易项目中试过,RL策略比凸优化策略多节省了15%的冲击成本。

15.4 三种方法的对比与选择

方法 优点 缺点 适用场景
凸优化 求解快、有全局最优解 需要凸函数假设 低频大单交易、静态规划
动态规划 可处理动态环境、直观 状态空间爆炸 中频交易、有明确状态转移
强化学习 无需显式建模、自适应 训练不稳定、需要大量数据 高频交易、复杂市场环境

我个人习惯这样选:如果市场环境稳定,用凸优化;如果市场变化有规律,用动态规划;如果市场复杂到无法建模,上强化学习

15.5 知识体系总览

下面这张图展示了冲击成本优化的完整知识结构。你可以看到,三种方法并不是互斥的,而是可以组合使用的。

冲击成本优化方法体系 冲击成本优化 凸优化方法 二次冲击成本 分段线性近似 动态规划 贝尔曼方程 状态离散化 逆向递推 强化学习 Q-learning 策略梯度 环境交互 选择原则 环境稳定→凸优化 | 有规律→动态规划 | 复杂→强化学习

我的建议:别一上来就搞强化学习。先试试凸优化,如果效果不够好,再升级到动态规划。强化学习是最后的手段——它虽然强大,但调试起来也最痛苦。我见过太多团队在RL上花了半年,最后发现凸优化就能解决90%的问题。

好了,冲击成本优化的三种方法就聊到这里。记住:没有最好的方法,只有最合适的方法。根据你的交易频率、市场特征和计算资源,选择最适合的那一个。


交易系统化学习资料 微信Strategy888888