Esempio n. 1
0
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
Esempio n. 2
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)
Esempio n. 3
0
def optimMarkowitz(datatrain, datatest, pmin, pmax, optimmodel, returnmodel,
                   riskmodel, Gam, rf):

    try:
        if returnmodel == 'historical':
            mu = expected_returns.mean_historical_return(datatrain)
        elif returnmodel == 'emahistorical':
            mu = expected_returns.ema_historical_return(datatrain)

        if riskmodel == 'historicalcov':
            S = risk_models.sample_cov(datatrain)
        elif riskmodel == 'exphistoricalcov':
            S = risk_models.exp_cov(datatrain)

        ef = EfficientFrontier(mu, S, weight_bounds=(pmin, pmax))

        #gamma>0 permet de forcer l'optimiseur à utiliser plus de titres
        ef.add_objective(objective_functions.L2_reg, gamma=Gam)

        if optimmodel == 'min_volatility':
            ef.min_volatility()
        elif optimmodel == 'max_sharpe':
            ef.max_sharpe(risk_free_rate=rf)

        cleaned_weights = ef.clean_weights()  #round and clean ...
        ef.save_weights_to_file(
            '/Users/Maxime/AMUNDI/PortMgmnt/ModulePyPortfolioOpt/OptimiseurProjet/weights.csv'
        )  # save to file
        perf = ef.portfolio_performance(verbose=True, risk_free_rate=rf)
        weightsfinal = pd.read_csv(
            '/Users/Maxime/AMUNDI/PortMgmnt/ModulePyPortfolioOpt/OptimiseurProjet/weights.csv',
            header=None)

        #For the following chart
        poids = weightsfinal.to_numpy()
        poids = poids[:, 1]
        RankedDataFrame = pd.DataFrame(index=datatest.index)

        for i, rows in weightsfinal.iterrows():
            RankedDataFrame[rows[0]] = datatest[rows[0]]
        weightsfinal.rename(columns={
            0: ' Asset Class',
            1: 'Poids'
        },
                            inplace=True)
        weightsfinal['Poids'] = round(weightsfinal['Poids'] * 100, 4)

    except ValueError:
        print('Le modèle spécifié est incorrect')

    return poids, RankedDataFrame, cleaned_weights, S, mu, perf
def test_efficient_risk_market_neutral_L2_reg():
    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(-1, 1))
    ef.add_objective(objective_functions.L2_reg)

    w = ef.efficient_risk(0.19, 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.10755645826336145, 0.11079556786108302, 0.7902523535340413),
        atol=1e-6,
    )
def test_efficient_risk_market_neutral_L2_reg():
    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(-1, 1))
    ef.add_objective(objective_functions.L2_reg)

    w = ef.efficient_risk(0.19, 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.12790320789339854, 0.1175336636355454, 0.9180621496492316),
        atol=1e-6,
    )
def test_max_sharpe_L2_reg_with_shorts():
    ef_no_reg = setup_efficient_frontier()
    ef_no_reg.max_sharpe()
    initial_number = sum(ef_no_reg.weights > 0.01)

    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(None, None))
    ef.add_objective(objective_functions.L2_reg)
    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.3076093180094401, 0.22415982749409985, 1.2830546901496447),
    )
    new_number = sum(ef.weights > 0.01)
    assert new_number >= initial_number
def test_max_sharpe_L2_reg_with_shorts():
    ef_no_reg = setup_efficient_frontier()
    ef_no_reg.max_sharpe()
    initial_number = sum(ef_no_reg.weights > 0.01)

    ef = EfficientFrontier(*setup_efficient_frontier(data_only=True),
                           weight_bounds=(None, None))
    ef.add_objective(objective_functions.L2_reg)
    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.2995338981166366, 0.2234696161770517, 1.2508810052063901),
    )
    new_number = sum(ef.weights > 0.01)
    assert new_number >= initial_number
Esempio n. 8
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)
Esempio n. 9
0
    :type skew: np.ndarray
    :param cov_matrix: covariance matrix
    :type cov_matrix: np.ndarray
    :param negative: whether quantity should be made negative (so we can minimise) 
    :type negative: boolean
    :return: (negative) Sharpe ratio
    :rtype: float
    """
    sk = w @ skew
    sign = -1 if negative else 1
    return sign * sk


ef_skew = EfficientFrontier(exp_ret, S, weight_bounds=(0.0, 0.15))
ef_skew.add_sector_constraints(sector_mapper, sector_lower, sector_upper)
ef_skew.add_objective(objective_functions.L2_reg, gamma=20)
#ef.add_objective(minimize_negative_skew, skew= skw)
ef_skew.convex_objective(minimize_negative_skew, skew=skw)
#ef.max_sharpe()
weights_skew = ef_skew.clean_weights()
weights_skew
ef_skew.portfolio_performance(verbose=True)

# %%

weight_dict = { 
    "Miniumum Variance" : weights_minvol,
    "Maximum Sharpe Ratio" : weights_maxsharpe,
    "Maximum Quadratic Utility" : weights_maxquad, 
    "Efficient Target Risk" : weights_effrisk,
    "Efficient Target Return" : weights_effret, 
Esempio n. 10
0
print("Funds remaining: ${:.2f}".format(leftover))
"""
Expected annual return: 33.0%
Annual volatility: 21.7%
Sharpe Ratio: 1.43

Discrete allocation: {'AAPL': 5.0, 'FB': 11.0, 'BABA': 5.0, 'AMZN': 1.0, 
                      'BBY': 7.0, 'MA': 14.0, 'PFE': 50.0, 'SBUX': 5.0}
Funds remaining: $8.42
"""

# Long-only minimum volatility portfolio, with a weight cap and regularisation
# e.g if we want at least 15/20 tickers to have non-neglible weights, and no
# asset should have a weight greater than 10%
ef = EfficientFrontier(mu, S, weight_bounds=(0, 0.10))
ef.add_objective(objective_functions.L2_reg, gamma=0.1)
weights = ef.min_volatility()
print(weights)
ef.portfolio_performance(verbose=True)
"""
{'GOOG': 0.0584267903998156,
 'AAPL': 0.0369081348579286,
 'FB': 0.0997609043032782,
 'BABA': 0.1,
 'AMZN': 0.0,
 'GE': 0.0646457157900559,
 'AMD': 0.0,
 'WMT': 0.1,
 'BAC': 0.0,
 'GM': 0.1,
 'T': 0.1,
Esempio n. 11
0
class OptPortfolio(BaseEstimator):
    '''
    Portfolio optimization used both for train and validation
    '''
    def __init__(self,
                 target_function: str = "efficient_risk",
                 target_function_params: dict = {},
                 budget: int = 10000):
        self.target_function = target_function
        self.target_function_params = target_function_params
        self.budget = budget
        self.frequency = None
        # self.mu = expected_returns.mean_historical_return(prices)
        # self.S = risk_models.CovarianceShrinkage(prices).ledoit_wolf()
        # self.ef = EfficientFrontier(self.mu, self.S)
        # self.ef.add_objective(objective_functions.L2_reg)
        # getattr(self.ef,target_function)(**target_function_params)
        # self.weights = self.ef.clean_weights()
        #
        # self.da = DiscreteAllocation(self.weights, prices.iloc[-1], total_portfolio_value=money)
        # alloc, leftover = self.da.lp_portfolio()
        # print(f"Leftover: ${leftover:.2f}")
        # print(f"Alloc: ${alloc:.2f}")
        # self.discrete_portfolio = (
        #         prices[[k for k, v in alloc.items()]] * np.asarray([[v for k, v in alloc.items()]])).dropna().sum(
        # axis=1)

    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

    def predict(self, prices: pd.DataFrame):
        '''
        Predicts portfolio given found optimal portoflio weights.
        :param prices:
        :return: optimal portofolio (in currency of input)
        '''
        self.allocate(prices)
        # da = DiscreteAllocation(self.coef_, prices.iloc[-1], total_portfolio_value=self.budget)
        # alloc, leftover = da.lp_portfolio()
        # print(f"Leftover: ${leftover:.2f}")
        # print(f"Alloc: ${alloc}")
        discrete_portfolio = (
            prices[[k for k, v in self.alloc.items()]] *
            np.asarray([[v for k, v in self.alloc.items()]])).dropna()
        return discrete_portfolio

    def allocate(self, prices: pd.DataFrame) -> Tuple[dict, float]:
        '''
        Given weights for portfolio and last prices, finds best discrete allocation of assets.
        :param prices:
        :return: allocation and leftover of portfolio
        '''
        da = DiscreteAllocation(self.coef_,
                                prices.iloc[-1],
                                total_portfolio_value=self.budget)
        self.alloc, self.leftover = da.lp_portfolio()
        print("Period end:", prices.index[0])
        print(f"Leftover: ${self.leftover:.2f}")
        print(f"Alloc: ${self.alloc}")

        return self.alloc, self.leftover

    @property
    def weights(self):
        return self.coef_

    @property
    def allocations(self):
        return self.alloc

    @property
    def leftover(self):
        return self.leftover
Esempio n. 12
0
vtabx_history = vtabx_raw_history[[
    'Adj Close'
]].copy().rename(columns={"Adj Close": "VTABX"})

merged_history = pd.merge(vtsax_history,
                          vtiax_history,
                          left_index=True,
                          right_index=True)
merged_history = merged_history.merge(vbtlx_history,
                                      left_index=True,
                                      right_index=True)
merged_history = merged_history.merge(vtabx_history,
                                      left_index=True,
                                      right_index=True)
print(merged_history)

# Calculate expected returns and sample covariance
mu = expected_returns.mean_historical_return(merged_history)
print(mu)
S = risk_models.sample_cov(merged_history)
print(S)

# Optimise for 10% return, maybe reasonable for long term goals
ef = EfficientFrontier(mu, S)
ef.add_objective(objective_functions.L2_reg, gamma=1)
raw_weights = ef.max_sharpe()
#raw_weights = ef.efficient_return(target_return=0.12)
cleaned_weights = ef.clean_weights()
print(cleaned_weights)
ef.portfolio_performance(verbose=True)
Esempio n. 13
0
#different risk models; guessing that you can also use the pandas.cov function
S = risk_models.semicovariance(prices)
T = risk_models.CovarianceShrinkage(prices).ledoit_wolf()

plotting.plot_covariance(S)
plotting.plot_covariance(T)

#equal weights
initial_weights = np.array([1 / len(tickers)] * len(tickers))
print(initial_weights)

#transaction cost objective
ef = EfficientFrontier(mum, T)
# 1% broker commission
ef.add_objective(objective_functions.transaction_cost,
                 w_prev=initial_weights,
                 k=0.01)
ef.min_volatility()
weights = ef.clean_weights()
weights

# smaller broker comms
ef = EfficientFrontier(mu, S)
ef.add_objective(objective_functions.transaction_cost,
                 w_prev=initial_weights,
                 k=0.001)
ef.min_volatility()
weights = ef.clean_weights()
weights

#limit number of zero weights