How can I include the absolute value of a decision variable in PuLP objective function

Question:

The problem setup is fairly simple. There are 5 available instruments in a portfolio that can be traded. The optimizer needs to figure out which instruments need to be bought and / or sold to make max profit, There are the estimates for price change and some risk constraints.

Now as in the real world, there are always transaction costs. These are always positive whether the securities are bought or sold. How do I setup this optimization problem?

Below is what I have setup without transaction costs, and I have included the commented line to indicate how the transaction cost would work.

``````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)

instr_avl = LpVariable.dicts("Instr", df['instrument'].values,lowBound=None, upBound=None, cat= 'Integer')

# The objective function
prob += (lpSum([instr_avl[i] * df[df['instrument']==i]['price_change'].values[0]
for i in df['instrument'].values]), "Total Profit")

# Factor constraints
prob +=  lpSum([instr_avl[i] * df[df['instrument']==i]['factor_A'].values[0] for i in df['instrument'].values]) == 0, "factor_A Constraint"
prob += lpSum([instr_avl[i] * df[df['instrument']==i]['factor_B'].values[0] for i in df['instrument'].values]) <= 1000, "factor_B max Constraint"
prob += lpSum([instr_avl[i] * df[df['instrument']==i]['factor_B'].values[0] for i in df['instrument'].values]) >= -1000, "factor_B min Constraint"

# The problem is solved using PuLP's choice of Solver
prob.solve()

for v in prob.variables():
print(v.name, "=", v.varValue, v.lowBound, v.upBound, v.cat)

print("Total profit= ", value(prob.objective))
``````

Of course the code does not run if the commented line is uncommented. Would highly appreciate any ideas on how to implement this or any workarounds!

1. Introduce a non-negative variable say `absv[i]`.
2. Add the two constraints: `absv[i] >= instr_avl[i]` and `absv[i] >= -instr_avl[i]`.
3. Add the term: `-absv[i]*df[df['instrument']==i]['spread_cost'].values[0]` to the objective.