def test_maximum_sharpe_ratio(): d = d_pass[3] pf = build_portfolio(**d) max_sharpe_weights = np.array( [0.0, 0.41322217986076903, 0.5867778201392311, 2.2858514942065993e-17]) ef_opt_weights = pf.ef_maximum_sharpe_ratio() assert np.allclose(ef_opt_weights.values.transpose(), max_sharpe_weights, atol=weak_abse)
def test_efficient_volatility(): d = d_pass[3] pf = build_portfolio(**d) efficient_volatility_weights = np.array( [0.0, 0.5325563159992046, 0.4674436840007955, 0.0]) ef_opt_weights = pf.ef_efficient_volatility(0.191) assert np.allclose(ef_opt_weights.values.transpose(), efficient_volatility_weights, atol=weak_abse)
def __init__(self, y_stocks: list, a_float: float, legend_place: str): yahoo_list: list = list() self._size = a_float self._a_title = 'a title' self._legend_place = legend_place t_s: TimeSpan = y_stocks[0].TimeSpan for y_stock in y_stocks: yahoo_list.append(y_stock.Ticker) pf = build_portfolio(names=yahoo_list, start_date=t_s.StartDateStr, end_date=t_s.EndDateStr, data_api='yfinance') self._data = pf.data # print(pf.properties()) print(pf.portfolio.name) self._portfolio_df = pf.portfolio # annualised expected return self._annualised_expected_return = pf.expected_return # annualised mean returns self._annualised_mean_return_series = pf.comp_mean_returns() # volatility self._volatility = pf.volatility # Sharpe ratio (computed with a risk free rate of 0.005 by default) self._sharpe_risk_free005 = pf.sharpe # Getting Skewness and Kurtosis of the stocks self._skewness_series = pf.skew self._kurtosis_series = pf.kurtosis # daily returns (percentage change) price_{t} - price_{t=0}) / price_{t=0} self._cumulative_return_df = pf.comp_cumulative_returns() self._cumulative_log_return_df = pf.comp_daily_log_returns().cumsum() # daily percentage changes of returns self._pct_chng_return_df = pf.comp_daily_returns() self._pct_chng_log_return_df = pf.comp_daily_log_returns() # building a portfolio by providing stock data # pf = build_portfolio(data=df_data) # # Portfolio optimisation # ## Efficient Frontier # Based on the **Efficient Frontier**, the portfolio can be optimised for # - minimum volatility # - maximum Sharpe ratio # - minimum volatility for a given target return # - maximum Sharpe ratio for a given target volatility # See below for an example for each optimisation. # if needed, change risk free rate and frequency/time window of the portfolio self._freq = pf.freq self._risk_free_rate = pf.risk_free_rate print('ef_minimum_volatility') pf.ef_minimum_volatility(verbose=True) # optimisation for maximum Sharpe ratio print('ef_maximum_sharpe_ratio') pf.ef_maximum_sharpe_ratio(verbose=True) # minimum volatility for a given target return of 0.26 print('ef_efficient_return: target return 0.26') pf.ef_efficient_return(0.26, verbose=True) # maximum Sharpe ratio for a given target volatility of 0.22 print('ef_efficient_volatility: target volatility 0.22') pf.ef_efficient_volatility(0.22, verbose=True)
def test_Stock(): d = d_pass[3] pf = build_portfolio(**d) # loop over all stocks stored within pf and check that values # are equal to the ones in pf for i in range(len(pf.stocks)): assert isinstance(pf.get_stock(names[0]), Stock) stock = pf.get_stock(names[i]) assert stock.name == pf.portfolio["Name"][i] assert all(stock.data - pf.data[stock.name].to_frame() <= strong_abse) assert all(stock.investmentinfo == pf.portfolio.loc[ pf.portfolio["Name"] == stock.name])
def test_get_ef(): d = d_pass[3] pf = build_portfolio(**d) ef = pf._get_ef() assert isinstance(ef, EfficientFrontier) assert isinstance(pf.ef, EfficientFrontier) assert pf.ef == ef assert (pf.comp_mean_returns(freq=1) == ef.mean_returns).all() assert (pf.comp_cov() == ef.cov_matrix).all().all() assert pf.freq == ef.freq assert pf.risk_free_rate == ef.risk_free_rate assert ef.names == pf.portfolio["Name"].values.tolist() assert ef.num_stocks == len(pf.stocks)
def test_ef_minimum_volatility(): d = d_pass[3] pf = build_portfolio(**d) min_vol_weights = np.array([ 0.15515521225480033, 2.168404344971009e-18, 0.4946241856546514, 0.35022060209054834, ]) ef_opt_weights = pf.ef_minimum_volatility() assert np.allclose(ef_opt_weights.values.transpose(), min_vol_weights, atol=weak_abse)
def test_buildPF_pass_5(): d = d_pass[5] pf = build_portfolio(**d) assert isinstance(pf, Portfolio) assert isinstance(pf.get_stock(names[0]), Stock) assert isinstance(pf.data, pd.DataFrame) assert isinstance(pf.portfolio, pd.DataFrame) assert len(pf.stocks) == len(pf.data.columns) assert pf.data.columns.tolist() == names assert pf.data.index.name == "Date" assert ((pf.portfolio == df_pf2).all()).all() assert (pf.comp_weights() - weights_no_df_pf <= strong_abse).all() pf.properties()
def test_efficient_return(): d = d_pass[3] pf = build_portfolio(**d) efficient_return_weights = np.array([ 0.09339785373366818, 0.1610699937778475, 0.5623652130240258, 0.18316693946445858, ]) ef_opt_weights = pf.ef_efficient_return(0.2542) assert np.allclose(ef_opt_weights.values.transpose(), efficient_return_weights, atol=weak_abse)
def test_mc_optimisation(): d = d_pass[3] pf = build_portfolio(**d) # since the monte carlo optimisation is based on random numbers, # we set a seed, so that the results can be compared. np.random.seed(seed=0) # orig values: minvol_res_orig = [ 0.18560926749041448, 0.1333176229402258, 1.3547291311321408 ] maxsharpe_res_orig = [ 0.33033770744503416, 0.16741461860370618, 1.9433052511092475 ] minvol_w_orig = [ 0.09024151309669741, 0.015766238378839476, 0.514540537132381, 0.37945171139208195, ] maxsharpe_w_orig = [ 0.018038812127367274, 0.37348740385059126, 0.5759648343129179, 0.03250894970912355, ] labels_orig = ["min Volatility", "max Sharpe Ratio", "Initial Portfolio"] xlabel_orig = "Volatility [period=252]" ylabel_orig = "Expected Return [period=252]" # run Monte Carlo optimisation through pf opt_w, opt_res = pf.mc_optimisation(num_trials=500) # tests assert (minvol_res_orig - opt_res.iloc[0].values <= strong_abse).all() assert (maxsharpe_res_orig - opt_res.iloc[1].values <= strong_abse).all() assert (minvol_w_orig - opt_w.iloc[0].values <= strong_abse).all() assert (maxsharpe_w_orig - opt_w.iloc[1].values <= strong_abse).all() # also test the plot plt.figure() pf.mc_plot_results() # get axis object ax = plt.gca() # only checking legend and axis labels, and assume that the plot # was successfully created labels_plot = ax.get_legend_handles_labels()[1] xlabel_plot = ax.get_xlabel() ylabel_plot = ax.get_ylabel() assert labels_orig == labels_plot assert xlabel_orig == xlabel_plot assert ylabel_orig == ylabel_plot
def test_buildPF_pass_6(): d = d_pass[6] pf = build_portfolio(**d) assert isinstance(pf, Portfolio) assert isinstance(pf.data, pd.DataFrame) assert isinstance(pf.portfolio, pd.DataFrame) assert len(pf.stocks) == len(pf.data.columns) assert pf.data.columns.tolist() == names assert pf.data.index.name == "Date" assert ((pf.portfolio == df_pf).all()).all() assert (pf.comp_weights() - weights_df_pf <= strong_abse).all() assert expret_orig - pf.expected_return <= strong_abse assert vol_orig - pf.volatility <= strong_abse assert sharpe_orig - pf.sharpe <= strong_abse assert freq_orig - pf.freq <= strong_abse assert risk_free_rate_orig - pf.risk_free_rate <= strong_abse pf.properties()
def test_efficient_frontier(): d = d_pass[3] pf = build_portfolio(**d) efrontier = np.array([ [0.13309804281267365, 0.2], [0.13382500317474913, 0.21], [0.13491049715255884, 0.22], [0.13634357140158387, 0.23], [0.13811756026939967, 0.24], [0.14021770106367654, 0.25], [0.1426296319926618, 0.26], [0.1453376889002686, 0.27], [0.14832574432346657, 0.28], [0.15157724434785497, 0.29], [0.15507572162309227, 0.3], ]) targets = [round(0.2 + 0.01 * i, 2) for i in range(11)] ef_efrontier = pf.ef_efficient_frontier(targets) assert np.allclose(ef_efrontier, efrontier, atol=weak_abse)
def test_plot_optimal_portfolios(): d = d_pass[3] pf = build_portfolio(**d) # just checking if a plot is successfully created, # not checking for content pf.ef_plot_optimal_portfolios()
In [119]: pf.data Out[119]: GOOG AMZN MCD DIS Date 1962-01-02 NaN NaN NaN 0.058360 1962-01-03 NaN NaN NaN 0.059143 1962-01-04 NaN NaN NaN 0.059143 1962-01-05 NaN NaN NaN 0.059339 1962-01-08 NaN NaN NaN 0.059143 ... ... ... ... ... 2020-12-18 1731.010010 3201.649902 215.080002 172.889999 ''' df_p = pd.DataFrame() stock_list = [ "000725", "600837", "600036", "600519", "600276", "601318", "000333", "600030", "000858", "002475" ] #stock_index = '601398' start_date = '2020-01-01' end_date = '2020-12-20' for s1 in stock_list: df1 = stock_data(s1, start_date, end_date) df_p[s1] = df1.close.values dates = df1.dt.values df_p.index = dates df_p.index.name = 'Date' pf1 = build_portfolio(data=df_p)
# <codecell> # here we set the list of names based on the names in # the DataFrame pf_allocation names = pf_allocation['Name'].values.tolist() # dates can be set as datetime or string, as shown below: start_date = datetime.datetime(2015,1,1) end_date = '2017-12-31' # While quandl will download lots of different prices for each stock, # e.g. high, low, close, etc, FinQuant will extract the column "Adj. Close". pf = build_portfolio( names=names, pf_allocation=pf_allocation, start_date=start_date, end_date=end_date ) # <markdowncell> # ## Portfolio is successfully built # Getting data from the portfolio # <codecell> # the portfolio information DataFrame pf.portfolio # <codecell>
new_name = input("Please add stock ticker, or enter 'exit': ") # Add the new name to our list if new_name != 'exit': names.append(new_name) year = int(input('Enter a year for start date: ')) #year for start date month = int(input('Enter a month for start date: ')) #month for start date day = int(input('Enter a day for start date: ')) #day for start date # use datetime for start_date and end_date start_date = datetime.datetime(year, month, day) end_date = datetime.datetime.now() # Use build_protfolio from finquant with yahoo finance as data api otherwise it will use quandl pf = build_portfolio(names=names,start_date=start_date, end_date=end_date, data_api="yfinance") pf.comp_cumulative_returns().plot().axhline(y = 0, color = "black", lw = 3) plt.title('Cumlative Returns') plt.show() # get stock data x = input("If you want to do moving average for particular data then say 'y' :" ) if x in ['y', 'Y', 'yes', 'Yes', 'YES']: dis = pf.get_stock(input('Get Stock data for moving average: ')).data.copy(deep=True) spans = [10, 50, 100, 150, 200] ma = compute_ma(dis, ema, spans, plot=True) plt.show() else: print('OK, we will continue to further calculations.....')
def test_buildPF_fail_26(): d = d_fail[26] with pytest.raises(Exception): build_portfolio(**d)
def test_plot_stocks(): d = d_pass[3] pf = build_portfolio(**d) # just checking if a plot is successfully created, not checking for content pf.plot_stocks()
for i,element in enumerate(stock_index_list): try: a2 = element jj_name_in = jj_name[i] list1 = element list2 = "\""+list1.replace(",",",\"").replace(",\"","\",\"")+"\"" sql3 = """ select dt,lpad(stock_index_raw,6,'0') as stock_index,close from stock_dev.baostock_byyear where lpad(stock_index_raw,6,'0') in (%s) """%(list2) df_r1 = spark.sql(sql3) df_r2 = df_r1.toPandas() df_r2["close"] = [ np.float(x) for x in df_r2["close"].values.tolist()] df_r3 = pd.pivot_table(df_r2,index="dt",columns="stock_index",values="close") df_r4 = df_r3.dropna() df_r4.index.name = 'Date' #df_r4["portfolio_return"] = df_r4.sum(axis=1) df_r4.columns = df_r4.columns.values.tolist() pf = build_portfolio(data=df_r4) df_out = pd.DataFrame(port_val(pf)) df_out["jijin_name"] = jj_name_in out_data.append(df_out) except: pass df_f1 = pd.concat(out_data) df_f1.to_csv("tt.csv",index=0) #print(df_f1.reset_index())
# `build_portfolio()` is an interface that can be used in different ways. Two of which is shown below. For more information the docstring is shown below as well. # In this example `build_portfolio()` is being passed `df_data`, which was read in from file above. # <codecell> print(build_portfolio.__doc__) # <markdowncell> # ## Building a portfolio with data only # Below is an example of only passing a `DataFrame` containing data (e.g. stock prices) to `build_portfolio()` in order to build an instance of `Portfolio`. In this case, the allocation of stocks is automatically generated by equally distributing the weights across all stocks. # <codecell> # building a portfolio by providing stock data pf = build_portfolio(data=df_data) # <markdowncell> # ### Portfolio is successfully built # Below it is shown how the allocation of the stocks and the data (e.g. prices) of the stocks can be obtained from the object `pf`. # <codecell> # the portfolio information DataFrame print(pf.portfolio.name) print(pf.portfolio) # <codecell> # the portfolio stock data, prices DataFrame