Robinhood API – A Complete Guide

35 min read

Get 10-day Free Algo Trading Course

Last Updated on September 15, 2020

Table of Contents

  1. What is the Robinhood API?
  2. Why should I use the Robinhood API?
  3. Why shouldn’t I use the Robinhood API?
  4. Is there a Python library for the Robinhood API?
  5. Who can use the Robinhood API?
  6. What are the different Robinhood account types?
  7. How do I get started with the Robinhood API?
  8. How do I place an order for stocks using the Robinhood API?
  9. How do I place an order for crypto using the Robinhood API?
  10. How do I place an order for options using the Robinhood API?
  11. How do I place an order for Visa when Mastercard hits a certain price using the Robinhood API?
  12. How do I place an order for Visa when Mastercard moved 1% in the last hour using the Robinhood API?
  13. How do I fire a pair trade using the Robinhood API?
  14. How do I buy a call option when the underlying stock moved using the Robinhood API?
  15. How do I retrieve the option Greeks using the Robinhood API?
  16. How do I place a covered call trade using the Robinhood API?
  17. How do I set take profits and stop losses using the Robinhood API?
  18. How do I get a summary of my current positions and holdings using the Robinhood API?
  19. How do I cancel existing orders using the Robinhood API?
  20. How do I get historical data using the Robinhood API?
  21. How do I get fundamentals data using the Robinhood API?
  22. How do I get options data using the Robinhood API?
  23. How do I export/save my history of completed orders using the Robinhood API?
  24. Final thoughts
  25. Link to download code

What is the Robinhood API?

The Robinhood API is a means to interact with your Robinhood account remotely and programatically using HTTP GET and POST requests.

You can do absolutely everything through the API that you can do normally from within your account- placing buy and sell orders, cancelling orders, looking at your order history, fetching historical data for a given stock and so forth.

Robinhood itself was originally a mobile trading/investing app launched in 2013 aimed at making investing easy for the common person, but has expanded to offer web based trading as well since 2017.

The name probably makes reference to the whole “take from the rich, give to the poor” ethos from the legendary Robin Hood, as RobinHood prides itself on offering commission free trading, allowing users of modest means to invest by allowing the purchase of fractional shares, and even gives back to its users by paying 0.3% interest APY on cash left un-invested idling in accounts.

You can trade stocks, ETFs, options and crypto on Robinhood, and the API also allows you to draw limited resolution historical data, a decent range of fundamentals data, and of course a range of information specifically about your account- your open positions and your trading history and so forth.

Note that while you can interact with your account with this API, it’s sort of an unofficial API and RobinHood does not provide any in-house libraries to help use the API.

In this guide we will use an up-to-date 3rd-party Python library to help use the API, but bear in mind with such a setup there is always a risk that Robinhood updates their underlying API, causing the 3rd party library’s methods to break in functionality or return odd results. That said, our assessment is that the library used in this guide makes very few assumptions about the data returned from the API, so is unlikely to encounter many future problems.

In the following sections we will talk about Robinhood as a brokerage as well as specifically their API, since actions made through the API are bound by exactly the same limitations (and benefits) as acting directly through your account- so deciding to use the Robinhood API is as much of a decision on using Robinhood as a brokerage as it is on using the API.

Why should I use the Robinhood API?

  • No commissions
  • No account minimums
  • Instant deposits
  • Interest on un-invested funds (new cash management feature)
  • Can buy fractional shares
  • Margin trading
  • Automatic dividend re-investment
  • SIPC protection for up to $500,000 ($250,000 for cash)

Firstly, and perhaps the biggest draw for the casual/rookie investor- no commission fees! Robinhood charge 0% commissions on regular buys and sells and only the most miniscule of regulatory trading fees specifically for sell orders ($22 dollars per $million…).

So how do they make money? Allegedly through lending un-invested money in investor accounts to banks, taking a cut of fees from the market makers they route orders to on the other end (Robinhood uses Citadel Securities, Two Sigma, Wolverine and Virtu), membership fees for their premium (gold) accounts and interest on money borrowed margin trading on those accounts (5% AER).

You can checkout a comprehensive list of their fees for different services here.

No account minimums. You can start trading with as little as $1 in your account.

The instant and gold accounts also have instant deposits. Instant accounts are the default account type you start when you sign-up with Robinhood and allow $1000 instant deposits, and for the low price of $5/month you can upgrade to a gold account for a hefty $50,000 daily instant deposit limit (among other benefits).

Robinhood’s cash accounts unfortunately do not offer instant deposits, with money transfers taking 4-5 days to clear, but they do not suffer from the usual day trading rules Robinhood imposes for low value accounts for its other account types.

We succinctly outline the pros and cons of each account type in the Robinhood account type section of this guide.

0.3% interest on un-invested funds. Robinhood has recently started offering a cash management feature, which will give you a Robinhood debit card and 0.3% APR on any money left uninvisted sitting in your account, a nifty little bonus for whenever you’re sitting out of trades.

You’ll have to apply for this specifically though- check it out here.

Robinhood also allows you to buy fractional shares. This again plays into the theme of helping rookie or poorer (and younger) investors get into the markets, where buying even a single share for a stock could be prohibitive- for instance at the time of writing this article a single share of Amazon trades at ~$2800 USD!

Margin trading is also possible with the gold account, with a max leverage of 2:1 and fees of 5% APY for any money you borrow.

Automatic dividend re-investment (DRIP). Robinhood recently released this feature, which you can toggle on and off as you please from within your account. Not so useful if you are making frequent trades but definitely helpful if you are taking some long term positions you want to double down on!

Finally, Robinhood has SIPC protection for up to $500,000 in total (securities and cash) and $250,000 cash only, letting most retail traders breathe a little easier a night!

Why shouldn’t I use the Robinhood API?

  • Limited resolution historical data
  • Low value accounts are blocked from frequent day trading (except cash)
  • No demo account
  • Real-time data concerns 
  • Basic charts
  • No websocket for live data
  • No short selling/limited order types
  • Un-official API

Firstly, the historical data available through the API is a bit limited. The API provides only 5 minute|10 minute|30 minute|day|week intervals for data, and only returns data in the day|week|year|5year|all ranges.

Notably, this is missing high resolution 1 minute data, and the popular 1 hour and 4 hour time-frames for trading on.

Low value accounts are blocked from frequent day trading. This is a pretty big one but not particularly limited to Robinhood since its intended as a industry-wide form of protection for “unsophisticated” investors by the SEC.

This applies to both instant and gold accounts with balances under $25,000, which are not allowed to make more than 3 day trades in any 5 consecutive business day period.

A day trade is any trade in which you “reverse” direction in the same day.

For instance buying stock A at 10am and buying stock A again at 11am is not a day trade, since you are maintaining the same direction (buying).

However, buying stock A at 10am and selling stock A at 11am is a direction reversal since you have gone from buying to selling so counts as 1 day trade.

Similarly buying stock A at 10am, selling stock A at 11am, buying stock A again at 11:30am and selling at 11:40am counts as 3 day trades as you changed direction 3 times.

Making 4 day trades in 5 business days will mark your account for “Pattern Day Trading” (PDT), and you will have 5 days to deposit funds into your account to bring your balance above $25,000 or you will be banned from making any day trades for 90 days.

You can get around this by asking for a “downgrade” to the cash account, which allows any number of day trades for account balances under $25,000, but cash accounts do not have instant settlements and deposits like the gold and instant accounts.

This is itself a form of limitation regulation as whereas with instant settlement if you close a trade at 11:30am, you can enter a new trade with the same money from the sale at 11:31am, without instant settlement it can take up to 2 days for the cash to be re-available for trading, effectively placing similar limitations on how often you can “day trade” with your full account balance.

Robinhood doesn’t offer a demo account. Demo accounts where you can trade pretend money can be useful both for beginners and for testing new trading strategies.

Of course, with zero fees and the ability to purchase fractional shares, you can scale down your positions to negligible sums of money anyway for strategy testing, but this is both a pain in the ass and does not properly simulate the effect of a given position size in your strategy/on the market- particularly important when trading less liquid markets.

Real-time data concerns. Despite the actual app showing quote data in real-time, Robinhood’s terms and conditions point out that data may be delayed by up to 20 minutes (top of page 3).

Probably not much of a real concern, but it is well known their price feeds often lag several seconds- Robinhood is definitely on the budget end of data quality.

Basic charts. For the longest time one of the biggest gripes many people had about Robinhood were their incredibly basic charts. In 2018 they expanded their offering to include candlestick charts, but compared to competitors their charts are still very basic and lack customisation options.

No websocket for live data. Most serious brokerage’s APIs offer a websocket that continuously pushes you live price updates as they come in. The Robinhood API has no such functionality, which means you will have to continuously query the API for the latest price of a ticker- slow and highly inefficient.

No short selling/limited order types. You can’t actually short sell on Robinhood (borrowing stocks from someone else and selling them at the current market value, to hopefully buy them back cheaper later and return them to the lender with the difference in hand)- probably to do with Robinhood trying to minimise the range of risky moves their investors can make.

There’s also a lack of advanced order types, like being able to set stop losses and take profits to a buy order, or one-cancels-the-other (OCO) orders- causing issues implementing more sophisticated strategies.

The Robinhood API is an un-official API. This means it could be withdrawn at any time without warning, rendering any infrastructure you built on top of it useless.

Also, Robinhood does not provide any libraries to help interact with the API. Third party solutions exist, but this compounds risk in that any alteration to the API by Robinhood might lead to broken functionality in any of the 3rd party libraries you use to query the API.

Summary

Everything about Robinhood is designed with ease of use for the beginner investor in mind, with an added focus on attractive fees and benefits.

From a trading perspective, the Robinhood API’s (and Robinhood itself’s) biggest weaknesses are the lack of ability to short sell, lack of more advanced order types like attaching stop losses and take profits to orders, one-cancels-other orders, and market orders for options- making more advanced strategies tricky to implement. This is all a consequence of trying to remain as easy to use as possible for beginners, and protecting them from big losses by minimising the amount of risky moves they are allowed to take.

Also remember, unless you downgrade to a cash account or maintain a balance of over $25,000, you will be unable to make more than 3 day trades in every 5 day period.

Combining all this with the fact that the Robinhood API is an unofficial API that could be withdrawn at any time, we recommend NOT using the Robinhood API for any high frequency or more advanced trading strategies. Algorithmic trading leans to the more sophisticated side of trading which is not Robinhood’s target audience of novice retail traders.

That said, there is perhaps still a sweet spot to use the Robinhood API programmatically, where you have a modest account balance of $5000-$25,000, downgrade to a cash account and make regular trades with smaller positions such that you never cycle through more than your whole account balance in any 2-day period (the maximum time taken for settlements in a cash account) whilst sticking to simple order types and investment strategies.

Is there a Python library for the Robinhood API?

Yes!

Again, Robinhood itself doesn’t provide any official libraries but there are many 3rd party libraries available in a range of programming languages.

For this guide we will use robin stocks, which is a Python library. We will go over how to use the library in detail in a bit.

Who can use the Robinhood API?

To use the Robinhood API you will obviously need an actual Robinhood account.

Currently Robinhood is only freely accessible to U.S residents.

You must:

  • Be 18 years or older
  • Have a valid Social Security Number
  • Have a legal U.S. residential address within the 50 states or Puerto Rico
  • Be a U.S. citizen, U.S. permanent resident, or have a valid U.S. visa

You can use your account pretty much anywhere in the world whilst travelling, except in the sanctioned jurisdictions of Cuba, Iran, North Korea, Syria, and the Crimea region of Ukraine, where you won’t be able to access your account and attempted log-ins may lead to account restrictions.

Robinhood was until recently also rolling out via wait-list in the UK, however as of July 2020 they have unfortunately scrapped any plans to operate in the UK for the foreseeable future, due to the Corona-virus pandemic.

What are the different Robinhood account types?

As we’ve already talked about a bit, Robinhood offers 3 account types- instant, cash and gold.

Instant is the default account type you receive when you open an account with Robinhood.

You can upgrade to gold for $5/month, which raises your instant deposit and settlement limit from $1000 to $50,000, allows you to leverage trade at a 2:1 ratio and gives you access to level II market data (full order books for buy and sell orders).

Alternatively you can “downgrade” to cash by request which loses you instant deposits and settlements but does not have any limitations on day trading for accounts with balances under $25,000.

Here is a table which outlines the main differences:

Source: https://brokerchooser.com/broker-reviews/robinhood-review

How do I get started with the Robinhood API?

Account creation

Firstly, you’ll need to create an account, either through the mobile app or you can head over to the Robinhood website signup page here.

And if you’re not from the US, unfortunately you can’t use Robinhood for now!

Opening an account with Robinhood is usually pretty fast, with the normal time taken being under a day. As an added bonus, Robinhood is currently even offering a lottery style free stock when you open account- with the occasional multi hundred dollar stock up for grabs!

Library installation

The next step is to install the robin stocks Python library which we will use to interact with Robinhood’s API.

Here is the full documentation.

Here is a slightly more dynamic documentation.

And the github is really useful to better understand how the functions work/look at a few examples.

That said, don’t worry about reading through all those right now, we will pick out the most relevant bits in the rest of this guide!

Since robin stocks is on PyPI, you can download and install the library with just one simple action in the command line:

pip install robin_stocks

Or if you prefer you can clone the repository from github:

git clone https://github.com/jmfernandes/robin_stocks.git

Change directory into robin_stocks:

cd robin_stocks

and then install using

pip install .

The only requirement for the library is a version of Python 3!

Importing and Logging in

Finally, before interacting with our account through the Robinhood API we will need to import robin stocks:

import robin_stocks as rs

Each time before initiating a script we will need to login to Robinhood:

rs.login(username=your_username,
         password=your_password,
         expiresIn=86400,
         by_sms=True)

Here your_username and your_password should be your username and password for your Robinhood account.

This function effectively logs you into Robinhood by getting an authentication token and saving it the the session header.

  • expiresIn is the time duration (in seconds) you will remain longed in. 86400 seconds (1 day) is the default and maximum possible, so you will need to re-authenticate at least once per day, but you can lower this if you like.
  • by_sms: {True, False}. If True sends you an SMS 6-digit code if logging in from a new device. If false emails it to you instead.

Note not all functions actually require you to log, however over time more and more of the Robinhood API has been getting gated behind a login- even functions making requests that do not ask for/interact with personal components of an account. Certainly anything interacting with your account like placing orders does require you to do so, so it is good practice in general to log in to Robinhood at the beginning of your script.

Setting username and password as environment variables

Finally if you wish to improve security during login you might want to consider setting your username and password as environment variables so that they are never plainly displayed in your code.

To do this in a Mac or Linux environment type the following into the command line:

export robinhood_username="your_username_here"
export robinhood_password="your_password_here"

To do this in a Windows enevironment type the following into the command prompt:

set robinhood_username=your_username_here
set robinhood_password=your_password_here

Here is an example for Mac/Linux where we also verify the environment variables are set correctly from inside the terminal using Python:

Therefore, with our Robinhood username and password set to the environment variables robinhood_username and robinhood_password as in the example before, we can login without our username/password plainly visible as follows:

import os 

robin_user = os.environ.get("robinhood_username")
robin_pass = os.environ.get("robinhood_password")

rs.login(username=robin_user,
         password=robin_pass,
         expiresIn=86400,
         by_sms=True)

Logging out

Finally, if you wish to log-out early, simply run:

rs.logout()

With all that done, you’re ready to begin!

How do I place an order for stocks using the Robinhood API?

You can place orders in several different ways such as:

  • By dollar amount of shares (market order)
  • By integer/fractional quantity of shares (market order)
  • By integer quantity of shares (limit order)

Market order by dollar amount

A market buy is simply a buy that is executed immediately- starting at the current market price and eating the sell book upwards until it is completed.

To market buy $X dollars worth of a stock we use the following function:

rs.orders.order_buy_fractional_by_price(symbol,
                                       ammountInDollars,
                                       timeInForce='gtc',
                                       extendedHours=False) 

It has the following parameters that are important:

  • symbol (str): the stock ticker of the stock to purchase
  • amountInDollars (float): the amount in dollars of the fractional shares you want to buy
  • timeInForce (Optional[str]): changes how long the order will be in effect for. ‘gtc’ = good until cancelled. ‘gfd’ = good for the day. ‘ioc’ = immediate or cancel. ‘opg’ execute at opening of trading.
  • extendedHours (Optional[str]): premium users only. Allows trading during extended hours. Should be true or false.

So if we wanted to market buy $500 of Apple stock during normal hours of trading we would do the following:

rs.orders.order_buy_fractional_by_price('AAPL',
                                        500,
                                        timeInForce='gtc',
                                        extendedHours=False)

Note that timeInForce is not hugely relevant for market orders (since they are executed immediately)- using good until cancelled should generally be fine.

Market order by integer/fractional quantity

There is a basic order function to buy integer quantities of shares, but since the fractional variant handles both integer and fractional requests, we recommend simply sticking to that!

Here is the function:

rs.orders.order_buy_fractional_by_quantity(symbol,
                                          quantity,
                                          timeInForce='gtc',
                                          extendedHours=False)

So to buy 7.3 shares of Apple (at whatever the current market price is) we would do:

rs.orders.order_buy_fractional_by_quantity('AAPL',
                                          7.3,
                                          timeInForce='gtc',
                                          extendedHours=False)

Of course remember make sure you have enough funds in your account to execute any quantity orders!

Limit order by integer quantity of shares

A limit order is a type of order that does not execute immediately, rather it executes when the price of an asset hits a certain price.

rs.orders.order_buy_limit(symbol,
                          quantity,
                          limitPrice,
                          timeInForce='gtc',
                          extendedHours=False)
  • limitPrice is the price per share (in dollars) you want to buy at.

So if say Apple was currently trading at $500/share, and we were interested in buying 5 shares of Apple but only at a slighter cheaper price- say $450 dollars/share- we could set a limit order as follows:

rs.orders.order_buy_limit('AAPL,
                          5,
                          450,
                          timeInForce='gtc',
                          extendedHours=False)

The point of a limit order is you can set it and forget- you don’t have to be constantly monitoring the markets until the price hits the level you are interested in buying at. Also this way you can take advantage of any violent downwards price wicks you might otherwise miss if you weren’t glued to your computer 24/7.

Note that unfortunately you can only place limit stock orders in integer quantities, and you might want to consider the timeInForce setting more carefully, since unlike a market order a limit order is not necessarily executed immediately (or even any time soon…).

How do I place an order for crypto using the Robinhood API?

The functions here are super similar to those for stocks, except that there are no extendedHours parameters since crypto markets trade 24/7, so we will just give a quick example of how to execute each order type.

Also note that you don’t fully “own” cryptocurrencies when you purchase them on Robinhood- you can’t access your wallet or send the cryptocurrencies to any other wallets, so you can’t use the cryptocurrencies for any of their existing purposes- all you are really buying is price exposure to the cryptocurrency.

That said Robinhood have stated they plan to allow coin withdrawals sometime in the future.

Market order by dollar amount

The following would market buy $1000 of Ethereum:

rs.orders.order_buy_crypto_by_price('ETH', 
                                 1000,
                                 timeInForce='gtc')

Market order by integer/fractional quantity

The following would market buy 15.9 Ethereum:

rs.orders.order_buy_crypto_by_quantity('ETH', 
                                 15.9,
                                 timeInForce='gtc')

Limit order by fractional quantity of shares

And finally the following would place a limit buy for 0.5 Bitcoin at $5000:

rs.orders.order_buy_crypto_limit('BTC', 
                                 0.5,
                                 5000,
                                 timeInForce='gtc')

How do I place an order for options using the Robinhood API?

Briefly, options are contracts giving a trader the right, but not the obligation, to buy (call) or sell (put) the underlying asset they represent at a specific price on or before a certain date.

To place a single limit order to buy a call or put option you can use the order_buy_option_limit() function:

rs.orders.order_buy_option_limit(positionEffect, 
                                 creditOrDebit, 
                                 price, 
                                 symbol,
                                 quantity,
                                 expirationDate, 
                                 strike, 
                                 optionType='both', 
                                 timeInForce='gtc')

It has the following parameters:

  • positionEffect (str) – Either ‘open’ for a buy to open effect or ‘close’ for a buy to close effect. As a beginner if you are only buying options, you will always be buying to ‘open’.
  • creditOrDebit (str) – Either ‘debit’ or ‘credit’. For beginners, if you’re only buying call or put options this will always be ‘debit’. If you’re doing something more advanced like writing (selling) options and/or doing fancier spreads, you probably know for yourself what to put here.
  • price (float) – The limit price to trigger a buy of the option.
  • symbol (str) – The stock ticker of the stock to trade.
  • quantity (int) – The number of options contracts to buy.
  • expirationDate (str) – The expiration date of the option in ‘YYYY-MM-DD’ format.
  • strike (float) – The strike price (price you can buy/sell the underlying asset on the option’s expiry date) of the option.
  • optionType (str) – This should be ‘call’ or ‘put’
  • timeInForce (Optional[str]) – Changes how long the order will be in effect for. ‘gtc’ = good until cancelled. ‘gfd’ = good for the day. ‘ioc’ = immediate or cancel. ‘opg’ execute at opening.

So if we wanted to place a limit buy order for a single call option that gave us the right to buy apple stock at $400 with an expiry date of 17/07/2020 and we were willing to pay $350 for the call contract (all numbers are purely hypothetical), we would fill the function as follows:

rs.orders.order_buy_option_limit('open',
                                 'debit',
                                 350,
                                 "AAPL",
                                 1,
                                 '2020-07-17', 
                                 400,
                                 optionType='call',
                                 timeInForce='gtc')

There are fancier order types you can use if you want to place multiple option orders at once (“spreads”) instead of placing them one by one with the above- for instance the order_option_spread() function- but we will skip going over them in this guide for brevity.

Check out the “Placing and Cancelling Orders” section of the robin_stocks function list for more options.

How do I place an order for Visa when Mastercard hits a certain price using the Robinhood API?

Achieving this will require some trading logic to constantly monitor the price of Mastercard. Of course, we could interchange Visa and Mastercard with any other two stocks if we wanted- the logic would remain entirely the same.

The function to get the latest price is stocks.get_latest_price(). It takes the inputs:

  • inputSymbols  (str or list): a single stock ticker or a list of stock tickers.
  • includeExtendedHours (bool): ‘True’ to get the extended hours price if available, ‘False’ for regular hours price only, even after hours- may as well leave this always as True!

And it returns a list of prices as strings- a list of length 1 if we only input a single ticker as we will here.

Let’s say we want to place an order for Visa when Mastercard crosses below $280.

First, we will need to get the latest price of Mastercard, and adjust the output from get_latest_price from a list containing a single string to a single float. Here is the code for that:

price = rs.stocks.get_latest_price('MA', includeExtendedHours=True
# assigning price to first (and only) item of list and converting from str to float
mastercard_price = float(price[0])

We will need a few imports for this rest of our trading script so lets get those out of the way:

from time import sleep
import pandas as pd

Now we will create an infinite loop.

The loop will first check the latest price of Mastercard. If it is below $280 it will fire an order for $500 of Visa and break the loop.

If it is not below $280, the script will go to sleep for 15 seconds before restarting the loop- to not overwhelm the Robinhood API with endless requests.

Here is the code to do that:

while True:
    price = rs.stocks.get_latest_price('MA', includeExtendedHours=True)
    # assigning price to first (and only) item of list and converting from str to float
    mastercard_price = float(price[0])

    if mastercard_price < 280:
        rs.orders.order_buy_fractional_by_price('V', 500)
        break
    else:
        sleep(15)
                
 

Finally, we will wrap in some try and except blocks with error handling so that our loop doesn’t break from any unexpected errors before firing an order.

Here is what the full code looks like:

while True:
    try:
        price = rs.stocks.get_latest_price('MA', includeExtendedHours=True)
        # assigning price to first (and only) item of list and converting from str to float
        mastercard_price = float(price[0])
        
        if mastercard_price < 280:
            try:
                rs.orders.order_buy_fractional_by_price('V', 500)
                break
                
            except Exception as e:
                print("Error placing order:", e)
        else:
            sleep(15)
                
    except Exception as e:
        print("Error fetching latest price:", e)
        
print("ORDER TRIGGERED at {}".format(pd.Timestamp.now()))

How do I place an order for Visa when Mastercard moved 1% in the last hour using the Robinhood API?

We will use a similar script structure as for the last section, but this time we have the added complication of having to keep a history of prices to know when the price of Mastercard has moved more than 1% in the last hour.

Firstly, we will create a data frame with a date and price column:

df = pd.DataFrame(columns=['date', 'price'])

Now for each iteration within the loop, we will append to the dataframe both the time (date) and the price at that time. Notice we use the existing length of the data frame to inform which index value to pass to .loc to append to the end of the data frame:

df.loc[len(df)] = [pd.Timestamp.now(), mastercard_price]

Next we determine the time one hour ago by subtracting 60 minutes from the most recent time in the dataframe using Pandas Timedelta.

start_time = df.date.iloc[-1] - pd.Timedelta(minutes=60)

Then we filter down our dataframe to include only the last hour of data:

df = df.loc[df.date >= start_time] # cuts dataframe to only include last hour of data

And find the minimum and maximum prices within the last hour to compare the current price to:

max_price = df.price.max()
min_price = df.price.min()

Finally, we compare the current price to both the max and min prices within the last hour and make a trade if the price has moved than 1%.

We will buy $500 of Visa if Mastercard drops more than 1% and sell $500 of Visa if it rises more than 1% as a mean reversion strategy. Note that this assumes we are already holding $500 or more of Visa to begin with- Robinhood doesn’t allow short selling.

if df.price.iloc[-1] < max_price * 0.99:
            try:
                rs.orders.order_buy_fractional_by_price('V', 500)
                print("DROPPED 1%, CURRENT PRICE: {} MAX PRICE: {}".format(df.price.iloc[-1], max_price))
                break
                
            except Exception as e:
                print("Error placing order:", e)
                
        elif df.price.iloc[-1] > min_price * 1.01:
            try:
                rs.orders.order_sell_fractional_by_price('V', 500)
                print("RISEN 1%, CURRENT PRICE: {} MIN PRICE: {}".format(df.price.iloc[-1], min_price))
                break
                
            except Exception as e:
                print("Error placing order:", e)
        
        else:
            print("NO ORDER, CURRENT PRICE: {} MIN PRICE: {} MAX PRICE: {}\n".format(df.price.iloc[-1], min_price, max_price))
            sleep(15)

So all together the code looks like this:

from time import sleep
import pandas as pd

df = pd.DataFrame(columns=['date', 'price'])

while True:
    try:
        price = rs.stocks.get_latest_price('MA', includeExtendedHours=True)
        # assigning price to first (and only) item of list and converting from str to float
        mastercard_price = float(price[0])
        
        df.loc[len(df)] = [pd.Timestamp.now(), mastercard_price]
        
        start_time = df.date.iloc[-1] - pd.Timedelta(minutes=60)
        df = df.loc[df.date >= start_time] # cuts dataframe to only include last hour of data
        max_price = df.price.max()
        min_price = df.price.min()
        
        if df.price.iloc[-1] < max_price * 0.99:
            try:
                rs.orders.order_buy_fractional_by_price('V', 500)
                print("DROPPED 1%, CURRENT PRICE: {} MAX PRICE: {}".format(df.price.iloc[-1], max_price))
                break
                
            except Exception as e:
                print("Error placing order:", e)
                
        elif df.price.iloc[-1] > min_price * 1.01:
            try:
                rs.orders.order_sell_fractional_by_price('V', 500)
                print("RISEN 1%, CURRENT PRICE: {} MIN PRICE: {}".format(df.price.iloc[-1], min_price))
                break
                
            except Exception as e:
                print("Error placing order:", e)
        
        else:
            print("NO ORDER, CURRENT PRICE: {} MIN PRICE: {} MAX PRICE: {}\n".format(df.price.iloc[-1], min_price, max_price))
            sleep(15)
                
    except Exception as e:
        print("Error fetching latest price:", e)
        
print("ORDER TRIGGERED at {}".format(pd.Timestamp.now()))

We created a mock simulation to show what the output of this script might look like (adding an extra line to print the data frame), with a 0.1 minute price consideration interval (instead of 60 minutes) and 4 second sleep per cycle to demonstrate how the data frame is continuously updated to only recent history:

How do I fire a pair trade using the Robinhood API?

In this section we will show how to long Box and short Dropbox (in equal dollar amounts) when they diverge more than 3% over the previous day.

A pair trade is a trading strategy where you identify two stocks that move with high correlation- and long the under-performing stock and short the over-performing stock if they begin to move unusually far apart as a mean reversion strategy- where you assume this is an unusual blip and they will shortly move closer together again.

Box and Dropbox are examples of two stocks that move with high correlation:

We will show you how to create a trading script that longs Box and shorts Dropbox if they began to move unusually far apart in a trading day compared to the last trading day.

Again by “shorting”, we make the assumption we were already holding some Dropbox that we can sell since we cannot directly short sell on Robinhood, so this strategy will only fully work if we are willing to have a minimum continuous exposure to Box and Dropbox in the first place.

The idea is that we buy Box when it falls unusually low relative to Dropbox and sell Dropbox with the expectation that the two move closer together again in the future. When they do, we can sell some Box and re-buy some Dropbox to re-balance our portfolio to it’s original levels (at net profit).

Firstly, lets grab the daily historical data for the last week for Box and Dropbox and convert the response into a pandas data frame:

dropbox_data = rs.stocks.get_stock_historicals("DBX", interval="day", span="week")
dropbox_historical = pd.DataFrame(dropbox_data)

box_data = rs.stocks.get_stock_historicals("BOX", interval="day", span="week")
box_historical = pd.DataFrame(box_data)

Now lets work out what the price difference between the stocks was at the daily close yesterday. Note we use .iloc[-1] to return the last row of the data frame, which will be yesterday’s daily data:

price_diff_yesterday = dropbox_historical.iloc[-1]['close_price'] - box_historical.iloc[-1]['close_price']

Now in a loop, we will query the Robinhood API for the most update to date Box and Dropbox prices and compute the difference:

while True:
    dropbox_today = float(rs.stocks.get_latest_price('DBX', includeExtendedHours=True)[0])
    box_today = float(rs.stocks.get_latest_price('BOX', includeExtendedHours=True)[0])
    
    price_diff_today = dropbox_today - box_today

       

We will then check if the prices have diverged more than 3% since yesterday.

If they have, we will long Box , short Dropbox and break the loop. If they haven’t, we will wait few seconds and query the latest prices again:

if price_diff_today > 1.03 * price_diff_yesterday:
    # LONG BOX SHORT DROPBOX
    rs.orders.order_buy_fractional_by_price('BOX',
                                            500,
                                            timeInForce='gtc',
                                            extendedHours=False) 

    rs.orders.order_sell_fractional_by_price('DBX',            
                                             500,
                                             timeInForce='gtc',
                                             extendedHours=False) 
    break
else:
    sleep(15)

Here is what the full code looks like we some error handling, and a few informational printouts:

# firing a pair trade when Dropbox and box diverge more than 3% over the previous day FULL EXAMPLE

dropbox_data = rs.stocks.get_stock_historicals("DBX", interval="day", span="week")
dropbox_historical = pd.DataFrame(dropbox_data)

box_data = rs.stocks.get_stock_historicals("BOX", interval="day", span="week")
box_historical = pd.DataFrame(box_data)

price_diff_yesterday = dropbox_historical.iloc[-1]['close_price'] - box_historical.iloc[-1]['close_price']

while True:
    try:
        dropbox_today = float(rs.stocks.get_latest_price('DBX', includeExtendedHours=True)[0])
        box_today = float(rs.stocks.get_latest_price('BOX', includeExtendedHours=True)[0])
        print("box today:", box_today)
        print("dropbox today:", dropbox_today)

        price_diff_today = dropbox_today - box_today

        if price_diff_today > 1.03 * price_diff_yesterday:
            try:
                # LONG BOX SHORT DROPBOX
                rs.orders.order_buy_fractional_by_price('BOX',
                                           500,
                                           timeInForce='gtc',
                                           extendedHours=False) 

                rs.orders.order_sell_fractional_by_price('DBX',            
                                           500,
                                           timeInForce='gtc',
                                           extendedHours=False) 

                print("Diverged MORE THAN 3%, YESTERDAY'S DIFFERENCE: {} TODAY'S DIFFERENCE: {} PERCENTAGE CHANGE: {}%\n".format(price_diff_yesterday, price_diff_today, (price_diff_today/price_diff_yesterday - 1)*100))
                break
            except Exception as e:
                print("Error placing orders:", e)
                sleep(15)


        else:
            print("STILL WAITING, YESTERDAY'S DIFFERENCE: {} TODAY'S DIFFERENCE: {} PERCENTAGE CHANGE: {}%\n".format(price_diff_yesterday, price_diff_today, ((price_diff_today/price_diff_yesterday - 1))*100))
            sleep(15)
    except Exception as e:
        print("Error fetching latest prices:", e)
        sleep(15)

print("ORDER TRIGGERED at {}".format(pd.Timestamp.now()))

Here is a little simulation we created to show you how the script works (of course, Box and Dropbox don’t actually trade anywhere near the prices shown here):

Note you could expand the script’s logic to long Dropbox and short Box if the prices converged by more than 3% as well. This way you’d be firing a logical pair trade irrespective of whether Box and Dropbox moved unusually far apart or closer together.

How do I buy a call option when the underlying stock moved using the Robinhood API?

We will demonstrate this by buying a Tesla call option when Tesla stock has moved 1% in the last hour.

Note that another limitation of Robinhood is that it does not allow you to market buy options contracts. The reasoning goes inline with the rest of their ethos- protect novice traders from harming themselves too much. The potential slippage on market options orders is far greater than on the spot market so they simply do not allow it in the name of investor safety.

One option could be to just go in with a limit order with a pre-determined price. The problem with this is the prices of contracts might have moved a lot by the time the underlying stock moves 1%, making the pre-determined price too low and so hard to fill, or too high and simply a bad price to pay.

To combat this, we are going to use either the

options.get_option_instrument_data_by_id() or options.find_options_by_expiration_and_strike()

function to find the most up to date bid price and set a limit buy just above this to give the best risk:likelihood of getting filled ratio.

In the example that follows we will use the second option and pretend we are interested in buying a call option with expiry ‘2020-07-17’ and strike price of 1580.

Right before we place our limit order, we will use the following code to find the highest existing bid price for the contract type we want to buy, and create a bid just over it (0.1% higher):


# finds current best bid for option contract we want to buy
best_bid = rs.options.find_options_by_expiration_and_strike('TSLA',
                                                 '2020-07-17',
                                                 1580,
                                                 optionType='call',
                                                 info='bid_price')
# converts output to float
best_bid = float(best_bid[0])
# we place our limit bid 0.1% above the current best bid
our_bid = 1.001 * best_bid

Aside from that, our trading script logic is almost identical to in the “How do I place an order for Visa when Mastercard moved 1% in the last hour?” section, except that our logic check only consists of one block written as:

if (df.price.iloc[-1] < max_price * 0.99 or df.price.iloc[-1] > min_price * 1.01):
    # BUY A CALL OPTION

So put together, our script looks like this:

from time import sleep
import pandas as pd

df = pd.DataFrame(columns=['date', 'price'])

while True:
    try:
        price = rs.stocks.get_latest_price('TSLA', includeExtendedHours=True)
        # assigning price to first (and only) item of list and converting from str to float
        tesla_price = float(price[0])
        
        df.loc[len(df)] = [pd.Timestamp.now(), tesla_price]

        
        start_time = df.date.iloc[-1] - pd.Timedelta(minutes=60)
        df = df.loc[df.date >= start_time] # cuts dataframe to only include last hour of data
        max_price = df.price.max()
        min_price = df.price.min()
        
        if (df.price.iloc[-1] < max_price * 0.99 or df.price.iloc[-1] > min_price * 1.01):
            try:
                # finds current best bid for option contract we want to buy
                best_bid = rs.options.find_options_by_expiration_and_strike('TSLA',
                                                                 '2020-07-17',
                                                                 1580,
                                                                 optionType='call',
                                                                 info='bid_price')
                # converts output to float
                best_bid = float(best_bid[0])
                # we place our limit bid 0.1% above the current best bid
                our_bid = 1.001 * best_bid
                
                rs.orders.order_buy_option_limit('open', 
                                 'debit', 
                                 our_bid, 
                                 'TSLA',
                                 1,
                                 '2020-07-17', 
                                 1580, 
                                 optionType='call', 
                                 timeInForce='gtc')
                print("MOVED MORE THAN 1%, TESLA CURRENT PRICE: {} MIN PRICE: {} MAX PRICE: {}\n".format(df.price.iloc[-1], min_price, max_price))
                break
                
            except Exception as e:
                print("Error placing order:", e)
        
        else:
            print("NO ORDER, TESLA CURRENT PRICE: {} MIN PRICE: {} MAX PRICE: {}\n".format(df.price.iloc[-1], min_price, max_price))
            sleep(15)
                
    except Exception as e:
        print("Error fetching latest price:", e)
        
print("ORDER TRIGGERED at {}".format(pd.Timestamp.now()))
print("LIMIT BUY FOR OPTION CALL PLACED AT:", our_bid)

How do I retrieve the option Greeks using the Robinhood API?

If you’re new to options trading and the Greek’s sound are a funnily named mystery to you, you can read a brief introduction to them here. They help a trader to understand how an option’s price might move under various market conditions.

You can get the major Greeks Delta, Gamma, Theta, Vega, Rho for any options contract very easily through either:

  • options.get_option_market_data(inputSymbols, expirationDate, strikePrice, optionType, info=None)
  • options.get_option_market_data_by_id(id, info=None)

The response for a single ticker/id value is as follows:

[{'adjusted_mark_price': '',
  'ask_price': '',
  'ask_size': '',
  'bid_price': '',
  'bid_size': '',
  'break_even_price': '',
  'high_price': '',
  'instrument': '',
  'last_trade_price': '',
  'last_trade_size': '',
  'low_price': '',
  'mark_price': '',
  'open_interest': '',
  'previous_close_date': '',
  'previous_close_price': '',
  'volume': '',
  'chance_of_profit_long': '',
  'chance_of_profit_short': '',
  'delta': '',
  'gamma': '',
  'implied_volatility': '',
  'rho': '',
  'theta': '',
  'vega': '',
  'high_fill_rate_buy_price': '',
  'high_fill_rate_sell_price': '',
  'low_fill_rate_buy_price': '',
  'low_fill_rate_sell_price': ''}]

You can use the ‘info’ parameter to filter for a specific value.

So for instance if we wanted to get the Delta value for a Tesla call option with expiry date 2020-07-17 and strike price of 1580, we could do the following:

delta = float(rs.options.get_option_market_data('TSLA',
                                          '2020-07-17',
                                          1580,
                                          optionType='call',
                                          info='delta')[0])

Remember the float(list[0]) part is to convert the response to numerical from a list of length 1 containing a string.

We can get any of the other Greek’s by changing the info filter to the Greek desired.

How do I place a covered call trade using the Robinhood API?

A covered call is an options strategy constructed by holding a long position in a stock and then selling (writing) call options for the same stock, representing the same size as the stock position.

An option contract gives the right to buy or sell 100 shares of the underlying stock, so 100 shares covers a single option contract. The trade is called “covered” because the trader already owns the shares necessary to fulfil the options contract if it expires in the money and is exercised.

A covered call is a good strategy if you are mildly but not overwhelmingly bullish on the underlying stock- you will benefit from any price increase up to the call strike price and also get the premium from selling the call option, and so hence slight effective downside protection also.

The downside is limiting your upside by not benefiting from any movements past the call strike, since you will have to sell your shares at that price when the option is presumably exercised if in the money- so the optimal outcome for a covered call trade is the price of the stock moving up to the strike price but not beyond.

How to place a Covered Call Trade (Tesla)

Let’s have a go placing a covered call trade for tesla.

Let’s assume Tesla is trading at $1546, and we are interested in selling (writing) a Tesla call option with a strike of 1600 and expiry of 2020-07-17.

First, since Robinhood doesn’t allow market option orders, let’s first find what the going ask price is for such an option:

ask_price = float(rs.options.find_options_by_expiration_and_strike('TSLA',
                                                                   '2020-07-17',
                                                                   1600,
                                                                   optionType='call',
                                                                   info='ask_price')[0])

Now lets sell a single call option with our desired parameters at the ask_price (almost indirectly equivalent to a market sell):

rs.orders.order_sell_option_limit('open',
                                  'credit',
                                  ask_price,
                                  'TSLA',
                                  1,
                                  '2020-07-17',
                                  1600,
                                  optionType='call',
                                  timeInForce='gtc')

And finally market buy 100 Tesla shares to cover the call:

rs.orders.order_buy_fractional_by_quantity('TSLA', 100)

Here we get additional profit if the call option expires with Tesla trading in the $1548-$1600 range- since the option expires as worthless so will not be exercised and we get the extra premium from selling the call option.

How to sell a call while buying Tesla stock in a delta-hedged manner

Delta is the Greek that measures the change of an option’s price resulting from a change in the price of the underlying security.

Calls range in delta from 0 to 1, and puts range in delta from -1 to 0, so an option with a delta of 0.6 would be expected to change $0.6 in price for every $1 the underlying stock moved.

Delta hedging (delta neutrality) is a strategy where one attempts to be market neutral.

One way to achieve this is to sell a call option whilst buying shares of the underlying stock. Owning 1 share of stock gives you a position delta of 1, since obviously stocks change in value by $1 for every $1 they change in value.

A call option has a positive delta, so selling a call option gives you negative delta.

Therefore, one can delta hedge 60 shares of a stock (delta +60) buy selling a call option with delta 0.6 (-0.6*100 = -60)- remember, an options contract typically gives the right to buy or sell 100 of the underlying stock.

Lets have a go doing this programatically with some Tesla stock.

First, lets sell a Tesla call option, using the same method as before to fetch a sensible limit price:

ask_price = float(rs.options.find_options_by_expiration_and_strike('TSLA',
                                                                   '2020-07-17',
                                                                   1600,
                                                                   optionType='call',
                                                                   info='ask_price')[0])
rs.orders.order_sell_option_limit('open',
                                  'credit',
                                  ask_price,
                                  'TSLA',
                                  1,
                                  '2020-07-17',
                                  1600,
                                  optionType='call',
                                  timeInForce='gtc')

Then find the current delta of that call option to know how many shares to buy to delta hedge with:

delta = float(rs.options.find_options_by_expiration_and_strike('TSLA',
                                                               '2020-07-17',
                                                               1600,
                                                               optionType='call',
                                                               info='delta')[0])

Now we buy enough shares of Tesla to balance out the call option’s delta:

rs.orders.order_buy_fractional_by_quantity('TSLA', delta*100)

Note that the delta of your overall position will constantly shift as the underlying stock changes in price- since the call option’s delta will vary as it does so. It can be very costly to constantly adjust for delta neutrality (to the point of losing money from fees), so infrequent calibration is often best.

How do I set take profits and stop losses using the Robinhood API?

Unfortunately Robinhood is a little unsophisticated and doesn’t allow us to set a stop loss and take profit directly with a buy order.

It also doesn’t allow us to set both a stop loss (market/limit sell below our buy level) and take profit (limit sell above our buy level) with the same shares.

For instance, if we buy 10 shares of Apple at $380, and place a stop loss for 10 shares at $370, then we are left with 0 shares with which we are allowed to set a take profit- at say $400. You cannot place two sell orders of any types with the same shares.

We will have to either pick whether we prefer to have a stop loss, a take profit, hedge our bets with 50% of our shares in either, or set up some custom logic to begin with a stop loss, and cancel the stop loss order and replace it with a market/limit sell if the price rises to a certain point (probably the best option).

Lets assume we have 10 shares of Apple that we just bought at $380.

This is how to set a market sell stop loss for all 10 shares, triggered at a price of $370 :

rs.orders.order_sell_stop_loss('AAPL',
                               10,
                               370,
                               timeInForce='gtc',
                               extendedHours=False)

And this is how to set a take profit for all 10 shares at $400:

rs.orders.order_sell_limit('AAPL',
                           10,
                           400,
                           timeInForce='gtc',
                           extendedHours=False)

Now we will implement our custom solution to the Robinhood API’s limitations.

We will place a market buy for 10 stocks of Apple (making the assumption its currently trading at ~$380):

rs.orders.order_buy_fractional_by_quantity('AAPL', 10)

Set out stop loss for all 10 shares at $370 and record the order id:

stoploss_order = rs.orders.order_sell_stop_loss('AAPL', 10, 370)
stoploss_order_id = stoploss_order['id']

Then in a loop keep checking the latest price of Apple- and if it goes above $400, immediately cancelling our stop loss order and placing a market sell instead:

while True:
    price = rs.stocks.get_latest_price('AAPL', includeExtendedHours=True)
    price = float(price[0]) # convert to single float

    if price > 400:
        rs.orders.cancel_stock_order(stoploss_order_id)
        rs.orders.order_sell_market('AAPL', 10)
        print("STOP LOSS CANCELLED AND MARKET SELL TRIGGERED, APPLE PRICE:", price)
        print("ORDER TRIGGERED at {}".format(pd.Timestamp.now()))
        break
    
    print("STILL WAITING, APPLE PRICE:", price)
    sleep(15)

We opted for a market instead of limit sell to avoid the possibility that the limit sell does not get filled fully before the price of Apple goes back down- and continues to go down all the way below our cancelled stoploss… But you could use a limit sell instead if you’re happy to take this minor risk.

Here is a simulation of what the output of the above script might look like:

STILL WAITING, APPLE PRICE: 383
STILL WAITING, APPLE PRICE: 394
STILL WAITING, APPLE PRICE: 395
STOP LOSS CANCELLED AND MARKET SELL TRIGGERED, APPLE PRICE: 408
ORDER TRIGGERED at 2020-07-15 16:59:16.485977

How do I get a summary of my current positions and holdings using the Robinhood API?

This is the function to get a global history (for all of stocks/crypto/options) of both open and closed orders at once:

rs.account.get_all_positions()

However, if you want only open orders you’ll have to use the stock/crypto/option sub-functions as follows:

  • get_all_open_crypto_orders()
  • get_all_open_option_orders()
  • get_all_open_stock_orders()

These all live in the orders module, so as an example to get a summary of all your open stock orders you’d do:

rs.orders.get_all_open_stock_orders()

How do I cancel existing orders using the Robinhood API?

This is really easy, the functions in robin_stocks are to cancel all orders:

  • cancel_all_crypto_orders()
  • cancel_all_option_orders()
  • cancel_all_stock_orders()

To cancel a specific order:

  • cancel_crypto_order(orderID)
  • cancel_option_order(orderID)
  • cancel_stock_order(orderID)

And you can find your orderID’s with these functions (or the “open” variants as in the previous section):

  • get_all_crypto_orders()
  • get_all_option_orders()
  • get_all_stock_orders()

All of these functions also lie in robin_stocks.orders, so an example to cancel all our open stock orders we would do the following:

rs.orders.cancel_all_stock_orders()

How do I get historical data using the Robinhood API?

The functions and parameters to do this for stocks and crypto are basically the same- with just a few alterations to the valid values for the parameters.

Stocks

The function to get historical data for stocks is stocks.get_stock_historicals().

It has the parameters:

  • inputSymbols (str or list): a single stock ticker or list of stick tickers to return historical data for.
  • interval (Optional[str]): interval of data sampling- default is “hour”. Values are [“5minute”, “10minute”, “hour”, “day”, “week”]
  • span (Optional[str]): sets the range of data to retrieve. Values are [‘day’, ‘week’, ‘month’, ‘3month’, ‘year’, ‘5year’] and the default is ‘week’.
  • bounds (Optional[str]): Whether to return data for standard trading hours of extended hours. Values are “extended” or “regular” and default is “regular”.

And returns a list of dictionaries where each dictionary is for a different time with the following dictionary keys:

  • begins_at, open_price, close_price, high_price, low_price, volume, session, interpolated, symbol

If multiple stocks are provided, the historical data is listed one after another.

So if you wanted to get 10 minute data for Tesla over the last year during only standard trading hours, you would do:

tesla_data= rs.stocks.get_stock_historicals("TSLA", interval="10minute", span="year")

Then you can convert the list of dictionaries to a dataframe like this:

tesla_dataframe= pd.DataFrame(tesla_data)

Depending on the parameters picked, the output should look something like this:

Crypto

The function is crypto.get_crypto_historicals() and has the exact same parameters as the stocks variant, with the following adjustments to valid parameter values:

  • interval: [’15second’, ‘5minute’, ’10minute’, ‘hour’, ‘day’, ‘week’] default ‘hour’.
  • span: [‘hour’, ‘day’, ‘week’, ‘month’, ‘3month’, ‘year’, ‘5year’]: default ‘week’.
  • bound: [‘regular’, ‘trading’, ‘extended’, ’24_7′]. Regular is 6 hours a day, trading is 9 hours, extended is 16 hours and ’24_7′ is unsurprisingly 24 hours a day. Default is ’24_7′ and we recommend always leaving it to that, since crypto markets do indeed trade 24/7.

Options

The function for getting options historical data is options.get_options_historical() and also has the parameters interval, span and bounds with the following valid values:

  • interval: [‘5minute’, ’10minute’, ‘hour’, ‘day’, ‘week’]- default ‘hour’.
  • span: [‘day’, ‘week’, ‘year’, ‘5year’]- default ‘week’.
  • bounds:{‘regular’: 6 hours, ‘trading’: 9 hours, ‘extended’: 16 hours]- default is ‘regular’.

Then additionally there are a few options specific parameters:

  • expirationDate (str): The expiration date of the option in the format ‘YYYY-MM-DD’.
  • strikePrice (str): The strike price of the option.
  • optionType (str): The option type- ‘call’ or ‘put’.

So an example request for option historical data might look like this:

rs.options.get_option_historicals('AAPL',
                                  '2020-07-17',
                                  '350',
                                  'put',
                                  interval='5minute',
                                  span='week',
                                  bounds='regular')

How do I get fundamentals data using the Robinhood API?

Getting fundamentals stock data is as easy as:

rs.stocks.get_fundamentals(inputSymbols, info=None)

This function returns information about the following in the format of a list containing a dictionary of key:value pairs for each ticker for each of the following keys:

  • open
  • high
  • low
  • volume
  • average_volume_2_weeks
  • average_volume
  • high_52_weeks
  • dividend_yield
  • float
  • low_52_weeks
  • market_cap
  • pb_ratio
  • pe_ratio
  • shares_outstanding
  • description
  • instrument
  • ceo
  • headquarters_city
  • headquarters_state
  • sector
  • industry
  • num_employees
  • year_founded
  • symbol

If info is set to one of the keys, the response will be a list of strings where the strings are the values of the key that corresponds to info- one string for each ticker.

inputSymbols can be a single ticker or a list of tickers, so for instance if we wanted fundamentals data for Apple, Amazon and Google all at once we could do:

rs.stocks.get_fundamentals(["AAPL,"AMZN","GOOGL"])

If we wanted just the dividend of Apple, we would do:

dividend = float(rs.stocks.get_fundamentals("AAPL", info='dividend_yield')[0])

How do I get options data using the Robinhood API?

All the functions in this section reside in the options module of robin_stocks.

Firstly, it would be useful to know the expiry dates for options for a stock.

To do this simply pass a stock ticker to the get_chains and filter info by ‘expiration_dates’ like this:

rs.options.get_chains("AAPL", info='expiration_dates')
['2020-07-17',
 '2020-07-24',
 '2020-07-31',
 '2020-08-07',
 '2020-08-14',
 '2020-08-21',
 '2020-08-28',
 '2020-09-18',
 '2020-10-16',
 '2020-11-20',
 '2020-12-18',
 '2021-01-15',
 '2021-06-18',
 '2021-09-17',
 '2022-01-21',
 '2022-06-17',
 '2022-09-16']

The most useful/general function to get options data is find_tradable_options() taking the parameters:

  • symbol, expirationDate, strikePrice, optionType

as seen many times already in this guide already.

So as an example if we were interested in browsing Apple call options with a strike price of $400, but we were open about the expiration date, we could do the following:

rs.options.find_tradable_options('AAPL', 
                                 expirationDate=None,
                                 strikePrice=400,
                                 optionType='call')

Note if you leave optionType as None, you get both calls and puts returned.

There are a bunch of other ways to filter for options data that might tickle your fancy, which you can find in the “Getting Option Information” of the robin_stocks functions list.

How do I export/save my history of completed orders using the Robinhood API?

robin_stocks lets you save a history of completed stock and option orders in CSV format.

The functions to do this are in the export module and are named:

  • export_completed_stock_orders()
  • export_completed_option_orders()

They both have the parameters:

  • dir_path: Absolute or relative path to the directory the file will be written.
  • file_name: (optional [str]) Optional argument for the name of the file. If None then the filename will be option_orders_{current date}.

So for instance we could do:

rs.export.export_completed_stock_orders("order_history",
                                        "stocks_monday")

Which would create a CSV file of our stock orders history at the location “/order_history/stocks_monday.csv” relative to our initial directory.

Final thoughts

Robinhood is really all about making investing for novices and the less wealthy more accessible and easy to take part in.

It achieves this through various incentives like commission free trades, interest on unused balances, easy to read graphs and simple order interfaces and so forth.

They also “protect” their investors by limiting the amount of risky moves they are allowed to make (like not allowing short selling, market option orders, day trading, and offering only limited leverage).

Unfortunately, all this combines to form an environment difficult to execute sophisticated trading strategies in, so it’s hard to recommend Robinhood and their API for the serious trader.

It’s still definitely possible to use the Robinhood API for a variety of trading strategies and it’s easy to use, so if you are drawn by the money saving incentives and are implementing mainly slower, lower frequency trading strategies, perhaps there is a place for the Robinhood API.

If you are looking for a slightly more sophisticated API and brokerage, check out the Alpaca Trading API and Interactive Brokers Python API guides on our site.

You can find the code used in this article here.

Greg Bland

Pairs Trading – A Real-World Guide

What is pairs trading? Pairs trading is a trading strategy that involves buying one asset and shorting another. The aim of pairs trading is...
Lucas Liew Lucas Liew
9 min read