You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PuLP目标函数中纳入决策变量绝对值以计算交易成本

投资组合优化:加入交易成本的线性规划实现

问题背景

现有5种可交易工具的投资组合优化需求,目标是确定各工具的买卖仓位以实现利润最大化,已知价格变动估算值及因子约束条件。需要在模型中加入双向交易成本(无论买卖都产生正向成本),但原代码中直接使用abs()函数会触发非线性问题,无法被PuLP的线性规划求解器处理。

核心问题

线性规划(LP)求解器不支持非线性的绝对值表达式abs(instr_avl[i]),必须将绝对值项线性化处理,把非线性问题转化为标准线性规划问题才能求解。

解决方案思路

将每个工具的持仓变量拆分为两个非负整数变量:

  • long_i:工具i的多头仓位(买入数量,≥0)
  • short_i:工具i的空头仓位(卖出数量,≥0)

实际仓位满足:instr_avl[i] = long_i - short_i
交易成本对应的绝对值项可转化为:abs(instr_avl[i]) = long_i + short_i(最优解中自然不会同时出现正的多头和空头仓位,无需额外约束)

修改后的完整代码

from pulp import *
import pandas as pd

df = pd.DataFrame({
                    'instrument':["A", "B", "C", "D", "E"],
                    'price_change':[-6.09, -3.15,  6.1 ,  6.43,  6.48],
                    'transaction_cost':[0.6, 0.6, 3.0, 6.0, 3.0],
                    'factor_A':[ 0.28032, -0.20112,  0.55631, -0.73323, -0.54905],
                    'factor_B':[18.87091, 15.73831, 29.61791, 24.64536, 29.68997]
                    })

prob = LpProblem("The portfolio Problem", LpMaximize)

# 拆分持仓为多头和空头变量,均为非负整数
long_pos = LpVariable.dicts("Long", df['instrument'].values, lowBound=0, cat='Integer')
short_pos = LpVariable.dicts("Short", df['instrument'].values, lowBound=0, cat='Integer')

# 目标函数:利润 = 价格变动收益 - 交易成本
objective_terms = []
for i in df['instrument'].values:
    price_change = df.loc[df['instrument'] == i, 'price_change'].values[0]
    trans_cost = df.loc[df['instrument'] == i, 'transaction_cost'].values[0]
    # 多头收益:long_pos[i] * price_change;空头收益:-short_pos[i] * price_change(空头赚价格下跌的钱)
    profit = long_pos[i] * price_change - short_pos[i] * price_change
    # 交易成本:无论多空都要付,所以是(long + short)*单位成本
    cost = (long_pos[i] + short_pos[i]) * trans_cost
    objective_terms.append(profit - cost)

prob += lpSum(objective_terms), "Total Profit"

# Factor约束:用拆分后的变量计算实际仓位
prob += lpSum([(long_pos[i] - short_pos[i]) * df.loc[df['instrument'] == i, 'factor_A'].values[0] 
               for i in df['instrument'].values]) == 0, "factor_A Constraint"

factor_B_total = lpSum([(long_pos[i] - short_pos[i]) * df.loc[df['instrument'] == i, 'factor_B'].values[0] 
                        for i in df['instrument'].values])
prob += factor_B_total <= 1000, "factor_B max Constraint"
prob += factor_B_total >= -1000, "factor_B min Constraint"

# 求解问题
prob.solve()

# 输出结果:计算实际仓位
for i in df['instrument'].values:
    long_val = value(long_pos[i])
    short_val = value(short_pos[i])
    actual_pos = long_val - short_val
    print(f"Instrument {i}: 仓位={actual_pos} (多头={long_val}, 空头={short_val})")

print(f"Total profit= {value(prob.objective):.2f}")

代码说明

  1. 变量拆分:将原单一仓位变量拆分为long_pos和short_pos,确保均为非负整数,符合线性规划要求。
  2. 目标函数线性化:通过long_pos + short_pos替代abs(instr_avl[i]),将交易成本转化为线性表达式。
  3. 约束适配:所有因子约束均使用long_pos[i] - short_pos[i]计算实际仓位,保持原约束逻辑不变。
  4. 结果输出:直接计算并输出实际仓位(多头-空头),更直观展示交易决策。

内容的提问来源于stack exchange,提问作者Generalenthu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 04:25:22