Bracket Order - Closing Positions

Will canceling a bracket order open position liquidate and close my bracket order position or will it just cancel the open position without liquidation?

For example, I have an open bracket order (buy) and it hasn’t hit the limit or stop price yet and I’d like to liquidate and sell the position. Will the ‘cancel_order’ function cancel the open order and/or liquidate and sell the long position? If it just cancels does this mean I’ll have to manually sell out of that position?

@suraj Canceling one leg of a bracket order will cancel the other leg too. It won’t liquidate anything. It simply deletes the order(s).

The best way to ‘sell out’ or close a position which has an outstanding bracket order is to replace the take profit limit price with a ‘marketable’ price. The take profit limit leg will then execute immediately and close the position. This is nice because it keeps all 3 orders intact.

Thank you Dan. Am I allowed to replace both the limit price and stop price in the same replace function? I tried replacing the limit price along with the stop price for my bracket order however it only allowed me to change limit price.

@suraj The replace_order endpoint requires an order number and only updates a single order at a time. The stop loss and take profit orders are two separate orders. Therefore you would need to update the stop price (for the stop loss order) and the limit price (for the take profit order) separately.

Thank you. I am using the order number (id number) when I query for the 2 open positions (limit price and stop price) and only ‘order type’ for ‘limit price’ is appearing. I am able to replace that leg however I am unable to find the open position for ‘stop price’. How do I query for open order type for ‘stop price’?

Trying to use the limit price id to replace stop price does not work and returns the error:
APIError: limit orders must not have stop_price

@suraj How are you getting the ‘order number’? Which order is it? Is it the parent order ID or one of the legs?

The best way to work with bracket orders is to keep track of the parent order ID. When you have that you can easily get the order IDs of the two leg orders. The leg order info is stored with the parent order in the attribute called legs.

The first leg (ie legs[0]) is always the take profit limit order. The second leg (ie legs[1]) is always the stop limit order. Below is an example of a parent bracket order with the two leg order details in the legs attribute.

{ ‘asset_class’: <AssetClass.US_EQUITY: ‘us_equity’>,
‘asset_id’: UUID(‘b0b6dd9d-8b9b-48a9-ba46-b9d54906e415’),
‘canceled_at’: None,
‘client_order_id’: ‘73773fa3-551f-4c54-adbe-fd9ae0f51334’,
‘created_at’: datetime.datetime(2023, 1, 24, 21, 31, 22, 224183, tzinfo=datetime.timezone.utc),
‘expired_at’: None,
‘extended_hours’: False,
‘failed_at’: None,
‘filled_at’: None,
‘filled_avg_price’: None,
‘filled_qty’: ‘0’,
‘hwm’: None,
‘id’: UUID(‘374e5da7-71fe-4b1d-8296-6d89285e4a67’),
‘legs’: [ { ‘asset_class’: <AssetClass.US_EQUITY: ‘us_equity’>,
‘asset_id’: UUID(‘b0b6dd9d-8b9b-48a9-ba46-b9d54906e415’),
‘canceled_at’: None,
‘client_order_id’: ‘e7199a8d-d82a-491d-bdb3-af576e0f706d’,
‘created_at’: datetime.datetime(2023, 1, 24, 21, 31, 22, 224215, tzinfo=datetime.timezone.utc),
‘expired_at’: None,
‘extended_hours’: False,
‘failed_at’: None,
‘filled_at’: None,
‘filled_avg_price’: None,
‘filled_qty’: ‘0’,
‘hwm’: None,
‘id’: UUID(‘300a3588-b274-4521-85d6-e851a7114dd9’),
‘legs’: None,
‘limit_price’: ‘150’,
‘notional’: None,
‘order_class’: <OrderClass.BRACKET: ‘bracket’>,
‘order_type’: <OrderType.LIMIT: ‘limit’>,
‘qty’: ‘1’,
‘replaced_at’: None,
‘replaced_by’: None,
‘replaces’: None,
‘side’: <OrderSide.SELL: ‘sell’>,
‘status’: <OrderStatus.HELD: ‘held’>,
‘stop_price’: None,
‘submitted_at’: datetime.datetime(2023, 1, 24, 21, 31, 22, 222565, tzinfo=datetime.timezone.utc),
‘symbol’: ‘AAPL’,
‘time_in_force’: <TimeInForce.DAY: ‘day’>,
‘trail_percent’: None,
‘trail_price’: None,
‘type’: <OrderType.LIMIT: ‘limit’>,
‘updated_at’: datetime.datetime(2023, 1, 24, 21, 31, 22, 224215, tzinfo=datetime.timezone.utc)},
{ ‘asset_class’: <AssetClass.US_EQUITY: ‘us_equity’>,
‘asset_id’: UUID(‘b0b6dd9d-8b9b-48a9-ba46-b9d54906e415’),
‘canceled_at’: None,
‘client_order_id’: ‘fb472043-1f4e-4445-b5f2-174d1535a118’,
‘created_at’: datetime.datetime(2023, 1, 24, 21, 31, 22, 224232, tzinfo=datetime.timezone.utc),
‘expired_at’: None,
‘extended_hours’: False,
‘failed_at’: None,
‘filled_at’: None,
‘filled_avg_price’: None,
‘filled_qty’: ‘0’,
‘hwm’: None,
‘id’: UUID(‘58a81cd9-f5ab-43a7-8835-5c543b022925’),
‘legs’: None,
‘limit_price’: None,
‘notional’: None,
‘order_class’: <OrderClass.BRACKET: ‘bracket’>,
‘order_type’: <OrderType.STOP: ‘stop’>,
‘qty’: ‘1’,
‘replaced_at’: None,
‘replaced_by’: None,
‘replaces’: None,
‘side’: <OrderSide.SELL: ‘sell’>,
‘status’: <OrderStatus.HELD: ‘held’>,
‘stop_price’: ‘100’,
‘submitted_at’: datetime.datetime(2023, 1, 24, 21, 31, 22, 222565, tzinfo=datetime.timezone.utc),
‘symbol’: ‘AAPL’,
‘time_in_force’: <TimeInForce.DAY: ‘day’>,
‘trail_percent’: None,
‘trail_price’: None,
‘type’: <OrderType.STOP: ‘stop’>,
‘updated_at’: datetime.datetime(2023, 1, 24, 21, 31, 22, 224232, tzinfo=datetime.timezone.utc)}],
‘limit_price’: ‘125’,
‘notional’: None,
‘order_class’: <OrderClass.BRACKET: ‘bracket’>,
‘order_type’: <OrderType.LIMIT: ‘limit’>,
‘qty’: ‘1’,
‘replaced_at’: None,
‘replaced_by’: None,
‘replaces’: None,
‘side’: <OrderSide.BUY: ‘buy’>,
‘status’: <OrderStatus.ACCEPTED: ‘accepted’>,
‘stop_price’: None,
‘submitted_at’: datetime.datetime(2023, 1, 24, 21, 31, 22, 222565, tzinfo=datetime.timezone.utc),
‘symbol’: ‘AAPL’,
‘time_in_force’: <TimeInForce.DAY: ‘day’>,
‘trail_percent’: None,
‘trail_price’: None,
‘type’: <OrderType.LIMIT: ‘limit’>,
‘updated_at’: datetime.datetime(2023, 1, 24, 21, 31, 22, 224183, tzinfo=datetime.timezone.utc)}

The leg info can fetched something like this

take_profit_leg = my_parent_order.legs[0]
stop_loss_leg = my_parent_order.legs[1]

Each of the legs can then be replaced using their respective order IDs

take_profit_order_id = take_profit_leg.id
stop_loss_leg_id = stop_loss_leg.id

Does that help?

Thank you. I realized I needed to use the ‘nested = true’ as an argument when getting all orders.

Can you please show python code that does this on an existing bracket order that uses a user specified client_order_id when the bracket order is originally submitted. thank you.

Also is a marketable price just a ‘market sell’ or do I have to determine the marketable price before replacing the take profit limit price?

thank you for help. seeing the python code do this would be so helpful.

@Dan_Whitnable_Alpaca If you use a bracket order to open a position, and then you submit a request to DELETE the position or to DELETE all positions, would either of those calls succeed?

@Alpaca Team, I’m having this issue to submit a bracket order. Use Case or Scenario: OKLO – 2025-09-19T12:56:56.243627 | :white_check_mark: OKLO filled: 15 shares at $129.90
Setting take profit: $132.50, stop loss: $123.41. I do see that TakeProfit Order @132.50 is available in the Alpaca Webpage, but StopLoss trade is not excuted, I’m getting error Trying alternative method: stop-loss first…
:white_check_mark: Stop loss order submitted: ceaef137-b2e2-4b17-a4ad-2853f66865fd
:cross_mark: Alternative method failed for OKLO: insufficient qty available for order (requested: 15, available: 0)
Last resort: Take-profit only…
:cross_mark: All methods failed for OKLO: insufficient qty available for order (requested: 15, available: 0)
:warning: OKLO position established without protective orders. Even if I try manually to update the stop loss in the Alpaca, its not allowing I’m getting this error messge how to resolve this issue – “Order failed: insufficient qty available for order (requested: 15, available: 0)” Any suggestion to resolve via python code?

@Orange_Bunny When you say “but StopLoss trade is not executed” what exactly do you mean? It won’t execute unless it is triggered (ie the price of OKLO drops below the stop price of 123.41). Are you just not seeing it under ‘open orders’? That is expected. Technically only the take profit limit order has been sent to an execution venue for execution. There can only be one open order waiting for execution at any given time (otherwise one could potentially sell the same stock twice). The stop loss order is there and it has a status of held (ie it’s being held but not submitted for execution until the price drops below 123.41). If you display ‘all’ orders (not just open orders) you will see it.

Could that be the case?