def test_efficient_return_short():
    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(None, None))
    target_return = 0.25
    weights_sum = 1.0  # Not market neutral, weights must sum to 1.
    w = ef.efficient_return(target_return)
    assert isinstance(w, dict)
    assert set(w.keys()) == set(ef.tickers)
    np.testing.assert_almost_equal(ef.weights.sum(), weights_sum)
    w_expected = simple_ef_weights(ef.expected_returns, ef.cov_matrix,
                                   target_return, weights_sum)
    np.testing.assert_almost_equal(ef.weights, w_expected)
    vol_expected = np.sqrt(
        objective_functions.portfolio_variance(w_expected, ef.cov_matrix))
    sharpe_expected = objective_functions.sharpe_ratio(w_expected,
                                                       ef.expected_returns,
                                                       ef.cov_matrix,
                                                       negative=False)
    np.testing.assert_allclose(ef.portfolio_performance(),
                               (target_return, vol_expected, sharpe_expected))
    sharpe = ef.portfolio_performance()[2]

    ef_long_only = setup_efficient_frontier()
    ef_long_only.efficient_return(target_return)
    long_only_sharpe = ef_long_only.portfolio_performance()[2]

    assert sharpe > long_only_sharpe
Esempio n. 2
0
    def optimizePortfolio(self, option='sharpe'):
        '''
            Optimize for maximal Sharpe ratio / minimum volatility (Default to Sharpe)
            TODO: Allow for more options
            Return EfficientFrontier object
        '''

        mu = self.calculateMu()
        S = self.calculateSampleCovarianceMatrix()
        ef = EfficientFrontier(mu, S)

        if option == 'sharpe':
            weights = ef.max_sharpe(
            )  #Maximize the Sharpe ratio, and get the raw weights

        elif option == 'volatility':
            weights = ef.min_volatility()

        else:
            raise SystemExit("Not found optimize option (Sharpe/Volatility)")

        self.cleaned_weights = ef.clean_weights()
        print(
            self.cleaned_weights
        )  #Note the weights may have some rounding error, meaning they may not add up exactly to 1 but should be close
        ef.portfolio_performance(verbose=True)

        return ef
Esempio n. 3
0
def min_var(my_portfolio, perf=True) -> list:
    ohlc = yf.download(
        my_portfolio.portfolio,
        start=my_portfolio.start_date,
        end=my_portfolio.end_date,
        progress=False,
    )
    prices = ohlc["Adj Close"].dropna(how="all")
    prices = prices.filter(my_portfolio.portfolio)

    mu = expected_returns.capm_return(prices)
    S = risk_models.CovarianceShrinkage(prices).ledoit_wolf()

    ef = EfficientFrontier(mu, S)
    ef.add_objective(objective_functions.L2_reg,
                     gamma=my_portfolio.diversification)
    if my_portfolio.min_weights is not None:
        ef.add_constraint(lambda x: x >= my_portfolio.min_weights)
    if my_portfolio.max_weights is not None:
        ef.add_constraint(lambda x: x <= my_portfolio.max_weights)
    ef.min_volatility()
    weights = ef.clean_weights()

    wts = weights.items()

    result = []
    for val in wts:
        a, b = map(list, zip(*[val]))
        result.append(b)

    if perf is True:
        ef.portfolio_performance(verbose=True)

    return flatten(result)
def test_min_volatility_vs_max_sharpe():
    # Test based on issue #75
    expected_returns_daily = pd.Series(
        [0.043622, 0.120588, 0.072331, 0.056586],
        index=["AGG", "SPY", "GLD", "HYG"])
    covariance_matrix = pd.DataFrame(
        [
            [0.000859, -0.000941, 0.001494, -0.000062],
            [-0.000941, 0.022400, -0.002184, 0.005747],
            [0.001494, -0.002184, 0.011518, -0.000129],
            [-0.000062, 0.005747, -0.000129, 0.002287],
        ],
        index=["AGG", "SPY", "GLD", "HYG"],
        columns=["AGG", "SPY", "GLD", "HYG"],
    )

    ef = EfficientFrontier(expected_returns_daily, covariance_matrix)
    ef.min_volatility()
    vol_min_vol = ef.portfolio_performance(risk_free_rate=0.00)[1]

    ef = EfficientFrontier(expected_returns_daily, covariance_matrix)
    ef.max_sharpe(risk_free_rate=0.00)
    vol_max_sharpe = ef.portfolio_performance(risk_free_rate=0.00)[1]

    assert vol_min_vol < vol_max_sharpe
Esempio n. 5
0
def calculEF(dataframe):
    mu = expected_returns.mean_historical_return(dataframe)
    S = risk_models.sample_cov(dataframe)
    ef = EfficientFrontier(mu, S)
    weights = ef.nonconvex_objective(deviation_risk_parity, ef.cov_matrix)
    ef.portfolio_performance(verbose=True)
    return pd.DataFrame([weights])
Esempio n. 6
0
def optimise(portfolio_data):
    returns = pd.Series(get_returns(portfolio_data))
    covariance_matrix = pd.DataFrame(get_cov_matrix(portfolio_data))

    ef = EfficientFrontier(returns, covariance_matrix)
    ef.min_volatility()  # max_sharpe or min_volatility
    cleaned_weights = ef.clean_weights()
    fix_keys(cleaned_weights, portfolio_data)
    print(cleaned_weights)
    ef.save_weights_to_file("weights.csv")  # saves to file
    ef.portfolio_performance(verbose=True)
Esempio n. 7
0
def test_efficient_semivariance_vs_heuristic():
    benchmark = 0
    es = setup_efficient_semivariance()
    es.efficient_return(0.20)
    mu_es, semi_deviation, _ = es.portfolio_performance()
    np.testing.assert_almost_equal(mu_es, 0.2)

    mean_return, historic_returns = setup_efficient_semivariance(
        data_only=True)

    pairwise_semivariance = risk_models.semicovariance(historic_returns,
                                                       returns_data=True,
                                                       benchmark=0,
                                                       frequency=1)
    ef = EfficientFrontier(mean_return, pairwise_semivariance)
    ef.efficient_return(0.20)
    mu_ef, _, _ = ef.portfolio_performance()
    # mu_ef *= 252

    portfolio_returns = historic_returns @ ef.weights
    drops = np.fmin(portfolio_returns - benchmark, 0)
    T = historic_returns.shape[0]
    semivariance = np.sum(np.square(drops)) / T * 252
    semi_deviation_ef = np.sqrt(semivariance)

    assert semi_deviation < semi_deviation_ef
    assert mu_es / semi_deviation > mu_ef / semi_deviation_ef
Esempio n. 8
0
def test_efficient_return_short():
    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(None, None))
    w = ef.efficient_return(0.25)
    assert isinstance(w, dict)
    assert set(w.keys()) == set(ef.tickers)
    np.testing.assert_almost_equal(ef.weights.sum(), 1)
    np.testing.assert_allclose(ef.portfolio_performance(),
                               (0.25, 0.17149595234895817, 1.3411395245760582))
    sharpe = ef.portfolio_performance()[2]

    ef_long_only = setup_efficient_frontier()
    ef_long_only.efficient_return(0.25)
    long_only_sharpe = ef_long_only.portfolio_performance()[2]

    assert sharpe > long_only_sharpe
Esempio n. 9
0
def test_custom_nonconvex_objective_market_neutral_efficient_risk():
    # Recreate the market-neutral efficient_risk optimiser using this API
    target_risk = 0.19
    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(-1, 1))

    weight_constr = {"type": "eq", "fun": lambda w: np.sum(w)}
    risk_constr = {
        "type": "eq",
        "fun":
        lambda w: target_risk**2 - np.dot(w.T, np.dot(ef.cov_matrix, w)),
    }
    constraints = [weight_constr, risk_constr]

    ef.nonconvex_objective(
        lambda w, mu: -w.T.dot(mu),
        objective_args=(ef.expected_returns),
        weights_sum_to_one=False,
        constraints=constraints,
    )
    np.testing.assert_allclose(
        ef.portfolio_performance(),
        (0.2591296227818582, target_risk, 1.258574109251818),
        atol=1e-6,
    )
Esempio n. 10
0
def max_quad_utility_weights(rets_bl, covar_bl, config):
    print('Begin max quadratic utility optimization')
    returns, sigmas, weights, deltas = [], [], [], []
    for delta in np.arange(1, 10, 1):
        ef = EfficientFrontier(rets_bl, covar_bl, weight_bounds= \
                (config['min_position_size'] ,config['max_position_size']))
        ef.max_quadratic_utility(delta)
        ret, sigma, __ = ef.portfolio_performance()
        weights_vec = ef.clean_weights()
        returns.append(ret)
        sigmas.append(sigma)
        deltas.append(delta)
        weights.append(weights_vec)
    fig, ax = plt.subplots()
    ax.plot(sigmas, returns)
    for i, delta in enumerate(deltas):
        ax.annotate(str(delta), (sigmas[i], returns[i]))
    plt.xlabel('Volatility (%) ')
    plt.ylabel('Returns (%)')
    plt.title('Efficient Frontier for Max Quadratic Utility Optimization')
    plt.show()
    opt_delta = float(
        input('Enter the desired point on the efficient frontier: '))
    ef = EfficientFrontier(rets_bl, covar_bl, weight_bounds= \
            (config['min_position_size'] ,config['max_position_size']))
    ef.max_quadratic_utility(opt_delta)
    opt_weights = ef.clean_weights()
    opt_weights = pd.DataFrame.from_dict(opt_weights, orient='index')
    opt_weights.columns = ['Max Quad Util']
    return opt_weights, ef
Esempio n. 11
0
    def portfolio_opt(self):
        portfolio = self.portfolio.split(",")
        df = self.db.load_data(TableName.DAY,
                               time_from=self.time_from,
                               symbols=portfolio)
        # df = FinI.add_date_col(df)
        df = df[["close", "sym"]]
        df2 = df.copy()
        df2 = df2.drop(columns=["close", "sym"])
        for sym in portfolio:
            df2[sym] = df[df["sym"] == sym]["close"]

        df2 = df2.drop_duplicates()

        # df = df.transpose()
        # df.index = pd.to_datetime(df['date']).astype(int) / 10**9
        st.write(df2)
        # Calculate expected returns and sample covariance
        mu = expected_returns.mean_historical_return(df2)
        S = risk_models.sample_cov(df2)

        # Optimize for maximal Sharp ratio
        ef = EfficientFrontier(mu, S)
        raw_weights = ef.max_sharpe()
        cleaned_weights = ef.clean_weights()
        # ef.save_weights_to_file("weights.csv")  # saves to file
        st.write(cleaned_weights)
        mu, sigma, sharpe = ef.portfolio_performance(verbose=True)
        st.write("Expected annual return: {:.1f}%".format(100 * mu))
        st.write("Annual volatility: {:.1f}%".format(100 * sigma))
        st.write("Sharpe Ratio: {:.2f}".format(sharpe))
Esempio n. 12
0
def test_efficient_semivariance_vs_heuristic_weekly():
    benchmark = 0
    _, historic_returns = setup_efficient_semivariance(data_only=True)
    weekly_returns = historic_returns.resample("W").sum()
    mean_weekly_returns = weekly_returns.mean(axis=0)

    es = EfficientSemivariance(mean_weekly_returns,
                               weekly_returns,
                               frequency=52)
    es.efficient_return(0.20 / 52)
    mu_es, semi_deviation, _ = es.portfolio_performance()

    pairwise_semivariance = risk_models.semicovariance(weekly_returns,
                                                       returns_data=True,
                                                       benchmark=0,
                                                       frequency=1)
    ef = EfficientFrontier(mean_weekly_returns, pairwise_semivariance)
    ef.efficient_return(0.20 / 52)
    mu_ef, _, _ = ef.portfolio_performance()
    portfolio_returns = historic_returns @ ef.weights
    drops = np.fmin(portfolio_returns - benchmark, 0)
    T = weekly_returns.shape[0]
    semivariance = np.sum(np.square(drops)) / T * 52
    semi_deviation_ef = np.sqrt(semivariance)

    assert semi_deviation < semi_deviation_ef
    assert mu_es / semi_deviation > mu_ef / semi_deviation_ef
def test_efficient_return_market_neutral():
    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(-1, 1))
    w = ef.efficient_return(0.25, market_neutral=True)
    assert isinstance(w, dict)
    assert set(w.keys()) == set(ef.tickers)
    np.testing.assert_almost_equal(ef.weights.sum(), 0)
    assert (ef.weights < 1).all() and (ef.weights > -1).all()
    np.testing.assert_almost_equal(
        ef.portfolio_performance(),
        (0.25, 0.1833060046337015, 1.2547324920403273))
    sharpe = ef.portfolio_performance()[2]
    ef_long_only = setup_efficient_frontier()
    ef_long_only.efficient_return(0.25)
    long_only_sharpe = ef_long_only.portfolio_performance()[2]
    assert long_only_sharpe < sharpe
def test_efficient_return_short():
    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(None, None))
    w = ef.efficient_return(0.25)
    assert isinstance(w, dict)
    assert set(w.keys()) == set(ef.tickers)
    np.testing.assert_almost_equal(ef.weights.sum(), 1)
    np.testing.assert_allclose(ef.portfolio_performance(),
                               (0.25, 0.16826225873038014, 1.3669137793315087))
    sharpe = ef.portfolio_performance()[2]

    ef_long_only = setup_efficient_frontier()
    ef_long_only.efficient_return(0.25)
    long_only_sharpe = ef_long_only.portfolio_performance()[2]

    assert sharpe > long_only_sharpe
Esempio n. 15
0
def build_portfolio_weights(stock_data, weights_filename):

    # Calculate expected returns and sample covariance
    if isinstance(stock_data, pd.Series):
        stock_data = stock_data.to_frame()

    mu = expected_returns.mean_historical_return(stock_data)
    S = risk_models.sample_cov(stock_data)

    # Optimize for maximal Sharpe ratio
    ef = EfficientFrontier(mu, S)
    raw_weights = ef.max_sharpe()
    cleaned_weights = ef.clean_weights()
    ef.save_weights_to_file(weights_filename)  # saves to file
    ef.portfolio_performance(verbose=True)
    return cleaned_weights
def test_efficient_return_market_neutral():
    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(-1, 1))
    w = ef.efficient_return(0.25, market_neutral=True)
    assert isinstance(w, dict)
    assert set(w.keys()) == set(ef.tickers)
    np.testing.assert_almost_equal(ef.weights.sum(), 0)
    assert (ef.weights < 1).all() and (ef.weights > -1).all()
    np.testing.assert_almost_equal(
        ef.portfolio_performance(),
        (0.25, 0.20567263154580923, 1.1182819914898223))
    sharpe = ef.portfolio_performance()[2]
    ef_long_only = setup_efficient_frontier()
    ef_long_only.efficient_return(0.25)
    long_only_sharpe = ef_long_only.portfolio_performance()[2]
    assert long_only_sharpe > sharpe
Esempio n. 17
0
def show_ef(stocks: List[str], other_args: List[str]):
    parser = argparse.ArgumentParser(add_help=False, prog="ef")

    parser.add_argument(
        "-p",
        "--period",
        default="3mo",
        dest="period",
        help="period to get yfinance data from",
        choices=period_choices,
    )
    parser.add_argument(
        "-n", default=300, dest="n_port", help="number of portfolios to simulate"
    )

    try:
        ns_parser = parse_known_args_and_warn(parser, other_args)
        if not ns_parser:
            return
        if len(stocks) < 2:
            print("Please have at least 2 loaded tickers to calculate weights.\n")
            return

        stock_prices = process_stocks(stocks, ns_parser.period)
        mu = expected_returns.mean_historical_return(stock_prices)
        S = risk_models.sample_cov(stock_prices)
        ef = EfficientFrontier(mu, S)
        fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)

        # Generate random portfolios
        n_samples = ns_parser.n_port
        w = np.random.dirichlet(np.ones(len(mu)), n_samples)
        rets = w.dot(mu)
        stds = np.sqrt(np.diag(w @ S @ w.T))
        sharpes = rets / stds
        ax.scatter(stds, rets, marker=".", c=sharpes, cmap="viridis_r")

        plotting.plot_efficient_frontier(ef, ax=ax, show_assets=True)
        # Find the tangency portfolio
        ef.max_sharpe()
        ret_sharpe, std_sharpe, _ = ef.portfolio_performance()
        ax.scatter(std_sharpe, ret_sharpe, marker="*", s=100, c="r", label="Max Sharpe")

        ax.set_title("Efficient Frontier")
        ax.legend()
        plt.tight_layout()
        plt.grid(b=True, which="major", color="#666666", linestyle="-")
        plt.minorticks_on()
        plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)

        if gtff.USE_ION:
            plt.ion()

        plt.show()
        print("")

    except Exception as e:
        print(e)
        print("")
Esempio n. 18
0
def optimise_portfolio(stock_price, Portfolio):
    returns = stock_price.pct_change().dropna()
    # Calculate expected returns and sample covariance
    mu = expected_returns.mean_historical_return(stock_price)
    S = risk_models.sample_cov(stock_price)

    # Optimise for maximal Sharpe ratio
    ef = EfficientFrontier(mu, S)
    raw_weights = ef.max_sharpe()
    cleaned_weights = ef.clean_weights()
    ef.save_weights_to_file("weights.csv")  # saves to file
    print(cleaned_weights)
    ef.portfolio_performance(verbose=True)
    Portfolio.ef = ef
    Portfolio.mu = mu
    Portfolio.S = S
    Portfolio.weights = cleaned_weights
def test_ef_example_weekly():
    df = get_data()
    prices_weekly = df.resample("W").first()
    mu = expected_returns.mean_historical_return(prices_weekly, frequency=52)
    S = risk_models.sample_cov(prices_weekly, frequency=52)
    ef = EfficientFrontier(mu, S)
    ef.efficient_return(0.2)
    np.testing.assert_almost_equal(ef.portfolio_performance()[0], 0.2)
def test_ef_example():
    df = get_data()
    mu = expected_returns.mean_historical_return(df)
    S = risk_models.sample_cov(df)

    ef = EfficientFrontier(mu, S)
    ef.efficient_return(0.2)
    np.testing.assert_almost_equal(ef.portfolio_performance()[0], 0.2)
def test_max_quadratic_utility_market_neutral():
    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(-1, 1))
    ef.max_quadratic_utility(market_neutral=True)
    np.testing.assert_almost_equal(ef.weights.sum(), 0)
    np.testing.assert_allclose(
        ef.portfolio_performance(),
        (1.13434841843883, 0.9896404148973286, 1.1260134506071473),
    )
def test_max_sharpe_short():
    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(None, None))
    w = ef.max_sharpe()
    assert isinstance(w, dict)
    assert set(w.keys()) == set(ef.tickers)
    np.testing.assert_almost_equal(ef.weights.sum(), 1)
    np.testing.assert_allclose(
        ef.portfolio_performance(),
        (0.4072439477276246, 0.24823487545231313, 1.5599900981762558),
    )
    sharpe = ef.portfolio_performance()[2]

    ef_long_only = setup_efficient_frontier()
    ef_long_only.max_sharpe()
    long_only_sharpe = ef_long_only.portfolio_performance()[2]

    assert sharpe > long_only_sharpe
def test_min_volatility_short():
    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(None, None))
    w = ef.min_volatility()
    assert isinstance(w, dict)
    assert set(w.keys()) == set(ef.tickers)
    np.testing.assert_almost_equal(ef.weights.sum(), 1)
    np.testing.assert_allclose(
        ef.portfolio_performance(),
        (0.1721356467349655, 0.1555915367269669, 0.9777887019776287),
    )

    # Shorting should reduce volatility
    volatility = ef.portfolio_performance()[1]
    ef_long_only = setup_efficient_frontier()
    ef_long_only.min_volatility()
    long_only_volatility = ef_long_only.portfolio_performance()[1]
    assert volatility < long_only_volatility
def test_max_quadratic_utility_market_neutral():
    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(-1, 1))
    ef.max_quadratic_utility(market_neutral=True)
    np.testing.assert_almost_equal(ef.weights.sum(), 0)
    np.testing.assert_allclose(
        ef.portfolio_performance(),
        (1.248936321062371, 1.0219175004907117, 1.2025787996313317),
    )
def test_efficient_frontier_expected_returns_list():
    """Cover the edge case that the expected_returns param is a list."""
    ef = setup_efficient_frontier()
    ef.min_volatility()
    ef_r = EfficientFrontier(expected_returns=ef.expected_returns.tolist(),
                             cov_matrix=ef.cov_matrix)
    ef_r.min_volatility()
    np.testing.assert_equal(ef.portfolio_performance(),
                            ef_r.portfolio_performance())
def test_max_sharpe_short():
    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(None, None))
    w = ef.max_sharpe()
    assert isinstance(w, dict)
    assert set(w.keys()) == set(ef.tickers)
    np.testing.assert_almost_equal(ef.weights.sum(), 1)
    np.testing.assert_allclose(
        ef.portfolio_performance(),
        (0.4937195216716211, 0.29516576454651955, 1.6049270564945908),
    )
    sharpe = ef.portfolio_performance()[2]

    ef_long_only = setup_efficient_frontier()
    ef_long_only.max_sharpe()
    long_only_sharpe = ef_long_only.portfolio_performance()[2]

    assert sharpe > long_only_sharpe
def test_efficient_risk_market_neutral():
    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(-1, 1))
    w = ef.efficient_risk(0.21, market_neutral=True)
    assert isinstance(w, dict)
    assert set(w.keys()) == set(ef.tickers)
    np.testing.assert_almost_equal(ef.weights.sum(), 0)
    assert (ef.weights < 1).all() and (ef.weights > -1).all()
    np.testing.assert_allclose(
        ef.portfolio_performance(),
        (0.2552600197428133, 0.21, 1.1202858085349783),
        atol=1e-6,
    )
    sharpe = ef.portfolio_performance()[2]

    ef_long_only = setup_efficient_frontier()
    ef_long_only.efficient_risk(0.21)
    long_only_sharpe = ef_long_only.portfolio_performance()[2]
    assert long_only_sharpe > sharpe
def test_max_quadratic_utility_with_shorts():
    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(-1, 1))
    ef.max_quadratic_utility()
    np.testing.assert_almost_equal(ef.weights.sum(), 1)

    np.testing.assert_allclose(
        ef.portfolio_performance(),
        (1.3318330413711252, 1.0198436183533854, 1.2863080356272452),
    )
def test_max_quadratic_utility_with_shorts():
    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(-1, 1))
    ef.max_quadratic_utility()
    np.testing.assert_almost_equal(ef.weights.sum(), 1)

    np.testing.assert_allclose(
        ef.portfolio_performance(),
        (1.4170505733098597, 1.0438577623242156, 1.3383533884915872),
    )
Esempio n. 30
0
def test_efficient_risk_market_neutral():
    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(-1, 1))
    w = ef.efficient_risk(0.21, market_neutral=True)
    assert isinstance(w, dict)
    assert set(w.keys()) == set(ef.tickers)
    np.testing.assert_almost_equal(ef.weights.sum(), 0)
    assert (ef.weights < 1).all() and (ef.weights > -1).all()
    np.testing.assert_allclose(
        ef.portfolio_performance(),
        (0.28640632960825885, 0.20999999995100788, 1.2686015698590967),
        atol=1e-6,
    )
    sharpe = ef.portfolio_performance()[2]

    ef_long_only = setup_efficient_frontier()
    ef_long_only.efficient_risk(0.21)
    long_only_sharpe = ef_long_only.portfolio_performance()[2]
    assert long_only_sharpe > sharpe