Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] Dollar-Based Buy Orders Incorrectly Set to Limit Order During Regular Market Hours #485

Open
hassan12-code opened this issue Jul 24, 2024 · 6 comments

Comments

@hassan12-code
Copy link

When attempting to place a dollar-based buy order during regular market hours using the order_buy_fractional_by_price function, the order is incorrectly set as a limit order due to the preset_percent_limit parameter being added along with the type being set as limit. This behavior contradicts the expected functionality where dollar-based buy orders should be executed as market orders.

Steps to Reproduce:

Use the order_buy_fractional_by_price function to place a dollar-based buy order during regular market hours.
Observe that the order is submitted as a limit order instead of a market order.

Expected Behavior:

Dollar-based buy orders should be executed as market orders when placed during regular market hours.

Actual Behavior:

Dollar-based buy orders are converted to limit orders during regular market hours due to the preset_percent_limit parameter and type being set as limit.

Relevant Code:

The issue lies in the order function:

if market_hours == 'regular_hours':
    if side == "buy":
        payload['preset_percent_limit'] = "0.05"
        payload['type'] = 'limit'

Suggested Fix:

Remove or conditionally set the preset_percent_limit and type to ensure dollar-based buy orders are processed as market orders:

if market_hours == 'regular_hours':
    if side == "buy":
        payload['type'] = 'market'
@BigFav
Copy link

BigFav commented Jul 29, 2024

Have you tried removing that code locally in your package manager?

The Robinhood API just broke when I tried, so I ended up adding it back.

@hassan12-code
Copy link
Author

Have you tried removing that code locally in your package manager?

The Robinhood API just broke when I tried, so I ended up adding it back.

Yes, I tried modifying or even removing that code, but similar to your experience, I encountered an error, and the API broke for me as well.

@khulaid22
Copy link

I thought I was doing something wrong but turns out that this is a bug. It seems an important matter that requires quick fixing.

@BigFav
Copy link

BigFav commented Jul 29, 2024

Have you tried removing that code locally in your package manager?
The Robinhood API just broke when I tried, so I ended up adding it back.

Yes, I tried modifying or even removing that code, but similar to your experience, I encountered an error, and the API broke for me as well.

Yeah, then your suggested fix seems to not work. There might be something going on with Robinhood here.

@hassan12-code
Copy link
Author

Have you tried removing that code locally in your package manager?
The Robinhood API just broke when I tried, so I ended up adding it back.

Yes, I tried modifying or even removing that code, but similar to your experience, I encountered an error, and the API broke for me as well.

Yeah, then your suggested fix seems to not work. There might be something going on with Robinhood here.

I totally agree, and apologies that I didn't mention that the proposed solution was giving errors. I just thought this might be a potential fix along with some other adjustments to address the error response from Robinhood.

@hassan12-code
Copy link
Author

UPDATE (FIX):

I made the following changes to ensure that dollar-based buy orders are correctly processed as market orders during regular market hours:

1. New Parameters:

  • Added isFractional and priceInDollars to handle fractional and dollar-based orders.
def order(symbol, quantity, side, limitPrice=None, stopPrice=None, account_number=None, timeInForce='gtc', extendedHours=False, jsonify=True, market_hours='regular_hours', isFractional=False, priceInDollars = None):

2. Modified Payload for Buy Orders:

  • For dollar-based buy orders during regular hours (if market_hours == 'regular_hours'):
if side == "buy":
    payload['dollar_based_amount'] = {
        'amount': str(priceInDollars),
        'currency_code': 'USD'
    }
    del payload['price']
    del payload['quantity']
    del payload['extended_hours']

3. Cleanup for Market Orders:

  • Removed stop_price when orderType == 'market' to prevent conflicts:
del payload['stop_price']

4. Set json=True in POST call:

data = request_post(url, payload, json=True)

- Completed Order Function:

@login_required
def order(symbol, quantity, side, limitPrice=None, stopPrice=None, account_number=None, timeInForce='gtc', extendedHours=False, jsonify=True, market_hours='regular_hours', isFractional=False, priceInDollars = None):
    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))


    from datetime import datetime
    payload = {
        'account': load_account_profile(account_number=account_number, info='url'),
        'instrument': get_instruments_by_symbols(symbol, info='url')[0],
        'symbol': symbol,
        'price': price,
        'ask_price': str(round_price(next(iter(get_latest_price(symbol, "ask_price", extendedHours)), 0.00))),
        'bid_ask_timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f'),
        'bid_price': str(round_price(next(iter(get_latest_price(symbol, "bid_price", extendedHours)), 0.00))),
        'quantity': quantity,
        'ref_id': str(uuid4()),
        'type': orderType,
        'stop_price': stopPrice,
        'time_in_force': timeInForce,
        'trigger': trigger,
        'side': side,
        'market_hours': market_hours, # choices are ['regular_hours', 'all_day_hours']
        'extended_hours': extendedHours,
        'order_form_version': 4
    }

    # adjust market orders
    if orderType == 'market':
        del payload['stop_price']

    if market_hours == 'regular_hours':
        if side == "buy":
            payload['dollar_based_amount'] = {
                'amount': str(priceInDollars),
                'currency_code': 'USD'
            }
            del payload['price']
            del payload['quantity']
            del payload['extended_hours']
        # regular market sell
        elif orderType == 'market' and side == 'sell':
            del payload['price']
    elif market_hours == 'all_day_hours':
        payload['type'] = 'limit'
        payload['quantity']=int(payload['quantity']) # round to integer instead of fractional

    url = orders_url()
    data = request_post(url, payload, json=True)

    return(data)

- Order Buy Fractional By Price Function:

@login_required
def order_buy_fractional_by_price(symbol, amountInDollars, account_number=None, timeInForce='gfd', extendedHours=False, jsonify=True, market_hours='regular_hours'):
    if amountInDollars < 1:
        print("ERROR: Fractional share price should meet minimum 1.00.", file=get_output())
        return None

    # turn the money amount into decimal number of shares
    price = next(iter(get_latest_price(symbol, 'ask_price', extendedHours)), 0.00)
    fractional_shares = 0 if (price == 0.00) else round_price(amountInDollars/float(price))

    return order(symbol, fractional_shares, "buy", None, None, account_number, timeInForce, extendedHours, jsonify, market_hours, priceInDollars=amountInDollars)

Please note, these changes were a quick fix given my scenario; the code might be optimized further.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants