-1

I have been struggling with solving the following problem: I have some values stored in variable returns, and I want to multiply them by a weight (x_vars)in order to make the sum of the products and obtain the value of the variable target_return. As the following equation:

$$\sum_{i=0}^{n}(returns_i\cdot x_var_i)  = target_return$$

I am struggling with the answer returned, as it saying x_13 = 1. But is not correct. I have tried to do it with normal constrains and eslastic but I get no correct answer. I have a tolerance of let's say 0.01% of error.

Any guess?

Thanks

import pulp as plp
# Name model
# set variables   
target_return = 0.0204185791833761
returns = [0.025865338474480914,
 0.031617753987556174,
 0.017530329404997325,
 -0.0008543358059154293,
 0.010510143115372461,
 0.012048338516174262,
 0.04959181591738604,
 0.06059545751936519,
 0.05926623356137273,
 0.058971753714631814,
 0.03442022388647947,
 0.013688974565667422,
 0.02104075216985901,
 -0.0021299262578251543,
 0.017882182143459602,
 0.018964184657020766,
 0.005792320704504306,
 0.018823216764509265,
 -0.0015860431556348198,
 0.008352716776521163,
 0.030728674721250515,
 0.016529301951210496,
 0.0184734317514465,
 -0.0008822232596910062,
 0.010912806711330658,
 0.023530497410194418,
 0.0378090116601979,
 0.009456335242604919,
 0.005556382185357922,
 0.020013334218681678,
 0.05852489326632937,
 0.047988175193893645,
 0.016134386609760742,
 0.014350880108888964,
 0.006756782462879585]

# Initialize model
prob=plp.LpProblem("Find Weights Model", plp.LpMinimize)
x_vars=plp.LpVariable.dicts("x", range(0, len(returns)), 0, 1)
for index in range(len(returns)):
    x_vars[index].setInitialValue(0.5)

#Set problem
prob += plp.lpSum([x_vars[i] for i in x_vars]) == 1

#Set constrain
constrain=plp.LpConstraint(plp.lpSum(
    [returns[i]*x_vars[i] for i in range(0, len(returns))]), rhs=target_return)
# To use standard constrain uncomment following line
#prob.addConstraint(constrain)
# To use elastic constrain uncomment following line
elastic_constrain=constrain.makeElasticSubProblem(penalty = 500000,proportionFreeBoundList  =[0.001,0.0001])
prob.extend(elastic_constrain) 


prob.solve(plp.PULP_CBC_CMD(msg=True, warmStart=True))
final_weights={}
for v in prob.variables():
    final_weights[v.name]=v.varValue

print("Status:", plp.LpStatus[prob.status])

final_weights

Possible solutions:

solution1 = [0.00962135141677065,
0.00962135141677065,
0.0277264834687149,
0.0297957188693739,
0.0324961558793471,
0.030826881062523,
0.0306009427392119,
0.0250863577897657,
0.0234700849350161,
0.0236653284777789,
0.0237085827820698,
0.0273148420035226,
0.0303599573647406,
0.0292800893464517,
0.0326835213770196,
0.0297440370126145,
0.0295851066643113,
0.0315198597719625,
0.0296058126214705,
0.0326036329340179,
0.0311437752841399,
0.0278570759221869,
0.0299427552142207,
0.0296571910611703,
0.0325002521378998,
0.0307677356659276,
0.0289143823239777,
0.0268170787933395,
0.0309816698637205,
0.0315545156635921,
0.0294310019878726,
0.023774220455596,
0.0253219090166822,
0.0300007623180508,
0.0302627332639599]

solution2 = [0.0291039150753347,
0.0291039150753347,
0.028739103831572,
0.0296325128619877,
0.0307984495156388,
0.0300777243941537,
0.0299801757193628,
0.027599206714805,
8.34695965451632E-05,
0.0269856659961344,
0.0270043421537945,
0.0285613748092319,
0.0298761263170002,
0.0294098868961038,
0.0308793458966854,
0.0296102001652331,
0.0295415791679557,
0.0303769265588311,
0.0295505206943934,
0.0308448536374279,
0.0302145485146196,
0.0287954885757358,
0.0296959977222549,
0.0295727013961937,
0.030800217918514,
0.0300521885203749,
0.0292519883685474,
0.0283464607865791,
0.0301445556616913,
0.030391887092054,
0.0294750434895131,
0.0270326804365011,
0.0277009088398652,
0.0297210421051448,
0.0298341506415484]

In excel, I've got the solutions using the following configuration: enter image description here

arodrisa
  • 300
  • 4
  • 17
  • This link might be useful : https://stackoverflow.com/questions/57309541/pulp-what-does-lpdot-does-how-to-use-it. Otherwise, you can use numpy.dot. – Catalina Chircu Aug 16 '20 at 20:04
  • Thanks for you answer. I've checked your answer but I dont see how it can help. If you execute my code, you may find that if you check prob content, you will already see that there are the equations which makes sense. I know it has an answer as I've tested it in excel previously. – arodrisa Aug 16 '20 at 21:09
  • Do you know what the correct answer should be? This would help debug what the problem is. – pchtsp Aug 17 '20 at 08:25
  • I've changed the target_return, that I set it up wrong before (sorry) and two possible answers – arodrisa Aug 17 '20 at 09:07

1 Answers1

1

I think the solution you got from pulp (CBC) is correct, it's just not the same as the one from Excel. To confirm the constraints are respected you can do the following:

solution3 = [x.value() for x in x_vars.values()]

# objective: 0.0204185791833761
sum(val*returns[i] for i, val in enumerate(solution1))
# 0.02053629325573023
sum(val*returns[i] for i, val in enumerate(solution3))
# 0.02039816058427895

# constraint:
sum(val for i, val in enumerate(solution1))
# 0.9782431569057903
sum(val for i, val in enumerate(solution3))
# 0.999999999

In fact, the solution from pulp is closer to the objective and respects a lot better the constraint of sum()=1.

pchtsp
  • 794
  • 1
  • 6
  • 15