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