Understand Orders

Using Alpaca Trade API, a user can monitor, place and cancel their orders with Alpaca. Each order has a unique identifier provided by the client. This client-side unique order ID will be automatically generated by the system if not provided by the client, and will be returned as part of the order object along with the rest of the fields described below. Once an order is placed, it can be queried using the client-side order ID or system-assigned unique ID to check the status. Updates on open orders at Alpaca will also be sent over the streaming interface, which is the recommended method of maintaining order state.

Buying Power

In order to accept your orders that would open new positions or add to existing ones, your account must have sufficient buying power. Alpaca applies a “buying” power check to both buy long and sell short positions.

The calculated value of an opening buy order is the order’s limit price multiplied by the order’s quantity. In the case of market buy orders, the limit price is 2.5% to 4% above the current market price as noted above.

The calculated value of an opening sell short order is MAX(order’s limit price, 3% above the current ask price) multiplied by the order’s quantity. In the case of market short orders, the value is simply 3% above the current ask price * order quantity.

The order’s calculated value is then checked against your available buying power to determine if it can be accepted. Please note that your available buying power is reduced by your existing open buy long and sell short orders, whereas your sell long and buy to cover orders do not replenish your available buying power until they have executed.

For example, if your buying power is $10,000 and you submit a limit buy order with an order value of $3,000, your order will be accepted and your remaining available buying power will be $7,000. Even if this order is unfilled, as long as it is open and has not been cancelled, it will count against your available buying power. If you then submitted another order with an order value of $8,000, it would be rejected.

Orders Submitted Outside of Eligible Trading Hours

Orders not eligible for extended hours submitted between 4:00pm - 7:00pm ET will be rejected.

Orders not eligible for extended hours submitted after 7:00pm ET will be queued and eligible for execution at the time of the next market open.

Orders eligible for extended hours submitted outside of 9:00am - 6:00pm ET are handled as described in the section below.

Extended Hours Trading

Using API v2, you can submit and fill orders during pre-market and after-hours. Extended hours trading has specific risks due to the less liquidity. Please read through our disclosure for more details.

Currently, we support the following extended hours:
Pre-market: 9:00 - 9:30am
After-hours: 4:00 - 6:00pm

Additionally, please be aware of the following constraints.

  • If the order is submitted between 6:00pm and 8:00pm ET on a market day, the order request is returned with error. Alpaca reserves this time window for future expansion of supported hours.
  • If the order is submitted after 8:00pm but before 9:00am ET of the following trading day, the order request is queued and will be eligible for execution from the beginning of the next available supported pre-market hours at 9:00am.

Submitting an Extended Hours Eligible Order

To indicate an order is eligible for extended hours trading, you need to supply a boolean parameter named extended_hours to your order request. By setting this parameter as true, the order is will be eligible to execute in the pre-market or after-hours.

Only limit day orders will be accepted as extended hours eligible. All other order types and TIFs will be rejected with an error. You must adhere to these settings in order to participate in extended hours:\

  1. The order type must be set to limit (with limit price). Any other type of orders will be rejected with an error.\
  2. Time-in-force must be set to be day. Any other time-in-force will be rejected with an error.

All symbols supported during regular market hours are also supported during extended hours. Short selling is also treated the same.

Order Types

When you submit an order, you can choose one of supported order types. Currently, Alpaca supports four different types of orders.

Market Order

A market order is a request to buy or sell a security at the currently available market price. It provides the most likely method of filling an order. Market orders fill nearly instantaneously.

As a trade-off, your fill price may slip depending on the available liquidity at each price level as well as any price moves that may occur while your order is being routed to its execution venue. There is also the risk with market orders that they may get filled at unexpected prices due to short-term price spikes.

Alpaca uses the following rounding mechanics with respect to buy orders: (1) rounded down to two decimal places if the last trade price is over $1.00; otherwise, rounded down to four decimal places.

Limit Order

A limit order is an order to buy or sell at a specified price or better. A buy limit order (a limit order to buy) is executed at the specified limit price or lower (i.e., better). Conversely, a sell limit order (a limit order to sell) is executed at the specified limit price or higher (better). Unlike a market order, you have to specify the limit price parameter when submitting your order.

While a limit order can prevent slippage, it may not be filled for a quite a bit of time, if at all. For a buy limit order, if the market price is within your specified limit price, you can expect the order to be filled. If the market price is equivalent to your limit price, your order may or may not be filled; if the order cannot immediately execute against resting liquidity, then it is deemed non-marketable and will only be filled once a marketable order interacts with it. You could miss a trading opportunity if price moves away from the limit price before your order can be filled.

Hyper-marketable Limit Order Rejection A limit orders with a limit price that significantly exceeds the current market price will be rejected as part of our risk checks to mitigate against “fat finger” errors. We currently use exchange guidelines for erroneous trades to determine the thresholds at which orders are rejected:

Share Price Threshold
Greater than $0.00 up to and including $25.00 10%
Greater than $25.00 up to and including $50.00 5%
Greater than $50.00 3%

The thresholds are doubled during pre-market and after-hours.

Stop Order

A stop (market) order is an order to buy or sell a security when its price moves past a particular point, ensuring a higher probability of achieving a predetermined entry or exit price. Once the market price crosses the specified stop price, the stop order becomes a market order. Alpaca converts buy stop orders into stop limit orders with a limit price that is 4% higher than a stop price < $50 (or 2.5% higher than a stop price >= $50). Sell stop orders are not converted into stop limit orders.

A stop order does not guarantee the order will be filled at a certain price after it is converted to a market order.

In order to submit a stop order, you will need to specify the stop price parameter in the API.

Stop Limit Order

A stop-limit order is a conditional trade over a set time frame that combines the features of a stop order with those of a limit order and is used to mitigate risk. The stop-limit order will be executed at a specified limit price, or better, after a given stop price has been reached. Once the stop price is reached, the stop-limit order becomes a limit order to buy or sell at the limit price or better.

In order to submit a stop limit order, you will need to specify both the limit and stop price parameters in the API.

Opening and Closing Auction Orders

Market on open and limit on open orders are only eligible to execute in the opening auction. Market on close and limit on close orders are only eligible to execute in the closing auction. Please see the Time in Force section for more details.

Bracket Orders

A bracket order is a chain of three orders that can be used to manage your position entry and exit. It is a common use case of an OTOCO (One Triggers OCO {One Cancels Other}) order.

The first order is used to enter a new long or short position, and once it is completely filled, two conditional exit orders are activated. One of the two closing orders is called a take-profit order, which is a limit order, and the other is called a stop-loss order, which is either a stop or stop-limit order. Importantly, only one of the two exit orders can be executed. Once one of the exit orders is filled, the other is canceled.

Without a bracket order, you would not be able to submit both entry and exit orders simultaneously since Alpaca’s system only accepts exit orders for existing positions. Additionally, even if you had an open position, you would not be able to submit two conditional closing orders since Alpaca’s system would view one of the two orders as exceeding the available position quantity. Bracket orders address both of these issues, as Alpaca’s system recognizes the entry and exit orders as a group and queues them for execution appropriately.

In order to submit a bracket order, you need to supply additional parameters to the API. First, add a parameter order_class as “bracket”. Second, give two additional fields take_profit and stop_loss both of which are nested JSON objects. The take_profit object needs limit_price as a field value that specifies limit price of the take-profit order, and the stop_loss object needs a mandatory stop_price and optional limit_price fields. If limit_price is specified in stop_loss, the stop-loss order is queued as a stop-limit order, but otherwise it is queued as a stop order.

An example JSON body parameter to submit a bracket order is as follows.

{
  "side": "buy",
  "symbol": "SPY",
  "type": "market",
  "qty": "100",
  "time_in_force": "gtc",
  "order_class": "bracket",
  "take_profit": {
    "limit_price": "301"
  },
  "stop_loss": {
    "stop_price": "299",
    "limit_price": "298.5"
  }
}

This creates three orders.

  • A buy market order for 100 SPY with GTC
  • A sell limit order for the same 100 SPY, with limit price = 301
  • A sell stop-limit order, with stop price = 299 and limit price = 298.5

The second and third orders won’t be active until the first order is completely filled. Additional bracket order details include:

  • If any one of the orders is canceled, any remaining open order in the group is canceled.
  • take_profit.limit_price must be higher than stop_loss.stop_price for a buy bracket order, and vice versa for a sell.
  • Both take_profit.limit_price and stop_loss.stop_price must be present.
  • Extended hours are not supported. extended_hours must be “false” or omitted.
  • time_in_force must be “day” or “gtc”.
  • Each order in the group is always sent with a DNR/DNC (Do Not Reduce/Do Not Cancel) instruction. Therefore, the order price will not be adjusted and the order will not be canceled in the event ofa dividend or other corporate action.
  • If the take-profit order is partially filled, the stop-loss order will be adjusted to the remaining quantity.
  • Order replacement (PATCH /v2/orders) is supported to update limit_price and stop_price.

Each order of the group is reported as an independent order in GET /v2/orders endpoint. But if you specify additional parameter nested=true, the order response will nest the result to include child orders under the parent order with an array field legs in the order entity.

OCO Orders

OCO (One-Cancels-Other) is another type of advanced order type. This is a set of two orders with the same side (buy/buy or sell/sell) and currently only exit order is supported. In other words, this is the second part of the bracket orders where the entry order is already filled, and you can submit the take-profit and stop-loss in one order submission.

With OCO orders, you can add take-profit and stop-loss after you open the position, without thinking about those two legs upfront.

In order to submit an OCO order, specify “oco” for the order_class parameter.

{
  "side": "sell",
  "symbol": "SPY",
  "type": "limit",
  "qty": "100",
  "time_in_force": "gtc",
  "order_class": "oco",
  "take_profit": {
    "limit_price": "301"
  },
  "stop_loss": {
    "stop_price": "299",
    "limit_price": "298.5"
  }
}

The type parameter must always be “limit”, indicating the take-profit order type is a limit order. The stop-loss order is a stop order if only stop_price is specified, and is a stop-limit order if both limit_price and stop_price are specified (i.e. stop_price must be present in any case). Those two orders work exactly the same way as the two legs of the bracket orders.

Note that when you retrieve the list of orders with the nested parameter true, the take-profit order shows up as the parent order while the stop-loss order appears as a child order.

Like bracket orders, order replacement is supported to update limit_price and stop_price.

OTO Orders

OTO (One-Triggers-Other) is a variant of bracket order. It takes one of the take-profit or stop-loss order in addition to the entry order. For example, if you want to set only a stop-loss order attached to the position, without a take-profit, you may want to consider OTO orders.

The order submission is done with the order_class parameter be “oto”.

{
  "side": "buy",
  "symbol": "SPY",
  "type": "market",
  "qty": "100",
  "time_in_force": "gtc",
  "order_class": "oto",
  "stop_loss": {
    "stop_price": "299",
    "limit_price": "298.5"
  }
}

Either of take_profit or stop_loss must be present (the above example is for take-profit case), and the rest of requirements are the same as the bracket orders.

Like bracket orders, order replacement is not supported yet.

Threshold on stop price of stop-loss orders

For the stop-loss order leg of advanced orders, please be aware the order request can be rejected because of the restriction of the stop_price parameter value. The stop price input has to be 0.1% below or lower (for stop-loss sell, above and higher for buy) than the “base price”. The base price is determined as follows.

  • It is the limit price of the take-profit, for OCO orders.
  • It is the limit price of the entry order, for bracket or OTO orders if the entry type is limit.
  • It is also the current market price for any, of OCO, OTO and bracket.

This restriction is to avoid potential race-conditions in the order handling, but as we improve our system capability, this may be loosened in the future.

Trailing Stop Orders

Trailing stop orders allow you to continuously and automatically keep updating the stop price threshold based on the stock price movement. You request a single order with a dollar offset value or percentage value as the trail and the actual stop price for this order changes as the stock price moves in your favorable way, or stay at the last level otherwise. This way, you don’t need to monitor the price movement and keep sending replace requests to update the stop price close to the latest market movement.

Trailing stop orders keep track of the highest (for sell, lowest for buy) prices (called high water mark, or hwm) since the order was submitted, and the user-specified trail parameters determine the actual stop price to trigger relative to high water mark. Once the stop price is triggered, the order turns into a market order, and it may fill above or below the stop trigger price.

To submit a trailing stop order, you will set the type parameter to “trailing_stop”. There are two order submission parameters related to trailing stop, one of which is required when type is “trailing_stop”.

  • trail_price: string<number>
    a dollar value away from the highest water mark. If you set this to 2.00 for a sell trailing stop, the stop price is always hwm - 2.00.
  • trail_percent: string<number>
    a percent value away from the highest water mark. If you set this to 1.0 for a sell trailing stop, the stop price is always hwm * 0.99.

One of these values must be set for trailing stop orders. The following is an example of trailing order submission JSON parameter.

{
  "side": "sell",
  "symbol": "SPY",
  "type": "trailing_stop",
  "qty": "100",
  "time_in_force": "day",
  "trail_price": "6.15"
}

The Order entity returned from the GET method has a few fields related to trailing stop orders.

  • trail_price: string<number>
    This is the same value as specified when the order was submitted. It will be null if this was not specified.
  • trail_percent: string<number>
    This is the same value as specified when the order was submitted. It will be null if this was not specified.
  • hwm: string<number>
    The high water mark value. This continuously changes as the market moves towards your favorable way.
  • stop_price: string<number>
    This is the same as stop price in the regular stop/stop limit orders, but this is derived from hwm and trail parameter, and continuously updates as hwm changes.

If a trailing stop order is accepted, the order status becomes “new”. While the order is pending stop price trigger, you can update the trail parameter by the PATCH method.

  • trail: string<number>
    The new value of the trail_price or trail_percent value. Such a replace request is effective only for the order type is “trailing_stop” before the stop price is hit. Note, you cannot change the price trailing to the percent trailing or vice versa.

Here are some details of trailing stop.

  • Trailing stop will not trigger outside of the regular market hours.
  • Valid time-in-force values for trailing stop are “day” and “gtc”.
  • Trailing stop orders are currently supported only with single orders. However, we plan to support trailing stop as the stop loss leg of bracket/OCO orders in the future.

Time in Force

Alpaca supports the following Time-In-Force designations:

  • day
    A day order is eligible for execution only on the day it is live. By default, the order is only valid during Regular Trading Hours (9:30am - 4:00pm ET). If unfilled after the closing auction, it is automatically canceled. If submitted after the close, it is queued and submitted the following trading day. However, if marked as eligible for extended hours, the order can also execute during supported extended hours.
  • gtc
    The order is good until canceled. Non-marketable GTC limit orders are subject to price adjustments to offset corporate actions affecting the issue. We do not currently support Do Not Reduce(DNR) orders to opt out of such price adjustments.
  • opg
    Use this TIF with a market/limit order type to submit “market on open” (MOO) and “limit on open” (LOO) orders. This order is eligible to execute only in the market opening auction. Any unfilled orders after the open will be cancelled. OPG orders submitted after 9:28am but before 7:00pm ET will be rejected. OPG orders submitted after 7:00pm will be queued and routed to the following day’s opening auction. On open/on close orders are routed to the primary exchange. Such orders do not necessarily execute exactly at 9:30am / 4:00pm ET but execute per the exchange’s auction rules.
  • cls
    Use this TIF with a market/limit order type to submit “market on close” (MOC) and “limit on close” (LOC) orders. This order is eligible to execute only in the market closing auction. Any unfilled orders after the close will be cancelled. CLS orders submitted after 3:50pm but before 7:00pm ET will be rejected. CLS orders submitted after 7:00pm will be queued and routed to the following day’s closing auction. Only available with API v2.
  • ioc
    An Immediate Or Cancel (IOC) order requires all or part of the order to be executed immediately. Any unfilled portion of the order is canceled. Only available with API v2.
  • fok
    A Fill or Kill (FOK) order is only executed if the entire order quantity can be filled, otherwise the order is canceled. Only available with API v2.

Order Lifecycle

An order executed through Alpaca can experience several status changes during its lifecycle. The most common statuses are described in detail below:

  • new
    The order has been received by Alpaca, and routed to exchanges for execution. This is the usual initial state of an order.
  • partially_filled
    The order has been partially filled.
  • filled
    The order has been filled, and no further updates will occur for the order.
  • done_for_day
    The order is done executing for the day, and will not receive further updates until the next trading day.
  • canceled
    The order has been canceled, and no further updates will occur for the order. This can be either due to a cancel request by the user, or the order has been canceled by the exchanges due to its time-in-force.
  • expired
    The order has expired, and no further updates will occur for the order.
  • replaced
    The order was replaced by another order, or was updated due to a market event such as corporate action.
  • pending_cancel
    The order is waiting to be canceled.
  • pending_replace
    The order is waiting to be replaced by another order. The order will reject cancel request while in this state.

Less common states are described below. Note that these states only occur on very rare occasions, and most users will likely never see their orders reach these states:

  • accepted
    The order has been received by Alpaca, but hasn’t yet been routed to the execution venue. This could be seen often out side of trading session hours.
  • pending_new
    The order has been received by Alpaca, and routed to the exchanges, but has not yet been accepted for execution. This state only occurs on rare occasions.
  • accepted_for_bidding
    The order has been received by exchanges, and is evaluated for pricing. This state only occurs on rare occasions.
  • stopped
    The order has been stopped, and a trade is guaranteed for the order, usually at a stated price or better, but has not yet occurred. This state only occurs on rare occasions.
  • rejected
    The order has been rejected, and no further updates will occur for the order. This state occurs on rare occasions and may occur based on various conditions decided by the exchanges.
  • suspended
    The order has been suspended, and is not eligible for trading. This state only occurs on rare occasions.
  • calculated
    The order has been completed for the day (either filled or done for day), but remaining settlement calculations are still pending. This state only occurs on rare occasions.

An order may be canceled through the API up until the point it reaches a state of either filled, canceled, or expired.