def Main(): with st.sidebar.expander("DVD_HK"): st.info(f''' Dividends: Hong Kong Listed Stocks only (for now...) ''') default_tickers = get_index_tickers( st_asset=st.sidebar.expander('Load an Index', expanded=True)) tickers = tickers_parser(st.text_input( 'enter stock ticker(s) [space separated]', value=default_tickers), return_list=True) timeframe_params = get_timeframe_params( st_asset=st.sidebar.expander("Timeframe"), default_tenor='50y') if tickers: # - div history with ex-date true range vs div amount/ true range df = get_dvd(tickers, ex_date_after=timeframe_params['end_date'], aggregate=True) show_upcoming_div(df, st_asset=st.expander("View Upcoming Dividend", expanded=True), timeframe_params=timeframe_params, atr_period=22) df_all = get_dvd(tickers, aggregate=True) show_past_div(df_all, st_asset=st.expander("View Pass Dividend"), timeframe_params=timeframe_params, atr_period=22)
def get_ticker_data_with_technicals( ticker:str, interval:str = '1d', trade_date = datetime.date.today(), tenor:str = '2y', data_buffer_tenor:str = '1y', l_ma_periods:list = [22,11], atr_params = {'period': 13, 'use_ema': True, 'channel_dict' : None}, return_all_dates = False ): ''' Get Price Data for a Ticker and add various Technical Indicators intended for trend following strategies backtesting/ screening Args: l_ma_periods: list of moving averages periods to add return_all_dates: if False, return only data from start_date ''' start_date = (BusinessDate(trade_date)- tenor).to_date() data_start_date = (BusinessDate(start_date) - data_buffer_tenor).to_date() df = get_stocks_ohlc(tickers = tickers_parser(ticker), interval = interval, start_date = data_start_date, end_date = trade_date, proxies = get_proxies() ) for p in l_ma_periods: df = add_moving_average(df, period = p, type = 'ema') df = add_MACD(df) df = add_ATR(df, **atr_params) if atr_params else df return df if return_all_dates else df[df.index > pd.Timestamp(start_date)]
def Main(): with st.sidebar.expander("RT"): st.info(f''' Returns Analysis: what does your stock's return distribution look like? How fat are the tails? * inspired by this [blog post](https://www.codingfinance.com/post/2018-04-03-calc-returns-py/) ''') tickers = tickers_parser( st.text_input('enter stock ticker(s) [space separated]')) with st.sidebar.expander('settings', expanded=True): today = datetime.date.today() end_date = st.date_input('Period End Date', value=today) if st.checkbox('pick start date'): start_date = st.date_input('Period Start Date', value=today - datetime.timedelta(days=365)) else: tenor = st.text_input('Period', value='250b') start_date = (BusinessDate(end_date) - tenor).to_date() st.info(f'period start date: {start_date}') l_interval = [ '1d', '1m', '2m', '5m', '15m', '30m', '60m', '90m', '1h', '5d', '1wk', '1mo', '3mo' ] interval = st.selectbox('interval', options=l_interval) if interval.endswith(('m', 'h')): st.warning(f'intraday data cannot extend last 60 days') if tickers: side_config = st.sidebar.expander('charts configure', expanded=False) with side_config: # show_ohlc = st.checkbox('ohlc chart', value = True) # b_two_col = st.checkbox('two-column view', value = True) chart_size = st.number_input('Chart Size', value=500, min_value=400, max_value=1500) # if len(tickers.split())==1: # st.warning(f'This function works best with more than one tickers. Some features below might not render...') data_dict = get_yf_data(tickers, start_date=start_date, end_date=end_date, interval=interval) data = data_dict['prices'].copy() df_return = data_dict['returns'].copy() with st.expander('raw data'): st.subheader('Price Data') st.write(data) st.subheader('Returns') st.write(df_return) l_tickers = df_return.columns.tolist() if len(l_tickers) != len(tickers.split(' ')): st.warning( f'having trouble finding the right ticker?\nCheck it out first in `DESC` :point_left:' ) single_ticker = len(l_tickers) == 1 l_col, r_col = st.columns(2) with l_col: target_ticker = st.selectbox( 'Analyze', options=l_tickers if single_ticker else [''] + l_tickers) if target_ticker: with r_col: with st.expander(f'{target_ticker} descriptive stats'): st.write(df_return[target_ticker].describe()) if single_ticker: tmp_idx = pd.MultiIndex.from_tuples( [(col, target_ticker) for col in data.columns], names=['variable', 'ticker']) data.columns = tmp_idx plot_returns(df_returns=df_return, df_prices=data, target_ticker=target_ticker, chart_size=chart_size) else: compare_returns(df_returns=df_return, df_prices=data, chart_size=chart_size)
def Main(): with st.sidebar.expander("ATR"): st.info(f''' [Average True Range](https://www.thebalance.com/how-average-true-range-atr-can-improve-trading-4154923): Compare risk across multiple stocks and determine your [position sizing](https://therobusttrader.com/how-to-use-atr-in-position-sizing/) ''') tickers = tickers_parser( st.text_input('enter stock ticker(s) [space separated]'), max_items=None) with st.sidebar.expander('timeframe', expanded=False): today = datetime.date.today() end_date = st.date_input('Period End Date', value=today) if st.checkbox('pick start date'): start_date = st.date_input('Period Start Date', value=today - datetime.timedelta(days=365)) else: tenor = st.text_input('Period', value='250b') start_date = (BusinessDate(end_date) - tenor).to_date() st.info(f'period start date: {start_date}') # TODO: allow manual handling of data_start_date data_start_date = (BusinessDate(start_date) - "1y").to_date() l_interval = ['1d', '1m', '5m', '1h', '1wk'] interval = st.selectbox('interval', options=l_interval) if interval.endswith(('m', 'h')): st.warning(f'intraday data cannot extend last 60 days') if tickers: with st.sidebar.expander('ATR Configs', expanded=True): use_ema = st.checkbox('use exponential moving aveage') atr_period = st.number_input('ATR Period (number of bars)', value=22) atr_multiplier = st.number_input('ATR multiplier (stop-loss size)', value=2, step=1) var = st.number_input( 'Value To Risk (max drawdown on one position)', value=1000) data_dict = get_yf_data(tickers, start_date=data_start_date, end_date=end_date, interval=interval) data = data_dict['prices'].copy() df_return = data_dict['returns'].copy() with st.expander('raw data'): st.subheader('Price Data') st.write(data) l_tickers = df_return.columns.tolist() if len(l_tickers) != len(tickers.split(' ')): st.warning( f'having trouble finding the right ticker?\nCheck it out first in `DESC` :point_left:' ) # l_DFs is a list of [ {ticker: df}, ...] df_dict = { l_tickers[0]: data} if len(l_tickers) ==1 else \ get_dfs_by_tickers(data) results = [{ **{ 'ticker': t }, **get_ATR_calc(df, period=atr_period, use_ema=use_ema, atr_multiplier=atr_multiplier, var=var, price_col='Adj Close') } for t, df in df_dict.items()] # add HK lot size for r in results: if ".HK" in r['ticker']: r['lot_size'] = get_lot_size(r['ticker']) with st.expander(f'ATR Results', expanded=True): st.write(pd.DataFrame(results)) with st.expander('Visualize ATR'): chart_configs = get_charts_configs( st_asset=st.sidebar.expander("Chart Configs")) visualize_features(df_dict, chart_configs=chart_configs, atr_period=atr_period, start_date=start_date)
def Main(): with st.sidebar.expander("GP"): st.info(f''' Graph Prices (open-high-low-close) * inspired by this [blog post](https://towardsdatascience.com/creating-a-finance-web-app-in-3-minutes-8273d56a39f8) and this [youtube video](https://youtu.be/OhvQN_yIgCo) * plots by Plotly with thanks to this [kaggle notebook](https://www.kaggle.com/mtszkw/technical-indicators-for-trading-stocks) ''') tickers = tickers_parser(st.text_input('enter stock ticker'), max_items = 1) with st.sidebar.expander('timeframe', expanded = True): today = datetime.date.today() end_date = st.date_input('Period End Date', value = today) if st.checkbox('pick start date'): start_date = st.date_input('Period Start Date', value = today - datetime.timedelta(days = 365)) else: tenor = st.text_input('Period', value = '6m') start_date = (BusinessDate(end_date) - tenor).to_date() st.info(f'period start date: {start_date}') # TODO: allow manual handling of data_start_date # l_interval = ['1d','1wk','1m', '2m','5m','15m','30m','60m','90m','1h','5d','1mo','3mo'] interval = st.selectbox('interval', options = ['1d', '1wk', '1mo']) is_intraday = interval.endswith(('m','h')) data_start_date = start_date if is_intraday else \ (BusinessDate(start_date) - "1y").to_date() if is_intraday: st.warning(f''' intraday data cannot extend last 60 days\n also, some features below might not work properly ''') if tickers: stock_obj = yf.Ticker(tickers) if not valid_stock(stock_obj): st.error(f''' {tickers} is an invalid ticker.\n Having trouble finding the right ticker?\n Check it out first in `DESC` :point_left: ''') return None side_config = st.sidebar.expander('charts configure', expanded = False) with side_config: show_df = st.checkbox('show price dataframe', value = False) chart_size = st.number_input('Chart Size', value = 1200, min_value = 400, max_value = 1500, step = 50) side_stock_info = get_stock_info_container(stock_obj.info, st_asset= st.sidebar) data = get_stocks_ohlc(tickers, start_date = data_start_date, end_date = end_date, interval = interval, proxies = get_proxies()) with st.expander('Indicators'): l_col, m_col , r_col = st.columns(3) with l_col: st.write('#### the moving averages') ma_type = st.selectbox('moving average type', options = ['', 'ema', 'sma', 'vwap']) periods = st.text_input('moving average periods (comma separated)', value = '22,11') if ma_type: for p in periods.split(','): data = add_moving_average(data, period = int(p), type = ma_type) st.write('#### volume-based indicators') # do_volume_profile = st.checkbox('Volume Profile') data = add_AD(data) if st.checkbox('Show Advance/ Decline') else data data = add_OBV(data) if st.checkbox('Show On Balance Volume') else data with m_col: st.write('#### MACD') do_MACD = st.checkbox('Show MACD?', value = True) fast = st.number_input('fast', value = 12) slow = st.number_input('slow', value = 26) signal = st.number_input('signal', value = 9) if do_MACD: data = add_MACD(data, fast = fast, slow = slow, signal = signal ) with r_col: st.write('#### oscillator') do_RSI = st.checkbox('RSI') data = add_RSI(data, n = st.number_input('RSI period', value = 13)) if do_RSI else data tup_RSI_hilo = st.text_input('RSI chart high and low line (comma separated):', value = '70,30').split(',') \ if do_RSI else None tup_RSI_hilo = [int(i) for i in tup_RSI_hilo] if tup_RSI_hilo else None if do_RSI: data_over_hilo_pct = sum( ((data['RSI']> tup_RSI_hilo[0]) | (data['RSI']< tup_RSI_hilo[1])) & (data.index > pd.Timestamp(start_date)) ) / len(data[data.index > pd.Timestamp(start_date)]) st.info(f""" {round(data_over_hilo_pct * 100, 2)}% within hilo\n 5% of peaks and valley should be within hilo """) st.write('#### True Range Related') atr_period = int(st.number_input('Average True Range Period', value = 13)) atr_ema = st.checkbox('use EMA for ATR', value = True) show_ATR = st.checkbox('show ATR?', value = False) if ma_type: st.write('##### ATR Channels') atr_ma_name = st.selectbox('select moving average for ATR channel', options = [''] + get_moving_average_col(data.columns)) atr_channels = st.text_input('Channel Lines (comma separated)', value = "1,2,3") \ if atr_ma_name else None fill_channels = st.checkbox('Fill Channels with color', value = False) \ if atr_ma_name else None else: atr_ma_name = None data = add_ATR(data, period = atr_period, use_ema = atr_ema, channel_dict = {atr_ma_name: [float(c) for c in atr_channels.split(',')]} \ if atr_ma_name else None ) st.write(f'##### Directional System') do_ADX = st.checkbox('Show ADX') data = add_ADX(data, period = st.number_input("ADX period", value = 13)) \ if do_ADX else data with st.expander('advanced settings'): l_col, m_col , r_col = st.columns(3) with l_col: st.write('#### Market Type Classification') mkt_class_period = int(st.number_input('peroid (match your trading time domain)', value = 66)) mkt_class = market_classification(data, period = mkt_class_period, debug = False) if mkt_class_period else None if mkt_class: side_stock_info.write(f'market is `{mkt_class}` for the last **{mkt_class_period} bars**') side_stock_info.write(f'[kaufman efficiency_ratio](https://strategyquant.com/codebase/kaufmans-efficiency-ratio-ker/) ({mkt_class_period} bars): `{round(efficiency_ratio(data, period = mkt_class_period),2)}`') st.write('#### Events') do_div = st.checkbox('show ex-dividend dates') if do_div: data = add_div_col(df_price = data, df_div = stock_obj.dividends) side_stock_info.write( stock_obj.dividends[stock_obj.dividends.index > pd.Timestamp(start_date)] ) do_earnings = st.checkbox('show earning dates') if do_earnings and isinstance(stock_obj.calendar, pd.DataFrame): data = add_event_col(df_price = data, df_events = stock_obj.calendar.T.set_index('Earnings Date'), event_col_name= "earnings") side_stock_info.write(stock_obj.calendar.T) if do_MACD and ma_type: st.write("#### Elder's Impulse System") impulse_ema = st.selectbox('select moving average for impulse', options = [''] + get_moving_average_col(data.columns)) data = add_Impulse(data, ema_name = impulse_ema) if impulse_ema else data avg_pen_data = None with m_col: if ma_type: st.write("#### Average Penetration for Entry/ SafeZone") fair_col = st.selectbox('compute average penetration below', options = [''] + get_moving_average_col(data.columns)) avg_pen_data = add_avg_penetration(df = data, fair_col = fair_col, num_of_bars = st.number_input('period (e.g. 4-6 weeks)', value = 30), # 4-6 weeks use_ema = st.checkbox('use EMA for penetration', value = False), ignore_zero = st.checkbox('ignore days without penetration', value = True), coef = st.number_input( 'SafeZone Coefficient (stops should be set at least 1x Average Penetration)', value = 1.0, step = 0.1), get_df = True, debug = True ) if fair_col else None with r_col: if do_MACD: st.write('#### MACD Bullish Divergence') if st.checkbox('Show Divergence'): data = detect_macd_divergence(data, period = st.number_input('within number of bars (should be around 3 months)', value = 66), threshold = st.number_input('current low threshold (% of previous major low)', value = 0.95), debug = True ) st.write(f'#### Detect Kangaroo Tails') tail_type = st.selectbox('Tail Type', options = ['', 0, 1, -1]) data = detect_kangaroo_tails(data, atr_threshold = st.number_input('ATR Threshold', value = 2.0), period = st.number_input('period', value = 22), tail_type = tail_type) \ if tail_type else data beta_events_to_plot, l_events_to_color, l_col_to_scatter = [], [], [] show_beta_features(data = data, l_events_to_color=l_events_to_color, l_col_to_scatter = l_col_to_scatter, atr_period = atr_period) if show_df: with st.expander(f'raw data (last updated: {data.index[-1].strftime("%c")})'): st.write(data) if isinstance(avg_pen_data, pd.DataFrame): with st.expander('Buy Entry (SafeZone)'): avg_pen_dict = { 'average penetration': avg_pen_data['avg_lp'][-1], 'ATR': avg_pen_data['ATR'][-1], 'penetration stdv': avg_pen_data['std_lp'][-1], 'number of penetrations within period': avg_pen_data['count_lp'][-1], 'last': avg_pen_data['Close'][-1], 'expected ema T+1': avg_pen_data[fair_col][-1] + (avg_pen_data[fair_col][-1] - avg_pen_data[fair_col][-2]) } avg_pen_dict = {k:round(v,2) for k,v in avg_pen_dict.items()} avg_pen_dict['buy target T+1'] = avg_pen_dict['expected ema T+1'] - avg_pen_dict['average penetration'] st.write(avg_pen_dict) plot_avg_pen = st.checkbox('plot buy SafeZone and show average penetration df') plot_target_buy = False # st.checkbox('plot target buy T+1') # if plot_avg_pen: # st.write(avg_pen_data) if not(show_ATR) and 'ATR' in data.columns: del data['ATR'] #TODO: fix tz issue for interval < 1d # see: https://stackoverflow.com/questions/16628819/convert-pandas-timezone-aware-datetimeindex-to-naive-timestamp-but-in-certain-t fig = plotly_ohlc_chart( df = data if is_intraday else data[data.index > pd.Timestamp(start_date)], vol_col = 'Volume', tup_rsi_hilo = tup_RSI_hilo, b_fill_channel = fill_channels if atr_ma_name else None ) #, show_volume_profile = do_volume_profile) # SafeZone if isinstance(avg_pen_data, pd.DataFrame): fig = add_Scatter(fig, df = avg_pen_data[avg_pen_data.index > pd.Timestamp(start_date)], target_col = 'buy_safezone') \ if plot_avg_pen else fig if plot_target_buy: fig.add_hline(y = avg_pen_dict['buy target T+1'] , line_dash = 'dot', row =1, col = 1) # Events for d in ['MACD_Divergence', 'kangaroo_tails', 'ex-dividend', 'earnings'] + beta_events_to_plot: if d in data.columns: fig = add_Scatter_Event(fig, data[data.index > pd.Timestamp(start_date)], target_col = d, anchor_col = 'Low', textposition = 'bottom center', fontsize = 8, marker_symbol = 'triangle-up', event_label = d[0]) # Color Events for d in l_events_to_color: fig = add_color_event_ohlc(fig, data[data.index > pd.Timestamp(start_date)], condition_col = d['column'], color = d['color'] ) if d['column'] in data.columns else fig # Scatter Columns for c in l_col_to_scatter: fig = add_Scatter(fig, data[data.index > pd.Timestamp(start_date)], target_col = c['column'], line_color = c['color']) show_plotly(fig, height = chart_size, title = f"Price chart({interval}) for {tickers} : {stock_obj.info['longName']}")
def Main(): with st.sidebar.expander("MBRS"): st.info(f''' Members: getting Indices members * ETFs holdings using [etf4u](https://github.com/leoncvlt/etf4u) coming soon... ''') showIndices(st_asset=st.sidebar) default_tickers = get_index_tickers( st_asset=st.sidebar.expander('Load an Index', expanded=True)) with st.sidebar.expander('settings', expanded=False): df_height = int( st.number_input("members' df height", value=500, min_value=200)) tickers = tickers_parser( st.text_input("index members' tickers [space separated]", value=default_tickers)) if tickers: with st.expander('display keys'): l_col, r_col = st.columns(2) with l_col: l_keys_des = st.multiselect('descriptive', options=[ 'longName', 'previousClose', 'sector', 'fullTimeEmployees', 'country', 'industry', 'currency', 'exchangeTimezoneName' ], default=['longName']) l_keys_vol = st.multiselect( 'volume', options=[ 'averageVolume10days', 'circulatingSupply', 'sharesOutstanding', 'sharesShort', 'sharesPercentSharesOut', 'floatShares', 'shortRatio', 'heldPercentInsiders', 'impliedSharesOutstanding' ]) with r_col: l_keys_dvd = st.multiselect( 'dividend related', options=[ 'dividendRate', 'exDividendDate', 'dividendYield', 'lastDividendDate', 'exDividendDate', 'lastDividendValue' ]) l_keys_fun = st.multiselect('fundamental', options=[ 'marketCap', 'trailingPE', 'priceToSalesTrailing12Month', 'forwardPE', 'profileMargins', 'forwardEps', 'bookValue', 'priceToBook', 'payoutRatio' ]) l_keys = l_keys_des + l_keys_vol + l_keys_dvd + l_keys_fun if len(l_keys) < 1: st.warning(f'no key selected.') return None # st.subheader(f'Members of `{idx}`') st.subheader(f'Index Members stats') data = get_members_info_df(asset=tickers.split(), l_keys=['symbol'] + l_keys) st.dataframe(data, height=df_height)
def Main(): with st.sidebar.expander("BETA"): st.info(f''' Beta Analysis vs Benchmark Security ''') default_tickers = get_index_tickers( st_asset = st.sidebar.expander('Load an Index', expanded = True) ) tickers = tickers_parser( st.text_input('enter stock ticker(s) [space separated]', value = default_tickers) ) with st.sidebar.expander('settings', expanded = False): today = datetime.date.today() end_date = st.date_input('Period End Date', value = today) if st.checkbox('pick start date'): start_date = st.date_input('Period Start Date', value = today - datetime.timedelta(days = 365)) else: tenor = st.text_input('Period', value = '250b') start_date = (BusinessDate(end_date) - tenor).to_date() st.info(f'period start date: {start_date}') l_interval = ['1d','1m', '2m','5m','15m','30m','60m','90m','1h','5d','1wk','1mo','3mo'] interval = st.selectbox('interval', options = l_interval) if tickers: side_config = st.sidebar.expander('charts configure', expanded = False) with side_config: show_ohlc = st.checkbox('ohlc chart', value = True) # b_two_col = st.checkbox('two-column view', value = True) chart_size = st.number_input('Chart Size', value = 500, min_value = 400, max_value = 1500) data_dict = get_yf_data(tickers, start_date = start_date, end_date = end_date, interval = interval) df_returns = data_dict['returns'].copy() with st.expander('view returns data'): st.subheader('Returns') st.write(df_returns) l_tickers = df_returns.columns.tolist() if len(l_tickers) != len(tickers.split(' ')): st.warning(f'having trouble finding the right ticker?\nCheck it out first in `DESC` :point_left:') l_col, r_col = st.columns(2) with l_col: benchmark_ticker = st.selectbox('benchmark security', options = tickers.split()) beta_json = get_betas(df_returns, benchmark_col = benchmark_ticker.upper()) # TODO: add dividend yield? beta_df = pd.DataFrame.from_dict(beta_json) with r_col: plot_var_options = [col for col in beta_df.columns if col not in ['ticker']] y_var = st.selectbox('y-axis variable', options = plot_var_options) x_var = st.selectbox('x-axis variable', options = plot_var_options) with st.expander('Betas Calcuation'): st.write(beta_df) fig = px.scatter(beta_df, x = x_var, y = y_var, color = 'ticker') fig.update_layout(showlegend = False) show_plotly(fig)
def Main(): ticker = tickers_parser(st.text_input('enter a stock ticker'), max_items=1) with st.sidebar.expander("DESC"): st.info(f''' Description: get general information about the company, upcoming events, etc. ''') if ticker: # ticker = ticker.split('.')[0].zfill(4) + '.HK' if '.HK' in ticker.upper() else ticker side_config = st.sidebar.expander('configure', expanded=True) with side_config: show_ohlc = st.checkbox('ohlc chart', value=True) show_volume = st.checkbox('show volume', value=True) b_two_col = st.checkbox('two-column view', value=True) chart_size = st.number_input('Chart Size', value=500, min_value=400, max_value=1500) if b_two_col: col1, col2 = st.columns((2, 1)) else: col1 = col2 = st.container() stock = yf.Ticker(ticker) if not valid_stock(stock): st.error(f'Cannot find `{ticker}`') return None #TODO: # 1. show key keys info # 2. add twitter & NewsAPI # 4. Download price DF with col1: stock_info = stock.info with st.expander(f'Stock Info for {stock_info["longName"]}'): str_desc = f'[:link:]({stock_info["website"]}) ' \ if 'website' in stock_info.keys() else '' str_desc += stock_info["longBusinessSummary"] \ if "longBusinessSummary" in stock_info.keys() else ":warning: Business Summary not available" st.write(f'{str_desc}') if st.checkbox('show info JSON'): st.json(stock_info) df_all = stock.history(period="max") with side_config: number_td = st.number_input("Number of trading days", value=min(250, len(df_all)), min_value=5, max_value=len(df_all)) df_all = df_all.tail(number_td) with st.expander('Price Chart', expanded=True): if show_ohlc: fig = plotly_ohlc_chart( df=df_all, vol_col='Volume' if show_volume else None) else: fig = px.line(df_all, y='Close', color_discrete_sequence=["#b58900"]) # color_discrete_sequence = ['yellow']) fig.update_layout( height=chart_size, title= f'{ticker.upper()} last {number_td} trading days- ohlc chart', template='plotly_dark') st.plotly_chart(fig, use_container_width=True, height=chart_size) with st.expander('Historical Prices'): st.dataframe(df_all) # High, Low, Open, Close, Volume, Adj Close # trading_data = stock.trading_data # st.dataframe(trading_data) # show actions (dividends, splits) with st.expander("Corporate Actions"): st.dataframe(stock.actions) # show dividends with st.expander("Dividends"): st.dataframe(stock.dividends) # show splits with st.expander("Splits"): st.dataframe(stock.splits) with col2: # show financials with st.expander("Financials"): st.write(stock.financials) # msft.quarterly_financials # show major holders with st.expander("Major Holders"): st.dataframe(stock.major_holders) # show institutional holders with st.expander("Institutional Holders"): st.dataframe(stock.institutional_holders) # show balance sheet with st.expander("Balance Sheet"): st.write(stock.balance_sheet) # msft.quarterly_balance_sheet # show cashflow with st.expander("Cashflow"): st.write(stock.cashflow) # msft.quarterly_cashflow # show earnings with st.expander("Earnings"): st.write(stock.earnings) # msft.quarterly_earnings # show sustainability with st.expander("Sustainability"): # this is a df issue on ST side: # https://discuss.streamlit.io/t/after-upgrade-to-the-latest-version-now-this-error-id-showing-up-arrowinvalid/15794/24 # print(type(stock.sustainability)) st.write(stock.sustainability) # show analysts recommendations with st.expander("Analysts Recommendations"): # TODO: # 1. set "Firm" as index # 2. turn datetime index as a col st.dataframe(stock.recommendations) # show next event (earnings, etc) with st.expander("Calendar"): if isinstance(stock.calendar, pd.DataFrame): st.dataframe(stock.calendar.T)