示例#1
0
    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.get(urls.build_orders(orderId))
示例#2
0
    def submit_sell_order(  # noqa: C901
        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 (:obj:`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)
        if (current_quote["bid_price"] == 0) or (current_quote["bid_price"] is None):
            current_bid_price = current_quote["last_trade_price"]
        else:
            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_sell_order"
                    )
                )
            raise (ValueError("Instrument_URL not passed to submit_sell_order"))

        if symbol is None:
            raise (ValueError("Symbol not passed to submit_sell_order"))

        if side is None:
            raise (
                ValueError("Order is neither buy nor sell in call to submit_sell_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_sell_order"))

        if order_type == "limit":
            if price is None:
                raise (
                    ValueError("Limit order has no price in call to submit_sell_order")
                )
            if price <= 0:
                raise (
                    ValueError(
                        "Price must be positive number in call to submit_sell_order"
                    )
                )

        if trigger == "stop":
            if stop_price is None:
                raise (
                    ValueError(
                        "Stop order has no stop_price in call to submit_sell_order"
                    )
                )
            if price <= 0:
                raise (
                    ValueError(
                        "Stop_price must be positive number in call to "
                        "submit_sell_order"
                    )
                )

        if stop_price is not None:
            if trigger != "stop":
                raise (
                    ValueError(
                        "Stop price set for non-stop order in call to submit_sell_order"
                    )
                )

        if price is None:
            if order_type == "limit":
                raise (
                    ValueError("Limit order has no price in call to submit_sell_order")
                )

        if price is not None:
            if order_type.lower() == "market":
                raise (
                    ValueError(
                        "Market order has price limit in call to submit_sell_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_sell_order"))

        quantity = int(quantity)

        if quantity <= 0:
            raise (
                ValueError(
                    "Quantity must be positive number in call to submit_sell_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

        try:
            res = self.post(urls.build_orders(), data=payload)
            return res
        except Exception as ex:
            # sometimes Robinhood asks for another log in when placing an order
            # TODO: fix bare except
            try:
                self.auth_method
            except:  # noqa: E722
                print(ex)
示例#3
0
    def cancel_order(self, order_id):  # noqa: C901
        """Cancels specified order and returns the response.

        If order cannot be cancelled, `None` is returned.
        (results from `orders` command).

        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.get(urls.build_orders() + order_id)
            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.post(order["cancel"])
                    return res
                except requests.exceptions.HTTPError:
                    try:
                        # sometimes Robinhood asks for another log in when placing an
                        # order
                        res = self.post(order["cancel"])
                        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 isinstance(order_id, dict):
            order_id = order_id["id"]
            try:
                order = self.get(urls.build_orders() + order_id)
            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.post(order["cancel"])
                    return res
                except requests.exceptions.HTTPError:
                    try:
                        # sometimes Robinhood asks for another log in when placing an
                        # order
                        res = self.post(order["cancel"])
                        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)
示例#4
0
    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

        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 (:obj:`Transaction`): BUY or SELL enum
            trigger (:obj:`Trigger`): IMMEDIATE or STOP enum
            order (:obj:`Order`): MARKET or LIMIT
            time_in_force (:obj:`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"]

            if (price == 0) or (price is None):
                price = self.quote_data(instrument["symbol"])["last_trade_price"]

        payload = {
            "account": self.get_account()["url"],
            "instrument": unquote(instrument["url"]),
            "symbol": instrument["symbol"],
            "type": order.lower(),
            "time_in_force": time_in_force.lower(),
            "trigger": trigger,
            "quantity": quantity,
            "side": transaction.name.lower(),
        }

        if order.lower() == "stop":
            payload["stop_price"] = float(price)
        else:
            payload["price"] = float(price)

        try:
            res = self.post(urls.build_orders(), data=payload)
            return res

        except Exception as ex:
            # sometimes Robinhood asks for another log in when placing an order
            # TODO: fix bare except
            try:
                self.auth_method
            except:  # noqa: E722
                print(ex)