def cancel_order(self, order_id): """ Cancels specified order and returns the response (results from `orders` command). If order cannot be cancelled, `None` is returned. Args: order_id (str or dict): Order ID string that is to be cancelled or open order dict returned from order get. Returns: (:obj:`requests.request`): result from `orders` put command """ if isinstance(order_id, str): try: order = self.session.get(endpoints.orders() + order_id, timeout=15).json() except (requests.exceptions.HTTPError) as err_msg: raise ValueError('Failed to get Order for ID: ' + order_id + '\n Error message: ' + repr(err_msg)) if order.get('cancel') is not None: try: res = self.session.post(order['cancel'], timeout=15) res.raise_for_status() return res except (requests.exceptions.HTTPError) as err_msg: raise ValueError('Failed to cancel order ID: ' + order_id + '\n Error message: ' + repr(err_msg)) return None if isinstance(order_id, dict): order_id = order_id['id'] try: order = self.session.get(endpoints.orders() + order_id, timeout=15).json() except (requests.exceptions.HTTPError) as err_msg: raise ValueError('Failed to get Order for ID: ' + order_id + '\n Error message: ' + repr(err_msg)) if order.get('cancel') is not None: try: res = self.session.post(order['cancel'], timeout=15) res.raise_for_status() return res except (requests.exceptions.HTTPError) as err_msg: raise ValueError('Failed to cancel order ID: ' + order_id + '\n Error message: ' + repr(err_msg)) return None elif not isinstance(order_id, str) or not isinstance(order_id, dict): raise ValueError( 'Cancelling orders requires a valid order_id string or open order dictionary' ) # Order type cannot be cancelled without a valid cancel link else: raise ValueError('Unable to cancel order ID: ' + order_id)
def order_history(self, orderId=None): """Wrapper for portfolios Optional Args: add an order ID to retrieve information about a single order. Returns: (:obj:`dict`): JSON dict from getting orders """ return self.session.get(endpoints.orders(orderId), timeout=15).json()
def order_history(self): """Wrapper for portfolios Returns: (:obj:`dict`): JSON dict from getting orders """ return self.session.get(endpoints.orders(), timeout=15).json()
def place_order(self, instrument, quantity=1, price=0.0, transaction=None, trigger='immediate', order='market', time_in_force='gfd'): """Place an order with Robinhood Notes: OMFG TEST THIS PLEASE! Just realized this won't work since if type is LIMIT you need to use "price" and if a STOP you need to use "stop_price". Oops. Reference: https://github.com/sanko/Robinhood/blob/master/Order.md#place-an-order Args: instrument (dict): the RH URL and symbol in dict for the instrument to be traded quantity (int): quantity of stocks in order bid_price (float): price for order transaction (:enum:`Transaction`): BUY or SELL enum trigger (:enum:`Trigger`): IMMEDIATE or STOP enum order (:enum:`Order`): MARKET or LIMIT time_in_force (:enum:`TIME_IN_FORCE`): GFD or GTC (day or until cancelled) Returns: (:obj:`requests.request`): result from `orders` put command """ if isinstance(transaction, str): transaction = Transaction(transaction) if not price: price = self.quote_data(instrument['symbol'])['bid_price'] payload = { 'account': self.get_account()['url'], 'instrument': unquote(instrument['url']), 'quantity': quantity, 'side': transaction.name.lower(), 'symbol': instrument['symbol'], 'time_in_force': time_in_force.lower(), 'trigger': trigger, 'type': order.lower() } if order.lower() == "stop": payload['stop_price'] = float(price) else: payload['price'] = float(price) res = self.session.post(endpoints.orders(), data=payload, timeout=15) res.raise_for_status() return res
def submit_order(self, instrument_URL=None, symbol=None, order_type=None, time_in_force=None, trigger=None, price=None, stop_price=None, quantity=None, side=None): """Submits order to Robinhood Notes: This is normally not called directly. Most programs should use one of the following instead: place_market_buy_order() place_limit_buy_order() place_stop_loss_buy_order() place_stop_limit_buy_order() place_market_sell_order() place_limit_sell_order() place_stop_loss_sell_order() place_stop_limit_sell_order() Args: instrument_URL (str): the RH URL for the instrument symbol (str): the ticker symbol for the instrument order_type (str): 'MARKET' or 'LIMIT' time_in_force (:enum:`TIME_IN_FORCE`): GFD or GTC (day or until cancelled) trigger (str): IMMEDIATE or STOP enum price (float): The share price you'll accept stop_price (float): The price at which the order becomes a market or limit order quantity (int): The number of shares to buy/sell side (str): BUY or sell Returns: (:obj:`requests.request`): result from `orders` put command """ # Used for default price input # Price is required, so we use the current bid price if it is not specified current_quote = self.get_quote(symbol) current_bid_price = current_quote['bid_price'] # Start with some parameter checks. I'm paranoid about $. if (instrument_URL is None): if (symbol is None): raise (ValueError( 'Neither instrument_URL nor symbol were passed to submit_order' )) for result in self.instruments(symbol): if result['symbol'].upper() == symbol.upper(): instrument_URL = result['url'] break if (instrument_URL is None): raise (ValueError( 'instrument_URL could not be defined. Symbol %s not found' % symbol)) if (symbol is None): symbol = self.session.get(instrument_URL, timeout=15).json()['symbol'] if (side is None): raise (ValueError( 'Order is neither buy nor sell in call to submit_order')) if (order_type is None): if (price is None): if (stop_price is None): order_type = 'market' else: order_type = 'limit' symbol = str(symbol).upper() order_type = str(order_type).lower() time_in_force = str(time_in_force).lower() trigger = str(trigger).lower() side = str(side).lower() if (order_type != 'market') and (order_type != 'limit'): raise (ValueError('Invalid order_type in call to submit_order')) if (order_type == 'limit'): if (price is None): raise (ValueError( 'Limit order has no price in call to submit_order')) if (price <= 0): raise (ValueError( 'Price must be positive number in call to submit_order')) if (trigger == 'stop'): if (stop_price is None): raise (ValueError( 'Stop order has no stop_price in call to submit_order')) if (stop_price <= 0): raise (ValueError( 'Stop_price must be positive number in call to submit_order' )) if (stop_price is not None): if (trigger != 'stop'): raise (ValueError( 'Stop price set for non-stop order in call to submit_order' )) if (price is None): if (order_type == 'limit'): raise (ValueError( 'Limit order has no price in call to submit_order')) if (price is not None): if (order_type.lower() == 'market'): raise (ValueError( 'Market order has price limit in call to submit_order')) price = float(price) else: price = current_bid_price # default to current bid price if (quantity is None): raise (ValueError('No quantity specified in call to submit_order')) quantity = int(quantity) if (quantity <= 0): raise (ValueError( 'Quantity must be positive number in call to submit_order')) payload = {} for field, value in [('account', self.get_account()['url']), ('instrument', instrument_URL), ('symbol', symbol), ('type', order_type), ('time_in_force', time_in_force), ('trigger', trigger), ('price', price), ('stop_price', stop_price), ('quantity', quantity), ('side', side)]: if (value is not None): payload[field] = value print(payload) res = self.session.post(endpoints.orders(), data=payload, timeout=15) res.raise_for_status() return res