예제 #1
0
def get_mu_sigma(prices, returns_model='mean_historical_return', risk_model='ledoit_wolf',
                 frequency=252, span=500):
    """Get mu (returns) and sigma (asset risk) given a expected returns model and risk model

        prices (pd.DataFrame) – adjusted closing prices of the asset,
            each row is a date and each column is a ticker/id.
        returns_model (string, optional) - Model for estimating expected returns of assets,
            either 'mean_historical_return' or 'ema_historical_return' (default: mean_historical_return)
        risk_model (string, optional) - Risk model to quantify risk: sample_cov, ledoit_wolf,
            defaults to ledoit_wolf, as recommended by Quantopian in their lecture series on quantitative finance.
        frequency (int, optional) – number of time periods in a year, defaults to 252 (the number of trading days in a year)
        span (int, optional) – Applicable only for 'ema_historical_return' expected returns.
            The time-span for the EMA, defaults to 500-day EMA)
    """
    CHOICES_EXPECTED_RETURNS = {
        'mean_historical_return': expected_returns.mean_historical_return(prices, frequency),
        'ema_historical_return': expected_returns.ema_historical_return(prices, frequency, span)
    }

    CHOICES_RISK_MODEL = {
        'sample_cov': risk_models.sample_cov(prices),
        'ledoit_wolf': risk_models.CovarianceShrinkage(prices).ledoit_wolf()
    }

    mu = CHOICES_EXPECTED_RETURNS.get(returns_model.lower(), None)
    S = CHOICES_RISK_MODEL.get(risk_model.lower(), None)

    if mu is None:
        raise Exception('Expected returns model %s is not supported. Only mean_historical_return and ema_historical_return are supported currently.' % risk_model)

    if S is None:
        raise Exception('Risk model %s is not supported. Only sample_cov and ledoit_wolf are supported currently.' % risk_model)

    return mu, S
예제 #2
0
def test_correlation_plot():
    plt.figure()
    df = get_data()
    S = risk_models.CovarianceShrinkage(df).ledoit_wolf()
    ax = plotting.plot_covariance(S, showfig=False)
    assert len(ax.findobj()) == 256
    plt.clf()
    ax = plotting.plot_covariance(S, plot_correlation=True, showfig=False)
    assert len(ax.findobj()) == 256
    plt.clf()
    ax = plotting.plot_covariance(S, show_tickers=False, showfig=False)
    assert len(ax.findobj()) == 136
    plt.clf()
    ax = plotting.plot_covariance(S,
                                  plot_correlation=True,
                                  show_tickers=False,
                                  showfig=False)
    assert len(ax.findobj()) == 136
    plt.clf()

    plot_filename = "tests/plot.png"
    ax = plotting.plot_covariance(S, filename=plot_filename, showfig=False)
    assert len(ax.findobj()) == 256
    assert os.path.exists(plot_filename)
    assert os.path.getsize(plot_filename) > 0
    os.remove(plot_filename)
    plt.clf()
    plt.close()
예제 #3
0
파일: BL_WebApp.py 프로젝트: grreis/app
def allocate(df):
    tickers = [df.columns[k] for k in range(df.shape[1])]

    ohlc = yf.download(tickers, start="2010-01-01", end="2020-01-01")
    prices = ohlc["Adj Close"]

    market_prices = yf.download("^BVSP", start="2010-01-01",
                                end="2020-01-01")["Adj Close"]

    mcaps = {}
    for t in tickers:
        stock = yf.Ticker(t)
        mcaps[t] = stock.info["marketCap"]

    S = risk_models.CovarianceShrinkage(prices).ledoit_wolf()
    delta = black_litterman.market_implied_risk_aversion(market_prices)

    market_prior = black_litterman.market_implied_prior_returns(
        mcaps, delta, S)

    bl = BlackLittermanModel(S,
                             pi="market",
                             market_caps=mcaps,
                             risk_aversion=delta,
                             absolute_views=df.to_dict('records')[0])

    ret_bl = bl.bl_returns()
    S_bl = bl.bl_cov()

    ef = EfficientFrontier(ret_bl, S_bl)
    ef.add_objective(objective_functions.L2_reg)
    ef.max_sharpe()
    weights = ef.clean_weights()

    return weights
예제 #4
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)
예제 #5
0
def test_correlation_plot():
    plt.figure()
    df = get_data()
    S = risk_models.CovarianceShrinkage(df).ledoit_wolf()
    ax = plotting.plot_covariance(S, showfig=False)
    assert len(ax.findobj()) == 256
    plt.clf()
    ax = plotting.plot_covariance(S, plot_correlation=True, showfig=False)
    assert len(ax.findobj()) == 256
    plt.clf()
    ax = plotting.plot_covariance(S, show_tickers=False, showfig=False)
    assert len(ax.findobj()) == 136
    plt.clf()
    ax = plotting.plot_covariance(S,
                                  plot_correlation=True,
                                  show_tickers=False,
                                  showfig=False)
    assert len(ax.findobj()) == 136
    plt.clf()

    temp_folder = tempfile.TemporaryDirectory()
    temp_folder_path = temp_folder.name
    plot_filename = os.path.join(temp_folder_path, "plot.png")
    ax = plotting.plot_covariance(S, filename=plot_filename, showfig=False)
    assert len(ax.findobj()) == 256
    assert os.path.exists(plot_filename)
    assert os.path.getsize(plot_filename) > 0
    temp_folder.cleanup()
    plt.clf()
    plt.close()
def get_corr(org_data):
    cov = risk_models.CovarianceShrinkage(org_data).ledoit_wolf()
    var = np.eye(cov.shape[0]) * cov
    std = np.power(var, 0.5)
    I = np.linalg.inv(std)
    corr = I.dot(cov).dot(I)
    return corr
예제 #7
0
def test_correlation_plot():
    df = get_data()

    S = risk_models.CovarianceShrinkage(df).ledoit_wolf()
    ax = Plotting.plot_covariance(S, showfig=False)
    assert len(ax.findobj()) == 256
    ax = Plotting.plot_covariance(S, show_tickers=False, showfig=False)
    assert len(ax.findobj()) == 136
예제 #8
0
def test_shrunk_covariance_frequency():
    df = get_data()
    cs = risk_models.CovarianceShrinkage(df, frequency=52)
    # if delta = 0, no shrinkage occurs
    shrunk_cov = cs.shrunk_covariance(0)

    S = risk_models.sample_cov(df, frequency=52)
    np.testing.assert_array_almost_equal(shrunk_cov.values, S)
예제 #9
0
def test_oracle_approximating():
    df = get_data()
    cs = risk_models.CovarianceShrinkage(df)
    shrunk_cov = cs.oracle_approximating()
    assert 0 < cs.delta < 1
    assert shrunk_cov.shape == (20, 20)
    assert list(shrunk_cov.index) == list(df.columns)
    assert list(shrunk_cov.columns) == list(df.columns)
    assert not shrunk_cov.isnull().any().any()
예제 #10
0
def test_ledoit_wolf():
    df = get_data()
    cs = risk_models.CovarianceShrinkage(df)
    shrunk_cov = cs.ledoit_wolf()
    assert 0 < cs.delta < 1
    assert shrunk_cov.shape == (20, 20)
    assert list(shrunk_cov.index) == list(df.columns)
    assert list(shrunk_cov.columns) == list(df.columns)
    assert not shrunk_cov.isnull().any().any()
예제 #11
0
def test_shrunk_covariance():
    df = get_data()
    cs = risk_models.CovarianceShrinkage(df)
    shrunk_cov = cs.shrunk_covariance(0.2)
    assert cs.delta == 0.2
    assert shrunk_cov.shape == (20, 20)
    assert list(shrunk_cov.index) == list(df.columns)
    assert list(shrunk_cov.columns) == list(df.columns)
    assert not shrunk_cov.isnull().any().any()
    assert risk_models._is_positive_semidefinite(shrunk_cov)
    with pytest.warns(RuntimeWarning) as w:
        cs_numpy = risk_models.CovarianceShrinkage(df.to_numpy())
        assert len(w) == 1
        assert str(w[0].message) == "data is not in a dataframe"
        shrunk_cov_numpy = cs_numpy.shrunk_covariance(0.2)
        assert isinstance(shrunk_cov_numpy, pd.DataFrame)
        np.testing.assert_equal(shrunk_cov_numpy.to_numpy(),
                                shrunk_cov.to_numpy())
예제 #12
0
def test_shrunk_covariance():
    df = get_data()
    cs = risk_models.CovarianceShrinkage(df)
    shrunk_cov = cs.shrunk_covariance(0.2)
    assert cs.delta == 0.2
    assert shrunk_cov.shape == (20, 20)
    assert list(shrunk_cov.index) == list(df.columns)
    assert list(shrunk_cov.columns) == list(df.columns)
    assert not shrunk_cov.isnull().any().any()
예제 #13
0
def test_bl_cov_default():
    df = get_data()
    cov_matrix = risk_models.CovarianceShrinkage(df).ledoit_wolf()
    viewdict = {"AAPL": 0.20, "BBY": -0.30, "BAC": 0, "SBUX": -0.2, "T": 0.131321}
    bl = BlackLittermanModel(cov_matrix, absolute_views=viewdict)
    S = bl.bl_cov()
    assert S.shape == (20, 20)
    assert S.index.equals(df.columns)
    assert S.index.equals(S.columns)
    assert S.notnull().all().all()
예제 #14
0
def test_ledoit_wolf_constant_correlation():
    df = get_data()
    cs = risk_models.CovarianceShrinkage(df)
    shrunk_cov = cs.ledoit_wolf(shrinkage_target="constant_correlation")
    assert 0 < cs.delta < 1
    assert shrunk_cov.shape == (20, 20)
    assert list(shrunk_cov.index) == list(df.columns)
    assert list(shrunk_cov.columns) == list(df.columns)
    assert not shrunk_cov.isnull().any().any()
    assert risk_models._is_positive_semidefinite(shrunk_cov)
예제 #15
0
def test_shrunk_covariance_extreme_delta():
    df = get_data()
    cs = risk_models.CovarianceShrinkage(df)
    # if delta = 0, no shrinkage occurs
    shrunk_cov = cs.shrunk_covariance(0)
    np.testing.assert_array_almost_equal(shrunk_cov.values, risk_models.sample_cov(df))
    # if delta = 1, sample cov does not contribute to shrunk cov
    shrunk_cov = cs.shrunk_covariance(1)
    N = df.shape[1]
    F = np.identity(N) * np.trace(cs.S) / N
    np.testing.assert_array_almost_equal(shrunk_cov.values, F * 252)
def test_efficient_return_shrunk():
    df = get_data()
    ef = setup_efficient_frontier()
    ef.cov_matrix = risk_models.CovarianceShrinkage(df).ledoit_wolf(
        shrinkage_target="single_factor")
    w = ef.efficient_return(0.22)
    assert isinstance(w, dict)
    assert set(w.keys()) == set(ef.tickers)
    np.testing.assert_almost_equal(ef.weights.sum(), 1)
    assert all([i >= 0 for i in w.values()])
    np.testing.assert_allclose(ef.portfolio_performance(),
                               (0.22, 0.0849639369932322, 2.353939884117318))
예제 #17
0
 def build_portfolio(self, price_pivot, portfolio_total=10000):
     ''' build a portfolio from price data'''
     mu = expected_returns.mean_historical_return(price_pivot)
     shrink = risk_models.CovarianceShrinkage(price_pivot)
     S = shrink.ledoit_wolf()
     ef = EfficientFrontier(mu, S, weight_bounds=(0, 0.2), gamma=0.8)
     weights = ef.max_sharpe()
     weights = ef.clean_weights()
     latest_prices = get_latest_prices(price_pivot)
     weights = {k: v for k, v in weights.items() if weights[k] > 0.0}
     da = DiscreteAllocation(weights, latest_prices, total_portfolio_value=portfolio_total)
     allocation, leftover = da.lp_portfolio()
     # print("Discrete allocation:", allocation)
     return allocation
예제 #18
0
def get_weights(data,
                start_date,
                end_date,
                columns,
                n_threads=1,
                fixed='sharpe',
                value=0.05):
    """

    :param data: DataFrame,
        Full data without missing values, columns are identifiers
        for different funds, index is datetime.
    :param start_date: str
        Start date to estimate mu and sigma.
    :param end_date: str
        End date to estimate mu and sigma.
    :param columns: list, ['id1', 'id2',..., 'idn']
        Identifiers of funds to use to optimize.
    :param n_threads: int
        Number of threads.
    :param fixed: str, 'sharpe' or 'volatility' or 'return'
        Optimization constraints, defaults to 'sharpe'.
    :param value: float
        Optimization constraints. No need to set if fixed is
        'sharpe', defaults to 0.05.
    :return: tuple, (float, float, float, dict)
        The closest answer given fixed constraints.
        (return, volatility, Sharpe ratio, weights)
        weights == {'id1':w1, 'id2':w2, ..., 'idn':wn}
    """
    while start_date not in data.index:
        splits = start_date.split('-')
        y, m, d = int(splits[0]), int(splits[1]), int(splits[2])
        start_date = (datetime.datetime(y, m, d) +
                      datetime.timedelta(days=1)).strftime('%Y-%m-%d')
    while end_date not in data.index:
        splits = end_date.split('-')
        y, m, d = int(splits[0]), int(splits[1]), int(splits[2])
        end_date = (datetime.datetime(y, m, d) +
                    datetime.timedelta(days=-1)).strftime('%Y-%m-%d')

    # print(start_date)
    # print(end_date)
    subdata = data.loc[start_date:end_date, columns]
    optimizer = PortfolioOptimizer(
        expected_returns.ema_historical_return(subdata),
        risk_models.CovarianceShrinkage(subdata).ledoit_wolf())
    optimizer.optimize(n_threads=n_threads)
    return optimizer.get_fixed_ans(fixed, value)
def test_min_volatilty_shrunk_L2_reg():
    df = get_data()
    ef = setup_efficient_frontier()
    ef.add_objective(objective_functions.L2_reg)

    ef.cov_matrix = risk_models.CovarianceShrinkage(df).ledoit_wolf(
        shrinkage_target="constant_correlation")
    w = ef.min_volatility()

    assert isinstance(w, dict)
    assert set(w.keys()) == set(ef.tickers)
    np.testing.assert_almost_equal(ef.weights.sum(), 1)
    assert all([i >= 0 for i in w.values()])
    np.testing.assert_allclose(
        ef.portfolio_performance(),
        (0.17358178582309983, 0.19563960638632416, 0.7850239972361532),
    )
예제 #20
0
    def weight(
        self,
        market_state: pd.DataFrame,
        agent_portfolio: Dict[str, float],
        is_recommendation: bool = False,
    ) -> Dict[str, float]:
        # make default weight map

        weights = {}
        stocks = set(market_state.symbol.unique())
        for stock in stocks:
            weights[stock] = 0.0

        current_date = market_state.date.max()

        if current_date.year == market_state.date.min().year:
            # there is no previous year
            return weights
        if not is_recommendation:
            if current_date != market_state.loc[market_state.date.dt.year ==
                                                current_date.year].date.min():

                # it's not the first trading day of the current year
                if current_date == self.all_dates[
                    (self.all_dates.date.dt.year == current_date.year)
                        & (self.all_dates.date.dt.month == 12)].date.max():
                    for stock in agent_portfolio.keys():
                        weights[stock] = -1
                    return weights
                return weights

        prices = market_state.pivot(values="adjusted_close",
                                    index="date",
                                    columns="symbol")

        # Get Mu and sigma for efficient frontier
        mu = expected_returns.mean_historical_return(prices)
        sigma = risk_models.CovarianceShrinkage(prices).ledoit_wolf()

        # Calculate efficient portfolio, objective: maximize sharpe ratio
        ef = EfficientFrontier(mu, sigma, weight_bounds=(0, 1))
        ef.max_sharpe()
        cleaned_weights = ef.clean_weights()

        print(cleaned_weights)
        return dict(cleaned_weights)
def test_min_volatilty_shrunk_L2_reg():
    df = get_data()
    ef = setup_efficient_frontier()
    ef.add_objective(objective_functions.L2_reg)

    ef.cov_matrix = risk_models.CovarianceShrinkage(df).ledoit_wolf(
        shrinkage_target="constant_correlation")
    w = ef.min_volatility()

    assert isinstance(w, dict)
    assert set(w.keys()) == set(ef.tickers)
    np.testing.assert_almost_equal(ef.weights.sum(), 1)
    assert all([i >= 0 for i in w.values()])
    np.testing.assert_allclose(
        ef.portfolio_performance(),
        (0.23127405291296832, 0.19563921371709164, 1.079916694096337),
    )
예제 #22
0
 def fit(self, prices: pd.DataFrame):
     # TODO: make prices instance of portfolio
     '''
     Given prices finds wieghts (coefficients), most optimal portfolio given target function.
     :param prices:
     :return:
     '''
     self.frequency = autodetect_frequency(prices)
     self.mu = expected_returns.mean_historical_return(
         prices, frequency=self.frequency)
     self.S = risk_models.CovarianceShrinkage(
         prices, frequency=self.frequency).ledoit_wolf()
     # self.S=risk_models.exp_cov(prices)
     self.ef = EfficientFrontier(self.mu, self.S)
     self.ef.add_objective(objective_functions.L2_reg)
     getattr(self.ef, self.target_function)(**self.target_function_params)
     self.coef_ = self.ef.clean_weights()
     return self
예제 #23
0
def test_bl_relative_views():
    df = get_data()
    S = risk_models.CovarianceShrinkage(df).ledoit_wolf()

    # 1. SBUX will drop by 20%
    # 2. GOOG outperforms FB by 10%
    # 3. BAC and JPM will outperform T and GE by 15%
    views = np.array([-0.20, 0.10, 0.15]).reshape(-1, 1)
    picking = np.array([
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
        [1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, -0.5, 0, 0, 0.5, 0, -0.5, 0, 0, 0, 0, 0, 0, 0, 0.5, 0],
    ])

    bl = BlackLittermanModel(S, Q=views, P=picking)
    rets = bl.bl_returns()
    assert rets["SBUX"] < 0
    assert rets["GOOG"] > rets["FB"]
    assert (rets["BAC"] > rets["T"]) and (rets["JPM"] > rets["GE"])
def test_bl_returns_all_views():
    df = get_data()
    prior = expected_returns.ema_historical_return(df)
    S = risk_models.CovarianceShrinkage(df).ledoit_wolf()
    views = pd.Series(0.1, index=S.columns)

    bl = BlackLittermanModel(S, pi=prior, Q=views)
    posterior_rets = bl.bl_returns()
    assert isinstance(posterior_rets, pd.Series)
    assert list(posterior_rets.index) == list(df.columns)
    assert posterior_rets.notnull().all()
    assert posterior_rets.dtype == "float64"

    np.testing.assert_array_almost_equal(
        posterior_rets,
        np.array(
            [
                0.11774473,
                0.1709139,
                0.12180833,
                0.21202423,
                0.28120945,
                -0.2787358,
                0.17274774,
                0.12714698,
                0.25492005,
                0.11229777,
                0.07182723,
                -0.01521839,
                -0.21235465,
                0.06399515,
                -0.11738365,
                0.28865661,
                0.23828607,
                0.12038049,
                0.2331218,
                0.10485376,
            ]
        ),
    )
예제 #25
0
def test_bl_returns_all_views():
    df = get_data()
    prior = expected_returns.ema_historical_return(df)
    S = risk_models.CovarianceShrinkage(df).ledoit_wolf()
    views = pd.Series(0.1, index=S.columns)

    bl = BlackLittermanModel(S, pi=prior, Q=views)
    posterior_rets = bl.bl_returns()
    assert isinstance(posterior_rets, pd.Series)
    assert list(posterior_rets.index) == list(df.columns)
    assert posterior_rets.notnull().all()
    assert posterior_rets.dtype == "float64"

    np.testing.assert_array_almost_equal(
        posterior_rets,
        np.array(
            [
                0.11168648,
                0.16782938,
                0.12516799,
                0.24067997,
                0.32848296,
                -0.22789895,
                0.16311297,
                0.11928542,
                0.25414308,
                0.11007738,
                0.06282615,
                -0.03140218,
                -0.16977172,
                0.05254821,
                -0.10463884,
                0.32173375,
                0.26399864,
                0.1118594,
                0.22999558,
                0.08977448,
            ]
        ),
    )
예제 #26
0
def mean_var(my_portfolio, vol_max=0.15, perf=True) -> list:
    # changed to take in desired timeline, the problem is that it would use all historical data

    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)

    # sometimes we will pick a date range where company isn't public we can't set price to 0 so it has to go to 1
    prices = prices.fillna(1)

    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.efficient_risk(vol_max)
    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)
예제 #27
0
def calculateInvestment(limit=10,
                        count=10,
                        write_to_file=True,
                        show_cla=False,
                        tpv=20000):
    symbols = getSymbolsFromDatabase()
    prices = createDataFrame(symbols[:limit], count)
    mu = expected_returns.mean_historical_return(prices)
    S = risk_models.CovarianceShrinkage(prices).ledoit_wolf()
    ef = EfficientFrontier(mu, S, weight_bounds=(-1, 1))
    ef.add_objective(objective_functions.L2_reg)
    ef.min_volatility()
    c_weights = ef.clean_weights()
    if write_to_file == True:
        ef.save_weights_to_file("weights.txt")
    if show_cla == True:
        cla = CLA(mu, S)
        ef_plot(cla)
    ef.portfolio_performance(verbose=True)
    latest_prices = disc_alloc.get_latest_prices(prices)
    allocation_minv, leftover = disc_alloc.DiscreteAllocation(
        c_weights, latest_prices, total_portfolio_value=tpv).lp_portfolio()
    return allocation_minv, leftover
예제 #28
0
def test_ledoit_wolf_raises_not_implemented():
    df = get_data()
    cs = risk_models.CovarianceShrinkage(df)
    with pytest.raises(NotImplementedError):
        cs.ledoit_wolf(shrinkage_target="I have not been implemented!")
예제 #29
0
def test_covariance_shrinkage_init():
    df = get_data()
    cs = risk_models.CovarianceShrinkage(df)
    assert cs.S.shape == (20, 20)
    assert not (np.isnan(cs.S)).any()
예제 #30
0
    downside = long_df.loc[long_df["foxInstrumentName"] == i]["downsidePrice"].values[0]
    down[i] = downside
    exp_ret_upside[i] = ((upside + carry) - current) / current
    skew[i] = (((upside + carry) - current) / current) / (
        (current - (downside)) / current
    )

exp_ret = pd.Series(exp_ret_upside)
skw = pd.Series(skew)
#%%

sector_upper["Oil & Oil Services"] = 0.25
sector_upper["Consumer & Retail"] = 0.25

mu = expected_returns.mean_historical_return(df)
S = risk_models.CovarianceShrinkage(df).ledoit_wolf()
#plotting.plot_covariance(S)
corr = df.corr()


layout = go.Layout(title='Correlation Heatmap',
                   xaxis=dict(tickfont = dict(size = 6)
                              ),
                   yaxis=dict(tickfont = dict(size = 6)
                              ),
                   showlegend=True,
                   )

fig = go.Figure(data=go.Heatmap(
    z=corr,
    x=df.columns,