├── __init__.py ├── requirements.txt ├── example.py ├── README.md ├── .gitignore ├── LICENSE └── Robinhood.py /__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | -------------------------------------------------------------------------------- /example.py: -------------------------------------------------------------------------------- 1 | from Robinhood import Robinhood 2 | my_trader = Robinhood(username="USERNAME HERE", password="PASSWORD HERE") 3 | 4 | #get stock information about a stock 5 | # Note: for some stock names, more than one instrument 6 | # may be returned for a given stock symbol 7 | stock_instrument = my_trader.instruments("GEVO")[0] 8 | 9 | #You can stock information about current bid_price, etc 10 | quote_info = my_trader.quote_data("GEVO") 11 | 12 | #place a buy order (uses market bid price) 13 | buy_order = my_trader.place_buy_order(stock_instrument, 1) 14 | 15 | #place a sell order 16 | sell_order = my_trader.place_sell_order(stock_instrument, 1) 17 | 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Robinhood 2 | Python Framework to make trades with Robinhood Private API 3 | See Blog Post: https://medium.com/@rohanpai25/reversing-robinhood-free-accessible-automated-stock-trading-f40fba1e7d8b 4 | 5 | Current Features Include: 6 | - Placing buy orders (Robinhood.place_buy_order) 7 | - Placing sell order (Robinhood.place_sell_order) 8 | - Quote Information (Robinhood.quote_data) 9 | - More coming soon 10 | 11 | How To Install: 12 | 13 | >pip install -r requirements.txt 14 | 15 | How to Use (see example.py): 16 | 17 | from Robinhood import Robinhood 18 | my_trader = Robinhood(username="USERNAME HERE", password="PASSWORD HERE") 19 | stock_instrument = my_trader.instruments("GEVO")[0] 20 | quote_info = my_trader.quote_data("GEVO") 21 | buy_order = my_trader.place_buy_order(stock_instrument, 1) 22 | sell_order = my_trader.place_sell_order(stock_instrument, 1) 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Rohan Pai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Robinhood.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import urllib 3 | 4 | class Robinhood: 5 | 6 | endpoints = { 7 | "login": "https://api.robinhood.com/api-token-auth/", 8 | "investment_profile": "https://api.robinhood.com/user/investment_profile/", 9 | "accounts":"https://api.robinhood.com/accounts/", 10 | "ach_iav_auth":"https://api.robinhood.com/ach/iav/auth/", 11 | "ach_relationships":"https://api.robinhood.com/ach/relationships/", 12 | "ach_transfers":"https://api.robinhood.com/ach/transfers/", 13 | "applications":"https://api.robinhood.com/applications/", 14 | "dividends":"https://api.robinhood.com/dividends/", 15 | "edocuments":"https://api.robinhood.com/documents/", 16 | "instruments":"https://api.robinhood.com/instruments/", 17 | "margin_upgrades":"https://api.robinhood.com/margin/upgrades/", 18 | "markets":"https://api.robinhood.com/markets/", 19 | "notifications":"https://api.robinhood.com/notifications/", 20 | "orders":"https://api.robinhood.com/orders/", 21 | "password_reset":"https://api.robinhood.com/password_reset/request/", 22 | "quotes":"https://api.robinhood.com/quotes/", 23 | "document_requests":"https://api.robinhood.com/upload/document_requests/", 24 | "user":"https://api.robinhood.com/user/", 25 | "watchlists":"https://api.robinhood.com/watchlists/", 26 | } 27 | 28 | session = None 29 | 30 | username = None 31 | 32 | password = None 33 | 34 | headers = None 35 | 36 | auth_token = None 37 | 38 | account_url = None 39 | 40 | def __init__(self, username, password): 41 | self.session = requests.session() 42 | self.session.proxies = urllib.getproxies() 43 | self.username = username 44 | self.password = password 45 | self.headers = { 46 | "Accept": "*/*", 47 | "Accept-Encoding": "gzip, deflate", 48 | "Accept-Language": "en;q=1, fr;q=0.9, de;q=0.8, ja;q=0.7, nl;q=0.6, it;q=0.5", 49 | "Content-Type": "application/x-www-form-urlencoded; charset=utf-8", 50 | "X-Robinhood-API-Version": "1.0.0", 51 | "Connection": "keep-alive", 52 | "User-Agent": "Robinhood/823 (iPhone; iOS 7.1.2; Scale/2.00)" 53 | } 54 | 55 | self.session.headers = self.headers 56 | self.login() 57 | 58 | ## set account url 59 | acc = self.get_account_number() 60 | self.account_url = self.endpoints['accounts'] + acc + "/" 61 | 62 | 63 | def login(self): 64 | data = "password=%s&username=%s" % (self.password, self.username) 65 | res = self.session.post(self.endpoints['login'], data=data) 66 | res = res.json() 67 | self.auth_token = res['token'] 68 | self.headers['Authorization'] = 'Token '+self.auth_token 69 | 70 | def get_account_number(self): 71 | res = self.session.get(self.endpoints['ach_relationships']) 72 | res = res.json()['results'][0] 73 | account_number = res['account'].split('accounts/', 1)[1][:-1] 74 | print account_number 75 | return account_number 76 | 77 | def investment_profile(self): 78 | self.session.get(self.endpoints['investment_profile']) 79 | 80 | def instruments(self, stock=None): 81 | res = self.session.get(self.endpoints['instruments'], params={'query':stock.upper()}) 82 | res = res.json() 83 | return res['results'] 84 | 85 | def quote_data(self, stock): 86 | params = { 'symbols': stock } 87 | res = self.session.get(self.endpoints['quotes'], params=params) 88 | res = res.json() 89 | return res['results'] 90 | 91 | def place_order(self, instrument, quantity=1, bid_price = None, transaction=None): 92 | if bid_price == None: 93 | bid_price = self.quote_data(instrument['symbol'])[0]['bid_price'] 94 | data = 'account=%s&instrument=%s&price=%f&quantity=%d&side=%s&symbol=%s&time_in_force=gfd&trigger=immediate&type=market' % (urllib.quote(self.account_url), urllib.unquote(instrument['url']), float(bid_price), quantity, transaction, instrument['symbol']) 95 | res = self.session.post(self.endpoints['orders'], data=data) 96 | return res 97 | 98 | def place_buy_order(self, instrument, quantity, bid_price=None): 99 | transaction = "buy" 100 | return self.place_order(instrument, quantity, bid_price, transaction) 101 | 102 | def place_sell_order(self, instrument, quantity, bid_price=None): 103 | transaction = "sell" 104 | return self.place_order(instrument, quantity, bid_price, transaction) 105 | 106 | --------------------------------------------------------------------------------