With a background in finance and data science, I have always had an interest in building dynamic financial models. When I came across Robinhood's API, I became very intrigued by its abilities. The API not only allows a user to pull account, stock, and cryptocurrencies information, it also enables a savvy developer then to build a trading bot with buying and selling capabilities. In this article, I go into some of these interesting features that I have explored in the API.
Before getting started, you will need to have the Pandas & Robin_Stocks packages installed in your Python library. You will need to enter you own username and password into the appropriate variable. Note, there are more secure ways to store and call passwords that I will not go into, but such steps should absolutely be taken. Below is the initial code that is required to connect and login to Robinhood's API.
# ---------------------------------------------------------------------
# Initialization:
# ---------------------------------------------------------------------
import pandas as pd
import robin_stocks as r
# ---------------------------------------------------------------------
# Login:
# ---------------------------------------------------------------------
user = '<Enter a User Name Here>'
pswd = '<Enter a Password Here>'
login = r.login(user,pswd)
# ---------------------------------------------------------------------
# Logout:
# ---------------------------------------------------------------------
# r.authentication.logout()
Once you have successfully logged in, you will be able to run any of the commands shown on this website. Note, if you have 2FA enabled, there are some extra steps you will want to investigate. 2FA instructions can also be found on that website. I wrote the below script to get an account summary view of my stock and crypto positions.
# ---------------------------------------------------------------------
# Account Summary:
# ---------------------------------------------------------------------
keyList = []; valueList = [];
my_stocks = r.build_holdings()
for key,value in my_stocks.items():
keyList.append(key)
valueList.append(value)
value = pd.DataFrame.from_dict(valueList)
stocks = {'Name': value['name'],
'Symbol': keyList,
'Category': 'stock',
'Price': value['price'].astype(float).map("{:.2f}".format),
'Quantity': value['quantity'].astype(float).map("{:.2f}".format),
'Equity': value['equity'].astype(float).map("{:.2f}".format),
'ROI': ((value['percent_change'].astype(float))/100).map("{0:.2%}".format),
'P&L': value['equity_change'].astype(float).map("{:.2f}".format)}
# ---------------------------------------------------------------------
# Crypto Summary:
# ---------------------------------------------------------------------
# Get data:
quantity = ["{:.2f}".format(float(i)) for i in (r.crypto.get_crypto_positions('quantity'))][:-1] # The "[:-1] removes the USD record
coin = pd.DataFrame.from_dict(r.crypto.get_crypto_positions('currency'))['code'][:-1] # The "[:-1] removes the USD record
name = pd.DataFrame.from_dict(r.crypto.get_crypto_positions('currency'))['name'][:-1] # The "[:-1] removes the USD record
# Current market price of coins:
i = 0
CryptoMkt = []
for j in coin:
CryptoMkt.append("${:,.2f}".format(float( r.crypto.get_crypto_quote(coin[i])['mark_price'])))
i = i+1
# Current market price of crypto-investments:
CryptoInvest = []
for i in range(0, len([k for k in [float(k) for k in quantity]])):
CryptoInvest.append([k for k in [float(k) for k in quantity]][i] * [j for j in [float(i[1:].replace(',', '')) for i in CryptoMkt]][i])
CryptoInvest = ["%.2f" % i for i in CryptoInvest] # Formatting
crypto = {'Name': name,
'Symbol': coin,
'Category': 'crypto',
'Price': [i[1:].replace(',', '') for i in CryptoMkt],
'Quantity': quantity,
'Equity': CryptoInvest,
'ROI': '',
'P&L': ''}
# ---------------------------------------------------------------------
# Summary:
# ---------------------------------------------------------------------
stocks = pd.DataFrame(stocks)
crypto = pd.DataFrame(crypto)
summary = pd.DataFrame(pd.concat([stocks, crypto])).reset_index(drop=True).style.set_properties(subset=['Name'], **{'text-align': 'left'})\
.set_properties(subset=['Symbol','Category'], **{'text-align': 'center'})\
.hide_index()
summary
Output:
Bank Transactions
There are a bunch of other functions that you can use through the API. For example, the below script will give you a record of all your bank deposits:
# ---------------------------------------------------------------------
# See Bank Transactions:
# ---------------------------------------------------------------------
df = pd.concat([
pd.DataFrame.from_dict(r.account.get_bank_transfers('amount')),
pd.DataFrame.from_dict(r.account.get_bank_transfers('direction')),
pd.DataFrame.from_dict(r.account.get_bank_transfers('fees')),
pd.DataFrame.from_dict(r.account.get_bank_transfers('expected_landing_date'))
], axis=1, join="outer")
df.columns = ['Amount', 'Direction','Fees','Expected Landing Date']
df.head()
Output:
Exporting Stock Orders
The below script will export into Excel a historical view of all your stock purchase orders:
FileLocation = r'<File Location>'
StockReport_Export = r.export.export_completed_stock_orders(FileLocation, file_name=None)
StockReport_Export
Output:
Dividends
The below script will give you will give you a historical view of all your collected dividends:
Dividends = {'Amount': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.account.get_dividends())['amount'])]),
'Rate': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.account.get_dividends())['rate'])]),
'Position': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.account.get_dividends())['position'])]),
'Record Date': pd.Series([i for i in (pd.DataFrame.from_dict(r.account.get_dividends())['record_date'])]),
'Payable Date': pd.Series([i for i in (pd.DataFrame.from_dict(r.account.get_dividends())['payable_date'])]),
'State': pd.Series([i for i in (pd.DataFrame.from_dict(r.account.get_dividends())['state'])])}
pd.DataFrame(Dividends)
Output:
Analysis
If you want to do some analysis on individual stocks or crypto currencies, you could run this script followed by any of the following concepts:
Ticker = 'VZ'
Coin = 'BTC'
Now that you have defined your ticker, one can get some basic information about the company. We can either do a simple search like this:
CompanyData = pd.DataFrame([pd.DataFrame.from_dict(r.stocks.get_instruments_by_symbols(Ticker)).get(key) for key in ['simple_name', 'symbol','type', 'country', 'list_date']])
CompanyData.rename(columns={0: Ticker})
Output:
Or a more complicated search such as this:
Fundamentals = {
'Open Price': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['open'])]),
'High': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['high'])]),
'Low': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['low'])]),
'Year Low': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['low_52_weeks'])]),
'Year High': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['high_52_weeks'])]),
'Volume': pd.Series(["{:.0f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['volume'])]),
'2 Week Average Volume': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['average_volume_2_weeks'])]),
'Average Volume': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['average_volume'])]),
'Market Cap': pd.Series(["{:.0f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['market_cap'])]),
'Dividend Yield': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['dividend_yield'])]),
'PB Ratio': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['pb_ratio'])]),
'PE Ratio': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['pe_ratio'])]),
'Shares Outstanding': pd.Series(["{:.0f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['shares_outstanding'])]),
'CEO': pd.Series([i for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['ceo'])]),
'City HQ': pd.Series([i for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['headquarters_city'])]),
'State HQ': pd.Series([i for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['headquarters_state'])]),
'Sector': pd.Series([i for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['sector'])]),
'Industry': pd.Series([i for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['industry'])]),
'Employee Headcount': pd.Series([i for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['num_employees'])]),
'Foundation Year': pd.Series([i for i in (pd.DataFrame.from_dict(r.stocks.get_fundamentals(Ticker))['year_founded'])])}
pd.DataFrame(Fundamentals).rename(index={0: Ticker}).T
Output:
Stock Historical - 5 Year
The below script will give you an historical view of a stock’s prices:
Interval = 'day' # '5minute', '10minute', 'hour', 'day' or 'week'
Span = '5year' # 'day', 'week', 'month', '3month', 'year', or '5year'
StocksSnapshot = {
'month' : pd.to_datetime(pd.DataFrame.from_dict(r.stocks.get_stock_historicals(Ticker,interval='day',span='5year'))['begins_at']).dt.month,
'day': pd.to_datetime(pd.DataFrame.from_dict(r.stocks.get_stock_historicals(Ticker,interval='day',span='5year'))['begins_at']).dt.day,
'year': pd.to_datetime(pd.DataFrame.from_dict(r.stocks.get_stock_historicals(Ticker,interval='day',span='5year'))['begins_at']).dt.year}
StocksSnapshot = pd.Series(StocksSnapshot['month'].astype(str) + '/' + StocksSnapshot['day'].astype(str) + '/' + StocksSnapshot['year'].astype(str))
StocksHistoricals = {
'Snapshot': pd.Series([i for i in StocksSnapshot]),
'Open Price': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.stocks.get_stock_historicals(Ticker,interval=Interval,span=Span))['open_price'])]),
'Close Price': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.stocks.get_stock_historicals(Ticker,interval=Interval,span=Span))['close_price'])]),
'High Price': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.stocks.get_stock_historicals(Ticker,interval=Interval,span=Span))['high_price'])]),
'Low Price': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.stocks.get_stock_historicals(Ticker,interval=Interval,span=Span))['low_price'])])}
pd.DataFrame(StocksHistoricals)
Output:
Crypto Historical - 5 Year
The below script will give you an historical view of a crypto prices:
Interval = 'day' # '5minute', '10minute', 'hour', 'day' or 'week'
Span = '5year' # 'day', 'week', 'month', '3month', 'year', or '5year'
CryptoSnapshot = {
'month' : pd.to_datetime(pd.DataFrame.from_dict(r.crypto.get_crypto_historicals(Coin,interval='day',span='5year'))['begins_at']).dt.month,
'day': pd.to_datetime(pd.DataFrame.from_dict(r.crypto.get_crypto_historicals(Coin,interval='day',span='5year'))['begins_at']).dt.day,
'year': pd.to_datetime(pd.DataFrame.from_dict(r.crypto.get_crypto_historicals(Coin,interval='day',span='5year'))['begins_at']).dt.year}
CryptoSnapshot = pd.Series(CryptoSnapshot['month'].astype(str) + '/' + CryptoSnapshot['day'].astype(str) + '/' + CryptoSnapshot['year'].astype(str))
CryptoHistoricals = {
'Snapshot': pd.Series([i for i in CryptoSnapshot]),
'Open Price': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.crypto.get_crypto_historicals(Coin,interval=Interval,span=Span))['open_price'])]),
'Close Price': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.crypto.get_crypto_historicals(Coin,interval=Interval,span=Span))['close_price'])]),
'High Price': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.crypto.get_crypto_historicals(Coin,interval=Interval,span=Span))['high_price'])]),
'Low Price': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.crypto.get_crypto_historicals(Coin,interval=Interval,span=Span))['low_price'])])}
pd.DataFrame(CryptoHistoricals)
Output:
Rankings
The API also gives insight to multiple ranking views such as:
Robinhood's Top 100
RobinhoodTop100 = {'Ticker': pd.Series([i for i in (pd.DataFrame.from_dict(r.markets.get_top_100())['symbol'])]),
'Last Trade Price': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.markets.get_top_100())['last_trade_price'])])}
pd.DataFrame(RobinhoodTop100).head()
Output:
Robinhood's Top Movers
RobinhoodTopMovers= {'Ticker': pd.Series([i for i in (pd.DataFrame.from_dict(r.markets.get_top_movers())['symbol'])]),
'Last Trade Price': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.markets.get_top_movers())['last_trade_price'])]),
'Previous Close': pd.Series(["{:.2f}".format(float(i)) for i in (pd.DataFrame.from_dict(r.markets.get_top_movers())['previous_close'])]) }
pd.DataFrame(RobinhoodTopMovers).head()
Output:
S&P 500 Top Movers
SP500TopMovers= {'Ticker': pd.Series([i for i in (pd.DataFrame.from_dict(r.markets.get_top_movers_sp500('up'))['symbol'])]),
'Movement': pd.DataFrame.from_dict(i for i in (pd.DataFrame.from_dict(r.markets.get_top_movers_sp500('up'))['price_movement']))['market_hours_last_movement_pct'],
'Last Trade Price': pd.DataFrame.from_dict(i for i in (pd.DataFrame.from_dict(r.markets.get_top_movers_sp500('up'))['price_movement']))['market_hours_last_price']}
pd.DataFrame(SP500TopMovers).head()
Output:
Defining Limits in Python
If you were so inclined, it is possible to configure a python investing bot that either uses the functionality of the API or build on your own defined configurations. Below is my own crypto-limit concept. When you initiate limit orders in Robinhood, it requires you to set aside cash to cover that position at the time of order. The advantage of using this method over the API would be that you would not be required to transfer cash into Robinhood until the limit is reached assuming you have your Python script running.
MarginBench = 0.05
# Market Price
BTC_Mkt = float(r.crypto.get_crypto_quote('BTC')['mark_price'])
y = "${:,.2f}".format(BTC_Mkt)
print("Market Price: {}".format(y))
# Buy Price:
BTC_Buy = (1-MarginBench )*BTC_Mkt
y = "${:,.2f}".format(BTC_Buy)
print("Buy Price: {}".format(y))
# Sell Price:
BTC_Sell = (1+MarginBench )*BTC_Mkt
y = "${:,.2f}".format(BTC_Sell)
print("Sell Price: {}".format(y))
# Profit:
Invest = 100
Margin = Invest*((BTC_Sell-BTC_Buy)/BTC_Buy)
y = "${:,.2f}".format(Margin)
print("Profit: {}".format(y))
Initiate Orders
Lastly, it is possible to buy and sell stocks and crypto currencies through the API. I have not tested this, but I would imagine that the script below would be properly configured.
quantity = 1
orderType = 'market' # or 'limit'
trigger = 'immediate' # or 'stop'
side = 'buy' # or 'sell'
OrderStock = r.orders.order(Ticker, quantity, orderType, trigger)
amountUSD = 1
OrderCrypto = r.orders.order_buy_crypto_by_price(Coin, amountUSD, 'mark_price')
Final Thoughts
There is a lot of functionality that the Robinhood API provides, much more then what I have explored in this article. If you are interested in learning more, I would recommend visiting this website. The API allows for analysis on your own account, on prospect investments and even the ability to initiate purchase and sell orders. The advantage of this lets you manage your own analysis of your investments. With such capabilities and the added benefit of Python, it would not be too difficult to build a fully functional investing bot that is configured with limit orders that you define.
Comentários