|
| 1 | +from Robinhood import Robinhood |
| 2 | +import pandas as pd |
| 3 | +from collections import defaultdict |
| 4 | + |
| 5 | +class InfoRetriever: |
| 6 | + INTERESTED_STOCK_ATTR = [ |
| 7 | + 'name', 'symbol', 'last_trade_price', 'quantity_held', 'dividend_yield', 'pe_ratio', 'pb_ratio', |
| 8 | + 'open', 'high', 'low', 'volume', 'float', 'high_52_weeks', 'low_52_weeks', 'description', |
| 9 | + 'sector', 'industry', 'market_cap' |
| 10 | + ] |
| 11 | + |
| 12 | + def __init__(self, trader): |
| 13 | + self.trader = trader |
| 14 | + |
| 15 | + def get_instruments_quant_owned(self): |
| 16 | + securities_owned = self.trader.securities_owned()['results'] |
| 17 | + instruments_quant = [] |
| 18 | + for sec in securities_owned: |
| 19 | + instrument_id, quantity = sec['instrument'].rsplit('/', 2)[-2], float(sec['quantity']) |
| 20 | + instruments_quant.append((instrument_id, quantity)) |
| 21 | + return instruments_quant |
| 22 | + |
| 23 | + def get_stock_symbols_owned(self): |
| 24 | + instruments_quant = self.get_instruments_quant_owned() |
| 25 | + instrument_ids = [] |
| 26 | + for instrument_id, quant in instruments_quant: |
| 27 | + instrument_ids.append(instrument_id) |
| 28 | + return self.get_stock_symbols(instrument_ids) |
| 29 | + |
| 30 | + def get_stock_symbols(self, instruments): |
| 31 | + symbols = [] |
| 32 | + for instrument in instruments: |
| 33 | + symbols.append(self.get_stock_symbol(instrument)) |
| 34 | + return symbols |
| 35 | + |
| 36 | + def get_stock_symbol(self, instrument_id): |
| 37 | + instrument_details = self.trader.instrument(instrument_id) |
| 38 | + return (instrument_details['symbol'], instrument_details['simple_name']) |
| 39 | + |
| 40 | + def quotes(self, symbols): |
| 41 | + return self.trader.quotes_data(symbols) |
| 42 | + |
| 43 | + def fundamentals(self, symbols): |
| 44 | + fundamentals = [] |
| 45 | + for symbol in symbols: |
| 46 | + fundamentals.append(self.trader.fundamentals(symbol)) |
| 47 | + return fundamentals |
| 48 | + |
| 49 | + def portfolio_holdings(self): |
| 50 | + instruments_quant = self.get_instruments_quant_owned() |
| 51 | + stocks_owned = self.get_stock_symbols_owned() |
| 52 | + stock_symbols = [symbol for symbol, name in stocks_owned] |
| 53 | + quotes = self.quotes(stock_symbols) |
| 54 | + fundamentals = self.fundamentals(stock_symbols) |
| 55 | + |
| 56 | + df_rows = [] |
| 57 | + for (symbol, name), (instr, quant), quote, fundamental \ |
| 58 | + in zip(stocks_owned, instruments_quant, quotes, fundamentals): |
| 59 | + merged_quote_fundamental_dict = quote.copy() |
| 60 | + merged_quote_fundamental_dict.update(fundamental) |
| 61 | + merged_quote_fundamental_dict['instrument_id'] = instr |
| 62 | + merged_quote_fundamental_dict['quantity_held'] = quant |
| 63 | + merged_quote_fundamental_dict['name'] = name |
| 64 | + |
| 65 | + df_row = {} |
| 66 | + for attribute in InfoRetriever.INTERESTED_STOCK_ATTR: |
| 67 | + df_row[attribute] = merged_quote_fundamental_dict[attribute] |
| 68 | + df_rows.append(df_row) |
| 69 | + |
| 70 | + return pd.DataFrame(df_rows) |
| 71 | + |
| 72 | +def get_dashboard_data(user, password): |
| 73 | + my_trader = Robinhood() |
| 74 | + logged_in = my_trader.login(username=user, password=password) |
| 75 | + |
| 76 | + retriever = InfoRetriever(my_trader) |
| 77 | + portfolio_holdings = retriever.portfolio_holdings() |
| 78 | + |
| 79 | + total_port_value = 0 |
| 80 | + sector_mkt_val = defaultdict(int) |
| 81 | + for _, row in portfolio_holdings.iterrows(): |
| 82 | + total_port_value += float(row['last_trade_price']) * float(row['quantity_held']) |
| 83 | + sector_mkt_val[row['sector']] += float(row['last_trade_price']) * float(row['quantity_held']) |
| 84 | + |
| 85 | + sector_mkt_val_percent = {} |
| 86 | + for sector, val in sector_mkt_val.items(): |
| 87 | + sector_mkt_val_percent[sector] = val / total_port_value * 100 |
| 88 | + |
| 89 | + data = [] |
| 90 | + for _, row in portfolio_holdings.iterrows(): |
| 91 | + stock_info = { |
| 92 | + 'name': row['name'], |
| 93 | + 'symbol': row['symbol'], |
| 94 | + 'market_cap': float(row['market_cap']), |
| 95 | + 'pe_ratio': -6 if row['pe_ratio'] is None or float(row['pe_ratio']) < 0 else float(row['pe_ratio']), |
| 96 | + 'dividend_yield': 0 if row['dividend_yield'] is None else float(row['dividend_yield']), |
| 97 | + 'holding_val': float(row['last_trade_price']) * float(row['quantity_held']), |
| 98 | + 'last_trade_price': float(row['last_trade_price']), |
| 99 | + 'quantity_held': float(row['quantity_held']), |
| 100 | + 'port_percent': float(row['last_trade_price']) * float(row['quantity_held']) / total_port_value * 100, |
| 101 | + 'industry': row['industry'], |
| 102 | + 'sector': row['sector'], |
| 103 | + 'sector_port_percent': sector_mkt_val_percent[row['sector']], |
| 104 | + 'description': row['description'], |
| 105 | + } |
| 106 | + data.append(stock_info) |
| 107 | + |
| 108 | + return data |
0 commit comments