jmfernandes / robin_stocks

This is a library to use with Robinhood Financial App. It currently supports trading crypto-currencies, options, and stocks. In addition, it can be used to get real time ticker information, assess the performance of your portfolio, and can also get tax documents, total dividends paid, and more. More info at
http://www.robin-stocks.com
MIT License
1.69k stars 459 forks source link

Trading Error for "order_buy_market" and "order_sell_market" #401

Open cpasean opened 1 year ago

cpasean commented 1 year ago

Encountered error messages since 2 weeks ago: (robin-stocks ver: 3.0.4)

rs.order_buy_market('AAPL', 1) Error in request_post: Expecting value: line 1 column 1 (char 0)

rs.order_sell_market('AAPL', 1) {'non_field_errors': ['Your app version is missing important stock trading updates. You can still place orders on the web.']}

I will be grateful to have your advice ASAP, please help.

meldinman commented 1 year ago

getting the same error this morning...

SingularityMan commented 1 year ago

This is directly related to the orders.order() method. I am still figuring it out on my end but every method that includes placing orders always calls orders.order, which as of robin_stocks 3.0.4 includes a modified payload.

The problem lies in the payload itself, but I am still figuring out how to modify the payload to provide the correct set of parameters.

This is the method underlying all the other order methods:

@login_required
def order(symbol, quantity, side, limitPrice=None, stopPrice=None, account_number=None, timeInForce='gtc', extendedHours=False, jsonify=True):
    """A generic order function.

    :param symbol: The stock ticker of the stock to sell.
    :type symbol: str
    :param quantity: The number of stocks to sell.
    :type quantity: int
    :param side: Either 'buy' or 'sell'
    :type side: str
    :param limitPrice: The price to trigger the market order.
    :type limitPrice: float
    :param stopPrice: The price to trigger the limit or market order.
    :type stopPrice: float
    :param account_number: the robinhood account number.
    :type account_number: Optional[str]
    :param timeInForce: Changes how long the order will be in effect for. 'gtc' = good until cancelled. \
    'gfd' = good for the day.
    :type timeInForce: str
    :param extendedHours: Premium users only. Allows trading during extended hours. Should be true or false.
    :type extendedHours: Optional[str]
    :param jsonify: If set to False, function will return the request object which contains status code and headers.
    :type jsonify: Optional[str]
    :returns: Dictionary that contains information regarding the purchase or selling of stocks, \
    such as the order id, the state of order (queued, confired, filled, failed, canceled, etc.), \
    the price, and the quantity.

    """ 
    try:
        symbol = symbol.upper().strip()
    except AttributeError as message:
        print(message, file=get_output())
        return None

    orderType = "market"
    trigger = "immediate"

    if side == "buy":
        priceType = "ask_price"
    else:
        priceType = "bid_price"

    if limitPrice and stopPrice:
        price = round_price(limitPrice)
        stopPrice = round_price(stopPrice)
        orderType = "limit"
        trigger = "stop"
    elif limitPrice:
        price = round_price(limitPrice)
        orderType = "limit"
    elif stopPrice:
        stopPrice = round_price(stopPrice)
        if side == "buy":
            price = stopPrice
        else:
            price = None
        trigger = "stop"
    else:
        price = round_price(next(iter(get_latest_price(symbol, priceType, extendedHours)), 0.00))
    payload = {
        'account': load_account_profile(account_number=account_number, info='url'),
        'instrument': get_instruments_by_symbols(symbol, info='url')[0],
        'symbol': symbol,
        'price': price,
        'quantity': quantity,
        'ref_id': str(uuid4()),
        'type': orderType,
        'stop_price': stopPrice,
        'time_in_force': timeInForce,
        'trigger': trigger,
        'side': side,
        'extended_hours': extendedHours
    }
    # BEGIN PATCH FOR NEW ROBINHOOD BUY FORM (GuitarGuyChrisB 5/26/2023)
    if side == "buy":
        payload['order_form_version'] = "2"
        payload['preset_percent_limit'] = "0.05"
    # END PATCH FOR NEW ROBINHOOD BUY FORM (GuitarGuyChrisB 5/26/2023)

    url = orders_url()

    data = request_post(url, payload, jsonify_data=jsonify)

    return(data)

That's what I have so far but I am still working on fixing the payload.

meldinman commented 1 year ago

Hey, Check out the pull request and my post on this issue #379 discussion where this issue has been going on...

sanathnair09 commented 1 year ago

So today I received the same error when trying to do an order_buy_market. I added breakpoints and took a look at where the error was being raised from and these were my findings.

Error is raised from helper.py Line 353 (the except block)

def request_post(url, payload=None, timeout=16, json=False, jsonify_data=True):
    data = None
    res = None
    try:
        if json:
            update_session('Content-Type', 'application/json')
            res = SESSION.post(url, json=payload, timeout=timeout)
            update_session(
                'Content-Type', 'application/x-www-form-urlencoded; charset=utf-8')
        else:
            res = SESSION.post(url, data=payload, timeout=timeout)
        data = res.json()
    except Exception as message:
        print("Error in request_post: {0}".format(message), file=get_output())
    # Either return response <200,401,etc.> or the data that is returned from requests.
    if jsonify_data:
        return(data)
    else:
        return(res)

Essentially what is happening is that when an order_buy_market or sell is called the server responds with an HTTP 500 error. (making a speculation here but I'd assume this issue really occurs whenever the def order(symbol, quantity, side, limitPrice=None, stopPrice=None, account_number=None, timeInForce='gtc', extendedHours=False, jsonify=True) order method is called)

And then when the line data = res.json() is called, a JSONDecodeError is raised because the formatting of the 500 response doesn't seem to follow the guideline. (I'm not well versed in JSON standards but it seems the field doc was causing the issues.)

Screenshot 2023-06-22 at 8 47 19 AM

henryzhangpku commented 1 year ago

It adjusts the order payload params due to recent Robinhood API changes , and works for both market buy/sell stocks orders : Market Buy : image Market Sell : image

cpasean commented 1 year ago

Would you elaborate on how you cleared the error and made the order by sharing your code more in detail? Please...

henryzhangpku commented 1 year ago

Sure , here is my PR where you can see all my code fix : https://github.com/jmfernandes/robin_stocks/pull/403

RHS api is really all about REST. Open your chrome console , place a trade via web (100% working), and from console/Network you will see the POST request sent to RHS /orders url. Comparing the actual working POST request/payload to the code , you will see what params have been removed/added by RHS in their new API version/POST request. From that you get the answer to get it working .

Would you elaborate on how you cleared the error and made the order by sharing your code more in detail? Please...

cpasean commented 1 year ago

Sure , here is my PR where you can see all my code fix : #403

RHS api is really all about REST. Open your chrome console , place a trade via web (100% working), and from console/Network you will see the POST request sent to RHS /orders url. Comparing the actual working POST request/payload to the code , you will see what params have been removed/added by RHS in their new API version/POST request. From that you get the answer to get it working .

Would you elaborate on how you cleared the error and made the order by sharing your code more in detail? Please...

I really appreciate your tips. I got Buy Order fixed, but still struggling with Sell-order:

order_sell_market('BIIB', 1) {'non_field_errors': ['Invalid Good Til Canceled order.']}

Would you help me with fixing this 'non field errors'?

henryzhangpku commented 1 year ago

My PR has both buy/sell working. Take a look at my PR.

H

Sure , here is my PR where you can see all my code fix : #403

RHS api is really all about REST. Open your chrome console , place a trade via web (100% working), and from console/Network you will see the POST request sent to RHS /orders url. Comparing the actual working POST request/payload to the code , you will see what params have been removed/added by RHS in their new API version/POST request. From that you get the answer to get it working .

Would you elaborate on how you cleared the error and made the order by sharing your code more in detail? Please...

I really appreciate your tips. I got Buy Order fixed, but still struggling with Sell-order:

order_sell_market('BIIB', 1)

{'non_field_errors': ['Invalid Good Til Canceled order.']}

Would you help me with fixing this 'non field errors'?

cpasean commented 1 year ago

My PR has both buy/sell working. Take a look at my PR.

H

Sure , here is my PR where you can see all my code fix : #403

RHS api is really all about REST. Open your chrome console , place a trade via web (100% working), and from console/Network you will see the POST request sent to RHS /orders url. Comparing the actual working POST request/payload to the code , you will see what params have been removed/added by RHS in their new API version/POST request. From that you get the answer to get it working .

Would you elaborate on how you cleared the error and made the order by sharing your code more in detail? Please...

I really appreciate your tips. I got Buy Order fixed, but still struggling with Sell-order:

order_sell_market('BIIB', 1)

{'non_field_errors': ['Invalid Good Til Canceled order.']} Would you help me with fixing this 'non field errors'?

I've finally fixed the issue with your help. I appreciate that!

paraluke23 commented 1 year ago

Will the PR 403 get merged soon? I cannot run it and am unable to follow the PR to change my code. Thanks.

emily111123 commented 1 year ago

@henryzhangpku

thanks for the scripts, this code in my computer: "url = orders_url() always shows: it's not defined",could you please help me with this ? thanks

Adelantado commented 1 year ago

robin-stocks 3.0.5 has been out for a few days. Hope it helps.

paraluke23 commented 1 year ago

No, 3.0.5 doesn't fix the issue: Error in request_post: Expecting value: line 1 column 1 (char 0)

henryzhangpku commented 1 year ago

@henryzhangpku

thanks for the scripts, this code in my computer: "url = orders_url() always shows: it's not defined",could you please help me with this ? thanks

Can you share more details of this error ? I can help you out.

doctorcolossus commented 10 months ago

@henryzhangpku, nice work, but you seem to have forgotten to update the docstring, which would keep people from having to come fish around here in the issues to find out how this works. Also, market_hours in snake-case seems inconsistent with the extendedHours argument in camel-case, but maybe it's too late to change now to avoid breaking peoples' code. Anyway, thanks for the fix!

henryzhangpku commented 10 months ago

Np. One thing you should note is this API changes (from RH side obviously) , so from time to time the parameters have to be updated . I had a few recent changes on my end as well , with that I have 24 hours market 100% working.

@henryzhangpku, nice work, but you seem to have forgotten to update the docstring, which would keep people from having to come fish around here in the issues to find out how this works. Also, market_hours in snake-case seems inconsistent with the extendedHours argument in camel-case, but maybe it's too late to change now to avoid breaking peoples' code. Anyway, thanks for the fix!