def test_custom_lower_bound(): ef = EfficientFrontier( *setup_efficient_frontier(data_only=True), weight_bounds=(0.02, 1) ) ef.max_sharpe() assert ef.weights.min() >= 0.02 np.testing.assert_almost_equal(ef.weights.sum(), 1)
def getMinVolatilityPortfolio(data): mu, Sigma = getMuSigma(data) ef = EfficientFrontier(mu, Sigma) raw_weights = ef.min_volatility() weights = ef.clean_weights() performance = ef.portfolio_performance() return weights, performance
def test_lp_portfolio_allocation_different_params(): df = get_data() mu = mean_historical_return(df) S = sample_cov(df) ef = EfficientFrontier(mu, S) w = ef.max_sharpe() latest_prices = get_latest_prices(df) da = DiscreteAllocation(w, latest_prices, total_portfolio_value=80000, short_ratio=0.4) allocation, leftover = da.lp_portfolio() # assert allocation == { # "GOOG": 3, # "AAPL": 32, # "FB": 99, # "BABA": 34, # "AMZN": 2, # "BBY": 15, # "MA": 164, # "PFE": 438, # "SBUX": 15, # } total = 0 for ticker, num in allocation.items(): total += num * latest_prices[ticker] np.testing.assert_almost_equal(total + leftover, 80000, decimal=4)
def test_lp_portfolio_allocation_different_params(): df = get_data() mu = mean_historical_return(df) S = sample_cov(df) ef = EfficientFrontier(mu, S) w = ef.max_sharpe() latest_prices = get_latest_prices(df) da = DiscreteAllocation( w, latest_prices, min_allocation=0.002, total_portfolio_value=80000, short_ratio=0.4, ) allocation, leftover = da.lp_portfolio() assert da.allocation == { "GOOG": 1, "AAPL": 43, "FB": 95, "BABA": 44, "AMZN": 4, "BBY": 69, "MA": 114, "PFE": 412, "SBUX": 51, } total = 0 for ticker, num in allocation.items(): total += num * latest_prices[ticker] np.testing.assert_almost_equal(total + leftover, 80000)
def get_momentum_stocks(df, date, portfolio_size, cash): # Filter the df to get the top 10 momentum stocks for the latest day df_top_m = df.loc[df['date'] == pd.to_datetime(date)] df_top_m = df_top_m.sort_values( by='momentum', ascending=False).head(portfolio_size) # Set the universe to the top momentum stocks for the period universe = df_top_m['symbol'].tolist() # Create a df with just the stocks from the universe df_u = df.loc[df['symbol'].isin(universe)] # Create the portfolio # Pivot to format for the optimization library df_u = df_u.pivot_table(index='date', columns='symbol', values='close', aggfunc='sum') # Calculate expected returns and sample covariance mu = expected_returns.mean_historical_return(df_u) S = risk_models.sample_cov(df_u) # Optimise the portfolio for maximal Sharpe ratio ef = EfficientFrontier(mu, S, gamma=1) # Use regularization (gamma=1) weights = ef.max_sharpe() cleaned_weights = ef.clean_weights() # Allocate latest_prices = get_latest_prices(df_u) da = DiscreteAllocation(cleaned_weights, latest_prices, total_portfolio_value=cash) allocation = da.lp_portfolio()[0] # Put the stocks and the number of shares from the portfolio into a df symbol_list = [] num_shares_list = [] for symbol, num_shares in allocation.items(): symbol_list.append(symbol) num_shares_list.append(num_shares) # Now that we have the stocks we want to buy we filter the df for those ones df_buy = df.loc[df['symbol'].isin(symbol_list)] # Filter for the period to get the closing price df_buy = df_buy.loc[df_buy['date'] == date].sort_values( by='symbol') # Add in the qty that was allocated to each stock df_buy['qty'] = num_shares_list # Calculate the amount we own for each stock df_buy['amount_held'] = df_buy['close'] * df_buy['qty'] df_buy = df_buy.loc[df_buy['qty'] != 0] return df_buy
def get_mean_variance_share_allocation(): dates, ticker_to_closing_prices = get_ticker_to_closing_prices( START_DATE, TEST_START_DATE - timedelta(days=1)) tickers = ticker_to_closing_prices.keys() prices = list( zip(*[ticker_to_closing_prices[ticker] for ticker in tickers])) df = pd.DataFrame( prices, index=dates, columns=tickers, ) mu = mean_historical_return(df) S = CovarianceShrinkage(df).ledoit_wolf() ef = EfficientFrontier(mu, S) weights = ef.max_sharpe() _, ticker_to_closing_prices_at_test_start = get_ticker_to_closing_prices( TEST_START_DATE, TEST_END_DATE) prices_at_test_start = pd.Series([ float(ticker_to_closing_prices_at_test_start[ticker][0]) for ticker in tickers ], index=tickers) da = DiscreteAllocation(weights, prices_at_test_start, total_portfolio_value=INITIAL_PORTFOLIO_VAL) allocation, leftover = da.lp_portfolio() for ticker in tickers: if ticker not in allocation: allocation[ticker] = 0 return allocation
def test_allocation_errors(): df = get_data() mu = mean_historical_return(df) S = sample_cov(df) ef = EfficientFrontier(mu, S) w = ef.max_sharpe() latest_prices = get_latest_prices(df) assert DiscreteAllocation(w, latest_prices) with pytest.raises(TypeError): DiscreteAllocation(ef.weights, latest_prices) with pytest.raises(TypeError): DiscreteAllocation(w, latest_prices.values.tolist()) with pytest.raises(ValueError): DiscreteAllocation(w, latest_prices, total_portfolio_value=0) with pytest.raises(ValueError): DiscreteAllocation(w, latest_prices, short_ratio=-0.4) with pytest.raises(NameError): da = DiscreteAllocation(w, latest_prices) da.lp_portfolio(solver="ABCDEF") w2 = w.copy() w2["AAPL"] = np.nan with pytest.raises(ValueError): DiscreteAllocation(w2, latest_prices) latest_prices.iloc[0] = np.nan with pytest.raises(TypeError): DiscreteAllocation(w, latest_prices)
def get_sorted_weights(prices): ''' prices: dataframe of the following shape. Column as symbols, Date as indices AAL AAPL GOOGL Date 2014-02-14 32.439728 17.411098 0.00 2014-02-15 32.439728 17.411098 0.00 ''' # calculate parameters mu = expected_returns.mean_historical_return(prices) S = risk_models.sample_cov(prices) # remove infinite values symbols = prices.columns for symbol in symbols: # if value is infinite mu_value = mu[symbol] if not np.isfinite(mu_value) or mu_value == 0: # delete from means del mu[symbol] # delete from sample covariance S.drop(symbol, axis=1, inplace=True) S.drop(symbol, axis=0, inplace=True) # calculate efficient frontier ef = EfficientFrontier(mu, S) weights = ef.max_sharpe() cleaned_weights = ef.clean_weights() sorted_weights = sorted(cleaned_weights.items(), key=lambda x: -x[1]) return sorted_weights
def expected_r(tickers, start_date): today = pd.datetime.today() if start_date == '1y': delta = today - pd.DateOffset(years=1) delta = delta.date() delta = delta.strftime('%Y-%m-%d') elif start_date == '3y': delta = today - pd.DateOffset(years=3) delta = delta.date() delta = delta.strftime('%Y-%m-%d') elif start_date == '5y': delta = today - pd.DateOffset(years=5) delta = delta.date() delta = delta.strftime('%Y-%m-%d') elif start_date == '10y': delta = today - pd.DateOffset(years=10) delta = delta.date() delta = delta.strftime('%Y-%m-%d') elif start_date == 'max': delta = today - pd.DateOffset(years=30) delta = delta.date() delta = delta.strftime('%Y-%m-%d') prices = ffn.get(tickers, start=delta) mu = expected_returns.mean_historical_return(prices) S = risk_models.sample_cov(prices) ef = EfficientFrontier(mu, S) raw_weights = ef.max_sharpe() cleaned_weights = ef.clean_weights() st.write(cleaned_weights) metrics = ef.portfolio_performance(verbose=True) st.write('Expected Return: {:.2f}'.format(metrics[0])) st.write('Annual Volatility: {:.2f}'.format(metrics[1])) st.write('Sharpe Ratio {:.2f}'.format(metrics[2]))
def __min_vol(mu: pd.Series, cov_matrix: pd.DataFrame) -> pd.DataFrame: # Setup ef = EfficientFrontier(mu, cov_matrix) # Optimizes for minimum volatility min_ptf = ef.min_volatility() return pd.DataFrame.from_dict(data=min_ptf, orient='index').T
def test_greedy_portfolio_allocation(): df = get_data() mu = mean_historical_return(df) S = sample_cov(df) ef = EfficientFrontier(mu, S) w = ef.max_sharpe() latest_prices = get_latest_prices(df) da = DiscreteAllocation(w, latest_prices) allocation, leftover = da.greedy_portfolio() assert da.allocation == { "MA": 14, "FB": 12, "PFE": 51, "BABA": 5, "AAPL": 5, "AMZN": 0, "BBY": 9, "SBUX": 6, "GOOG": 1, } total = 0 for ticker, num in allocation.items(): total += num * latest_prices[ticker] np.testing.assert_almost_equal(total + leftover, 10000)
def getMaxSharpePortfolio(data): mu, Sigma = getMuSigma(data) ef = EfficientFrontier(mu, Sigma) raw_weights = ef.max_sharpe() weights = ef.clean_weights() performance = ef.portfolio_performance() return weights, performance
def test_custom_bounds_same(): ef = EfficientFrontier(*setup_efficient_frontier(data_only=True), weight_bounds=(0.03, 0.13)) ef.max_sharpe() assert ef.weights.min() >= 0.03 assert ef.weights.max() <= 0.13 np.testing.assert_almost_equal(ef.weights.sum(), 1)
def opt_data(ticker, start, end, amt): weight = np.array([1 / len(ticker)] * len(ticker)) hist_data = get_data(ticker, start, end) daily_returns = hist_data.pct_change() cov_annual_mat = daily_returns.cov() * 255 port_variance = np.dot(weight.T, np.dot(cov_annual_mat, weight)) port_volatility = np.sqrt(port_variance).round(4) port_simple_annual_return = np.sum(daily_returns.mean() * weight) * 255 mu = expected_returns.mean_historical_return(hist_data) S = risk_models.sample_cov(hist_data) ef = EfficientFrontier(mu, S) w = ef.max_sharpe() cw = ef.clean_weights() e = ef.portfolio_performance(verbose=False) latest_prices = get_latest_prices(hist_data) da = DiscreteAllocation(cw, latest_prices, total_portfolio_value=amt) allocation, leftover = da.lp_portfolio() return { "orignal_port_volatility": str(round(port_volatility, 3) * 100) + "%", "orignal_annual_return": str(round(port_simple_annual_return, 3) * 100) + "%", "new_port_volatility": str(round(e[1], 3) * 100) + "%", "new_annual_return": str(round(e[0], 3) * 100) + "%", "Allocation": cw, "AllocationNo": allocation, "Left_Amount": str(round(leftover, 2)) }
def run_allocation(date, duration): df = pd.DataFrame(columns=symbols) for symbol in symbols: try: data = get_all_binance(symbol, date, duration, save=False) df[symbol] = data["close"] except BinanceAPIException: print("Symbol was : " + symbol) df = df.apply(pd.to_numeric) df.fillna(0) print(df) mu = mean_historical_return(df) S = CovarianceShrinkage(df).ledoit_wolf() ef = EfficientFrontier(mu, S) weights = ef.max_sharpe() #aws, graphql, table'a ekle cleaned_weights = ef.clean_weights() print(ef.portfolio_performance(verbose=True)) lists = sorted(weights.items()) # sorted by key, return a list of tuples lists = {x: y for x, y in lists if y > 0} f = open("Coin" + duration + ".txt", "w") f.write(str(lists)) f.close() print(weights) s3 = boto3.client('s3') with open("Coin" + duration + ".txt", "rb") as f: s3.upload_fileobj(f, "model-predictions", "Coin" + duration + ".txt")
def test_greedy_portfolio_allocation(): df = get_data() mu = mean_historical_return(df) S = sample_cov(df) ef = EfficientFrontier(mu, S) w = ef.max_sharpe() latest_prices = get_latest_prices(df) da = DiscreteAllocation(w, latest_prices, short_ratio=0.3) allocation, leftover = da.greedy_portfolio() assert allocation == { "MA": 20, "FB": 12, "PFE": 54, "BABA": 4, "AAPL": 4, "BBY": 2, "SBUX": 1, "GOOG": 1, } total = 0 for ticker, num in allocation.items(): total += num * latest_prices[ticker] np.testing.assert_almost_equal(total + leftover, 10000, decimal=4) # Cover the verbose parameter, allocation_verbose, leftover_verbose = da.greedy_portfolio(verbose=True) assert allocation_verbose == allocation assert leftover_verbose == leftover
def asset_allocation(tickers, start_date): today = pd.datetime.today() if start_date == '1y': delta = today - pd.DateOffset(years=1) delta = delta.date() delta = delta.strftime('%Y-%m-%d') elif start_date == '3y': delta = today - pd.DateOffset(years=3) delta = delta.date() delta = delta.strftime('%Y-%m-%d') elif start_date == '5y': delta = today - pd.DateOffset(years=5) delta = delta.date() delta = delta.strftime('%Y-%m-%d') elif start_date == '10y': delta = today - pd.DateOffset(years=10) delta = delta.date() delta = delta.strftime('%Y-%m-%d') elif start_date == 'max': delta = today - pd.DateOffset(years=30) delta = delta.date() delta = delta.strftime('%Y-%m-%d') prices = ffn.get(tickers, start=delta) mu = expected_returns.mean_historical_return(prices) S = risk_models.sample_cov(prices) ef = EfficientFrontier(mu, S) raw_weights = ef.max_sharpe() cleaned_weights = ef.clean_weights() latest_prices = discrete_allocation.get_latest_prices(prices) da = DiscreteAllocation(cleaned_weights, latest_prices, total_portfolio_value=amount) allocation, leftover = da.lp_portfolio() st.subheader('Asset Allocation breakdown: ') st.write(allocation) st.write("Funds remaining: ${:.2f}".format(leftover))
def ef_risk_strategy(returns=None, cov_matrix=None, target_volatility=5.0): assert returns is not None assert cov_matrix is not None ef = EfficientFrontier(returns, cov_matrix) ef.add_objective(objective_functions.L2_reg, gamma=0.1) weights = ef.efficient_risk(target_volatility=target_volatility) return weights, portfolio_performance(ef), ef
def ef_sharpe_strategy(returns=None, cov_matrix=None): assert returns is not None ef = EfficientFrontier(returns, cov_matrix) ef.add_objective(objective_functions.L2_reg, gamma=0.1) # eliminate minor weights weights = ef.max_sharpe() return weights, portfolio_performance(ef), ef
def max_sharpe_multi(ticker_list, time='1d', cash=10000000): data = yf.download(ticker_list, period='10y', interval=time) if len(ticker_list) > 1: data = yf.download(ticker_list, period='10y', interval=time, group_by='ticker') new_data = [] df = pd.DataFrame() weight = 1 / len(ticker_list) for i in ticker_list: stock_normal_ret = data['Close'] / data.iloc[0]['Close'] df[i] = data['Close'] if len(ticker_list) > 1: stock_normal_ret = data[i]['Close'] / data[i].iloc[0]['Close'] df[i] = data[i]['Close'] alloc = stock_normal_ret * weight balance = alloc * cash new_data.append(balance) mu = expected_returns.mean_historical_return(df) s = risk_models.sample_cov(df) ef = EfficientFrontier(mu, s) weights = ef.max_sharpe() cleaned_weights = ef.clean_weights() x = ef.portfolio_performance(verbose=True) return cleaned_weights, round(2.5 * x[2] / 15, 3) # sharpe adjusted weight
def test_custom_lower_bound(): ef = EfficientFrontier( *setup_efficient_frontier(data_only=True), weight_bounds=(0.02, 1) ) ef.max_sharpe() assert ef.weights.min() >= 0.02 np.testing.assert_almost_equal(ef.weights.sum(), 1)
def get_momentum_stocks(df, date, portfolio_size, cash): # Convert dates and filter all momentum scores to include only top `portfolio_size` movers df_top_movers = df.loc[df['date'] == pd.to_datetime(date)] df_top_movers = df_top_movers.sort_values(by='momentum', ascending=False).head(portfolio_size) # Create a universe of top momentum stocks universe = df_top_movers['symbol'].tolist() # Create universe as DF for these stocks df_universe_top_movers = df.loc[df['symbol'].isin(universe)] # Create pre-optimzed portfolio df_universe_top_movers = df_universe_top_movers.pivot_table( index='date', columns='symbol', values='close', aggfunc='sum') # Calculate expected returns and sample covariance mu = expected_returns.mean_historical_return(df_universe_top_movers) S = risk_models.sample_cov(df_universe_top_movers) # Optimize by Sharpe Ratio ef = EfficientFrontier(mu, S, gamma=1) # Use regularization (gamma=1) weights = ef.max_sharpe() cleaned_weights = ef.clean_weights() # Allocate latest_prices = get_latest_prices(df_universe_top_movers) allocated = DiscreteAllocation( cleaned_weights, latest_prices, total_portfolio_value=cash) allocation = allocated.lp_portfolio()[0] # Put the stocks and the number of shares from the portfolio into a df symbols = [] num_shares = [] for sym, shares in allocation.items(): symbols.append(sym) num_shares.append(shares) # Create the to-buy dataframe df_buy = df.loc[df['symbol'].isin(symbols)] # Filter out irrelevant dates df_buy = df_buy.loc[df_buy['date'] == date].sort_values(by='symbol') # Add quantity allocations into dataframe df_buy['qty'] = num_shares # has thrown -> ValueError # Calculate the new/desired equity for each stock df_buy['equity'] = df_buy['close'] * df_buy['qty'] df_buy = df_buy.loc[df_buy['qty'] != 0] return df_buy
def test_custom_upper_bound(): ef = EfficientFrontier( *setup_efficient_frontier(data_only=True), weight_bounds=(0, 0.10) ) ef.max_sharpe() ef.portfolio_performance() assert ef.weights.max() <= 0.1 np.testing.assert_almost_equal(ef.weights.sum(), 1)
def new_w(self, new_pred, date): new_ret = self.train_ret.append(new_pred) new_vcv = new_ret.cov() new_mu = new_ret.mean() eff = EfficientFrontier(expected_returns=new_mu, cov_matrix=new_vcv, weight_bounds=self.w_bounds) return pd.DataFrame(eff.max_sharpe(risk_free_rate=0), index=[date])
def markowitz(tickers, start=None, end=None, regularize=False): prices = load_prices(tickers, start, end) mu = expected_returns.mean_historical_return(prices, frequency=12) S = risk_models.sample_cov(prices, frequency=12) ef = EfficientFrontier(mu, S) if regularize: ef.gamma = 1 return ef
def calculate(self, date, universe): prices = universe.pricing['price'].unstack()[self.assets].iloc[-self.window:] mu = mean_historical_return(prices) S = CovarianceShrinkage(prices).ledoit_wolf() ef = EfficientFrontier(mu, S) weights = ef.min_volatility() weights = pd.Series(weights, index=self.assets) return weights
def test_efficient_frontier_init_errors(): df = get_data() mean_returns = df.pct_change().dropna(how="all").mean() with pytest.raises(TypeError): EfficientFrontier("test", "string") with pytest.raises(TypeError): EfficientFrontier(mean_returns, mean_returns)
def min_CVaR(self): prices = self.prices returns = self.returns cov = self.covariance ef = EfficientFrontier(None, cov) optimal_weights = ef.custom_objective(negative_cvar, returns) return optimal_weights, None
def ef_sharpe_strategy(ld: LazyDictionary, **kwargs) -> None: ef = EfficientFrontier( expected_returns=kwargs.get("returns"), cov_matrix=kwargs.get("cov_matrix", None), ) ef.add_objective(objective_functions.L2_reg, gamma=0.1) # eliminate minor weights ld["optimizer"] = ef ld["raw_weights"] = lambda ld: ld["optimizer"].max_sharpe()
def __init__(self, dfs, on='date', rf=0.02): df = reduce(lambda left, right: pd.merge(left, right, on=on), dfs) df_pct = df.pct_change() self.prices = df self.mu = expected_returns.mean_historical_return(df) self.rf = rf self.S = risk_models.sample_cov(df) self.ef = EfficientFrontier(self.mu, self.S) self.ef.max_sharpe(risk_free_rate=rf)
def test_bounds_errors(): with pytest.raises(ValueError): EfficientFrontier(*setup_efficient_frontier(data_only=True), weight_bounds=(0.06, 1)) assert EfficientFrontier(*setup_efficient_frontier(data_only=True), weight_bounds=(0, 1)) with pytest.raises(ValueError): EfficientFrontier(*setup_efficient_frontier(data_only=True), weight_bounds=(0.06, 1, 3))
def __init__(self, dataframe): self.dataframe = dataframe # Calculate expected returns and sample covariance self.mu = expected_returns.mean_historical_return(self.dataframe) self.S = risk_models.sample_cov(self.dataframe) # Optimise for maximal Sharpe ratio self.ef = EfficientFrontier(self.mu, self.S) self.weights = self.ef.max_sharpe() self.ef.portfolio_performance(verbose=True)
def test_clean_weights_short(): ef = setup_efficient_frontier() ef = EfficientFrontier( *setup_efficient_frontier(data_only=True), weight_bounds=(-1, 1) ) ef.max_sharpe() # In practice we would never use such a high cutoff number_tiny_weights = sum(np.abs(ef.weights) < 0.05) cleaned = ef.clean_weights(cutoff=0.05) cleaned_weights = cleaned.values() clean_number_tiny_weights = sum(abs(i) < 0.05 for i in cleaned_weights) assert clean_number_tiny_weights == number_tiny_weights
def test_max_sharpe_input_errors(): with pytest.raises(ValueError): ef = EfficientFrontier( *setup_efficient_frontier(data_only=True), gamma="2" ) with warnings.catch_warnings(record=True) as w: ef = EfficientFrontier( *setup_efficient_frontier(data_only=True), gamma=-1) assert len(w) == 1 assert issubclass(w[0].category, UserWarning) assert ( str(w[0].message) == "in most cases, gamma should be positive" ) with pytest.raises(ValueError): ef.max_sharpe(risk_free_rate="0.2")
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) assert set(w.keys()) == set(ef.expected_returns.index) np.testing.assert_almost_equal(ef.weights.sum(), 1) np.testing.assert_allclose( ef.portfolio_performance(), (0.25, 0.168264744226909, 1.3640929002973508) ) 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
def test_portfolio_allocation_errors(): df = get_data() e_ret = mean_historical_return(df) cov = sample_cov(df) ef = EfficientFrontier(e_ret, cov) w = ef.max_sharpe() latest_prices = discrete_allocation.get_latest_prices(df) with pytest.raises(TypeError): discrete_allocation.portfolio(ef.weights, latest_prices) with pytest.raises(TypeError): discrete_allocation.portfolio(w, latest_prices.values.tolist()) with pytest.raises(ValueError): discrete_allocation.portfolio(w, latest_prices, min_allocation=0.5) with pytest.raises(ValueError): discrete_allocation.portfolio(w, latest_prices, total_portfolio_value=0)
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) assert set(w.keys()) == set(ef.expected_returns.index) np.testing.assert_almost_equal(ef.weights.sum(), 1) np.testing.assert_allclose( ef.portfolio_performance(), (0.40723757138191374, 0.24823079451957306, 1.5524922427959371), ) 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_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) assert set(w.keys()) == set(ef.expected_returns.index) 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.20567621957041887, 1.1087335497769277) ) 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_risk_market_neutral(): ef = EfficientFrontier( *setup_efficient_frontier(data_only=True), weight_bounds=(-1, 1) ) w = ef.efficient_risk(0.19, market_neutral=True) assert isinstance(w, dict) assert set(w.keys()) == set(ef.tickers) assert set(w.keys()) == set(ef.expected_returns.index) 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.2309497469661495, 0.19000021138101422, 1.1021245569881066) ) 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_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) assert set(w.keys()) == set(ef.expected_returns.index) np.testing.assert_almost_equal(ef.weights.sum(), 1) np.testing.assert_allclose( ef.portfolio_performance(), (0.1719799158957379, 0.15559547854162945, 0.9734986722620801), ) # 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_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.gamma = 1 w = ef.max_sharpe() assert isinstance(w, dict) assert set(w.keys()) == set(ef.tickers) assert set(w.keys()) == set(ef.expected_returns.index) np.testing.assert_almost_equal(ef.weights.sum(), 1) np.testing.assert_allclose( ef.portfolio_performance(), (0.3236047844566581, 0.20241509723550233, 1.4969817524033966), ) new_number = sum(ef.weights > 0.01) assert new_number >= initial_number
def test_efficient_risk_short(): ef = EfficientFrontier( *setup_efficient_frontier(data_only=True), weight_bounds=(None, None) ) w = ef.efficient_risk(0.19) assert isinstance(w, dict) assert set(w.keys()) == set(ef.tickers) assert set(w.keys()) == set(ef.expected_returns.index) np.testing.assert_almost_equal(ef.weights.sum(), 1) np.testing.assert_allclose( ef.portfolio_performance(), (0.30468522897560224, 0.19, 1.4947624032507056), atol=1e6, ) 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
def test_portfolio_allocation(): df = get_data() e_ret = mean_historical_return(df) cov = sample_cov(df) ef = EfficientFrontier(e_ret, cov) w = ef.max_sharpe() latest_prices = discrete_allocation.get_latest_prices(df) allocation, leftover = discrete_allocation.portfolio(w, latest_prices) assert allocation == { "MA": 14, "FB": 12, "PFE": 51, "BABA": 5, "AAPL": 5, "AMZN": 0, "BBY": 9, "SBUX": 6, "GOOG": 1, } total = 0 for ticker, num in allocation.items(): total += num * latest_prices[ticker] np.testing.assert_almost_equal(total + leftover, 10000)
from pypfopt.efficient_frontier import EfficientFrontier from pypfopt import risk_models from pypfopt import expected_returns from pypfopt.hierarchical_risk_parity import hrp_portfolio from pypfopt.value_at_risk import CVAROpt from pypfopt import discrete_allocation # Reading in the data; preparing expected returns and a risk model df = pd.read_csv("tests/stock_prices.csv", parse_dates=True, index_col="date") returns = df.pct_change().dropna(how="all") mu = expected_returns.mean_historical_return(df) S = risk_models.sample_cov(df) # Long-only Maximum Sharpe portfolio, with discretised weights ef = EfficientFrontier(mu, S) weights = ef.max_sharpe() ef.portfolio_performance(verbose=True) latest_prices = discrete_allocation.get_latest_prices(df) allocation, leftover = discrete_allocation.portfolio(weights, latest_prices) print("Discrete allocation:", allocation) print("Funds remaining: ${:.2f}".format(leftover)) """ Expected annual return: 33.0% Annual volatility: 21.7% Sharpe Ratio: 1.43 Discrete allocation: {'MA': 14, 'FB': 12, 'PFE': 51, 'BABA': 5, 'AAPL': 5, 'AMZN': 0, 'BBY': 9, 'SBUX': 6, 'GOOG': 1} Funds remaining: $12.15