Skip to content

Commit

Permalink
MPC working with covariance matrix risk aversion and l2 transaction c…
Browse files Browse the repository at this point in the history
…osts.
  • Loading branch information
Sinbad-The-Sailor committed Feb 18, 2024
1 parent b70ae2c commit 53e947d
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 4 deletions.
7 changes: 6 additions & 1 deletion run.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from src.abacus.utils.portfolio import Portfolio
from src.abacus.simulator.simulator import Simulator
from src.abacus.assessor.risk_assessor import RiskAssessor
from src.abacus.optimizer.optimizer import SPMaximumUtility, MPCMaximumUtility
from src.abacus.optimizer.optimizer import SPMaximumUtility, MPCMaximumUtility, MPCMaximumReturn



Expand Down Expand Up @@ -60,4 +60,9 @@
# optimizer.solve()


print()
optimizer = MPCMaximumReturn(portfolio, simulator.return_tensor, gamma=10, l1_penalty=0, l2_penalty=1, covariance_matrix=simulator.covariance_matrix)
optimizer.solve()


print("OK!")
35 changes: 35 additions & 0 deletions src/abacus/optimizer/optimization_models/mpc_maximize_return.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
problem mpcMaximizeReturn;

set assets;

param gamma;
param inital_weights {assets};
param number_of_time_steps > 0 integer;
param returns {1..number_of_time_steps, assets};
param covariance {assets, assets};
param l1_penalty {assets};
param l2_penalty {assets};

var weights {0..number_of_time_steps, assets};

maximize OBJECTIVE:
sum{t in 1..number_of_time_steps} (sum {a in assets} (returns[t,a] * weights[t,a])
- gamma * sum{a in assets, b in assets} weights[t, a] * covariance[a , b] * weights [t, b]
- sum{a in assets} ( l1_penalty[a] * abs(weights[t, a] - weights[t-1, a]) + l2_penalty[a] * (weights[t, a] - weights[t-1, a]) **2))
;

subject to WEIGHT_CONSTRAINT_SUM {t in 1..number_of_time_steps}:
sum{a in assets} weights[t, a] = 1
;

subject to WEGIHT_CONSTRAINT {t in 1..number_of_time_steps, a in assets}:
weights[t, a] <= 1
;

subject to WEGIHT_CONSTRAINT_NON_NEGATIVE {t in 1..number_of_time_steps, a in assets}:
weights[t, a] >= 0
;

subject to INITIAL_WEIGHTS {a in assets}:
weights[0, a] = inital_weights[a]
;
47 changes: 44 additions & 3 deletions src/abacus/optimizer/optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,53 @@ def _set_ampl_data(self):
number_of_time_steps = tensor_size[1]
return_dict = {(j+1, asset.identifier): expected_return_tensor[asset.id][j] for asset in assets for j in range(number_of_time_steps)}

print(return_dict)
print(asset_identifiers)
print(inital_weights)
self._ampl.get_set("assets").set_values(asset_identifiers)
self._ampl.param["gamma"] = self._gamma
self._ampl.param["number_of_time_steps"] = number_of_time_steps
self._ampl.param["inital_weights"] = inital_weights
self._ampl.param["returns"] = return_dict


class MPCMaximumReturn(OptimizationModel):

_model_specification = OptimizationSpecifications.MPC_MAXIMIZE_RETURN

def __init__(self, portfolio: Portfolio, simulation_tensor: torch.Tensor, gamma: float, l1_penalty: float, l2_penalty: float,
covariance_matrix: torch.Tensor):
super().__init__(portfolio, simulation_tensor)
self._gamma = gamma
self._l1_penalty = l1_penalty
self._l2_penalty = l2_penalty
self._covariance_matrix = covariance_matrix

@property
def _return_expectation_tensor(self):
return torch.mean(self._simulation_tensor, dim=2)

def solve(self):
super().solve()
print(self._ampl.get_variable("weights").get_values())
print(self._ampl.eval("display OBJECTIVE;"))

def _set_ampl_data(self):
assets = self._portfolio.instruments
inital_weights = self._portfolio.weights
asset_identifiers = [instrument.identifier for instrument in assets]
inital_weights = dict(zip(asset_identifiers, inital_weights.values()))
expected_return_tensor = np.array(self._return_expectation_tensor)
tensor_size = expected_return_tensor.shape
number_of_time_steps = tensor_size[1]
return_dict = {(j+1, asset.identifier): expected_return_tensor[asset.id][j] for asset in assets for j in range(number_of_time_steps)}
covariance_matrix = np.array(self._covariance_matrix)

l1_penalty_vector = self._l1_penalty * np.ones(len(assets))
l2_penalty_vector = self._l2_penalty * np.ones(len(assets))

self._ampl.get_set("assets").set_values(asset_identifiers)
self._ampl.param["gamma"] = self._gamma
self._ampl.param["number_of_time_steps"] = number_of_time_steps
self._ampl.param["inital_weights"] = inital_weights
self._ampl.param["returns"] = return_dict
self._ampl.param["covariance"] = covariance_matrix
self._ampl.param["l1_penalty"] = l1_penalty_vector
self._ampl.param["l2_penalty"] = l2_penalty_vector
1 change: 1 addition & 0 deletions src/abacus/utils/enumerations.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
class OptimizationSpecifications(Enum):
SP_MAXIMIZE_UTILITY = "sp_maximize_utility.mod"
MPC_MAXIMIZE_UTILITY = "mpc_maximize_utility.mod"
MPC_MAXIMIZE_RETURN = "mpc_maximize_return.mod"

class DataTypes(Enum):
LOG_RETURNS = auto(),
Expand Down

0 comments on commit 53e947d

Please sign in to comment.