def get_trades(self, portfolio, t=None): """ Get optimal trade vector for given portfolio at time t. Parameters ---------- portfolio : pd.Series Current portfolio vector. t : pd.timestamp Timestamp for the optimization. """ if t is None: t = pd.datetime.today() value = sum(portfolio) w = portfolio / value z = cvx.Variable(w.size) # TODO pass index wplus = w.values + z if isinstance(self.return_forecast, BaseReturnsModel): alpha_term = self.return_forecast.weight_expr(t, wplus) else: alpha_term = cvx.sum(cvx.multiply( time_locator(self.return_forecast, t, as_numpy=True), wplus)) assert(alpha_term.is_concave()) costs, constraints = [], [] for cost in self.costs: cost_expr, const_expr = cost.weight_expr(t, wplus, z, value) costs.append(cost_expr) constraints += const_expr constraints += [item for item in (con.weight_expr(t, wplus, z, value) for con in self.constraints)] for el in costs: assert (el.is_convex()) for el in constraints: assert (el.is_dcp()) self.prob = cvx.Problem( cvx.Maximize(alpha_term - sum(costs)), [cvx.sum_entries(z) == 0] + constraints) self.prob.solve(solver=self.solver, **self.solver_opts) logging.error( f'The problem is {self.prob.status}. Defaulting to no trades') return self._nulltrade(portfolio) return pd.Series(index=portfolio.index, data=(z.value.A1 * value))
def get_trades(self, portfolio, t=pd.datetime.today()): prediction = time_locator(self.return_forecast, t, as_numpy=False) sorted_ret = prediction.sort_values() short_trades = sorted_ret.index[:self.num_short] long_trades = sorted_ret.index[-self.num_long:] u = pd.Series(0., index=prediction.index) u[short_trades] = -1. u[long_trades] = 1. u /= sum(abs(u)) u = sum(portfolio) * u * self.target_turnover # import pdb; pdb.set_trace() # # # ex-post cash neutrality # old_cash = portfolio[-1] # if old_cash > 0: # u[short] = u[short] + old_cash/self.num_short # else: # u[long] = u[long] + old_cash/self.num_long return u
def get_rounded_trades(self, portfolio, prices, t): """Get trades vector as number of shares, rounded to integers.""" return np.round(self.get_trades(portfolio, t) / time_locator(prices, t))[:-1]