Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Trading with the unofficial Robinhood API w/ Code examples

Now, I'm not an expert in stock trading nor coding so I can't say the code is the cleanest, but it gets the job done and is a good starting point for anyone looking to get back into algo trading with Robinhood. I'm doing this because I'm poor and cheap. Again I may of taken the long route on some of this code, but it's hard to find good examples. This is why I'm posting here.

-Example 1: Logging in to Robinhood
-Example 2: Pulling Stock data from Robinhood (Doesn't require login)
-Example 3: Simple SMA back test using Pyalgotrade.py and data from Google Finance (Doesn't require login)

Requirements:

-Python 2.7+
-curl (curl is included in linux but if using windows download here: https://curl.haxx.se/download.html) You could also use PYCurl but I didn't feel like learning it.
-pyalgotrade.py (for example 3)

References:

-https://www.python.org/
-https://github.com/sanko/Robinhood
-http://gbeced.github.io/pyalgotrade/

Example 1: Logging in

All this code does is login into your account, print some account info to the screen, and then logout. You'll have to enter username and password in the code where appropriate. I'm not a network expert, but I don't think this connection would be encrypted fyi. After logging in it gives you a token which then is used when making requests related to your account such as buying or selling a stock.

import subprocess

def login(username, password):  
    command = 'curl -v https://api.robinhood.com/api-token-auth/ -H "Accept: application/json" -d "username='+username+'&password='+password+'"'  
    p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr= subprocess.PIPE)  
    out, err = p.communicate()  
    if len(out) < 1:  
        print 'Error connecting to server:'  
        print err  
    else:  
        print 'Connection successful.'  
    return out

def logout(token):  
    command = 'curl -v https://api.robinhood.com/api-token-logout/ -H "Accept: application/json" -H "Authorization: Token '+token+'" -d ""'  
    p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr= subprocess.PIPE)  
    out, err = p.communicate()


def accountInfo(token):  
    command = 'curl -v https://api.robinhood.com/accounts/ -H "Accept: application/json" -H "Authorization: Token '+token+'"'  
    p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr= subprocess.PIPE)  
    out, err = p.communicate()  
    return out

def main():  
    print 'Logging in...'  
    token = login('ENTER USERNAME HERE', 'ENTER PASSWORD HERE')  
    token = token[10:-2]  
    print 'token: ', token  
    print 'Grabbing account information...'  
    account_info = accountInfo(token)  
    print account_info  
    print 'Logging out...'  
    logout(token)

main()

Example 2: Pulling Stock data from Robinhood

All this code does is grab some information about XIV from Robinhood itself. Because of the way I did it, and I don't know if there is a more efficient way, all the information is returned as one long string. So I just search through it and find the data I want, convert it to a float and assign it to a variable.

import subprocess

class data():  
    def __init__(self, stock):  
        self.stock = stock  
        parameter_list = ['open', 'high', 'low', 'volume', 'average_volume', 'last_trade_price', 'previous_close']  
        command_list = ['curl -v https://api.robinhood.com/quotes/'+self.stock+'/ -H "Accept: application/json"',  
                     'curl -v https://api.robinhood.com/fundamentals/'+self.stock+'/ -H "Accept: application/json"']

        for commands in command_list:  
            command = commands  
            p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr= subprocess.PIPE)  
            out, err = p.communicate()

            string = out  
            for p in parameter_list:  
                parameter = p  
                if parameter in string:  
                    x = 0  
                    output = ''  
                    iteration = 0  
                    for i in string:  
                        if i != parameter[x]:  
                            x = 0  
                        if i == parameter[x]:  
                            x = x+1  
                        if x == len(parameter):  
                            eowPosition = iteration  
                            break  
                        iteration = iteration + 1

                    target_position = eowPosition + 4  
                    for i in string[target_position:]:  
                        if i == '"':  
                            break  
                        elif i == 'u':  
                            output = 'NULL'  
                            break  
                        else:  
                            output = output+i

                    if output != 'NULL':  
                        output = float(output)  
                    if p == 'open':  
                        self.open = output  
                    if p == 'high':  
                        self.high = output  
                    if p == 'low':  
                        self.low = output  
                    if p == 'volume':  
                        self.volume = output  
                    if p == 'average_volume':  
                        self.average_volume = output  
                    if p == 'last_trade_price':  
                        self.current = output  
                    if p == 'previous_close':  
                        self.close = output  
XIV = data('XIV')

print 'Current price: ', XIV.current  
print 'Today\'s Open: ', XIV.open  
print 'Today\'s High: ', XIV.high  
print 'Today\'s Low: ', XIV.low  
print 'Today\'s Volume: ', XIV.volume  
print 'Average Volume: ', XIV.average_volume

Example 3: Simple SMA back test using Pyalgotrade.py and data from Google Finance

This downloads trade data for SPY from google finance, then finds what the best sma window would be. This strategy is completely flawed, it's only here to show how it can be done. Note if pyalgotrade functions, such as sma(), finds bad data in the data downloaded from google finance it will fault the script. You'll have to open the csv. file manually and enter in the information.


import os  
import datetime

import pyalgotrade.logger  
from pyalgotrade import bar  
from pyalgotrade.barfeed import googlefeed  
from pyalgotrade.utils import csvutils  
from pyalgotrade import strategy  
from pyalgotrade.technical import ma

class MyStrategy(strategy.BacktestingStrategy):  
    def __init__(self, feed, instrument, smaPeriod):  
        super(MyStrategy, self).__init__(feed, 10000)  
        self.__position = None  
        self.__instrument = instrument  
        self.__sma = ma.SMA(feed[instrument].getPriceDataSeries(), smaPeriod)

    def onEnterOk(self, position):  
        execInfo = position.getEntryOrder().getExecutionInfo()  
        self.info("BUY at $%.2f" % (execInfo.getPrice()))

    def onEnterCanceled(self, position):  
        self.__position = None

    def onExitOk(self, position):  
        execInfo = position.getExitOrder().getExecutionInfo()  
        self.info("SELL at $%.2f" % (execInfo.getPrice()))  
        self.__position = None

    def onExitCanceled(self, position):  
        # If the exit was canceled, re-submit it.  
        self.__position.exitMarket()

    def onBars(self, bars):  
        # Wait for enough bars to be available to calculate a SMA.  
        if self.__sma[-1] is None:  
            return

        bar = bars[self.__instrument]  
        # If a position was not opened, check if we should enter a long position.  
        if self.__position is None:  
            if bar.getPrice() > self.__sma[-1]:  
                # Enter a buy market order for 10 shares. The order is good till canceled.  
                self.__position = self.enterLong(self.__instrument, 10, True)  
        # Check if we have to exit the position.  
        elif bar.getPrice() < self.__sma[-1] and not self.__position.exitActive():  
            self.__position.exitMarket()


def run_strategy(smaPeriod):  
    # Load the google feed from the CSV file  
    feed = googlefeed.Feed()  
    feed.addBarsFromCSV("spy", "spy_2016.csv")

    # Evaluate the strategy with the feed.  
    myStrategy = MyStrategy(feed, "spy", smaPeriod)  
    myStrategy.run()  
    print "Final portfolio value: $%.2f" % myStrategy.getBroker().getEquity()

    return myStrategy.getBroker().getEquity()

def download_csv(instrument, begin, end):  
    url = "http://www.google.com/finance/historical"  
    params = {  
        "q": instrument,  
        "startdate": begin.strftime("%Y-%m-%d"),  
        "enddate": end.strftime("%Y-%m-%d"),  
        "output": "csv",  
    }

    return csvutils.download_csv(url, url_params=params, content_type="application/vnd.ms-excel")


def download_daily_bars(instrument, start, end, csvFile):  
    """Download daily bars from Google Finance for a given year.

    :param instrument: Instrument identifier.  
    :type instrument: string.  
    :param year: The year.  
    :type year: int.  
    :param csvFile: The path to the CSV file to write.  
    :type csvFile: string.  
    """

    bars = download_csv(instrument,  
                        datetime.date(start, 1, 1),  
                        datetime.date(end, 12, 31))  
    f = open(csvFile, "w")  
    f.write(bars)  
    f.close()

start = 2016  
end = 2016

download_daily_bars('spy', start, end, 'spy_2016.csv')

best_performance = 0

for i in range (10, 50):

    performance = run_strategy(i)  
    if performance > best_performance:  
        best_performance = performance  
        sma_period = i

print "Best performance was sma period:", sma_period," @ $%.2f" %best_performance
6 responses

How I view it? Doesn't matter if it's the cleanest. Get a workable version and then clean it up later :)

This would be run within the python shell or command line. There are ways to visual matplotlib library.

I got the error "data instance has no attribute 'open'" for part two

That's the example I was seeking. Wonderful supplement for Q's not live.

I got the error "data instance has no attribute 'open'" for part two

First make sure self.open is spelled right earlier. If it is, just change the last lines to just print XIV and that will print it's contents and tell you what it is actually in there.

There also another a Robinhood api python wrapper here: https://github.com/Jamonek/Robinhood
But there are some bugs in the ordering that need to be fixed before using it.

It's been a couple months since I submitted this and there are some better ways of connecting with Robinhood such as the above python wrapper. Also you can grab data straight from Robinhood instead of using google.

Have you gotten this to work? Any newer or better ways to patch in?