def show_dividend(ticker, start=None, end=None): """ Show annual dividend yield input: ticker ticker of the stock/ETF start start date, default '2000-01-01' end end date, default current Return a DataFrame """ from invest.useful import convert_time from invest.get_data import read_ETF from invest.calculation import add_dividend, get_dividend_yield start, end = convert_time(start, end) data = read_ETF(ticker)[start:end] add_dividend(data, price='Close', adj='Adj Close', out='Div') div = get_dividend_yield(data, price='Close', div='Div', style='simple') plt.figure(figsize=(14, 4)) plt.bar(div.index, div * 100) ret = data.Div[data.Div > 0].tail(6).to_frame() ret.index = ret.index.date print(ret) plt.show() return ret.T
def investment_performance(ticker, price, quantity, start, end=None): """ Calculate performance of given stock/ETF. input: ticker ticker of the stock/ETF start start date end end date, default current """ from invest.useful import convert_time from invest.get_data import read_ETF from invest.plot import plot_day_price from invest.calculation import add_dividend, get_return_vol from time_series.functions import resample start, end = convert_time(start, end) data = read_ETF(ticker)[start:end] plot_day_price(data) plt.plot([start], [price], 'ro') plt.show() add_dividend(data, price='Close', adj='Adj Close', out='Dividend') temp = data[['Dividend']][data.Dividend != 0].copy() temp.index = temp.index.date display(temp.T) weekly = resample(data, style='week', method='close') rv = get_return_vol(weekly[['Close', 'Adj Close']], scale=52, ret=False, plotit=False) rv['Total Return'] = data[['Close', 'Adj Close']].iloc[-1, :] / data[ ['Close', 'Adj Close']].iloc[0, :] - 1 rv = rv * 100 rv['Gain'] = np.round(price * quantity * rv['Total Return'] / 100, 2) display(rv) print("Actual gain without reinvest: {:.2f}".format( (data.Close[-1] - price) * quantity)) print("Dividend gain: {:.2f}".format(data.Dividend.sum() * quantity))
def show_yield(ticker, start=None, end=None, weeks=52): """ Calculate annualized return. Simple return is calculated input: ticker ticker of the stock/ETF start start date, default '2000-01-01' end end date, default current weeks number of weeks for each calculation, default 52 Return a DataFrame with three rows: Adj Close, Dividend, Close """ from invest.useful import convert_time from invest.get_data import read_ETF from invest.calculation import add_dividend, get_returns from time_series.functions import resample start, end = convert_time(start, end) data = read_ETF(ticker)[start:end] add_dividend(data, price='Close', adj='Adj Close', out='Dividend') data['Dividend'] = np.cumsum(data.Dividend) weekly = resample(data, style='week', method='close') weekly = weekly[(weekly.shape[0] - 1) % weeks::weeks] df = get_returns(weekly[['Adj Close', 'Dividend', 'Close']], 'simple') df['Dividend'] = (weekly.Dividend.diff() / weekly.Close.shift(1)) df = df * 100 * 52 / weeks from datetime import timedelta ds = df.index xlim = [ ds[0] - timedelta(days=3 * weeks), ds[-1] + timedelta(days=3 * weeks) ] plt.figure(figsize=(14, 3)) plt.title("Annualized Return") plt.hlines(xmin=xlim[0], xmax=xlim[1], y=0) plt.hlines(xmin=xlim[0], xmax=xlim[1], y=df['Adj Close'].mean(), linestyle='--', color='#1f77b4') plt.hlines(xmin=xlim[0], xmax=xlim[1], y=df.Dividend.mean(), linestyle='--', color='#ff7f0e') plt.bar(ds, df.Close, width=5 * weeks, label='Yield') plt.bar(ds, df.Dividend, bottom=df.Close, width=5 * weeks, label='Div_Yield') plt.plot(ds, df['Adj Close'], 'o-', label='Adj_Yield') plt.xlabel("Date to sell") plt.xlim(xlim) plt.ylim([np.min(df.values) - 0.2, np.max(df.values) + 0.2]) plt.legend(bbox_to_anchor=(1.01, 0.9), loc='upper left') plt.grid() df.index = df.index.date print(np.round(df, 2)) plt.show() return np.round(df, 2).T
def show_trend(ticker, start=None, end=None): """ Plot price change, return and volatility input: ticker ticker of the stock/ETF start start date, default '2000-01-01' end end date, default current Return correlation between return and volatility """ from invest.useful import convert_time from invest.get_data import read_ETF from invest.calculation import get_returns from time_series.functions import moving_agg, resample from basic.mathe import covariance, correlation start, end = convert_time(start, end) data = read_ETF(ticker)[start:end] fig = plt.figure(figsize=(14,6)) fig.add_axes([0.05,0.68,0.94,0.3]) for c in ['Close','Adj Close']: plt.plot(data.index, data[c], label=c) plt.xlim(data.index[0],data.index[-1]) plt.xticks([]) plt.ylabel("Price ($)") plt.legend(loc='best') weekly = resample(data, style='week', method='close') df = get_returns(weekly.Close, 'simple') fig.add_axes([0.05,0.38,0.94,0.3]) m = moving_agg(df, window=52, step=1, func=np.sum) plt.plot(df.index[51:], m*100) plt.hlines(xmin=data.index[0], xmax=data.index[-1], y=0, linestyle='--') plt.xlim(data.index[0],data.index[-1]) plt.xticks([]) plt.ylabel("Annual Return (%)") plt.legend(loc='best') fig.add_axes([0.05,0.08,0.94,0.3]) v = moving_agg(df, window=52, step=1, func=covariance) v = np.sqrt(v*52) plt.plot(df.index[51:], v*100) plt.xlim(data.index[0],data.index[-1]) plt.ylabel("Volatility (%)") plt.gca().set_ylim(bottom=0) plt.legend(loc='best') corr = correlation(m, v) print("Correlation between return and volatility:", corr) plt.show() return corr
def load_data_from_yahoo(tickers, start=None, end=None): """ Get historical data from Yahoo Finance input: tickers one ticker or a list of tickers start start date, default "2000-1-1"(defined in invest.useful) end end date, default current date(defined in invest.useful) return whatever the website returns """ from pandas_datareader import data as pdr import sys if not root in sys.path: sys.path.append(root) from invest.useful import convert_time logger = logging.getLogger(__name__) start, end = convert_time(start, end) logger.info("Download {} from Yahoo Finance for date range {} to {}".format( tickers, start.date(), end.date())) try: return pdr.get_data_yahoo(tickers, start=start, end=end) except: logger.error("Failed to download {} from Yahoo Finance. Return empty DataFrame"\ .format(tickers)) return pd.DataFrame()
def portfolio_analysis(tickers, alloc=None, start='2010-01-01', end=None): """ Given a series of tickers, return a summery of each ETF in a DataFrame input: tickers tickers of stocks/ETFs alloc allocation for given stocks/TEFs, default None start start date, default "2010-01-01" end end date, default today """ from invest.get_data import read_ETF, read_portfolio from invest.calculation import get_return_vol, get_alpha_beta, minimize_risk from invest.useful import convert_time from time_series.functions import resample from basic.useful import progress_bar from basic.plot import plot_correlation, plot_stacked_bar start, end = convert_time(start, end) if not (alloc is None): if len(tickers) != len(alloc): raise ValueError( "Length of shares and tickers should be the same if shares is given." ) alloc = np.array(alloc) / np.sum(alloc) plt.figure(figsize=(15, 3)) plt.subplot(131) plt.title("Calculated by Close Price") close = read_portfolio(tickers, 'Close', start, end) close = close / close.iloc[0, :] weekly = resample(close, style="week", method='close') al_clo = minimize_risk(weekly, returns=None, strict=True, riskfree=None, max_alloc=1, scale=52, ret=False, verbose=False, plotit=True) if not (alloc is None): weekly = weekly.dot(alloc) rv = get_return_vol(weekly, scale=52) * 100 plt.plot(rv.Volatility, rv.Return, 'bo') plt.subplot(132) plt.title("Calculated by Adjusted Close Price") adj = read_portfolio(tickers, 'Adj Close', start, end) adj = adj / adj.iloc[0, :] weekly = resample(adj, style="week", method='close') al_adj = minimize_risk(weekly, returns=None, strict=True, riskfree=None, max_alloc=1, scale=52, ret=False, verbose=False, plotit=True) if not (alloc is None): weekly = weekly.dot(alloc) rv = get_return_vol(weekly, scale=52) * 100 plt.plot(rv.Volatility, rv.Return, 'bo') plt.subplot(133) df = pd.DataFrame() def func(t): data = read_ETF(t) if data.index[0] < start: data = data[start:end] a, b = get_alpha_beta(data.Close, ret_type='simple', dspl=False) df.at[t, 'alpha'] = a df.at[t, 'beta'] = b progress_bar(tickers, func, disable=True) plt.plot(df.beta, df.alpha, 'o') if not (alloc is None): total = close.dot(alloc) alpha, beta = get_alpha_beta(total, ret_type='simple', dspl=False) plt.plot(beta, alpha, 'bo') plt.xlabel('Beta') plt.ylabel("Alpha") plt.hlines(xmin=-0.1, xmax=1.2, y=0, linestyles='--') plt.xlim(-0.1, 1.2) for t in df.index: plt.text(df.beta[t], df.alpha[t], t) plt.figure(figsize=(14, 3)) plt.title("Allocation calculated from close price") plot_stacked_bar(al_clo[al_clo.columns[-3::-1]].T.values, names=al_clo.columns[-3::-1], ticks=np.round(al_clo.Return * 100, 2)) plt.xlabel("Return in %") plt.figure(figsize=(14, 3)) plt.title("Allocation calculated from adjusted close price") plot_stacked_bar(al_adj[al_adj.columns[-3::-1]].T.values, names=al_adj.columns[-3::-1], ticks=np.round(al_adj.Return * 100, 2)) plt.xlabel("Return in %") plt.figure(figsize=(14, 3)) plt.title("Price change (not adjusted)") for c in close.columns: plt.plot(close.index, close[c], '-', label=c) plt.hlines(xmin=close.index[0], xmax=close.index[-1], y=1, linestyles='--') plt.xlim(close.index[0], close.index[-1]) plt.legend(bbox_to_anchor=(1.01, 0.99), loc='upper left') if not (alloc is None): plt.plot(close.index, total, 'k-') plt.figure(figsize=(6, 5)) plot_correlation(close) plt.show()