def get_instrument_replica(prices, returns, m, alphas=None): assert len(prices) == len(returns[0]) if alphas is None: alphas = np.array([i / m for i in range(1, m + 1)]) t = len(prices) mu = returns[:, -1] print('number of nans in returns:', np.isnan(returns).sum()) drawdown = ut.drawdown(prices) rhos = np.array([ut.cvar(drawdown, alpha) for alpha in alphas]) # create variables lambdas = cp.Variable(m) v = cp.Variable() us = cp.Variable((m, t)) aux = cp.Variable((m, t)) # aux = max(us, 0) objective = cp.Minimize(lambdas @ rhos - v) constraints = [ lambdas >= 0., cp.sum(lambdas) == 1., v * mu == returns @ cp.sum(us, axis=0), aux >= 0., aux >= us ] # add constraints for u and aux for i in range(m): constraints.append(cp.sum(us[i, :]) == 0.) constraints.append(cp.sum(aux[i, :]) <= lambdas[i]) constraints.append(cp.sum(us[i, :]) >= 0.) for k in range(t): if k >= 1: constraints.append(cp.sum(us[i, :k]) >= 0.) constraints.append(us[i, k] >= -1. * lambdas[i] / (alphas[i] * t)) # optimization problem = cp.Problem(objective, constraints) problem.solve(solver=cp.GLPK) return lambdas.value, v.value, us.value, problem.value
def get_constraint_violation(optimal_returns, all_returns, alpha): n, t = np.shape(all_returns) # calculate CDaR drawdowns = ut.drawdown(optimal_returns) q_var = cp.Variable(t) objective = cp.Maximize(q_var @ drawdowns) constraints = [q_var >= 0, q_var <= 1. / (alpha * t), cp.sum(q_var) == 1] problem = cp.Problem(objective, constraints) problem.solve(solver=cp.GLPK) cdar = problem.value q_opt = q_var.value betas = np.zeros(n) print('cdar1=', cdar, 'cdar2=', ut.cvar(drawdowns, alpha)) # construct list of indices of max elements k = [] for j in range(1, t + 1): k.append(np.argmax(optimal_returns[:j])) # construct betas for i in range(n): for j in range(t): betas[i] += q_opt[j] * (all_returns[i, k[j]] - all_returns[i, j]) / cdar violation = all_returns[:, -1] - optimal_returns[-1] * betas print('violations are', violation) return np.linalg.norm(violation, ord=2), np.linalg.norm(violation, ord=1)
def f(y): y_ext = np.zeros(len(y) + 1) y_ext[1:] = y y_ext[0] = (1. - returns[1:, -1] @ y) / returns[0, -1] ret = 0. for i in range(m): if lambdas[i] > 0: ret += lambdas[i] * ut.cvar(ut.drawdown(y_ext @ returns), alphas[i]) return ret
def drawdown(self): self.max_dd, self.max_ddd = utils.drawdown(self.cumreturns) self.results['Max DD'] = self.format_string(self.max_dd, '.2f', True) self.results['Max DD duration'] = self.format_string(self.max_ddd, 'd')
def f(y): ret = 0. for i in range(m): ret += lambdas[i] * ut.cvar(ut.drawdown(y @ returns), alphas[i]) return ret
def check_rhos(prices, alphas): for alpha in alphas: print(ut.cvar(ut.drawdown(prices), alpha))
def f(y): ret = 0. for i in range(m): ret += lambdas[i]*ut.cvar(ut.drawdown(y*prices1+(1-y)*prices2), alphas[i]) return ret
m = 2 n = 2 t = 454 weekly_r0 = np.power(1.03, 1. / 52) r0 = np.array([weekly_r0**i for i in range(t + 1)]) # adjusted returns of a risk-free asset if n == 505: returns = ut.get_all_adj_returns(r0) else: returns = ut.get_adj_returns(n, r0) # setting max heap size limit rsrc = resource.RLIMIT_DATA _, hard = resource.getrlimit(rsrc) resource.setrlimit(rsrc, ((1024**3) * 8, hard)) soft, hard = resource.getrlimit(rsrc) print('Soft RAM limit set to:', soft / (1024**3), 'GB') ls = [0., 1.] alphas = [1., 1. / t] y_opt1 = forward_portfolio_optimization_uncons(returns, alphas, ls, m, n) print('optimal y1=', y_opt1) print('constraint violation=', returns[:, -1] @ y_opt1 - 1.) print('MaxDD value=', max(ut.drawdown(y_opt1 @ returns))) y_opt2, opt_val = forward_portfolio_optimization_maxdd(returns) print('optimal y2=', y_opt2) print('constraint violation=', returns[:, -1] @ y_opt2 - 1.) print('MaxDD value=', max(ut.drawdown(y_opt2 @ returns))) print('Problem optimal value=', opt_val)
def drawdown(self): return utils.drawdown(self.assets())