Exemple #1
0
def solve(x0,
          risk_alphas,
          loadings,
          srisk,
          cost_per_trade=DEFAULT_COST,
          max_risk=0.01):
    N = len(x0)
    #  don't hold no risk data (likely dead)
    lim = np.where(srisk.isnull(), 0.0, 1.0)
    loadings = loadings.fillna(0)
    srisk = srisk.fillna(0)
    risk_alphas = risk_alphas.fillna(0)

    with Model() as m:
        w = m.variable(N, Domain.inRange(-lim, lim))
        longs = m.variable(N, Domain.greaterThan(0))
        shorts = m.variable(N, Domain.greaterThan(0))
        gross = m.variable(N, Domain.greaterThan(0))

        m.constraint(
            "leverage_consistent",
            Expr.sub(gross, Expr.add(longs, shorts)),
            Domain.equalsTo(0),
        )

        m.constraint("net_consistent", Expr.sub(w, Expr.sub(longs, shorts)),
                     Domain.equalsTo(0.0))

        m.constraint("leverage_long", Expr.sum(longs), Domain.lessThan(1.0))

        m.constraint("leverage_short", Expr.sum(shorts), Domain.lessThan(1.0))

        buys = m.variable(N, Domain.greaterThan(0))
        sells = m.variable(N, Domain.greaterThan(0))

        gross_trade = Expr.add(buys, sells)
        net_trade = Expr.sub(buys, sells)
        total_gross_trade = Expr.sum(gross_trade)

        m.constraint(
            "net_trade",
            Expr.sub(w, net_trade),
            Domain.equalsTo(np.asarray(x0)),  #  cannot handle series
        )

        #  add risk constraint
        vol = m.variable(1, Domain.lessThan(max_risk))
        stacked = Expr.vstack(vol.asExpr(), Expr.mulElm(w, srisk.values))
        stacked = Expr.vstack(stacked, Expr.mul(loadings.values.T, w))
        m.constraint("vol-cons", stacked, Domain.inQCone())

        alphas = risk_alphas.dot(np.vstack([loadings.T, np.diag(srisk)]))

        gain = Expr.dot(alphas, net_trade)
        loss = Expr.mul(cost_per_trade, total_gross_trade)
        m.objective(ObjectiveSense.Maximize, Expr.sub(gain, loss))

        m.solve()
        result = pd.Series(w.level(), srisk.index)
        return result
Exemple #2
0
def minimum_variance(matrix):
    # Given the matrix of returns a (each column is a series of returns) this method
    # computes the weights for a minimum variance portfolio, e.g.

    # min   2-Norm[a*w]^2
    # s.t.
    #         w >= 0
    #     sum[w] = 1

    # This is the left-most point on the efficiency frontier in the classic Markowitz theory

    # build the model
    with Model("Minimum Variance") as model:
        # introduce the weight variable

        weights = model.variable("weights", matrix.shape[1], Domain.inRange(0.0, 1.0))
        # sum of weights has to be 1
        model.constraint(Expr.sum(weights), Domain.equalsTo(1.0))
        # returns
        r = Expr.mul(Matrix.dense(matrix), weights)
        # compute l2_norm squared of those returns
        # minimize this l2_norm
        model.objective(ObjectiveSense.Minimize, __l2_norm_squared(model, "2-norm^2(r)", expr=r))
        # solve the problem
        model.solve()
        # return the series of weights
        return np.array(weights.level())
def lsq_pos_l1_penalty(matrix, rhs, cost_multiplier, weights_0):
    """
    min 2-norm (matrix*w - rhs)** + 1-norm(cost_multiplier*(w-w0))
    s.t. e'w = 1
           w >= 0
    """
    # define model
    model = mModel.build_model('lsqSparse')

    # introduce n non-negative weight variables
    weights = mModel.weights(model, "weights", n=matrix.shape[1], lb=0.0)

    # e'*w = 1
    mBound.equal(model, Expr.sum(weights), 1.0)

    # sum of squared residuals
    v = mMath.l2_norm_squared(model, "2-norm(res)**", __residual(matrix, rhs, weights))
    print matrix.shape[1]
    print weights_0
    print weights
    # \Gamma*(w - w0), p is an expression
    p = mMath.mat_vec_prod(cost_multiplier, Expr.sub(weights, weights_0))
    t = mMath.l1_norm(model, 'abs(weights)', p)

    # Minimise v + t
    mModel.minimise(model, __sum_weighted(1.0, v, 1.0, t))
    return np.array(weights.level())
Exemple #4
0
def lsq_pos_l1_penalty(matrix, rhs, cost_multiplier, weights_0):
    """
    min 2-norm (matrix*w - rhs)** + 1-norm(cost_multiplier*(w-w0))
    s.t. e'w = 1
           w >= 0
    """
    # define model
    with Model('lsqSparse') as model:
        # introduce n non-negative weight variables
        weights = model.variable("weights", matrix.shape[1], Domain.inRange(0.0, +np.infty))

        # e'*w = 1
        model.constraint(Expr.sum(weights), Domain.equalsTo(1.0))

        # sum of squared residuals
        v = __l2_norm_squared(model, "2-norm(res)**", __residual(matrix, rhs, weights))

        # \Gamma*(w - w0), p is an expression
        p = Expr.mulElm(cost_multiplier, Expr.sub(weights, weights_0))

        cost = model.variable("cost", matrix.shape[1], Domain.unbounded())
        model.constraint(Expr.sub(cost, p), Domain.equalsTo(0.0))

        t = __l1_norm(model, 'abs(weights)', cost)

        # Minimise v + t
        model.objective(ObjectiveSense.Minimize, __sum_weighted(1.0, v, 1.0, t))
        # solve the problem
        model.solve()

        return np.array(weights.level())
Exemple #5
0
def minimum_variance(matrix):
    # Given the matrix of returns a (each column is a series of returns) this method
    # computes the weights for a minimum variance portfolio, e.g.

    # min   2-Norm[a*w]^2
    # s.t.
    #         w >= 0
    #     sum[w] = 1

    # This is the left-most point on the efficiency frontier in the classic Markowitz theory

    # build the model
    with Model("Minimum Variance") as model:
        # introduce the weight variable

        weights = model.variable("weights", matrix.shape[1],
                                 Domain.inRange(0.0, 1.0))
        # sum of weights has to be 1
        model.constraint(Expr.sum(weights), Domain.equalsTo(1.0))
        # returns
        r = Expr.mul(Matrix.dense(matrix), weights)
        # compute l2_norm squared of those returns
        # minimize this l2_norm
        model.objective(ObjectiveSense.Minimize,
                        __l2_norm_squared(model, "2-norm^2(r)", expr=r))
        # solve the problem
        model.solve()
        # return the series of weights
        return np.array(weights.level())
Exemple #6
0
def lsq_pos_l1_penalty(matrix, rhs, cost_multiplier, weights_0):
    """
    min 2-norm (matrix*w - rhs)** + 1-norm(cost_multiplier*(w-w0))
    s.t. e'w = 1
           w >= 0
    """
    # define model
    with Model('lsqSparse') as model:
        # introduce n non-negative weight variables
        weights = model.variable("weights", matrix.shape[1],
                                 Domain.inRange(0.0, +np.infty))

        # e'*w = 1
        model.constraint(Expr.sum(weights), Domain.equalsTo(1.0))

        # sum of squared residuals
        v = __l2_norm_squared(model, "2-norm(res)**",
                              __residual(matrix, rhs, weights))

        # \Gamma*(w - w0), p is an expression
        p = Expr.mulElm(cost_multiplier, Expr.sub(weights, weights_0))

        cost = model.variable("cost", matrix.shape[1], Domain.unbounded())
        model.constraint(Expr.sub(cost, p), Domain.equalsTo(0.0))

        t = __l1_norm(model, 'abs(weights)', cost)

        # Minimise v + t
        model.objective(ObjectiveSense.Minimize,
                        __sum_weighted(1.0, v, 1.0, t))
        # solve the problem
        model.solve()

        return np.array(weights.level())
def Markowitz(mu, covar, alpha, L=1.0):
    # defineerime kasutatava mudeli kasutades keskväärtusi
    model = mosek_model.build_model('meanVariance')

    # toome sisse n mitte-negatiivset kaalu
    weights = mosek_model.weights(model, "weights", n=covar.shape[1])

    # leiame kaaludele vastavad finantsvõimendused
    lev = mosek_math.l1_norm(model, "leverage", weights)

    # nõuame, et oleks täidetud tingimus omega_1 + ... + omega_n = 1
    mosek_bound.equal(model, Expr.sum(weights), 1.0)

    # nõuame, et oleks täidetud tingimus |omega_1| + ... + |omega_n| <= L
    mosek_bound.upper(model, lev, L)

    v = Expr.dot(mu.values, weights)

    # arvutame variatsiooni
    var = mosek_math.variance(model, "variance", weights, alpha*covar.values)

    # maksimeerime sihifunktsiooni
    mosek_model.maximise(model, Expr.sub(v, var))

    # arvutame lõpuks kaalud ja tagastame need
    weights = pd.Series(data=np.array(weights.level()), index=stocks.keys())
    return weights
Exemple #8
0
def lsq_pos(matrix, rhs):
    """
    min 2-norm (matrix*w - rhs)^2
    s.t. e'w = 1
           w >= 0
    """
    # define model
    with Model('lsqPos') as model:
        # introduce n non-negative weight variables
        weights = model.variable("weights", matrix.shape[1],
                                 Domain.inRange(0.0, +np.infty))

        # e'*w = 1
        model.constraint(Expr.sum(weights), Domain.equalsTo(1.0))

        v = __l2_norm(model,
                      "2-norm(res)",
                      expr=__residual(matrix, rhs, weights))

        # minimization of the residual
        model.objective(ObjectiveSense.Minimize, v)
        # solve the problem
        model.solve()

        return np.array(weights.level())
Exemple #9
0
def __l1_norm(model, name, expr):
    """
    Given an expression (e.g. a vector) this returns the L1-norm of this vector as an expression.
    It also introduces n (where n is the size of the expression) auxiliary variables. Mosek requires a name
    for any variable that is added to a model. The user has to specify this name explicitly.
    This requirement may disappear in future version of this API.

    ATTENTION: THIS WORKS ONLY IF expr is a VARIABLE
    """
    return Expr.sum(__absolute(model, name, expr))
Exemple #10
0
def __l1_norm(model, name, expr):
    """
    Given an expression (e.g. a vector) this returns the L1-norm of this vector as an expression.
    It also introduces n (where n is the size of the expression) auxiliary variables. Mosek requires a name
    for any variable that is added to a model. The user has to specify this name explicitly.
    This requirement may disappear in future version of this API.

    ATTENTION: THIS WORKS ONLY IF expr is a VARIABLE
    """
    return Expr.sum(__absolute(model, name, expr))
Exemple #11
0
def solve_sdp_program(A):
    assert A.ndim == 2
    assert A.shape[0] == A.shape[1]
    A = A.copy()
    n = A.shape[0]
    with Model('theta_1') as M:
        A = Matrix.dense(A)
        # variable
        X = M.variable('X', Domain.inPSDCone(n))
        # objective function
        M.objective(ObjectiveSense.Maximize,
                    Expr.sum(Expr.dot(Matrix.ones(n, n), X)))
        # constraints
        M.constraint(f'c1', Expr.sum(Expr.dot(X, A)), Domain.equalsTo(0.))
        M.constraint(f'c2', Expr.sum(Expr.dot(X, Matrix.eye(n))),
                     Domain.equalsTo(1.))
        # solution
        M.solve()
        sol = X.level()
    return sum(sol)
Exemple #12
0
    def optimize_with_mosek(self, predicted, today):
        """
        使用Mosek来优化构建组合。在测试中Mosek比scipy的单纯形法快约18倍,如果可能请尽量使用Mosek。
        但是Mosek是一个商业软件,因此你需要一份授权。如果没有授权的话请使用scipy或optlang。
        """
        from mosek.fusion import Expr, Model, ObjectiveSense, Domain, SolutionError
        index_weight = self.index_weights.loc[today].fillna(0)
        index_weight = index_weight / index_weight.sum()
        stocks = list(predicted.index)

        with Model("portfolio") as M:
            x = M.variable("x", len(stocks),
                           Domain.inRange(0, self.constraint_config['stocks']))

            # 权重总和等于一
            M.constraint("sum", Expr.sum(x), Domain.equalsTo(1.0))

            # 控制风格暴露
            for factor_name, limit in self.constraint_config['factors'].items(
            ):
                factor_data = self.factor_data[factor_name].loc[today]
                factor_data = factor_data.fillna(factor_data.mean())
                index_exposure = (index_weight * factor_data).sum()
                stocks_exposure = factor_data.loc[stocks].values
                M.constraint(
                    factor_name, Expr.dot(stocks_exposure.tolist(), x),
                    Domain.inRange(index_exposure - limit,
                                   index_exposure + limit))

            # 控制行业暴露
            for industry_name, limit in self.constraint_config[
                    'industries'].items():
                industry_data = self.industry_data[industry_name].loc[
                    today].fillna(0)
                index_exposure = (index_weight * industry_data).sum()
                stocks_exposure = industry_data.loc[stocks].values
                M.constraint(
                    industry_name, Expr.dot(stocks_exposure.tolist(), x),
                    Domain.inRange(index_exposure - limit,
                                   index_exposure + limit))

            # 最大化期望收益率
            M.objective("MaxRtn", ObjectiveSense.Maximize,
                        Expr.dot(predicted.tolist(), x))
            M.solve()
            weights = pd.Series(list(x.level()), index=stocks)
            # try:
            #     weights = pd.Series(list(x.level()), index=stocks)
            # except SolutionError:
            #     raise RuntimeError("Mosek fail to find a feasible solution @ {}".format(str(today)))
        return weights[weights > 0]
def markowitz(exp_ret, covariance_mat, aversion):
    # define model
    model = mModel.build_model("mean_var")

    # set of n weights (unconstrained)
    weights = mModel.weights(model, "weights", n=len(exp_ret))

    mBound.equal(model, Expr.sum(weights), 1.0)

    # standard deviation induced by covariance matrix
    var = mMath.variance(model, "var", weights, covariance_mat)

    mModel.maximise(model=model, expr=Expr.sub(Expr.dot(exp_ret, weights), Expr.mul(aversion, var)))
    return np.array(weights.level())
Exemple #14
0
def markowitz(exp_ret, covariance_mat, aversion):
    # define model
    with Model("mean var") as model:
        # set of n weights (unconstrained)
        weights = model.variable("weights", len(exp_ret), Domain.inRange(-np.infty, +np.infty))

        model.constraint(Expr.sum(weights), Domain.equalsTo(1.0))

        # standard deviation induced by covariance matrix
        var = __variance(model, "var", weights, covariance_mat)

        model.objective(ObjectiveSense.Maximize, Expr.sub(Expr.dot(exp_ret, weights), Expr.mul(aversion, var)))
        model.solve()
        #mModel.maximise(model=model, expr=Expr.sub(Expr.dot(exp_ret, weights), Expr.mul(aversion, var)))
        return np.array(weights.level())
Exemple #15
0
def markowitz(exp_ret, covariance_mat, aversion):
    # define model
    with Model("mean var") as model:
        # set of n weights (unconstrained)
        weights = model.variable("weights", len(exp_ret),
                                 Domain.inRange(-np.infty, +np.infty))

        model.constraint(Expr.sum(weights), Domain.equalsTo(1.0))

        # standard deviation induced by covariance matrix
        var = __variance(model, "var", weights, covariance_mat)

        model.objective(
            ObjectiveSense.Maximize,
            Expr.sub(Expr.dot(exp_ret, weights), Expr.mul(aversion, var)))
        model.solve()
        #mModel.maximise(model=model, expr=Expr.sub(Expr.dot(exp_ret, weights), Expr.mul(aversion, var)))
        return np.array(weights.level())
def lsq_ls(matrix, rhs):
    """
    min 2-norm (matrix*w - rhs)^2
    s.t. e'w = 1
    """
    # define model
    model = mModel.build_model('lsqPos')

    # introduce n non-negative weight variables
    weights = mModel.weights(model, "weights", n=matrix.shape[1])

    # e'*w = 1
    mBound.equal(model, Expr.sum(weights), 1.0)

    v = mMath.l2_norm(model, "2-norm(res)", expr=__residual(matrix, rhs, weights))

    # minimization of the residual
    mModel.minimise(model=model, expr=v)

    return np.array(weights.level())
Exemple #17
0
def lsq_ls(matrix, rhs):
    """
    min 2-norm (matrix*w - rhs)^2
    s.t. e'w = 1
    """
    # define model
    with Model('lsqPos') as model:
        weights = model.variable("weights", matrix.shape[1], Domain.inRange(-np.infty, +np.infty))

        # e'*w = 1
        model.constraint(Expr.sum(weights), Domain.equalsTo(1.0))

        v = __l2_norm(model, "2-norm(res)", expr=__residual(matrix, rhs, weights))

        # minimization of the residual
        model.objective(ObjectiveSense.Minimize, v)
        # solve the problem
        model.solve()

        return np.array(weights.level())
Exemple #18
0
    def __init__(self,name, 
                 foods, 
                 nutrients,
                 daily_allowance,
                 nutritive_value):
        Model.__init__(self,name)
        finished = False
        try:
          self.foods     = [ str(f) for f in foods ]
          self.nutrients = [ str(n) for n in nutrients ]
          self.dailyAllowance = array.array(daily_allowance, float)
          self.nutrientValue = DenseMatrix(nutritive_value).transpose()

          M = len(self.foods)
          N = len(self.nutrients)
          if len(self.dailyAllowance) != N:
              raise ValueError("Length of daily_allowance does not match "
                               "the number of nutrients")
          if self.nutrientValue.numColumns() != M:
              raise ValueError("Number of rows in nutrient_value does not "
                               "match the number of foods")
          if self.nutrientValue.numRows() != N:
              raise ValueError("Number of columns in nutrient_value does "
                               "not match the number of nutrients")
          
          self.__dailyPurchase = self.variable('Daily Purchase', 
                                               StringSet(self.foods), 
                                               Domain.greaterThan(0.0))
          self.__dailyNutrients = \
              self.constraint('Nutrient Balance',
                              StringSet(nutrients),
                              Expr.mul(self.nutrientValue,self.__dailyPurchase),
                              Domain.greaterThan(self.dailyAllowance))
          self.objective(ObjectiveSense.Minimize, Expr.sum(self.__dailyPurchase))
          finished = True
        finally:
          if not finished:
            self.__del__()
Exemple #19
0
    def __init__(self,name, 
                 foods, 
                 nutrients,
                 daily_allowance,
                 nutritive_value):
        Model.__init__(self,name)
        finished = False
        try:
          self.foods     = [ str(f) for f in foods ]
          self.nutrients = [ str(n) for n in nutrients ]
          self.dailyAllowance = numpy.array(daily_allowance, float)
          self.nutrientValue = Matrix.dense(nutritive_value).transpose()

          M = len(self.foods)
          N = len(self.nutrients)
          if len(self.dailyAllowance) != N:
              raise ValueError("Length of daily_allowance does not match "
                               "the number of nutrients")
          if self.nutrientValue.numColumns() != M:
              raise ValueError("Number of rows in nutrient_value does not "
                               "match the number of foods")
          if self.nutrientValue.numRows() != N:
              raise ValueError("Number of columns in nutrient_value does "
                               "not match the number of nutrients")
          
          self.__dailyPurchase = self.variable('Daily Purchase', 
                                               StringSet(self.foods), 
                                               Domain.greaterThan(0.0))
          self.__dailyNutrients = \
              self.constraint('Nutrient Balance',
                              StringSet(nutrients),
                              Expr.mul(self.nutrientValue,self.__dailyPurchase),
                              Domain.greaterThan(self.dailyAllowance))
          self.objective(ObjectiveSense.Minimize, Expr.sum(self.__dailyPurchase))
          finished = True
        finally:
          if not finished:
            self.__del__()