Open metodmove opened 2 years ago
This is interesting – unfortunately due to how the package is designed (in particular, how it constructs the actual optimisation problem) this isn't straightforward. A possible sketch for a solution:
ef = EfficientFrontier(mu, S, solver_options={"warm_start": True})
ef.add_constraint(...)
for rets, cov_matrix in history:
ef. expected_returns = rets # each day pass the expected returns
ef.cov_matrix = cov_matrix # and the new cov matrix
w = ef.convex_objective(objective_functions.quadratic_utility, ef.expected_returns, ef.cov_matrix, risk_aversion))
Something like this should work. The reason why you have to use convex_objective
rather than max_quadratic_utility
) is an unforeseen consequence/bug of v1.5.0 (parameterised problems) here:
if update_existing_parameter:
self._validate_market_neutral(market_neutral)
self.update_parameter_value("risk_aversion", risk_aversion)
else:
self._objective = objective_functions.quadratic_utility(
self._w,
self.expected_returns,
self.cov_matrix,
risk_aversion=risk_aversion,
)
for obj in self._additional_objectives:
self._objective += obj
self._make_weight_sum_constraint(market_neutral)
Basically, if the risk aversion parameter has already been defined, then it doesn't reconstruct the cp.Problem
. But in this case you need the problem to be reconstructed since the expected_returns
and cov_matrix
are different each day.
I'm not sure if there is a simple fix for that.
I have a use case where I want to backtest a daily strategy over multiple years - this means that I want to run e.g.
for every trading day in a simulation. What this does (to the best of my understanding) is instantiate a new cvxpy Problem under the hood (in method
_solve_cvxpy_opt_problem
in BaseConvexOptimizer). This preventscvxpy
from reusing the previous solution, i.e. weights from day{t-1}, as an initial point when computing weights on day{t}.While this does not affect the actual weights we compute (provided that the convex solver converged the solution found should be independent of the initial point), it can be quite a bit slower since the solver needs to search for a feasible starting point first. See Warm Up chapter here for an example of speed-up that reusing the previous solution can bring in
cvxpy
.Would it make sense to add an option for reusing the previous solution to
EfficientFrontier
class? Or is this perhaps available already and I simply overlooked it?