Esempio n. 1
0
class RobinhoodExporter:
    """
  Exports metadata about a Robinhood user's held securities and portfolio.
  """
    def __init__(self, mfa_code, username=None, password=None):
        username = os.environ['rh_user'] if not username else username
        password = os.environ['rh_pass'] if not password else password

        try:
            self.rh = Robinhood()
            if not self.rh.login(username, password, mfa_code):
                raise LoginException("Invalid login credentials.")
        except:
            raise LoginException("Invalid login credentials.")

    def _securities_to_quotes(self, securities):
        return self.rh.get_url(quote_endpoint(securities))['results']

    def _stocks_from_securities(self, securities):
        for security, quote in zip(securities,
                                   self._securities_to_quotes(securities)):
            yield Stock.from_security_and_quote(security, quote)

    def export_portfolio(self, export_func=None):
        securities = self.rh.securities_owned()

        stocks = list(self._stocks_from_securities(securities['results']))

        total_equity = self.rh.equity()
        portfolio = Portfolio(total_equity, stocks)

        if export_func:
            export_func(portfolio)
        return portfolio
def RDataPull(BankInfo):
    from Robinhood import Robinhood

    Account = BankInfo["Usr"]
    PWord = BankInfo["Pass"]
    trader = Robinhood()
    trader.login(username=Account, password=PWord)
    cash = trader.get_account()['cash']
    equity = trader.equity()
    invested = float(equity) - float(cash)

    dsecowned = trader.securities_owned()['results']
    RData = {"cash": cash, "invested": invested}
    positions = {}

    for position in dsecowned:
        id = position['instrument'].split('/')[4]
        if float(position['quantity']) > 0:
            positions[trader.instrument(id)['symbol']] = position['quantity']

    RData["positions"] = positions

    return RData
Esempio n. 3
0
class RobinhoodShell(cmd.Cmd):
    intro = 'Welcome to the Robinhood shell. Type help or ? to list commands.\n'
    prompt = '> '

    # API Object
    trader = None

    # Cache file used to store instrument cache
    instruments_cache_file = 'instruments.data'

    # Maps Symbol to Instrument URL
    instruments_cache = {}

    # Maps URL to Symbol
    instruments_reverse_cache = {}

    # Cache file used to store instrument cache
    watchlist_file = 'watchlist.data'

    # Auth file
    auth_file = 'auth.data'

    # List of stocks in watchlist
    watchlist = []

    def _save_auth_data(self):
        auth_data = {}
        auth_data['device_token'] = self.trader.device_token
        auth_data['auth_token'] = self.trader.auth_token
        auth_data['refresh_token'] = self.trader.refresh_token
        open(self.auth_file, 'w').write(json.dumps(auth_data))

    def __init__(self):
        cmd.Cmd.__init__(self)
        self.trader = Robinhood()

        # Robinhood now uses 2FA
        # The workflow we use is as follows
        # If we find auth token in auth.data - try to see if it still works
        # If yes, continue
        # If no, try to refresh the token using refresh token
        # If it still fails, we need to relogin with 2FA
        try:
            data = open(self.auth_file).read()
            auth_data = json.loads(data)
            if 'auth_token' in auth_data:
              self.trader.device_token = auth_data['device_token']
              self.trader.auth_token = auth_data['auth_token']
              self.trader.refresh_token = auth_data['refresh_token']
              self.trader.headers['Authorization'] = 'Bearer ' + self.trader.auth_token
              try:
                self.trader.user()
              except:
                del self.trader.headers['Authorization']
                self.trader.relogin_oauth2()
                self._save_auth_data()
        except:
            challenge_type = 'email'
            if CHALLENGE_TYPE == 'sms':
              challenge_type = 'sms'
            self.trader.login(username = USERNAME, password = PASSWORD, challenge_type = challenge_type)
            self._save_auth_data()

        try:
            data = open(self.instruments_cache_file).read()
            self.instruments_cache = json.loads(data)
            for k in self.instruments_cache:
                self.instruments_reverse_cache[self.instruments_cache[k]] = k
        except:
            pass

        try:
            data = open(self.watchlist_file).read()
            self.watchlist = json.loads(data)
        except:
            pass

    # nytime = parser.parse('2018-06-15T23:14:15Z').astimezone(to_zone)
    # from dateutil import parser

    # ----- basic commands -----
    def do_l(self, arg):
        'Lists current portfolio'
        t = Terminal()
        portfolio = self.trader.portfolios()
        if portfolio['extended_hours_equity']:
            equity =  float(portfolio['extended_hours_equity'])
        else:
            equity =  float(portfolio['equity'])

        eq = '%.2f' % equity
        previous_close = float(portfolio['adjusted_equity_previous_close'])
        change = equity - previous_close
        change_pct =  '%.2f' % (change/previous_close * 100.0)

        # format
        change = f"{change:.2f}"

        # colorize
        change_pct = color_data(change_pct)
        change = color_data(change)

        account_details = self.trader.get_account()
        if 'margin_balances' in account_details:
            buying_power = account_details['margin_balances']['unallocated_margin_cash']

        account_table = SingleTable([['Portfolio Value','Change','Buying Power'],[eq, change+' ('+change_pct+'%)', buying_power]],'Account')
        print((account_table.table))

        # Load Stocks
        positions = self.trader.securities_owned()
        instruments = [position['instrument'] for position in positions['results']]
        symbols = [self.get_symbol(position['instrument']) for position in positions['results']]

        market_data = self.trader.get_stock_marketdata(instruments)

        table_data = []
        table_data.append(["Symbol", "Last", "Shares", "Equity", "Avg Cost", "Return" , "Day", "EquityChange", "Day %"])

        i = 0
        for position in positions['results']:
            quantity = int(float(position['quantity']))
            symbol = self.get_symbol(position['instrument'])
            price = market_data[i]['last_trade_price']
            total_equity = float(price) * quantity
            buy_price = float(position['average_buy_price'])
            p_l = f"{total_equity - (buy_price * quantity):.2f}"
            total_equity = f"{total_equity:.2f}"
            buy_price = f"{buy_price:.2f}"
            day_change = f"{float(market_data[i]['last_trade_price']) - float(market_data[i]['previous_close']):.2f}"
            day_change_q_val = f"{float(quantity) * float(day_change):.2f}"
            day_change_pct = f"{float(day_change) / float(market_data[i]['previous_close']) * 100:.2f}"
            price = f"{float(price):.2f}"

            table_data.append([
                symbol,
                price,
                quantity,
                total_equity,
                buy_price,
                color_data(p_l),
                color_data(day_change),
                color_data(day_change_q_val),
                color_data(day_change_pct)
                ])
            i += 1

        table = SingleTable(table_data,'Portfolio')
        table.inner_row_border = True
        table.justify_columns = {0: 'center' }

        print((table.table))

    def do_lo(self, arg):
        'Lists current options portfolio'
        # Load Options
        options_t_data=[]
        option_positions = self.trader.options_owned()
        options_table = SingleTable(options_t_data,'Options')
        options_table.inner_row_border = True
        options_table.justify_columns = {0: 'center' }
        options_t_data.append(["Symbol","Type","Experation","Strike", "Price", "QTY", "Equity", "Cost", "Total Return","Today"])

        for op in option_positions:
            quantity = float(op['quantity'])
            if quantity == 0:
                continue

            cost = float(op['average_price'])
            if op['type'] == 'short':
                quantity = -quantity
                cost = -cost

            instrument = op['option']
            option_data = self.trader.session.get(instrument).json()
            # skip expired  -- verify when it changes state day of or, after market close on expieration
            if option_data['state'] == "expired":
                continue
            expiration_date = option_data['expiration_date']
            strike = float(option_data['strike_price'])
            type = option_data['type']
            symbol = op['chain_symbol']
            option_type = str(type).upper()
            expiration = expiration_date
            strike_price = '$'+str(strike)
            info = self.trader.get_option_marketdata(instrument)
            last_price = float(info['adjusted_mark_price'])
            total_equity = (100 * last_price) * quantity
            change = total_equity - (float(cost) * quantity)
            change_pct = '{:04.2f}'.format(change / float(cost) * 100)
            day_change = float(info['adjusted_mark_price']) - float(info['previous_close_price'])
            day_pct = '{:04.2f}'.format((day_change / float(info['previous_close_price']) ) * 100)
            # format after calc
            day_change = f"{day_change:.3f}"
            options_t_data.append([
                symbol,option_type,
                expiration,
                strike_price ,
                last_price,
                quantity,
                total_equity,
                cost,
                color_data(change) +' ('+ color_data(change_pct) +'%)',
                color_data(day_change) +' ('+ color_data(day_pct) +'%)'
                ])

        print((options_table.table))

    def do_w(self, arg):
        'Show watchlist w \nAdd to watchlist w a <symbol> \nRemove from watchlist w r <symbols>'
        parts = re.split('\W+',arg.upper())

        if len(parts) >= 2:
            if parts[0] == 'A':
                for p in parts[1:]:
                    if p not in self.watchlist:
                        self.watchlist.append(p.strip())
            if parts[0] == 'R':
                self.watchlist = [r for r in self.watchlist if r not in parts[1:]]
            print("Done")
        else:
            watch_t_data=[]
            watch_table = SingleTable(watch_t_data,'Watch List')
            watch_table.inner_row_border = True
            watch_table.justify_columns = {0: 'center', 1: 'center', 2: 'center', 3:'center',4: 'center'}
            watch_t_data.append(["Symbol","Ask Price", "Open", "Today", "%"])

            if len(self.watchlist) > 0:
                instruments = [self.get_instrument(s)['url'] for s in
                        self.watchlist]
                raw_data = self.trader.get_stock_marketdata(instruments)
                quotes_data = {}
                for quote in raw_data:
                    day_change = float(quote['last_trade_price']) - float(quote['previous_close'])
                    day_change_pct = '{:05.2f}'.format(( day_change / float(quote['previous_close']) ) * 100)
                    watch_t_data.append([
                        quote['symbol'],
                        '{:05.2f}'.format(float(quote['last_trade_price'])),
                        '{:05.2f}'.format(float(quote['previous_close'])),
                        color_data(day_change),
                        color_data(day_change_pct)
                        ])
                print((watch_table.table))
            else:
                print("Watchlist empty!")

    def do_b(self, arg):
        'Buy stock b <symbol> <quantity> <price>'
        parts = arg.split()
        if len(parts) >= 2 and len(parts) <= 3:
            symbol = parts[0].upper()
            quantity = parts[1]
            if len(parts) == 3:
                price = float(parts[2])
            else:
                price = 0.0

            stock_instrument = self.get_instrument(symbol)
            if not stock_instrument['url']:
                print("Stock not found")
                return

            res = self.trader.place_buy_order(stock_instrument, quantity, price)

            if not (res.status_code == 200 or res.status_code == 201):
                print("Error executing order")
                try:
                    data = res.json()
                    if 'detail' in data:
                        print(data['detail'])
                except:
                    pass
            else:
                print("Done")
        else:
            print("Bad Order")

    def do_s(self, arg):
        'Sell stock s <symbol> <quantity> <?price>'
        parts = arg.split()
        if len(parts) >= 2 and len(parts) <= 3:
            symbol = parts[0].upper()
            quantity = parts[1]
            if len(parts) == 3:
                price = float(parts[2])
            else:
                price = 0.0

            stock_instrument = self.get_instrument(symbol)
            if not stock_instrument['url']:
                print("Stock not found")
                return

            res = self.trader.place_sell_order(stock_instrument, quantity, price)

            if not (res.status_code == 200 or res.status_code == 201):
                print("Error executing order")
                try:
                    data = res.json()
                    if 'detail' in data:
                        print(data['detail'])
                except:
                    pass
            else:
                print("Done")
        else:
            print("Bad Order")

    def do_sl(self, arg):
        'Setup stop loss on stock sl <symbol> <quantity> <price>'
        parts = arg.split()
        if len(parts) == 3:
            symbol = parts[0].upper()
            quantity = parts[1]
            price = float(parts[2])

            stock_instrument = self.trader.instruments(symbol)[0]
            res = self.trader.place_stop_loss_order(stock_instrument, quantity, price)

            if not (res.status_code == 200 or res.status_code == 201):
                print("Error executing order")
                try:
                    data = res.json()
                    if 'detail' in data:
                        print(data['detail'])
                except:
                    pass
            else:
                print("Done")
        else:
            print("Bad Order")

    def do_o(self, arg):
        'List open orders'
        open_orders = self.trader.get_open_orders()
        if open_orders:
            open_t_data=[]
            open_table = SingleTable(open_t_data,'open List')
            open_table.inner_row_border = True
            open_table.justify_columns = {0: 'center', 1: 'center', 2: 'center', 3:'center',4: 'center'}
            open_t_data.append( ["index", "symbol", "price", "quantity", "type", "id"])

            index = 1
            for order in open_orders:

                if order['trigger'] == 'stop':
                    order_price = order['stop_price']
                    order_type  = "stop loss"
                else:
                    order_price = order['price']
                    order_type  = order['side']+" "+order['type']

                open_t_data.append([
                    index,
                    self.get_symbol(order['instrument']),
                    order_price,
                    int(float(order['quantity'])),
                    order_type,
                    order['id'],
                ])
                index += 1

            print((open_table.table))
        else:
            print("No Open Orders")

    def do_c(self, arg):
        'Cancel open order c <index> or c <id>'
        order_id = arg.strip()
        order_index = -1
        try:
            order_index = int(order_id)
        except:
            pass

        if order_index > 0:
            order_index = order_index - 1
            open_orders = self.trader.get_open_orders()
            if order_index < len(open_orders):
                order_id = open_orders[order_index]['id']
            else:
                print("Bad index")
                return

        try:
            self.trader.cancel_order(order_id)
            print("Done")
        except Exception as e:
            print("Error executing cancel")
            print(e)

    def do_ca(self, arg):
        'Cancel all open orders'
        open_orders = self.trader.get_open_orders()
        for order in open_orders:
            try:
                self.trader.cancel_order(order['id'])
            except Exception as e:
                pass
        print("Done")

    def do_news(self,arg,show_num=5):
        if len(arg) == 0:
            print("Missing symbol")
        else:
            news_data = self.trader.get_news(arg.upper())

            if news_data['count'] == 0:
                print("No News available")
                return

            for x in range(0,show_num):
                news_box(news_data['results'][x]['source'], news_data['results'][x]['published_at'], news_data['results'][x]['summary'], news_data['results'][x]['title'],news_data['results'][x]['url'])

    def do_mp(self, arg):
        'Buy as many shares possible by defined max dollar amount:  mp <symbol> <max_spend> <?price_limit>'
        parts = arg.split()
        if len(parts) >= 2 and len(parts) <= 3:
            symbol = parts[0].upper()
            #quantity = parts[1]
            spend = parts[1]
            if len(parts) == 3:
                print("Parts: 3")
                price_limit = float(parts[2])
            else:
                price_limit = 0.0

            try:
                cur_data = self.trader.quote_data(symbol)
                last_price = cur_data['last_trade_price']
            except:
                print("Invalid Ticker?")
                pass
                return

            # quote['last_trade_price']
            quantity = int(math.floor(float(spend) / float(last_price)))
            print(("\nBuying %s\n Max Spend: %s\nQTY: %s\n Current Price: %s\nMax Price: %s\n" % (symbol,spend, quantity, last_price, price_limit)))

   #         stock_instrument = self.trader.instruments(symbol)[0]
   #         res = self.trader.place_buy_order(stock_instrument, quantity, price)

   #         if not (res.status_code == 200 or res.status_code == 201):
   #             print "Error executing order"
   #             try:
   #                 data = res.json()
   #                 if 'detail' in data:
   #                     print data['detail']
   #             except:
   #                 pass
   #         else:
   #             print "Done"
   #     else:
   #         print "Bad Order"

    def do_q(self, arg):
        'Get detailed quote for stock: q <symbol(s)>'

        symbols = re.split('\W+',arg.upper())

        if len(arg) == 0:
            print("Missing symbol(s)")
        else:
            instruments = [self.get_instrument(s)['url'] for s in symbols]
            raw_data = self.trader.get_stock_marketdata(instruments)
            quotes_data = {}
            quote_t_data=[]
            quote_table = SingleTable(quote_t_data,'Quote List')
            quote_table.inner_row_border = True
            quote_table.justify_columns = {0: 'center', 1: 'center', 2: 'center', 3:'center',4: 'center'}
            quote_t_data.append(["Symbol", "Current Price", "Open","Change", "Ask","Bid"])
            for quote in raw_data:
                if not quote:
                    continue
                day_change = float(quote['last_trade_price']) - float(quote['previous_close'])
                day_change_pct = ( day_change / float(quote['previous_close']) ) * 100
                ask_price = '{:05.2f}'.format(float(quote['ask_price']))
                ask_size = quote['ask_size']
                bid_price = '{:05.2f}'.format(float(quote['bid_price']))
                bid_size  = quote['bid_size']
                quote_t_data.append([
                    quote['symbol'],
                    '{:05.2f}'.format(float(quote['last_trade_price'])),
                    '{:05.2f}'.format(float(quote['previous_close'])),
                    color_data(day_change)+' ('+color_data('{:05.2f}'.format(day_change_pct))+'%)',
                    str(ask_price)+' x '+str(ask_size),
                    str(bid_price)+' x '+str(bid_size)
                    ])
            print((quote_table.table))

    def do_qq(self, arg):
        'Get quote for stock q <symbol> or option q <symbol> <call/put> <strike> <(optional) YYYY-mm-dd>'
        arg = arg.strip().split()
        try:
            symbol = arg[0].upper()
        except:
            print("Please check arguments again. Format: ")
            print("Stock: q <symbol>")
            print("Option: q <symbol> <call/put> <strike> <(optional) YYYY-mm-dd>")
        type = strike = expiry = None
        if len(arg) > 1:
            try:
                type = arg[1]
                strike = arg[2]
            except Exception as e:
                print("Please check arguments again. Format: ")
                print("q <symbol> <call/put> <strike> <(optional) YYYY-mm-dd>")

            try:
                expiry = arg[3]
            except:
                expiry = None

            arg_dict = {'symbol': symbol, 'type': type, 'expiration_dates': expiry, 'strike_price': strike, 'state': 'active', 'tradability': 'tradable'};
            quotes = self.trader.get_option_quote(arg_dict);

            qquote_t_data=[]
            qquote_table = SingleTable(qquote_t_data,'Quote List')
            qquote_table.inner_row_border = True
            qquote_table.justify_columns = {0: 'center', 1: 'center'}
            qquote_t_data.append(['expiry', 'price'])

            for row in quotes:
                qquote_t_data.append(row)

            print((qquote_table.table))
        else:
            try:
                self.trader.print_quote(symbol)
            except:
                print("Error getting quote for:", symbol)

    def do_bye(self, arg):
        open(self.instruments_cache_file, 'w').write(json.dumps(self.instruments_cache))
        open(self.watchlist_file, 'w').write(json.dumps(self.watchlist))
        self._save_auth_data()
        return True

    # ------ utils --------
    def get_symbol(self, url):
        if not url in self.instruments_reverse_cache:
            self.add_instrument_from_url(url)

        return self.instruments_reverse_cache[url]

    def get_instrument(self, symbol):
        if not symbol in self.instruments_cache:
            instruments = self.trader.instruments(symbol)
            for instrument in instruments:
                self.add_instrument(instrument['url'], instrument['symbol'])

        url = ''
        if symbol in self.instruments_cache:
            url = self.instruments_cache[symbol]

        return { 'symbol': symbol, 'url': url }

    def add_instrument_from_url(self, url):
        data = self.trader.get_url(url)
        if 'symbol' in data:
            symbol = data['symbol']
        else:
            types = { 'call': 'C', 'put': 'P'}
            symbol = data['chain_symbol'] + ' ' + data['expiration_date'] + ' ' + ''.join(types[data['type']].split('-')) + ' ' + str(float(data['strike_price']))
        self.add_instrument(url, symbol)

    def add_instrument(self, url, symbol):
        self.instruments_cache[symbol] = url
        self.instruments_reverse_cache[url] = symbol
Esempio n. 4
0
class Robinhood_AA (object):

    def __init__(self):
        self.start_time = datetime.now()
        self.my_trader = Robinhood()
        self.my_trader.login(username=usrnm, password=pssw)
        self.equity = self.my_trader.equity()
        self.owned_securities = self.my_trader.securities_owned()
        self.available_funds = self.my_trader.equity() - sum([x[1]*x[4] for x in self.my_trader.securities_owned()])
        self.buy_limit = 120
        self.stocks = []
        self.ld = 10  ## sell no matter what
        self.sd = 5  ## sell if positive
        self.file_path = home_path
        self.conn = sqlite3.connect(self.file_path+'log.db')
        self.conn.execute('drop table if exists history')
        self.conn.execute('''create table history
                (id int primary key     not null,
                date            text    not null,
                activity        text    not null,
                stock           text    not null,
                gain            text    not null);''')
        self.idCount = 1
        print('Deleting old files...')
        # delete old files
        os.chdir(self.file_path)
        for f in glob.glob("*.png"):
            os.remove(f)

    def today_stocks_to_buy(self):
        F = FGS('Low Cost', 100, {'minPrice':7,'maxPrice':35}, 'lowcost', self.file_path)
        stocks = F.find_good_stocks()
        self.stocks = [x[0] for x in stocks]
        print(self.stocks)

    def update_info(self):
        self.equity = self.my_trader.equity()
        self.owned_securities = self.my_trader.securities_owned()
        self.available_funds = self.my_trader.equity() - sum([x[1]*x[4] for x in self.my_trader.securities_owned()])

    def current_stock_info(self):
        self.open_log()
        try:
            table = []
            for s in self.owned_securities:
                datetime_format = datetime.strptime(s[2], '%Y-%m-%dT%H:%M:%S.%fZ')
                duration = datetime.now() - datetime_format
                table.append([s[0], round((s[4]/s[3]-1) * 100, 2), duration > timedelta(days=5), duration > timedelta(days=10)])
            table = sorted(table, key = lambda x: x[1])
            self.log.write(tabulate(table, headers = ['Stock', 'Total Gain/Loss', '> {} days', '> {} days'.format(self.sd, self.ld)]))
            self.log.write('\n')
        except Exception as e:
            self.log.write('Can\'t print table: unexpected error {}.\n'.format(e))
        self.close_log()

    def buy_stock(self, stock = None):
        self.open_log()
        self.log.write('\nBuying:\n')
        try:
            if stock == None:
                self.log.write('Nothing bought: no stock specified.\n')
            elif self.available_funds > self.buy_limit:
                last_price = float(self.my_trader.last_trade_price(stock))
                number_to_buy = int(self.buy_limit/last_price)
                self.my_trader.place_buy_order(self.my_trader.instruments(stock)[0], int(self.buy_limit/last_price))
                self.log.write('Buying {} stocks of {} at {} for a total of {}.\n'.format(number_to_buy, stock, last_price, last_price * number_to_buy))
                self.conn.execute('insert into history (id,date,activity,stock,gain) values (?, ?, ?, ?, ?)', (self.idCount, datetime.now(), 'BUY', stock, 'N/A'))
                self.idCount += 1
            else:
                self.log.write('Nothing bought: insufficient funds to buy stock. Need at least {} dollars.\n'.format(self.buy_limit))
        except Exception as e:
            self.log.write('Nothing bought: {}.\n'.format(e))
        self.close_log()

    def auto_buy_stocks(self):
        self.open_log()
        self.log.write('\nBuying:\n')
        try:
            if self.available_funds < self.buy_limit:
                self.log.write('Nothing bought: insufficient funds to buy stocks. Need at least {0} dollars.\n'.format(self.buy_limit))
            else:
                for i in range(int(self.available_funds / self.buy_limit)):
                    last_price = float(self.my_trader.last_trade_price(self.stocks[i]))
                    number_to_buy = int(self.buy_limit/last_price)
                    self.my_trader.place_buy_order(self.my_trader.instruments(self.stocks[i])[0], int(self.buy_limit/last_price))
                    self.log.write('Buying {} stocks of {} at {} for a total of {}.\n'.format(number_to_buy, self.stocks[i], last_price, last_price * number_to_buy))
                    self.conn.execute('insert into history (id,date,activity,stock,gain) values (?, ?, ?, ?, ?)', (self.idCount, datetime.now(), 'BUY', self.stocks[i], 'N/A'))
                    self.idCount += 1
                    time.sleep(10)
        #except Exception as e:
        except BufferError:
            self.log.write('Nothing bought: {}.\n'.format(e))
        self.close_log()

    def auto_sell_stocks(self):
        self.open_log()
        self.log.write('\nSelling:\n')
        try:
            for s in self.owned_securities:
                datetime_format = datetime.strptime(s[2], '%Y-%m-%dT%H:%M:%S.%fZ')
                duration = datetime.now() - datetime_format
                gain = round((s[4]/s[3]-1) * 100, 2)
                try:
                    if duration > timedelta(days=self.ld):
                        self.my_trader.place_sell_order(self.my_trader.instruments(s[0])[0], s[1])
                        self.log.write('Selling {}: More than {} days :|\n'.format(s[0], self.ld))
                        self.conn.execute('insert into history (id,date,activity,stock,gain) values (?, ?, ?, ?, ?)', (self.idCount, datetime.now(), 'SELL', s[0], gain))
                        self.idCount += 1
                    elif duration > timedelta(days=self.sd) and gain > 0:
                        self.my_trader.place_sell_order(self.my_trader.instruments(s[0])[0], s[1])
                        self.log.write('Selling {}: More than {} days and positive :)\n'.format(s[0], self.sd))
                        self.conn.execute('insert into history (id,date,activity,stock,gain) values (?, ?, ?, ?, ?)', (self.idCount, datetime.now(), 'SELL', s[0], gain))
                        self.idCount += 1
                    elif gain > 5:
                        self.my_trader.place_sell_order(self.my_trader.instruments(s[0])[0], s[1])
                        self.log.write('Selling {}: More than 5% :)\n'.format(s[0]))
                        self.conn.execute('insert into history (id,date,activity,stock,gain) values (?, ?, ?, ?, ?)', (self.idCount, datetime.now(), 'SELL', s[0], gain))
                        self.idCount += 1
                    elif gain < -5:
                        self.my_trader.place_sell_order(self.my_trader.instruments(s[0])[0], s[1])
                        self.log.write('Selling {}: Less than -5% :(\n'.format(s[0]))
                        self.conn.execute('insert into history (id,date,activity,stock,gain) values (?, ?, ?, ?, ?)', (self.idCount, datetime.now(), 'SELL', s[0], gain))
                        self.idCount += 1
                except Exception as e:
                    self.log.write('Couldn\'t sell {}: {}.\n'.format(s[0], e))
        except Exception as e:
            self.log.write('Nothing sold: {}.\n'.format(e))
        self.close_log()

    def new_log(self):
        # creates new log if different day
        if os.path.isfile('{}log{}.txt'.format(self.file_path,datetime.now().strftime('%y%m%d'))):
            pass
        else:
            self.log = open('{}log{}.txt'.format(self.file_path,datetime.now().strftime('%y%m%d')),'w')
            self.log.close()

    def open_log(self):
        self.log = open('{}log{}.txt'.format(self.file_path,datetime.now().strftime('%y%m%d')),'a')
        self.log.write('\n\nRobinhood Status: {}\n\n'.format(datetime.now()))

    def close_log(self):
        try:
            self.log.write('\nTook {} seconds.'.format(datetime.now() - self.start_time))
            self.log.close()
        except Exception as e:
            print('Couldn\'t close log: {}'.format(e))

    def printDB(self, db='log.db'):
        try:
            self.log.write('\nDatabase:')
            cur = sqlite3.connect(db).cursor()
            self.log.write('  '+str([header[0] for header in cur.execute("select * from history").description][1:]))
            for entry in cur.fetchall():
                self.log.write(entry)
            cur.close()
        except Exception as e:
            print('Couldn\'t print database: {}'.format(e))

    def send_email_AA(self):
        sendEmail(self.file_path, 'Robinhood Operation', ['*****@*****.**'],
                 ['blacklist.txt',self.file_path+'readme.txt',self.file_path+'log.db',
                 self.file_path+'.DS_Store', self.file_path+'log.db-journal'])
Esempio n. 5
0
#Print multiple symbols
#my_trader.print_quotes(stocks=["BBRY", "FB", "MSFT"])

#View all data for a given stock ie. Ask price and size, bid price and size, previous close, adjusted previous close, etc.
#quote_info = my_trader.quote_data("GEVO")
#print(quote_info)

#Place a buy order (uses market bid price)
#buy_order = my_trader.place_buy_order(stock_instrument, 1)

#Place a sell order
#sell_order = my_trader.place_sell_order(stock_instrument, 1)

portfolio = my_trader.portfolios()
positions = my_trader.positions()
securities = my_trader.securities_owned()

while True:
    exchange_closed = is_time_between(time(17, 00), time(9, 30))
    print exchange_closed

    if exchange_closed:
        print("Exhange not Open. Passing.")
        pass

    else:
        for key in securities['results']:

            instrument = my_trader.get_url(
                key['instrument'])  #get symbol of stock
            name = instrument['symbol']
Esempio n. 6
0
class RobinhoodShell(cmd.Cmd):
    intro = 'Welcome to the Robinhood shell. Type help or ? to list commands.\n'
    prompt = '> '

    # API Object
    trader = None

    # Cache file used to store instrument cache
    instruments_cache_file = 'instruments.data'

    # Maps Symbol to Instrument URL
    instruments_cache = {}

    # Maps URL to Symbol
    instruments_reverse_cache = {}

    def __init__(self):
        cmd.Cmd.__init__(self)
        self.trader = Robinhood()
        self.trader.login(username=USERNAME, password=PASSWORD)

        try:
            data = open('instruments.data').read()
            self.instruments_cache = json.loads(data)
            for k in self.instruments_cache:
                self.instruments_reverse_cache[self.instruments_cache[k]] = k
        except:
            pass

    # ----- basic commands -----
    def do_l(self, arg):
        'Lists current portfolio'
        portfolio = self.trader.portfolios()
        print 'Equity Value:', portfolio['equity']

        account_details = self.trader.get_account()
        if 'margin_balances' in account_details:
            print 'Buying Power:', account_details['margin_balances'][
                'unallocated_margin_cash']

        positions = self.trader.securities_owned()

        symbols = []
        for position in positions['results']:
            symbol = self.get_symbol(position['instrument'])
            symbols.append(symbol)

        raw_data = self.trader.quotes_data(symbols)
        quotes_data = {}
        for quote in raw_data:
            quotes_data[quote['symbol']] = quote['last_trade_price']

        table = BeautifulTable()
        table.column_headers = [
            "symbol", "current price", "quantity", "total equity"
        ]

        for position in positions['results']:
            quantity = int(float(position['quantity']))
            symbol = self.get_symbol(position['instrument'])
            price = quotes_data[symbol]
            total_equity = float(price) * quantity
            table.append_row([symbol, price, quantity, total_equity])

        print(table)

    def do_b(self, arg):
        'Buy stock b <symbol> <quantity> <price>'
        parts = arg.split()
        if len(parts) == 3:
            symbol = parts[0]
            quantity = parts[1]
            price = float(parts[2])

            stock_instrument = self.trader.instruments(symbol)[0]
            res = self.trader.place_buy_order(stock_instrument, quantity,
                                              price)

            if not (res.status_code == 200 or res.status_code == 201):
                print "Error executing order"
                try:
                    data = res.json()
                    if 'detail' in data:
                        print data['detail']
                except:
                    pass
            else:
                print "Done"
        else:
            print "Bad Order"

    def do_s(self, arg):
        'Sell stock s <symbol> <quantity> <price>'
        parts = arg.split()
        if len(parts) == 3:
            symbol = parts[0]
            quantity = parts[1]
            price = float(parts[2])

            stock_instrument = self.trader.instruments(symbol)[0]
            res = self.trader.place_sell_order(stock_instrument, quantity,
                                               price)

            if not (res.status_code == 200 or res.status_code == 201):
                print "Error executing order"
                try:
                    data = res.json()
                    if 'detail' in data:
                        print data['detail']
                except:
                    pass
            else:
                print "Done"
        else:
            print "Bad Order"

    def do_o(self, arg):
        'List open orders'
        open_orders = self.trader.get_open_orders()
        if open_orders:
            table = BeautifulTable()
            table.column_headers = [
                "symbol", "price", "quantity", "type", "id"
            ]

            for order in open_orders:
                table.append_row([
                    self.get_symbol(order['instrument']),
                    order['price'],
                    int(float(order['quantity'])),
                    order['side'],
                    order['id'],
                ])

            print(table)
        else:
            print "No Open Orders"

    def do_c(self, arg):
        'Cancel open order c <id>'
        order_id = arg.strip()
        try:
            self.trader.cancel_order(order_id)
            print "Done"
        except Exception as e:
            print "Error executing cancel"
            print e

    def do_q(self, arg):
        'Get quote for stock q <symbol>'
        symbol = arg.strip()
        try:
            self.trader.print_quote(symbol)
        except:
            print "Error getting quote for:", symbol

    def do_bye(self, arg):
        open(self.instruments_cache_file,
             'w').write(json.dumps(self.instruments_cache))
        return True

    # ------ utils --------
    def get_symbol(self, url):
        if not url in self.instruments_reverse_cache:
            self.add_instrument_from_url(url)

        return self.instruments_reverse_cache[url]

    def add_instrument_from_url(self, url):
        data = self.trader.get_url(url)
        symbol = data['symbol']
        self.instruments_cache[symbol] = url
        self.instruments_reverse_cache[url] = symbol
Esempio n. 7
0
class TKshell(cmd.Cmd):
    intro = 'Welcome to the Robinhood shell. Type help or ? to list commands.\n'
    prompt = '> '

    # API Object
    trader = None

    # Cache file used to store instrument cache
    instruments_cache_file = 'instruments.data'

    # Maps Symbol to Instrument URL
    instruments_cache = {}

    # Maps URL to Symbol
    instruments_reverse_cache = {}

    def __init__(self):
        cmd.Cmd.__init__(self)
        self.trader = Robinhood()
        self.trader.login_prompt()

        try:
            data = open('instruments.data').read()
            self.instruments_cache = json.loads(data)
            for k in self.instruments_cache:
                self.instruments_reverse_cache[self.instruments_cache[k]] = k
        except:
            pass

    # ----- basic commands -----
    def do_l(self, arg):
        'Lists current portfolio'
        portfolio = self.trader.portfolios()
        print('Equity Value:', portfolio['equity'])

        account_details = self.trader.get_account()
        if 'margin_balances' in account_details:
            print(
                'Buying Power:',
                account_details['margin_balances']['unallocated_margin_cash'])

        positions = self.trader.securities_owned()

        symbols = ''
        buy_price_data = {}
        for position in positions['results']:
            symbol = self.get_symbol(position['instrument'])
            buy_price_data[symbol] = position['average_buy_price']
            symbols += symbol + ','
        symbols = symbols[:-1]

        raw_data = self.trader.quote_data(symbols)
        quotes_data = {}
        for quote in raw_data:
            quotes_data[quote['symbol']] = quote['last_trade_price']
        d = []
        for position in positions['results']:
            quantity = int(float(position['quantity']))
            symbol = self.get_symbol(position['instrument'])
            price = quotes_data[symbol]
            total_equity = float(price) * quantity
            buy_price = float(buy_price_data[symbol])
            p_l = total_equity - buy_price * quantity
            d.append([symbol, price, quantity, total_equity, buy_price, p_l])

        column_headers = [
            "symbol", "current price", "quantity", "total equity",
            "cost basis", "p/l"
        ]
        table = tabulate(d, headers=column_headers)
        print(table)

    def do_q(self, arg):
        'Get quote for stock q <symbol>'
        symbols = arg.strip()
        headers = [
            'symbol', 'price', 'bid_size', 'bid_price', 'ask_size', 'ask_price'
        ]
        try:
            data = self.trader.get_quote_list(
                symbols,
                'symbol,last_trade_price,bid_size,bid_price,ask_size,ask_price'
            )
            print(tabulate(data, headers=headers))
        except:
            print("Error getting quote for:", symbols)

    def do_b(self, arg):
        'Buy stock b <symbol> <quantity> <price>'
        parts = arg.split()
        if len(parts) == 3:
            symbol = parts[0]
            quantity = parts[1]
            price = round(float(parts[2]), 2)

            stock_instrument = self.trader.instruments(symbol)[0]
            res = self.trader.place_buy_order(stock_instrument, quantity,
                                              price)

            if not (res.status_code == 200 or res.status_code == 201):
                print("Error executing order")
                try:
                    data = res.json()
                    if 'detail' in data:
                        print(data['detail'])
                except:
                    pass
            else:
                print("Done")
        else:
            print("Bad Order")

    def do_qb(self, arg):
        '''
        Quick Buy
        a quick buy is a limit buy which price is set at previous close + 15% * previous candle body
        :param arg: <symbol> <quantity>
        :return: order detail
        '''
        parts = arg.split()
        if len(parts) == 2:
            symbol = parts[0]
            quantity = parts[1]
            d = g_ts.get_intraday(symbol=symbol, interval='5min')[0][-2:-1]
            o = float(d['open'])
            c = float(d['close'])
            price = round(min(o, c) + 0.15 * abs(o - c), 2)

            stock_instrument = self.trader.instruments(symbol)[0]
            res = self.trader.place_buy_order(stock_instrument, quantity,
                                              price)

            if not (res.status_code == 200 or res.status_code == 201):
                print("Error executing order")
                try:
                    data = res.json()
                    if 'detail' in data:
                        print(data['detail'])
                except:
                    pass
            else:
                print("Done")
        else:
            print("Bad Order")

    def do_s(self, arg):
        'Sell stock s <symbol> <quantity> <price>'
        parts = arg.split()
        if len(parts) == 3:
            symbol = parts[0]
            quantity = parts[1]
            price = float(parts[2])

            stock_instrument = self.trader.instruments(symbol)[0]
            res = self.trader.place_sell_order(stock_instrument, quantity,
                                               price)

            if not (res.status_code == 200 or res.status_code == 201):
                print("Error executing order")
                try:
                    data = res.json()
                    if 'detail' in data:
                        print(data['detail'])
                except:
                    pass
            else:
                print("Done")
        else:
            print("Bad Order")

    def do_o(self, arg):
        'List open orders'
        open_orders = self.trader.order_history()['results'][:10]
        if open_orders:
            column_headers = [
                "index", "symbol", "state", "price", "quantity", "type", "id"
            ]
            global g_openorders, g_liststates
            g_openorders = []
            count = 1
            for order in open_orders:
                if order['state'] in g_liststates:
                    g_openorders.append([
                        count,
                        self.get_symbol(order['instrument']), order['state'],
                        order['price'],
                        int(float(order['quantity'])), order['side'],
                        order['id']
                    ])
                    count += 1
            g_openorders.reverse()
            table = tabulate(g_openorders, headers=column_headers)
            print(table)
        else:
            print("No Open Orders")

    def do_c(self, arg):
        '''
        Cancel an open order by index return in list orders
        :param arg:
        :return:
        '''
        order_index = int(arg.strip())
        try:
            self.trader.cancel_order(g_openorders[-order_index][-1])
        except Exception as e:
            print("Error executing cancel\n", e)
        print(g_openorders[-order_index], "has been cancelled.")

    def do_u(self, arg):
        '''
        refresh the watch list, combining positions owned with symbol in wl.json
        :param arg:
        :return:
        '''
        positions = self.trader.securities_owned()
        global g_watchlist
        g_watchlist = []
        for position in positions['results']:
            g_watchlist.append(self.trader.quote_data(position['instrument']))
            # TODO maybe add pre-calculated price level in the json file as well
        with open('wl.json', 'r') as f:
            d = json.load(f)
            for each in d:
                g_watchlist.append(each)

        print("Watchlist updated")
        print(tabulate(d))

    def do_r(self, arg):
        '''
        rate
        :param arg:
        :return:
        '''

    def do_bye(self, arg):
        open(self.instruments_cache_file,
             'w').write(json.dumps(self.instruments_cache))
        return True

    # ------ utils --------
    def get_symbol(self, url):
        if not url in self.instruments_reverse_cache:
            self.add_instrument_from_url(url)

        return self.instruments_reverse_cache[url]

    def add_instrument_from_url(self, url):
        data = self.trader.get_url(url)
        symbol = data['symbol']
        self.instruments_cache[symbol] = url
        self.instruments_reverse_cache[url] = symbol
Esempio n. 8
0
class RobinhoodShell(cmd.Cmd):
    intro = 'Welcome to the Robinhood shell. Type help or ? to list commands.\n'
    prompt = '> '

    # API Object
    trader = None

    # Cache file used to store instrument cache
    instruments_cache_file = 'instruments.data'

    # Maps Symbol to Instrument URL
    instruments_cache = {}

    # Maps URL to Symbol
    instruments_reverse_cache = {}

    # Cache file used to store instrument cache
    watchlist_file = 'watchlist.data'

    # List of stocks in watchlist
    watchlist = []

    def __init__(self):
        cmd.Cmd.__init__(self)
        self.trader = Robinhood()
        self.trader.login(username=USERNAME, password=PASSWORD)

        try:
            data = open(self.instruments_cache_file).read()
            self.instruments_cache = json.loads(data)
            for k in self.instruments_cache:
                self.instruments_reverse_cache[self.instruments_cache[k]] = k
        except:
            pass

        try:
            data = open(self.watchlist_file).read()
            self.watchlist = json.loads(data)
        except:
            pass

    # nytime = parser.parse('2018-06-15T23:14:15Z').astimezone(to_zone)
    # from dateutil import parser

    # ----- basic commands -----
    def do_l(self, arg):
        'Lists current portfolio'
        portfolio = self.trader.portfolios()
        if portfolio['extended_hours_equity']:
            equity = float(portfolio['extended_hours_equity'])
        else:
            equity = float(portfolio['equity'])

        print 'Equity Value: %.2f' % equity
        previous_close = float(portfolio['adjusted_equity_previous_close'])
        change = equity - previous_close
        print '%s%.2f Today (%.2f%%)' % (('+' if change > 0 else ''), change,
                                         change / previous_close * 100.0)

        account_details = self.trader.get_account()
        if 'margin_balances' in account_details:
            print 'Buying Power:', account_details['margin_balances'][
                'unallocated_margin_cash']

        # Load Stocks
        positions = self.trader.securities_owned()
        symbols = [
            self.get_symbol(position['instrument'])
            for position in positions['results']
        ]

        quotes_data = {}
        if len(symbols) > 0:
            raw_data = self.trader.quotes_data(symbols)
            for quote in raw_data:
                if quote['last_extended_hours_trade_price']:
                    price = quote['last_extended_hours_trade_price']
                else:
                    price = quote['last_trade_price']
                quotes_data[quote['symbol']] = price

        table = BeautifulTable()
        table.column_headers = [
            "symbol", "current price", "quantity", "total equity",
            "cost basis", "p/l"
        ]

        for position in positions['results']:
            quantity = int(float(position['quantity']))
            symbol = self.get_symbol(position['instrument'])
            price = quotes_data[symbol]
            total_equity = float(price) * quantity
            buy_price = float(position['average_buy_price'])
            p_l = total_equity - buy_price * quantity
            table.append_row(
                [symbol, price, quantity, total_equity, buy_price, p_l])

        print "Stocks:"
        print(table)

        # Load Options
        option_positions = self.trader.options_owned()
        table = BeautifulTable()
        table.column_headers = [
            "option", "price", "quantity", "equity", "cost basis", "p/l"
        ]

        for op in option_positions:
            quantity = float(op['quantity'])
            if quantity == 0:
                continue

            cost = float(op['average_price'])
            if op['type'] == 'short':
                quantity = -quantity
                cost = -cost

            instrument = op['option']
            option_data = self.trader.session.get(instrument).json()
            expiration_date = option_data['expiration_date']
            strike = float(option_data['strike_price'])
            type = option_data['type']
            symbol = op[
                'chain_symbol'] + ' ' + expiration_date + ' ' + type + ' $' + str(
                    strike)
            info = self.trader.get_option_marketdata(instrument)
            last_price = float(info['adjusted_mark_price'])
            total_equity = (100 * last_price) * quantity
            change = total_equity - (float(cost) * quantity)
            table.append_row(
                [symbol, last_price, quantity, total_equity, cost, change])

        print "Options:"
        print(table)

    def do_w(self, arg):
        'Show watchlist w \nAdd to watchlist w a <symbol> \nRemove from watchlist w r <symbol>'
        parts = arg.split()
        if len(parts) == 2:
            if parts[0] == 'a':
                self.watchlist.append(parts[1].strip())
            if parts[0] == 'r':
                self.watchlist = [
                    r for r in self.watchlist if not r == parts[1].strip()
                ]
            print "Done"
        else:
            table = BeautifulTable()
            table.column_headers = ["symbol", "current price"]

            if len(self.watchlist) > 0:
                raw_data = self.trader.quotes_data(self.watchlist)
                quotes_data = {}
                for quote in raw_data:
                    table.append_row(
                        [quote['symbol'], quote['last_trade_price']])
                print(table)
            else:
                print "Watchlist empty!"

    def do_b(self, arg):
        'Buy stock b <symbol> <quantity> <price>'
        parts = arg.split()
        if len(parts) >= 2 and len(parts) <= 3:
            symbol = parts[0]
            quantity = parts[1]
            if len(parts) == 3:
                price = float(parts[2])
            else:
                price = 0.0

            stock_instrument = self.get_instrument(symbol)
            if not stock_instrument['url']:
                print "Stock not found"
                return

            res = self.trader.place_buy_order(stock_instrument, quantity,
                                              price)

            if not (res.status_code == 200 or res.status_code == 201):
                print "Error executing order"
                try:
                    data = res.json()
                    if 'detail' in data:
                        print data['detail']
                except:
                    pass
            else:
                print "Done"
        else:
            print "Bad Order"

    def do_s(self, arg):
        'Sell stock s <symbol> <quantity> <?price>'
        parts = arg.split()
        if len(parts) >= 2 and len(parts) <= 3:
            symbol = parts[0]
            quantity = parts[1]
            if len(parts) == 3:
                price = float(parts[2])
            else:
                price = 0.0

            stock_instrument = self.get_instrument(symbol)
            if not stock_instrument['url']:
                print "Stock not found"
                return

            res = self.trader.place_sell_order(stock_instrument, quantity,
                                               price)

            if not (res.status_code == 200 or res.status_code == 201):
                print "Error executing order"
                try:
                    data = res.json()
                    if 'detail' in data:
                        print data['detail']
                except:
                    pass
            else:
                print "Done"
        else:
            print "Bad Order"

    def do_sl(self, arg):
        'Setup stop loss on stock sl <symbol> <quantity> <price>'
        parts = arg.split()
        if len(parts) == 3:
            symbol = parts[0]
            quantity = parts[1]
            price = float(parts[2])

            stock_instrument = self.trader.instruments(symbol)[0]
            res = self.trader.place_stop_loss_order(stock_instrument, quantity,
                                                    price)

            if not (res.status_code == 200 or res.status_code == 201):
                print "Error executing order"
                try:
                    data = res.json()
                    if 'detail' in data:
                        print data['detail']
                except:
                    pass
            else:
                print "Done"
        else:
            print "Bad Order"

    def do_o(self, arg):
        'List open orders'
        open_orders = self.trader.get_open_orders()
        if open_orders:
            table = BeautifulTable()
            table.column_headers = [
                "index", "symbol", "price", "quantity", "type", "id"
            ]

            index = 1
            for order in open_orders:

                if order['trigger'] == 'stop':
                    order_price = order['stop_price']
                    order_type = "stop loss"
                else:
                    order_price = order['price']
                    order_type = order['side'] + " " + order['type']

                table.append_row([
                    index,
                    self.get_symbol(order['instrument']),
                    order_price,
                    int(float(order['quantity'])),
                    order_type,
                    order['id'],
                ])
                index += 1

            print(table)
        else:
            print "No Open Orders"

    def do_c(self, arg):
        'Cancel open order c <index> or c <id>'
        order_id = arg.strip()
        order_index = -1
        try:
            order_index = int(order_id)
        except:
            pass

        if order_index > 0:
            order_index = order_index - 1
            open_orders = self.trader.get_open_orders()
            if order_index < len(open_orders):
                order_id = open_orders[order_index]['id']
            else:
                print "Bad index"
                return

        try:
            self.trader.cancel_order(order_id)
            print "Done"
        except Exception as e:
            print "Error executing cancel"
            print e

    def do_ca(self, arg):
        'Cancel all open orders'
        open_orders = self.trader.get_open_orders()
        for order in open_orders:
            try:
                self.trader.cancel_order(order['id'])
            except Exception as e:
                pass
        print "Done"

    def do_q(self, arg):
        'Get quote for stock q <symbol> or option q <symbol> <call/put> <strike> <(optional) YYYY-mm-dd>'
        arg = arg.strip().split()
        try:
            symbol = arg[0]
        except:
            print "Please check arguments again. Format: "
            print "Stock: q <symbol>"
            print "Option: q <symbol> <call/put> <strike> <(optional) YYYY-mm-dd>"
        type = strike = expiry = None
        if len(arg) > 1:
            try:
                type = arg[1]
                strike = arg[2]
            except Exception as e:
                print "Please check arguments again. Format: "
                print "q <symbol> <call/put> <strike> <(optional) YYYY-mm-dd>"

            try:
                expiry = arg[3]
            except:
                expiry = None

            arg_dict = {
                'symbol': symbol,
                'type': type,
                'expiration_dates': expiry,
                'strike_price': strike,
                'state': 'active',
                'tradability': 'tradable'
            }
            quotes = self.trader.get_option_quote(arg_dict)
            table = BeautifulTable()
            table.column_headers = ['expiry', 'price']

            for row in quotes:
                table.append_row(row)

            print table
        else:
            try:
                self.trader.print_quote(symbol)
            except:
                print "Error getting quote for:", symbol

    def do_bye(self, arg):
        open(self.instruments_cache_file,
             'w').write(json.dumps(self.instruments_cache))
        open(self.watchlist_file, 'w').write(json.dumps(self.watchlist))
        return True

    # ------ utils --------
    def get_symbol(self, url):
        if not url in self.instruments_reverse_cache:
            self.add_instrument_from_url(url)

        return self.instruments_reverse_cache[url]

    def get_instrument(self, symbol):
        if not symbol in self.instruments_cache:
            instruments = self.trader.instruments(symbol)
            for instrument in instruments:
                self.add_instrument(instrument['url'], instrument['symbol'])

        url = ''
        if symbol in self.instruments_cache:
            url = self.instruments_cache[symbol]

        return {'symbol': symbol, 'url': url}

    def add_instrument_from_url(self, url):
        data = self.trader.get_url(url)
        if 'symbol' in data:
            symbol = data['symbol']
        else:
            types = {'call': 'C', 'put': 'P'}
            symbol = data['chain_symbol'] + ' ' + data[
                'expiration_date'] + ' ' + ''.join(
                    types[data['type']].split('-')) + ' ' + str(
                        float(data['strike_price']))
        self.add_instrument(url, symbol)

    def add_instrument(self, url, symbol):
        self.instruments_cache[symbol] = url
        self.instruments_reverse_cache[url] = symbol
class Trader:
    def __init__(self):
        cfg = self.get_config()
        self.user_name = cfg.get('robinhood').get('user')
        self.password = cfg.get('robinhood').get('password')
        self.client = Robinhood()
        self.client.login(username=self.user_name, password=self.password)
        self.stock_list = self.get_stock_list(cfg.get('stock'))
        self.stock_owned()

    def get_stock_list(self, stock_dict):
        stock_list = []
        for stock in stock_dict:
            instrument = self.client.instrument(stock)[0].get('url')
            instrument_id = self.client.instrument(stock)[0].get('id')
            stock_details = stock_dict.get(stock)
            stock_details['instrument'] = instrument
            stock_details['instrument_id'] = instrument_id
            stock_details['symobl'] = stock
            stock_list.append(stock_details)
        return stock_list

    def stock_owned(self):
        stocks = self.client.securities_owned()
        for stock in stocks.get('results'):
            for s in self.stock_list:
                if s.get('instrument') == stock.get('instrument'):
                    s['amount_owned'] = float(stock.get('quantity'))
                    s['purchase_price'] = float(
                        stock.get('pending_average_buy_price'))
                    s['sell_price'] = float(s['purchase_price']) + float(
                        s.get('target-profit'))
                    break
                else:
                    s['amount_owned'] = 0
                    s['purchase_price'] = 0

                if not stock.get('purchase_price'):
                    s['sell_price'] = float(s.get('median-price')) + float(
                        s.get('target-profit'))
                    s['purchase_price'] = float(s.get('median-price')) + float(
                        s.get('price-target'))

    def create_buy_order(self, stock):
        qty = stock.get('position') - stock.get('amount_owned')
        if qty > 0:
            stock['order'] = self.client.place_limit_buy_order(
                None, stock.get('symobl'), 'GFD', stock.get('purchase_price'),
                qty).json()

    def create_sell_order(self, stock):
        qty = stock.get('amount_owned')
        if stock.get('can_sell_today'):
            self.client.place_limit_sell_order(None, stock.get('symobl'),
                                               'GFD', stock.get('sell_price'),
                                               qty).json()
        else:
            print("this might trigger day trading sorry no order created")

    def should_i_stop_trading(self):
        for stock in self.stock_list:
            if stock.get('can_sell_today'):
                print(stock)
                return False
        return True

    def create_market_position(self):
        for stock in self.stock_list:
            if stock.get('amount_owned') == 0:
                #prevent day tradding
                stock['can_sell_today'] = False
                self.create_buy_order(stock)
                stock['amount_owned'] = stock.get('position')
            else:
                self.create_sell_order(stock)

    def check_if_sell_order_confirmed(self):
        for stock in self.stock_list:
            order = stock.get('order')
            if order and order.get('side') == 'sell':
                order_state = self.client.order_history(
                    order.get('id')).get('state')
                if order_state == "filled":
                    stock['amount_owned'] = 0
                    self.create_market_position()

    def get_config(self):
        with open("config.yaml", 'r') as ymlfile:
            cfg = yaml.load(ymlfile)
        return cfg
Esempio n. 10
0
class Query:

    # __init__:Void
    # param email:String => Email of the Robinhood user.
    # param password:String => Password for the Robinhood user.
    def __init__(self, email, password):
        self.trader = Robinhood()
        self.trader.login(username=email, password=password)
        self.email = email
        self.password = password

    ##           ##
    #   Getters   #
    ##           ##

    # get_fundamentals_by_criteria:[String]
    # param price_range:(float, float) => High and low prices for the queried fundamentals.
    # returns List of symbols that fit the given criteria.
    def get_fundamentals_by_criteria(self,
                                     price_range=(0.00, sys.maxsize),
                                     tags=None):
        all_symbols = []
        if tags is not None and tags is not []:
            if isinstance(tags, Enum):
                try:
                    all_symbols = self.get_by_tag(tag)
                except Exception as e:
                    pass
            else:
                for tag in tags:
                    try:
                        all_symbols += self.get_by_tag(tag)
                    except Exception as e:
                        pass
        else:
            all_symbols = [
                instrument['symbol']
                for instrument in self.trader.instruments_all()
            ]
        queried_fundamentals = []
        for symbol in all_symbols:
            try:
                fundamentals = self.get_fundamentals(symbol)
                if fundamentals is not None and 'low' in fundamentals and 'high' in fundamentals and float(
                        fundamentals['low'] or -1) >= price_range[0] and float(
                            fundamentals['high']
                            or sys.maxsize + 1) <= price_range[1]:
                    fundamentals['symbol'] = symbol
                    queried_fundamentals.append(fundamentals)
            except Exception as e:
                continue
        return queried_fundamentals

    # get_symbols_by_criteria:[String]
    # param price_range:(float, float) => High and low prices for the queried symbols.
    # returns List of symbols that fit the given criteria.
    def get_symbols_by_criteria(self,
                                price_range=(0.00, sys.maxsize),
                                tags=None):
        queried_fundamentals = self.get_fundamentals_by_criteria(
            price_range, tags)
        queried_symbols = [
            fundamentals['symbol'] for fundamentals in queried_fundamentals
        ]
        return queried_symbols

    # get_current_price:[String:String]
    # param symbol:String => String symbol of the instrument to return.
    # returns Float value of the current price of the stock with the given symbol.
    def get_current_price(self, symbol):
        return float(self.trader.quote_data(symbol)['last_trade_price'])

    # get_quote:[String:String]
    # param symbol:String => String symbol of the instrument to return.
    # returns Quote data for the instrument with the given symbol.
    def get_quote(self, symbol):
        return self.trader.quote_data(symbol)

    # get_quotes:[[String:String]]
    # param symbol:[String] => List of string symbols of the instrument to return.
    # returns Quote data for the instruments with the given symbols.
    def get_quotes(self, symbols):
        return self.trader.quotes_data(symbols)

    # get_instrument:[String:String]
    # param symbol:String => String symbol of the instrument.
    # returns The instrument with the given symbol.
    def get_instrument(self, symbol):
        return self.trader.instruments(symbol)[0] or None

    # stock_from_instrument_url:Dict[String:String]
    # param url:String => URL of instrument.
    # returns Stock dictionary from the url of the instrument.
    def stock_from_instrument_url(self, url):
        return self.trader.stock_from_instrument_url(url)

    # get_history:[[String:String]]
    # param symbol:String => String symbol of the instrument.
    # param interval:Span => Time in between each value. (default: DAY)
    # param span:Span => Range for the data to be returned. (default: YEAR)
    # param bounds:Span => The bounds to be included. (default: REGULAR)
    # returns Historical quote data for the instruments with the given symbols on a 5-minute, weekly interval.
    def get_history(self,
                    symbol,
                    interval=Span.DAY,
                    span=Span.YEAR,
                    bounds=Bounds.REGULAR):
        return self.trader.get_historical_quotes(symbol, interval.value,
                                                 span.value, bounds.value)

    # get_news:[[String:String]]
    # param symbol:String => String symbol of the instrument.
    # returns News for the instrument with the given symbol.
    def get_news(self, symbol):
        return self.trader.get_news(symbol)

    # get_fundamentals:Dict[String:String]
    # param symbol:String => String symbol of the instrument.
    # returns Fundamentals for the instrument with the given symbol.
    def get_fundamentals(self, symbol):
        return self.trader.get_fundamentals(symbol)

    # get_fundamentals:[String:String]
    # param symbol:String => String symbol of the instrument.
    # param dates:Date => List of datetime.date objects.
    # param type:Option => Option.CALL or Option.PUT
    # returns Options for the given symbol within the listed dates for the given type.
    def get_options(self, symbol, dates, type):
        return self.trader.get_options(
            symbol, list(map(lambda date: date.isoFormat(), dates)),
            type.value)

    # get_market_data:[String:String]
    # param optionId:String => Option ID for the option to return.
    # returns Options for the given ID.
    def get_market_data(self, optionId):
        return self.trader.get_option_market_data(optionId)

    # get_by_tag:[String:String]
    # param tag:Tag => Type of tag to return the quotes by.
    # returns Quotes for the given tag.
    def get_by_tag(self, tag):
        return self.trader.get_tickers_by_tag(tag.value)

    # get_current_bid_price:Float
    # param symbol:String => String symbol of the quote.
    # returns The current bid price of the stock, as a float.
    def get_current_bid_price(self, symbol):
        return float(self.trader.get_quote(symbol)['bid_price']) or 0.0

    ##                ##
    #   User Methods   #
    ##                ##

    # user_portfolio:[String:String]
    # returns Portfolio model for the logged in user.
    def user_portfolio(self):
        quotes = []
        user_portfolio = self.user_stock_portfolio()
        for data in user_portfolio:
            symbol = data['symbol']
            count = float(data['quantity'])
            quotes.append(Quote(symbol, count))
        return Portfolio(self, quotes, 'User Portfolio')

    # user_stock_portfolio:[String:String]
    # TODO: Better documentation.
    # returns Stock perfolio for the user.
    def user_stock_portfolio(self):
        positions = self.trader.positions()['results'] or []
        return list(
            map(
                lambda position: Utility.merge_dicts(
                    position,
                    self.trader.session.get(position['instrument'], timeout=15)
                    .json()), positions))

    # user_portfolio:[String:String]
    # returns Positions for the logged in user.
    def user_positions(self):
        return self.trader.positions()

    # user_dividends:[String:String]
    # returns Dividends for the logged in user.
    def user_dividends(self):
        return self.trader.dividends()

    # user_securities:[String:String]
    # returns Securities for the logged in user.
    def user_securities(self):
        return self.trader.securities_owned()

    # user_equity:[String:String]
    # returns Equity for the logged in user.
    def user_equity(self):
        return self.trader.equity()

    # user_equity_prev:[String:String]
    # returns Equity upon the previous close for the logged in user.
    def user_equity_prev(self):
        return self.trader.equity_previous_close()

    # user_equity_adj_prev:[String:String]
    # returns Adjusted equity upon the previous close for the logged in user.
    def user_equity_adj_prev(self):
        return self.trader.adjusted_equity_previous_close()

    # user_equity_ext_hours:[String:String]
    # returns Extended hours equity for the logged in user.
    def user_equity_ext_hours(self):
        return self.trader.extended_hours_equity()

    # user_equity_last_core:[String:String]
    # returns Last core equity for the logged in user.
    def user_equity_last_core(self):
        return self.trader.last_core_equity()

    # user_excess_margin:[String:String]
    # returns Excess margin for the logged in user.
    def user_excess_margin(self):
        return self.trader.excess_margin()

    # user_market_value:[String:String]
    # returns Market value for the logged in user.
    def user_market_value(self):
        return self.trader.market_value()

    # user_market_value_ext_hours:[String:String]
    # returns Extended hours market value for the logged in user.
    def user_market_value_ext_hours(self):
        return self.trader.extended_hours_market_value()

    # user_market_value_last_core:[String:String]
    # returns Last core market value for the logged in user.
    def user_market_value_last_core(self):
        return self.trader.last_core_market_value()

    # user_order_history:[String:String]
    # param orderId:String => The order ID to return the order for.
    # returns A specified order executed by the logged in user.
    def user_order(self, orderId):
        return self.trader.order_history(orderId)

    # user_orders:[[String:String]]
    # returns The order history for the logged in user.
    def user_orders(self):
        return self.trader.order_history(None)

    # user_open_orders:[[String:String]]
    # returns The open orders for the user
    def user_open_orders(self):
        orders = self.trader.order_history(None)['results']
        open_orders = []
        for order in orders:
            if order['state'] == 'queued':
                open_orders.append(order)
        return open_orders

    # user_account:[[String:String]]
    # returns The user's account.
    def user_account(self):
        return self.trader.get_account()

    # user_buying_power:float
    # returns The user's buying power.
    def user_buying_power(self):
        return float(self.trader.get_account()['buying_power'] or 0.0)

    ##                     ##
    #   Execution Methods   #
    ##                     ##

    # exec_buy:[String:String]
    # param symbol:String => String symbol of the instrument.
    # param quantity:Number => Number of shares to execute buy for.
    # param stop:Number? => Sets a stop price on the buy, if not None.
    # param limit:Number? => Sets a limit price on the buy, if not None.
    # param time:GoodFor? => Defines the expiration for a limited buy.
    # returns The order response.
    def exec_buy(self, symbol, quantity, stop=None, limit=None, time=None):
        if time is None:
            time = GoodFor.GOOD_TIL_CANCELED
        if limit is not None:
            if stop is not None:
                return self.trader.place_stop_limit_buy_order(
                    None, symbol, time.value, stop, quantity)
            return self.trader.place_limit_buy_order(None, symbol, time.value,
                                                     limit, quantity)
        elif stop is not None:
            return self.trader.place_stop_loss_buy_order(
                None, symbol, time.value, stop, quantity)
        return self.trader.place_market_buy_order(None, symbol, time.value,
                                                  quantity)

    # exec_sell:[String:String]
    # param symbol:String => String symbol of the instrument.
    # param quantity:Number => Number of shares to execute sell for.
    # param stop:Number? => Sets a stop price on the sell, if not None.
    # param limit:Number? => Sets a limit price on the sell, if not None.
    # param time:GoodFor? => Defines the expiration for a limited buy.
    # returns The order response.
    def exec_sell(self, symbol, quantity, stop=None, limit=None, time=None):
        if time is None:
            time = GoodFor.GOOD_TIL_CANCELED
        if limit is not None:
            if stop is not None:
                return self.trader.place_stop_limit_sell_order(
                    None, symbol, time.value, stop, quantity)
            return self.trader.place_limit_sell_order(None, symbol, time.value,
                                                      limit, quantity)
        elif stop is not None:
            return self.trader.place_stop_loss_sell_order(
                None, symbol, time.value, stop, quantity)
        return self.trader.place_market_sell_order(None, symbol, time.value,
                                                   quantity)

    # exec_cancel:[String:String]
    # param order_id:String => ID of the order to cancel.
    # returns The canceled order response.
    def exec_cancel(self, order_id):
        return self.trader.cancel_order(order_id)

    # exec_cancel_open_orders:[String]
    # returns A list of string IDs for the cancelled orders.
    def exec_cancel_open_orders(self):
        orders = self.trader.order_history(None)['results']
        cancelled_order_ids = []
        for order in orders:
            if order['state'] == 'queued':
                self.trader.cancel_order(order['id'])
                cancelled_order_ids.append(order['id'])
        return cancelled_order_ids
Esempio n. 11
0
trader = Robinhood()
logged_in = trader.login(username=USERNAME, password=getpass.getpass())

stock_instrument = None
while True:
    quote_info = trader.quote_data(STOCK_NAME)
    stock_instrument = trader.instruments(STOCK_NAME)[0]
    print("################################")
    print("Time:        {}".format(time.ctime()))
    print("################################")
    print("Name:        {}".format(stock_instrument['name']))
    print("Symbol:      {}".format(STOCK_NAME))
    print("Price:       ${}".format(quote_info['last_trade_price']))
    instrument_url = stock_instrument['url']
    owned = trader.securities_owned()['results']
    print("################################")
    for sec in owned:
        if sec['instrument'] == instrument_url:
            price = sec['average_buy_price']
            quantity = sec['quantity']
            print("Ave. Price:  ${}".format(price))
            print("Shares:      {}".format(quantity))
            print("Total Value: ${}".format(
                round(float(price) * float(quantity)), 2))
    print("################################\n")


def sellIf(instrument, current_price, sell_price, quantity):
    if current_price >= sell_price:
        return trader.place_sell_order(instrument, quantity)
Esempio n. 12
0
class RobinhoodAccount:
    def __init__(self, username: str, password: str):
        self.username = username
        self.password = password
        self.robinhood = Robinhood()
        self.loggedin = False

    def __enter__(self):
        if self.loggedin:
            self.logout()
        self.login()

    def __exit__(self, *args):
        self.logout()

    def login(self):
        self.loggedin = self.robinhood.login(self.username, self.password)
        return self.loggedin

    def logout(self):
        self.robinhood.logout()

    def get_positions(self):
        positions = {}
        for pos in self.robinhood.securities_owned()['results']:
            symbol = RobinhoodUtility.instrument_2_symbol(pos['instrument'])
            pos['symbol'] = symbol
            positions[symbol] = pos
        return positions

    def get_open_orders(self, symbol: str) -> []:
        open_orders = []
        for order in self.robinhood.order_history()['results']:
            if RobinhoodUtility.is_order_open(order):
                if symbol == RobinhoodUtility.instrument_2_symbol(
                        order['instrument']):
                    open_orders.append(order)
        return open_orders

    def cancel_all_orders(self, symbol: str):
        for order in self.get_open_orders(symbol):
            self.cancel_order(order)

    def cancel_order(self, order):
        res = self.robinhood.session.post(
            'https://api.robinhood.com/orders/%s/cancel/' % order['id'])
        res.raise_for_status()

    def place_limit_sell_order(self,
                               position,
                               limit_price: float,
                               time_in_force: str = 'GFD',
                               shares: int = None):
        self.robinhood.place_limit_sell_order(
            instrument_URL=position['instrument'],
            symbol=position['symbol'],
            time_in_force=time_in_force,
            price=limit_price,
            quantity=shares or int(float(position['quantity'])))

    def place_stop_limit_sell_order(self,
                                    position,
                                    limit_price: float,
                                    stop_price: float = None,
                                    time_in_force: str = 'GFD',
                                    shares: int = None):
        self.robinhood.place_stop_limit_sell_order(
            instrument_URL=position['instrument'],
            symbol=position['symbol'],
            time_in_force=time_in_force,
            price=limit_price,
            stop_price=stop_price or limit_price,
            quantity=shares or int(float(position['quantity'])))
Esempio n. 13
0
class RobinhoodShell(cmd.Cmd):
    intro = 'Welcome to the Robinhood shell. Type help or ? to list commands.\n'
    prompt = '> '

    # API Object
    trader = None

    # Cache file used to store instrument cache
    instruments_cache_file = 'instruments.data'

    # Maps Symbol to Instrument URL
    instruments_cache = {}

    # Maps URL to Symbol
    instruments_reverse_cache = {}

    # Cache file used to store instrument cache
    watchlist_file = 'watchlist.data'

    # List of stocks in watchlist
    watchlist = []

    def __init__(self):
        cmd.Cmd.__init__(self)
        self.trader = Robinhood()
        self.trader.login(username=USERNAME, password=PASSWORD)

        try:
            data = open(self.instruments_cache_file).read()
            self.instruments_cache = json.loads(data)
            for k in self.instruments_cache:
                self.instruments_reverse_cache[self.instruments_cache[k]] = k
        except:
            pass

        try:
            data = open(self.watchlist_file).read()
            self.watchlist = json.loads(data)
        except:
            pass

    # ----- basic commands -----
    def do_l(self, arg):
        'Lists current portfolio'
        portfolio = self.trader.portfolios()
        print 'Equity Value:', portfolio['equity']

        account_details = self.trader.get_account()
        if 'margin_balances' in account_details:
            print 'Buying Power:', account_details['margin_balances']['unallocated_margin_cash']

        positions = self.trader.securities_owned()

        symbols = []
        buy_price_data = {}
        for position in positions['results']:
            symbol = self.get_symbol(position['instrument'])
            buy_price_data[symbol] = position['average_buy_price']
            symbols.append(symbol)

        quotes_data = {}
        if len(symbols) > 0:
            raw_data = self.trader.quotes_data(symbols)
            for quote in raw_data:
                quotes_data[quote['symbol']] = quote['last_trade_price']

        table = BeautifulTable()
        table.column_headers = ["symbol", "current price", "quantity", "total equity", "cost basis", "p/l"]

        for position in positions['results']:
            quantity = int(float(position['quantity']))
            symbol = self.get_symbol(position['instrument'])
            price = quotes_data[symbol]
            total_equity = float(price) * quantity
            buy_price = float(buy_price_data[symbol])
            p_l = total_equity - buy_price * quantity
            table.append_row([symbol, price, quantity, total_equity, buy_price, p_l])

        print(table)

    def do_w(self, arg):
        'Show watchlist w \nAdd to watchlist w a <symbol> \nRemove from watchlist w r <symbol>'
        parts = arg.split()
        if len(parts) == 2:
            if parts[0] == 'a':
                self.watchlist.append(parts[1].strip())
            if parts[0] == 'r':
                self.watchlist = [r for r in self.watchlist if not r == parts[1].strip()]
            print "Done"
        else:
            table = BeautifulTable()
            table.column_headers = ["symbol", "current price"]

            if len(self.watchlist) > 0:
                raw_data = self.trader.quotes_data(self.watchlist)
                quotes_data = {}
                for quote in raw_data:
                    table.append_row([quote['symbol'], quote['last_trade_price']])
                print(table)
            else:
                print "Watchlist empty!"

    def do_b(self, arg):
        'Buy stock b <symbol> <quantity> <price>'
        parts = arg.split()
        if len(parts) >= 2 and len(parts) <= 3:
            symbol = parts[0]
            quantity = parts[1]
            if len(parts) == 3:
                price = float(parts[2])
            else:
                price = 0.0

            stock_instrument = self.trader.instruments(symbol)[0]
            res = self.trader.place_buy_order(stock_instrument, quantity, price)

            if not (res.status_code == 200 or res.status_code == 201):
                print "Error executing order"
                try:
                    data = res.json()
                    if 'detail' in data:
                        print data['detail']
                except:
                    pass
            else:
                print "Done"
        else:
            print "Bad Order"

    def do_s(self, arg):
        'Sell stock s <symbol> <quantity> <?price>'
        parts = arg.split()
        if len(parts) >= 2 and len(parts) <= 3:
            symbol = parts[0]
            quantity = parts[1]
            if len(parts) == 3:
                price = float(parts[2])
            else:
                price = 0.0

            stock_instrument = self.trader.instruments(symbol)[0]
            res = self.trader.place_sell_order(stock_instrument, quantity, price)

            if not (res.status_code == 200 or res.status_code == 201):
                print "Error executing order"
                try:
                    data = res.json()
                    if 'detail' in data:
                        print data['detail']
                except:
                    pass
            else:
                print "Done"
        else:
            print "Bad Order"

    def do_sl(self, arg):
        'Setup stop loss on stock sl <symbol> <quantity> <price>'
        parts = arg.split()
        if len(parts) == 3:
            symbol = parts[0]
            quantity = parts[1]
            price = float(parts[2])

            stock_instrument = self.trader.instruments(symbol)[0]
            res = self.trader.place_stop_loss_order(stock_instrument, quantity, price)

            if not (res.status_code == 200 or res.status_code == 201):
                print "Error executing order"
                try:
                    data = res.json()
                    if 'detail' in data:
                        print data['detail']
                except:
                    pass
            else:
                print "Done"
        else:
            print "Bad Order"

    def do_o(self, arg):
        'List open orders'
        open_orders = self.trader.get_open_orders()
        if open_orders:
            table = BeautifulTable()
            table.column_headers = ["index", "symbol", "price", "quantity", "type", "id"]

            index = 1
            for order in open_orders:
                table.append_row([
                    index,
                    self.get_symbol(order['instrument']),
                    order['price'],
                    int(float(order['quantity'])),
                    order['side'],
                    order['id'],
                ])
                index += 1

            print(table)
        else:
            print "No Open Orders"

    def do_c(self, arg):
        'Cancel open order c <index> or c <id>'
        order_id = arg.strip()
        order_index = -1
        try:
            order_index = int(order_id)
        except:
            pass

        if order_index > 0:
            order_index = order_index - 1
            open_orders = self.trader.get_open_orders()
            if order_index < len(open_orders):
                order_id = open_orders[order_index]['id']
            else:
                print "Bad index"
                return

        try:
            self.trader.cancel_order(order_id)
            print "Done"
        except Exception as e:
            print "Error executing cancel"
            print e

    def do_ca(self, arg):
        'Cancel all open orders'
        open_orders = self.trader.get_open_orders()
        for order in open_orders:
            try:
                self.trader.cancel_order(order['id'])
            except Exception as e:
                pass
        print "Done"

    def do_q(self, arg):
        'Get quote for stock q <symbol>'
        symbol = arg.strip()
        try:
            self.trader.print_quote(symbol)
        except:
            print "Error getting quote for:", symbol

    def do_bye(self, arg):
        open(self.instruments_cache_file, 'w').write(json.dumps(self.instruments_cache))
        open(self.watchlist_file, 'w').write(json.dumps(self.watchlist))
        return True

    # ------ utils --------
    def get_symbol(self, url):
        if not url in self.instruments_reverse_cache:
            self.add_instrument_from_url(url)

        return self.instruments_reverse_cache[url]

    def add_instrument_from_url(self, url):
        data = self.trader.get_url(url)
        symbol = data['symbol']
        self.instruments_cache[symbol] = url
        self.instruments_reverse_cache[url] = symbol
Esempio n. 14
0
class PortfolioMgr:
    def __init__(self,
                 robin_un=None,
                 robin_pd=None,
                 name=None,
                 load_from=None):
        """
        Manager for multiple portfolios in the same account

        robin_un (str): username of robinhood account
        robin_pd (str): password of robinhood account
        name (str): name of the manager
        load_from (str): path to the saving file
        """
        assert robin_un is not None
        assert robin_pd is not None
        assert name is not None
        self.trader = Robinhood()
        self.trader.login(robin_un, robin_pd)
        self.name = name
        self.converter = SIconverter(trader=self.trader)
        self.unassigned_bp = float(self.trader.get_account()['margin_balances']
                                   ['unallocated_margin_cash'])
        self.unassigned_shares = {
            self.converter(d['instrument']): int(float(d['quantity']))
            for d in self.trader.securities_owned()['results']
        }
        self.portfolios = {}
        self.regisiter = {}
        self.working_now = True
        self.working_cv = Condition()

        self.check_work_v = True
        self.check_work_cv = Condition()

        self.threads = []
        self.log = []

    def add_portfolio(self,
                      name=None,
                      ini_bp=0,
                      load=None,
                      cancel_count=np.inf):
        """
        create a portfolio with the manager

        name (str): name of the portfolio
        ini_bp (float): initial buying power for this portfolio
        load (str): path to the saving file of this portfolio
        cancel_count (int|np.inf) used for specific trading algorithm, 
            order will be canceled if it can not be executed for cancel_count times
        """
        assert name is not None
        assert ini_bp < self.unassigned_bp
        self.portfolios[name] = Portfolio(trader=self.trader,
                                          name=name,
                                          iniFund=ini_bp,
                                          cancel_count=cancel_count,
                                          converter=self.converter)
        self.unassigned_bp -= ini_bp

    def update_allocatable_buying_power(self):
        """
        update the unassigned_bp variable. should never be used unless the user transfers money between bank and robinhood account.
        """
        allocated = 0
        for k, p in self.portfolios.items():
            allocated += p.bp
        self.unassigned_bp = self.get_bp_owned() - allocated

    def update_allocatable_shares(self):
        """
        update the unassigned_shares variable. should never be used unless the user sell/buy shares without using this mgr
        """
        owned_shares = self.get_securities_owned()
        for k, p in self.portfolios.items():
            p.portfolio_record_lock.acquire()
            for scode in p.portfolio_record.index:
                try:
                    owned_shares[scode] -= p.portfolio_record.loc[scode][
                        "SHARES"]
                except:
                    pass
            p.portfolio_record_lock.release()
        self.unassigned_shares = owned_shares

    def get_securities_owned(self):
        """
        get shares owned by the user
        """
        return {
            self.converter(d['instrument']): int(float(d['quantity']))
            for d in self.trader.securities_owned()['results']
        }

    def get_bp_owned(self):
        """
        get buying power owned by the user
        """
        return float(self.trader.get_account()['margin_balances']
                     ['unallocated_margin_cash'])

    def add_bp_to(self, name, amount):
        """
        add buying power from mgr to portfolio

        name (str): the name of the portfolio
        amount (float): money in USD to be added
        """
        assert name in self.portfolios
        self.update_allocatable_buying_power()
        assert self.unassigned_bp > amount
        self.portfolios[name].bp += amount
        self.unassigned_bp -= amount
        self.portfolios[name].add_trading_record("None", "None", amount, 1,
                                                 "add bp")

    def add_shares_to(self, name, scode, amount):
        """
        add shares from mgr to portfolio

        name (str): the name op the portfolio
        scode (str): symbol of the stock
        amount (int): number of shares
        """
        assert name in self.portfolios
        self.update_allocatable_shares()
        amount = int(amount)
        assert self.unassigned_shares[scode] >= amount
        self.portfolios[name].add_shares_from_pool(scode=scode, n=amount)
        self.unassigned_shares[scode] -= amount
        self.portfolios[name].add_trading_record("None", scode, "None", amount,
                                                 "add share")

    def add_multi_shares_to(self, name, **sa):
        for s, a in sa.items():
            self.add_shares_to(name, s, a)

    def draw_bp_from(self, name, amount):
        """
        draw bp from a portfolio to mgr

        name (str): name of the portfolio
        amount (float): money in USD to be draw
        """
        assert name in self.portfolios
        assert self.portfolios[name].bp >= amount
        self.portfolios[name].bp -= amount
        self.unassigned_bp += amount
        self.portfolios[name].add_trading_record("None", "None", amount, 1,
                                                 "draw bp")

    def draw_shares_from(self, name, scode, amount):
        """
        draw shares from a portfolio to mgr

        name (str): name of the portfolio
        scode (str): symbol of the stock
        amount (int): number of shares
        """
        assert name in self.portfolios
        amount = int(amount)
        assert self.portfolios[name].shares_owned(scode) >= amount
        self.portfolios[name].portfolio_record_lock.acquire()
        self.portfolios[name].portfolio_record.loc[scode]["SHARES"] -= amount
        if self.portfolios[name].portfolio_record.loc[scode]["SHARES"] == 0:
            self.portfolios[name].portfolio_record = self.portfolios[
                name].portfolio_record.drop(scode)
        self.portfolios[name].portfolio_record_lock.release()
        self.unassigned_shares[scode] += amount
        self.portfolios[name].add_trading_record("None", scode, "None", amount,
                                                 "draw share")

    def transfer_bp(self, from_name, to_name, amount):
        """
        transfer buying power between two portfolios
        
        from_name (str): name of the portfolio to send the buying power
        to_name (str): name of the portfolio to receive the buying power
        """
        assert from_name in self.portfolios
        assert to_name in self.portfolios
        self.portfolios[from_name].transfer_buying_power(
            self.portfolios[to_name], amount)

    def transfer_shares(self, from_name, to_name, scode, amount):
        """
        transfer shares between two portfolios
        
        from_name (str): name of the portfolio to send shares
        to_name (str): name of the portfolio to receive shares
        """
        assert from_name in self.portfolios
        assert to_name in self.portfolios
        self.portfolios[from_name].transfer_shares(self.portfolios[to_name],
                                                   scode, amount)

    def schedule(self,
                 algo=None,
                 method=None,
                 portfolio_name=None,
                 freq=None,
                 misc=None):
        """
        schedule an algorithm with this portfolio
        """
        assert portfolio_name not in self.regisiter
        assert algo is not None
        assert method is not None
        assert freq is not None
        p = self.portfolios[portfolio_name]
        if "cancel_count" in misc:
            p.cancel_count = misc["cancel_count"]

        def worker():
            p.confirm_order(loop=True)
            while self.working_now:
                try:
                    algo.__getattribute__(method)(self,
                                                  pname=portfolio_name,
                                                  args={
                                                      "call_from_mgr": True
                                                  },
                                                  misc=misc)
                except AssertionError:
                    p.unlock_all()
                    p.log_lock.acquire()
                    p.log.append("{}: Error Operation During Trading".format(
                        Portfolio.get_time()))
                    p.log_lock.release()
                self.working_cv.acquire()
                self.working_cv.wait(freq * 60)
                self.working_cv.release()
            p.log_lock.acquire()
            p.log.append("{}: {} worker stopped".format(
                Portfolio.get_time(), method))
            p.log_lock.release()
            p.unlock_all()
            p.stop_confirm()
            p.cancel_all_orders_in_queue()
            self.regisiter[portfolio_name][0] = 'STOPED'

        self.regisiter[portfolio_name] = ["PENDING", worker]
        if self.working_now:
            self.regisiter[portfolio_name] = ["STARTED", worker]
            t = Thread(target=worker)
            self.threads.append(t)
            t.start()
            p.log_lock.acquire()
            p.log.append("{}: {} worker started".format(
                Portfolio.get_time(), method))
            p.log_lock.release()

    def cnow(self):
        """
        begin to check the market hour, once every 900 secs 
        """
        def worker():
            while self.check_work_v:
                check_work()
                self.check_work_cv.acquire()
                self.log.append("{}: check work cv waiting now".format(
                    Portfolio.get_time()))
                self.check_work_cv.wait(900)
                self.log.append("{}: check work cv escaped")
                self.check_work_cv.release()

    def dnow(self):
        """
        stop checking the market hour
        """
        self.check_work_v = False
        self.log.append("{}: try down".format(Portfolio.get_time()))
        self.check_work_cv.acquire()
        self.check_work_cv.notify()
        self.check_work_cv.release()
        self.log.append("{}: down scuu".format(Portfolio.get_time()))

    def check_work(self):
        """
        check the market hour, is market is open, all panding or stoped algorithm will start
        """
        if not len(self.portfolios):
            self.working_now = False
            self.working_cv.acquire()
            self.working_cv.notifyAll()
            self.working_cv.release()
        if list(self.portfolios.values())[0].is_market_open():
            self.working_now = True
            for key in self.regisiter:
                s, w = self.regisiter[key]
                if s != 'STARTED':
                    t = Thread(target=w)
                    self.threads.append(t)
                    t.start()
                    self.regisiter[key][0] = 'STARTED'
        else:
            self.working_now = False
            self.working_cv.acquire()
            self.working_cv.notifyAll()
            self.working_cv.release()

    def quit(self):
        """
        quit this s**t
        """
        self.working_now = False
        self.check_work_v = False
        self.check_work_cv.acquire()
        self.check_work_cv.notify()
        self.check_work_cv.release()
        self.working_cv.acquire()
        self.working_cv.notify()
        self.working_cv.release()
        while len(self.threads):
            self.threads.pop().join()
        for p in list(self.portfolios.values()):
            p.quit()

    def save(self, sav=None):
        """
        save
        """
        if sav is None:
            sav = self.name
        sav = sav + '/'
        for k, p in self.portfolios.items():
            p.save(root_name=sav)

    def load(self, sav=None):
        """
        load
        """
        if sav is None:
            sav = self.name
        sav = sav + '/'
        for k, p in self.portfolios.items():
            p.load(root_name=sav)