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_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 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 { "MA": 14, "FB": 12, "PFE": 51, "BABA": 5, "AAPL": 5, "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, decimal=4)
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 calculate_mu_S(options): now = datetime.now() # Read in price data df = pd.read_csv(options.url, parse_dates=True, index_col="date") if back_to_future: global back_to_future_latest_prices back_to_future_latest_prices = get_latest_prices(df) last_date = df.index[-1] df = df[df.index < last_date - relativedelta(years=1)] print( f'0. read_csv (with negation): {(datetime.now() - now).microseconds} microseconds' ) now = datetime.now() # Calculate expected returns and sample covariance mu = expected_returns_calc_func[options.expected_returns_calc](df) print( f'1. expected_returns_calc_func: {(datetime.now() - now).microseconds} microseconds' ) now = datetime.now() S = risk_models.sample_cov(df) print( f'2. risk_models.sample_cov(df): {(datetime.now() - now).microseconds} microseconds' ) return mu, S, df
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 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 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 calc(stockStartTime,stockEndTime): #calculating 2 years prior of the start date tempdate = dt.datetime.fromisoformat(stockStartTime) tempdate = tempdate - dt.timedelta(weeks=104) prices = ffn.get('pfe,ibm,wmt,msft,cat', start= tempdate.strftime('%Y-%m-%d'), end=stockStartTime) # Expected returns and sample covariance mu = expected_returns.mean_historical_return(prices) S = risk_models.sample_cov(prices) #Minimum volatility. May be useful if you're trying to get an idea of how low the volatility could be, #but in practice it makes a lot more sense to me to use the portfolio that maximises the Sharpe ratio. # Optimise portfolio for maximum Sharpe Ratio to serve as benchmark ef = EfficientFrontier(mu, S) #raw_weights = ef.min_volatility() #ef.max_sharpe() cleaned_weights = ef.clean_weights() print("Cleaned weights:\n",cleaned_weights) print("Portfolio Performance:\n",ef.portfolio_performance(verbose=True)) #To achieve beta neutrality ef = EfficientFrontier(mu, S, weight_bounds=(-1, 1)) print(" Weights: ",ef.efficient_return(target_return=0.15, market_neutral=True)) weights = ef.efficient_return(target_return=0.2, market_neutral=True) #weight_sum = sum(w for w in weights.values() if w > 0) #normalised_weights = {k:v/weight_sum for k,v in weights.items()} #print("Normalized weights: ",normalised_weights) #We then need to convert these weights into an actual allocation, telling you how many shares of each asset you should purchase. latest_prices = get_latest_prices(prices) da = DiscreteAllocation(weights, latest_prices, total_portfolio_value=1000000) allocation, leftover = da.lp_portfolio() #print(allocation) print("") for key,val in allocation.items(): print("Number of positions in ",key," stock: ",val) print("") print("Funds remaining: ${:.2f}".format(leftover)) print("") prices2 = ffn.get('pfe,ibm,wmt,msft,cat', start=stockStartTime, end=stockEndTime) latest_prices2 = get_latest_prices(prices2) sum1 = 0 for key,val in allocation.items(): sum1 = sum1 - (latest_prices[key]*val) print("Value of Portfolio after short sales :\t",abs(sum1)) new = 0 for key,val in allocation.items(): new = new + (latest_prices2[key]*val) sum1 = sum1 + (latest_prices2[key]*val) print("Value at end of period :\t\t",new) print("Profit at end of time period :\t\t",sum1) return sum1
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 getoptimprices(df, weights, portvalue): latest_prices = get_latest_prices(df) da = DiscreteAllocation(weights, latest_prices, total_portfolio_value=portvalue) allocation, leftover = da.lp_portfolio() listshares = [] for k in allocation.values(): listshares.append(k) return allocation, leftover, listshares
def getDiscreteAllocations(df, weights): latest_prices = get_latest_prices(df) #plotting.plot_weights(weights) total_portfolio_value = 15000 da = DiscreteAllocation(weights, latest_prices, total_portfolio_value=total_portfolio_value) allocation, leftover = da.lp_portfolio() print("Best portfolio possible today for the given shares and given contraints for an investment of ", total_portfolio_value, ": ") print("Shares allocation:", allocation) print("Funds remaining: ${:.2f}".format(leftover))
def create_portfolio(): today = str(date.today()) #Create the DataFrame and fill with historical data df = pd.read_csv(csv, header = 0) df = df.clip(lower=0.1) print("NEGATIVE: " + str(df.agg(lambda x: sum(x < 0)).sum())) df = df.iloc[:, 0:200] assets = df.columns #Calculate the expected annualized returns and the annualized ... mu = expected_returns.mean_historical_return(df) S = risk_models.sample_cov(df) #Optimize fot the maximal Sharpe ratio ef = EfficientFrontier(mu,S) weights = ef.max_sharpe() cleaned_weights = ef.clean_weights() ef.portfolio_performance(verbose=True) #Get the discrete allocation of each share per stock latest_prices = get_latest_prices(df) weights = cleaned_weights da = DiscreteAllocation(weights, latest_prices, total_portfolio_value=portfolio_val) allocation, leftover = da.lp_portfolio() #print('Discrete allocation: ', allocation) #print('Funds Rreaming $', leftover) symbols = [] discrete_allocation_list = [] company_name = [] for symbol in allocation: company_name.append(get_company_name(symbol)) discrete_allocation_list.append(allocation.get(symbol)) #symbols.append(allocation.get(symbol)) portfolio_df = pd.DataFrame(columns=['Cég', 'Szimbólum', 'Részvények_száma']) portfolio_df['Cég'] = company_name portfolio_df['Szimbólum'] = allocation portfolio_df['Részvények_száma'] = discrete_allocation_list above_df = "Várható éves hozam: " + str(round(ef.portfolio_performance(verbose=True)[0] * 100, 2)) + "% | " + "Volatilitás: " + str(round(ef.portfolio_performance(verbose=True)[1] * 100, 2)) + "% | " + "Sharpe-ráta: " + str(round(ef.portfolio_performance(verbose=True)[2], 3)) st.write("Az első két oszlop a cég nevét és tőzsdei szimbólumát mutatja, a harmadik pedig azt, hogy hány darab részvényt kell belőle venned a kalkuláció szerint") st.success(str(above_df)) st.write(portfolio_df, 'A végén marad: ' + str(round(leftover, 2)) + "$") st.write("Elemzéshez felhasznált részvények listája:") st.write(assets)
def test_lp_allocation_rmse_error_short(): df = get_data() mu = mean_historical_return(df) S = sample_cov(df) ef = EfficientFrontier(mu, S, weight_bounds=(-1, 1)) w = ef.max_sharpe() latest_prices = get_latest_prices(df) da = DiscreteAllocation(w, latest_prices, short_ratio=0.3) da.lp_portfolio() assert da._allocation_rmse_error(verbose=False) < 0.1
def test_greedy_allocation_rmse_error(): 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) da.greedy_portfolio() np.testing.assert_almost_equal(da._allocation_rmse_error(), 0.0383845)
def test_lp_allocation_rmse_error_short(): df = get_data() mu = mean_historical_return(df) S = sample_cov(df) ef = EfficientFrontier(mu, S, weight_bounds=(-1, 1)) w = ef.max_sharpe() latest_prices = get_latest_prices(df) da = DiscreteAllocation(w, latest_prices) da.lp_portfolio() np.testing.assert_almost_equal(da._allocation_rmse_error(), 0.02901217)
def get_discrete_allocation(self): latest_prices = get_latest_prices(self.df) weights = self.get_expected_returns['cleanedWeights'] da = DiscreteAllocation(weights, latest_prices, total_portfolio_value=10000) discrete_allocarion_and_remaining = { 'discreteAllocation': 'Discrete allocation: ' + str(allocation), 'fundsRemaining': 'Funds remaining: ${:.2f}'.format(leftover) } return discrete_allocarion_and_remaining
def process_options(options): global back_to_future back_to_future = options.back_to_future if options.invert_returns: short_fix(options) ret_val = { "operation": "invert-returns", "filename": options.invert_returns } elif options.to_cache: mu, S, df = calculate_mu_S(options) latest_prices = get_latest_prices(df) cache_to_save = { 'mu': mu, 'S': S, 'latest_prices': latest_prices, 'url': options.url } store_cache_func[options.to_cache](cache_to_save) ret_val = { "operation": "saved-to-cache", "hash": hash(str(cache_to_save)) } elif options.reuse_cache: cache_loaded = load_cache_func[options.reuse_cache](options.cache_key) description = f'using cache {options.reuse_cache}, url {cache_loaded["url"]}' ret_val = calculate_all(cache_loaded['mu'], cache_loaded['S'], cache_loaded['latest_prices'], options, description) elif options.no_cache_calculation: mu, S, df = calculate_mu_S(options) latest_prices = get_latest_prices(df) ret_val = calculate_all(mu, S, latest_prices, options, 'no cache') else: ret_val = { "error": "options do not match. Either use cache result, or reuse cache or -x to calculate all" } return ret_val
def test_lp_allocation_rmse_error(): 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) da.lp_portfolio() np.testing.assert_almost_equal(da._allocation_rmse_error(verbose=False), 0.017070218149194846)
def get_discrete_allocation(self): latest_prices = get_latest_prices(self.price_data_df) da = DiscreteAllocation(self.weights, latest_prices, total_portfolio_value=self.portfolio_value) self.allocation, self.leftover = da.lp_portfolio() self.allocation = {k: int(v) for k, v in self.allocation.items()} print('Discrete allocation: {}'.format(self.allocation)) print('Funds remaining: ${:.2f}'.format(self.leftover)) self.exp_return, self.volatility, self.sharpe_ratio = self.ef.portfolio_performance( verbose=True)
def test_greedy_allocation_rmse_error_short(): df = get_data() mu = mean_historical_return(df) S = sample_cov(df) ef = EfficientFrontier(mu, S, weight_bounds=(-1, 1)) w = ef.max_sharpe() latest_prices = get_latest_prices(df) da = DiscreteAllocation(w, latest_prices, short_ratio=0.3) da.greedy_portfolio() np.testing.assert_almost_equal(da._allocation_rmse_error(verbose=False), 0.06063511265243106)
def calculate_allocation(stock_price, cash, Portfolio): mu = expected_returns.mean_historical_return(stock_price) S = risk_models.sample_cov(stock_price) ef = EfficientFrontier(mu, S) cleaned_weights = ef.clean_weights() latest_prices = get_latest_prices(stock_price) da = DiscreteAllocation(cleaned_weights, latest_prices, total_portfolio_value=cash) allocation, leftover = da.lp_portfolio() print("Discrete allocation:", allocation) print("Funds remaining: ${:.2f}".format(leftover))
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
def calculate_allocation(self, cash): # if you have cash to allocate to a set of stocks, this function will return how to allocate that # see rebalance_weight to identify most suitable portfolio self.cash = cash ef = EfficientFrontier(self.mu, self.S) weights = ef.max_sharpe() cleaned_weights = ef.clean_weights() latest_prices = get_latest_prices(self.stock_prices) da = DiscreteAllocation(cleaned_weights, latest_prices, total_portfolio_value=cash) allocation, leftover = da.lp_portfolio() print("Discrete allocation:", allocation) print("Funds remaining: ${:.2f}".format(leftover))
def GetPort( ): #tickers = ['BSX','AES','BRK-B','SEE','QQQ','SPY'], first = 0, funds = 10000): ticks = request.args.get('tickers') tickers = list(ticks.split(" ")) first = request.args.get('first') funds = request.args.get('Funds') thelen = len(tickers) price_data = [] for ticker in range(thelen): prices = web.DataReader(tickers[ticker], start='2015-01-01', end='2020-10-17', data_source='yahoo') price_data.append(prices.assign(ticker=ticker)[['Adj Close']]) df_stocks = pd.concat(price_data, axis=1) df_stocks.columns = tickers #print(df_stocks.head()) #nullin_df = pd.DataFrame(df_stocks,columns=tickers) #print(nullin_df.isnull().sum()) mu = expected_returns.mean_historical_return(df_stocks) Sigma = risk_models.sample_cov(df_stocks) if int(first) == 1: ef = EfficientFrontier(mu, Sigma, weight_bounds=(0, 1)) else: ef = EfficientFrontier(mu, Sigma, weight_bounds=(-1, 1)) sharpe_pfolio = ef.max_sharpe() cleaned_weights = ef.clean_weights() #print(cleaned_weights) #ef.portfolio_performance(verbose=True) latest_prices = get_latest_prices(df_stocks) da = DiscreteAllocation(cleaned_weights, latest_prices, total_portfolio_value=int(funds)) allocation, leftover = da.lp_portfolio() #print("Discrete allocation:", allocation) #print("Funds remaining: ${:.2f}".format(leftover)) #new_alloc = {str(key): str(value) for key, value in allocation} new_alloc = {} for key in allocation: new_alloc[key] = str(allocation[key]) allocjson = json.dumps(new_alloc) #print(allocjson) return jsonify(allocation=new_alloc, leftover=leftover)
def __init__(self, table): mu = expected_returns.mean_historical_return(table) S = risk_models.sample_cov(table) # Optimise for maximal Sharpe ratio ef = EfficientFrontier(mu, S) ef.max_sharpe() # Raw weights self.cleaned_weights = ef.clean_weights() print(self.cleaned_weights) ef.portfolio_performance(verbose=True) latest_prices = discrete_allocation.get_latest_prices(table) self.allocation, self.leftover = discrete_allocation.portfolio( self.cleaned_weights, latest_prices, total_portfolio_value=10000 )
def test_rmse_decreases_with_value(): # As total_portfolio_value increases, rmse should decrease. 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) da1 = DiscreteAllocation(w, latest_prices, total_portfolio_value=10000) da1.greedy_portfolio() rmse1 = da1._allocation_rmse_error(verbose=False) da2 = DiscreteAllocation(w, latest_prices, total_portfolio_value=100000) da2.greedy_portfolio() rmse2 = da2._allocation_rmse_error(verbose=False) assert rmse2 < rmse1
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) 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)
def test_greedy_portfolio_allocation_short(): df = get_data() mu = mean_historical_return(df) S = sample_cov(df) ef = EfficientFrontier(mu, S, weight_bounds=(-1, 1)) 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": 19, "PFE": 42, "FB": 7, "GOOG": 1, "BABA": 5, "AAPL": 4, "SBUX": 8, "BBY": 6, "XOM": 4, "WMT": 3, "BAC": -32, "AMD": -48, "SHLD": -132, "GM": -9, "RRC": -19, "GE": -14, "T": -5, "UAA": -8, } long_total = 0 short_total = 0 for ticker, num in allocation.items(): if num > 0: long_total += num * latest_prices[ticker] else: short_total -= num * latest_prices[ticker] np.testing.assert_almost_equal(long_total + short_total + leftover, 13000, decimal=4) # Cover the verbose parameter, allocation_verbose, leftover_verbose = da.greedy_portfolio(verbose=True) assert allocation_verbose == allocation assert leftover_verbose == leftover
def compute_portfolio(self, customer_metrics, stock_info_container): if customer_metrics.get_initial_investment() <= 0: return "" # TODO Integrate all customer_metrics # def generate_portfolio(starting_investment, stock_price_history): # Reset the date as the index # stock_price_history = stock_price_history.set_index(pd.DatetimeIndex(stock_price_history['Date'].values)) # Get the stock prices stock_price_history = stock_info_container.get_all_price_history() latest_prices = get_latest_prices(stock_price_history) # Clean up data # stock_price_history.dropna(axis=1, inplace=True) # Optimize the portfolio # Calculate the expected annualized returns and the annualized sample covariance matrix of the daily asset returns mu = expected_returns.mean_historical_return(stock_price_history) S = risk_models.sample_cov(stock_price_history) # Optimize for the maximal Sharpe ratio ef = EfficientFrontier(mu, S) # Creates the Efficient Frontier Object weights = ef.max_sharpe() cleaned_weights = ef.clean_weights() # Get expected performance expected_performance_tuple = ef.portfolio_performance(verbose=True) expected_performance = EfficientFrontierPerformance( expected_performance_tuple[0], expected_performance_tuple[1], expected_performance_tuple[2]) # Get the descret allocation of each share per stock da = DiscreteAllocation( cleaned_weights, latest_prices, total_portfolio_value=customer_metrics.get_initial_investment()) allocation, leftover = da.lp_portfolio() # Store in StockInfoContainer stock_info_container.add_portfolio_to_portfolio(allocation) stock_info_container.set_portfolio_performance(expected_performance) return stock_info_container
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_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)
def test_get_latest_prices_error(): df = get_data() with pytest.raises(TypeError): discrete_allocation.get_latest_prices(df.values)
def test_get_latest_prices(): df = get_data() latest_prices = discrete_allocation.get_latest_prices(df) assert len(latest_prices) == 20 assert list(latest_prices.index) == list(df.columns) assert latest_prices.name == pd.Timestamp(2018, 4, 11)
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 """ # Long-only minimum volatility portfolio, with a weight cap and regularisation