Investing in stocks and cryptocurrencies is a popular way to build wealth. However, getting started in this space can be intimidating due to the amount of bizarre jargon. In the pursuit of building your own portfolio, it's important to understand how to place orders for the assets you’re looking to buy or sell.
In this article, we review every order type that Alpaca has to offer, starting with the basics and working through to more advanced order types. Also covered is “Time in Force”, which gives investors more control over the execution of their orders. Supplementing all of this is a Google Colab notebook containing cells for each code snippet that you’ll find in this article. All examples are written in Python 3 using the Alpaca Trade client in this GitHub repo.
Getting Started with Alpaca Trading API
Before we’re able to start placing orders through Alpaca, we’ll need to sign up for an account and get our API keys. After you’ve created an account here, follow this quick guide to locate your API keys. Following the installation instructions in the GitHub repo, you’ll now be able to use Alpaca’s pre-defined tools locally. Now, you can instantiate the Alpaca Trade client in your program by importing the package and using your keys to authenticate. In addition to the API key and key secret, we’ll also pass in the paper trading URL as a base URL so our client can route our requests to our paper account.
# Importing the api and instantiating the rest client according to our keys
import alpaca_trade_api as api
import random
API_KEY = "<Your API Key>"
API_SECRET = "<Your Secret Key>"
BASE_URL = "https://paper-api.alpaca.markets"
alpaca = api.REST(API_KEY, API_SECRET, BASE_URL)
All of the following code examples assume that the above snippet has been run first. The function used to submit orders is called submit_order
and the definition can be found here. Note that the only required parameter is the stock/crypto symbol and that unless specified, orders are a market buy that will expire at the end of the day.
The Five Basic Order Types
After defining an asset you’d like to buy or sell, you’ll find yourself having to choose between one of the four basic order types before placing the order. These are the Market Order, Limit Order, Stop Order, Stop Limit Order, and Trailing Stop Order.
Market Orders
A market order is an order to buy or sell an asset at the market’s current best available price. The defining piece of a market order is that you don’t have control over the price your order fills at. This leaves the buyer to dictate one of two things: either how many shares they want to buy/sell or how much total money they want to be exchanged in this order. To use the former set the qty
parameter, and to use the latter set the notional
parameter. Submitting market orders by stock quantity or by notional value are mutually exclusive, it would be an error to pass both parameters into one function call. Market orders are great for people who want their orders filled faster rather than at a specific share price. To show both kinds of market orders we’ll define a stock symbol, quantity of shares to buy, the notional value of stock to buy, and place the orders using the client we’ve instantiated.
# Submitting a market buy order by qty
symbol = "SPY"
qty = 10
client_order_id=f"gcos_{random.randrange(100000000)}"
notional = 4500
alpaca.submit_order(symbol, qty=qty, client_order_id=client_order_id)
alpaca.submit_order(symbol, notional=notional, client_order_id=client_order_id)
Limit Orders
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. A limit order is great if a buyer/seller wants to be particular about the price the order is filled at, but a downside is it may not get filled for a while if there is no one willing to be on the other side of the trade. To submit a limit order, we’ll sell some of the $SPY shares we bought with the previous code example.
# Submitting a limit sell order for $SPY for no less than our limit
symbol = "SPY"
qty = 10
side = "sell"
type = "limit"
limit_price = 455
client_order_id=f"gcos_{random.randrange(100000000)}"
alpaca.submit_order(
symbol,
qty=qty,
side=side,
type=type,
limit_price=limit_price,
client_order_id=client_order_id
)
Stop Orders
A stop (market) order is an order to buy or sell a security that only becomes active once its price has reached the specified “stop” price or passed it. For example, a stop order to sell Tesla stock ($TSLA) would trigger once its stock price reaches your stop price or lower. Once the stop order has been triggered, it is converted into a market order and will be filled according to the behavior of a market order. A stop order does not guarantee the order will be filled at a certain price once it is triggered, but it can help. A stop order may be a good choice if you are certain that you want in or out of a position once a security’s price has reached a certain level. To submit a stop order you need to specify the stop price parameter. For this example, we’ll submit a stop order to buy five $TSLA shares once its price dips down to $900.
# Submitting a stop buy order for $TSLA that is triggered if the share price reaches $900
symbol = "TSLA"
qty = 5
type = "stop"
stop_price = 900
client_order_id=f"gcos_{random.randrange(100000000)}"
alpaca.submit_order(
symbol,
qty=qty,
type=type,
stop_price=stop_price,
client_order_id=client_order_id
)
Stop Limit Orders
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. 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. This makes stop-limit orders a great candidate if you’re looking to mitigate risk.
An example of this is placing a stop-limit buy order with a stop price of $100 and a limit price of $102. In this example, if the stock price were to gap down to $100 and keep dropping, we would not catch the falling knife. If the stock were to recover from this point and get back up to $102, we would open up a long position. As a supplement to this example, we’ll submit a stop-limit buy order for 10 Snapchat ($SNAP) shares with a stop price of $30 and a limit price of $31.50.
# Submitting a stop-limit buy order for $SNAP that is triggered if the share price reaches $30 with
# a limit price set at $31.50
symbol = "SNAP"
qty = 10
type = "stop_limit"
stop_price = 30
limit_price = 31.50
client_order_id=f"gcos_{random.randrange(100000000)}"
alpaca.submit_order(
symbol,
qty=qty,
type=type,
stop_price=stop_price,
limit_price=limit_price,
client_order_id=client_order_id
)
Trailing Stop Orders
A trailing stop order is similar to a stop order, but instead of defining an absolute stop price that your order should trigger at, you define a relative stop price to trigger at. Trailing stop orders allow you to continuously and automatically keep updating the stop price threshold based on the stock price movement. You request an 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 favorably, or stays 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 will behave accordingly. Trailing stop orders are good for mitigating risk without having to monitor the ticker frequently. When submitting a trailing stop order, you’ll need to set the type
parameter and one of trail_percent
or trail_price
. As an example, we’ll submit a buy trailing stop order for 10 GameStop ($GME) shares set to follow the price and trigger if it drops to 5% below its high-water mark.
# Submitting a trailing stop buy order for $GME set to trigger 5% under its high water mark.
symbol = "GME"
qty = 10
type = "trailing_stop"
trail_percent = 5
client_order_id=f"gcos_{random.randrange(100000000)}"
alpaca.submit_order(
symbol,
qty=qty,
type=type,
trail_percent=trail_percent,
client_order_id=client_order_id
)
Advanced Order Types
These more advanced order types are great for investors and traders who are looking to exercise a high level of control over their order execution. This usually involves a series of orders chained together.
Bracket Orders
A bracket order is a chain of three orders that can be used to manage your position entry and exit. The first order is used to enter a new long or short position, and once it is completely filled, two conditional exit orders become active. 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. Please note, however, that in extremely volatile and fast market conditions, both orders may fill before the cancellation occurs.
Bracket orders are great if you’d like to automate your risk management by removing in-the-moment decision-making. To submit bracket orders with Alpaca, you’ll need to specify that this order is a bracket order with parameter order_class
, and then define your take-profit
and stop-loss
orders with take_profit and stop_loss. Note that your take-profit and stop-loss parameters must be dictionaries. As an example, let’s submit a bracket buy order for Nvidia ($NVDA) stock that will take profit at a 10% gain and stop our losses at 5%.
# A bracket buy order for $NVDA that takes profit at a 10% gain, or submits a market sell at -5% loss
symbol = "NVDA"
qty = 10
type = "limit"
limit_price = 250
order_class = "bracket"
take_profit = {"limit_price": limit_price * 1.10} # 10% gain sets this value to $275
stop_loss = {"stop_price": limit_price * 0.95} # 5% loss sets this value to $237.50
client_order_id=f"gcos_{random.randrange(100000000)}"
alpaca.submit_order(
symbol,
qty=qty,
type=type,
limit_price=limit_price,
order_class=order_class,
take_profit=take_profit,
stop_loss=stop_loss,
client_order_id=client_order_id
)
One-Cancels-Other Orders (OCO)
One-Cancels-Other (OCO) orders are another type of advanced order type. This is a set of two orders with the same (buy/buy or sell/sell) where if one of the orders gets filled, the other one will cancel. 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. Currently, only OCO orders to exit a position are supported. OCO orders are great if you have an open position and you’d like to set a specific exit for your position, mitigating your risk and making your decision in advance. In this example, we’ll submit an OCO order to exit a long position in $SPY by setting the order_class
, take_profit
, and stop_loss
parameters. Just like in bracket orders, your take-profit and stop-loss parameters must be dictionaries.
# An OCO exit order for $SPY that takes profit at $465 and cuts losses with a stop-limit at $450
symbol = "SPY"
qty = 5
side = "sell"
type = "limit"
order_class = "oco"
take_profit = {"limit_price": 465}
stop_loss = {"stop_price": 450, "limit_price": 450}
client_order_id=f"gcos_{random.randrange(100000000)}"
alpaca.submit_order(
symbol,
qty=qty,
side=side,
type=type,
order_class=order_class,
take_profit=take_profit,
stop_loss=stop_loss,
client_order_id=client_order_id
)
One-Triggers-Other Orders (OTO)
One-Triggers-Other (OTO) orders are a variant of bracket orders. While it keeps the initial order that opens your position, OTO orders only have one of either a take-profit or stop-loss. A good use-case for an OTO order would be if you want to go long on a stock with no precise target for profit, but you know the maximum you’re willing to risk losing. Putting that use-case into code, we’ll go long on Apple ($AAPL) by submitting an OTO order with a market buy for 5 stocks that triggers a stop-loss at $160.
# An OTO order for $AAPL featuring a market buy for 5 stocks that triggers a stop loss at $160
symbol = "AAPL"
qty = 5
order_class = "oto"
stop_loss = {"stop_price": 160}
client_order_id=f"gcos_{random.randrange(100000000)}"
alpaca.submit_order(
symbol,
qty=qty,
order_class=order_class,
stop_loss=stop_loss,
client_order_id=client_order_id
)
Time in Force (TIF)
Time in force is a special designation that can be used to specify the conditions under which your order will expire. Every order must have a time in force designation. If there is not one explicitly defined, the default value is day. The parameter in submit_order for time in force is called time_in_force, and there are 6 options to choose from.
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.
As an example, we’ll submit a limit buy order for Spotify ($SPOT) stock that will expire at the end of the day in hopes that the price will dip before then.
# Submitting a limit buy for Spotify stock that will expire at the end of the day
symbol = "SPOT"
qty = 10
type = "limit"
time_in_force = "day"
limit_price = 160
client_order_id=f"gcos_{random.randrange(100000000)}"
alpaca.submit_order(
symbol,
qty=qty,
type=type,
time_in_force=time_in_force,
limit_price=limit_price,
client_order_id=client_order_id
)
Good-Til-Canceled (gtc)
As the name suggests, this designation means that the order is active until it’s filled or 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. This could be a good option if you have a long-term price target that you want to enter/exit at.
For example, if we were fearful that our long position in $SPY might suffer a large, sudden dip, we can submit a stop sell order that will be good until we cancel it. This helps mitigate risk without having to actively monitor the position.
# Submitting a stop sell order for $SPY that will remain active until filled or canceled
symbol = "SPY"
qty = 10
side = "sell"
type = "stop"
time_in_force = "gtc"
stop_price = 400
client_order_id=f"gcos_{random.randrange(100000000)}"
alpaca.submit_order(
symbol,
qty=qty,
side=side,
type=type,
time_in_force=time_in_force,
stop_price=stop_price,
client_order_id=client_order_id
)
Submit On Market Open (opg)
This TIF designates that this order is eligible to execute only in the market opening auction. Use this TIF with a market/limit order type to submit “market on open” (MOO) and “limit on open” (LOO) orders. Any unfilled orders after the open will be canceled. 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.
For example, if you anticipate a really great/awful day for your favorite stock following today and the markets are currently closed, you can submit this order and have your order executed as soon as possible. In this case, we’ll submit a market buy for Palantir ($PLTR) to execute right at tomorrow’s open.
# Submitting a market buy for Palantir that will execute on the following market opening day
symbol = "PLTR"
qty = 25
time_in_force = "opg"
client_order_id=f"gcos_{random.randrange(100000000)}"
alpaca.submit_order(
symbol,
qty=qty,
time_in_force=time_in_force,
client_order_id=client_order_id
)
Submit On Market Close (cls)
This TIF designates that this order is eligible to execute only in the market closing auction. Use this TIF with a market/limit order type to submit “market on close” (MOC) and “limit on close” (LOC) orders. Any unfilled orders after the close will be canceled. 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.
One scenario where one may want to use this TIF is if although the security in question has been trending downwards today, they anticipate a positive/negative move after an earnings report after market close. This way, you’ll be sure to get the best price possible and open your position up. As an example, we’ll short AMC ($AMC) by submitting a market sell that will execute at the end of the current day.
# Submitting a market sell for AMC that will execute at the end of the current day
symbol = "AMC"
qty = 100
side = "sell"
time_in_force = "cls"
client_order_id=f"gcos_{random.randrange(100000000)}"
alpaca.submit_order(
symbol,
qty=qty,
side=side,
time_in_force=time_in_force,
client_order_id=client_order_id
)
Immediate-Or-Cancel (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. Most market makers who receive IOC orders will attempt to fill the order on a principal basis only and cancel any unfilled balance. On occasion, this can result in the entire order being canceled if the market maker does not have any existing inventory of the security in question.
One reason you may want to use IOC is if you want to enter/exit a position and don’t have time to wait for it to fill. Here we’ll submit a limit buy for Netflix ($NFLX) for a little bit under its current value, hoping that we can snag some shares for a small discount and get the rest of our money back.
# Submitting a limit buy for Netflix that with the IOC time in force designation
symbol = "NFLX"
qty = 10
type="limit"
time_in_force = "ioc"
limit_price = 400
alpaca.submit_order(
symbol,
qty=qty,
type=type,
time_in_force=time_in_force,
limit_price=limit_price
)
Fill-Or-Kill (fok)
A Fill or Kill (FOK) order is only executed if the entire order quantity can be filled, otherwise, the order is canceled. This TIF is similar to Immediate-Or-Cancel but the key difference is that the whole order must be filled. This can make FOK orders simpler to think about because the only two outcomes are that every share and all money is exchanged, or none of those are.
One reason you may want to use FOK is if you want to ensure that your order resolves immediately. As an example, we’ll try to sell some Tesla ($TSLA) stock with a FOK limit sell at a price just a little above the latest ask price.
# Submitting a limit sell for Tesla using FOK to ensure immediate execution
symbol = "TSLA"
qty = 5
type ="limit"
side = "sell"
time_in_force = "fok"
limit_price = 920
client_order_id=f"gcos_{random.randrange(100000000)}"
alpaca.submit_order(
symbol,
qty=qty,
type=type,
side=side,
time_in_force=time_in_force,
limit_price=limit_price,
client_order_id=client_order_id
)
Conclusion
Alpaca offers many tools for exercising control over order submission. Knowing the behavior of different order types and time in force designations is a crucial piece of fundamental knowledge that is part of the transition from a newbie to an experienced investor. With any luck, these examples will help give you experience when it comes time for you to make moves within your portfolio.
Please note that this article is for educational and informational purposes only. All screenshots are for illustrative purposes only. Alpaca does not recommend any specific securities or investment strategies.
All investments involve risk and the past performance of a security, or financial product does not guarantee future results or returns. Keep in mind that while diversification may help spread risk it does not assure a profit, or protect against loss, in a down market. There is always the potential of losing money when you invest in securities, or other financial products. Investors should consider their investment objectives and risks carefully before investing.
Alpaca does not prepare, edit, or endorse Third Party Content. Alpaca does not guarantee the accuracy, timeliness, completeness or usefulness of Third Party Content, and is not responsible or liable for any content, advertising, products, or other materials on or available from third party sites.
Brokerage services are provided by Alpaca Securities LLC ("Alpaca"), member FINRA/SIPC, a wholly-owned subsidiary of AlpacaDB, Inc. Technology and services are offered by AlpacaDB, Inc.
This is not an offer, solicitation of an offer, or advice to buy or sell securities, or open a brokerage account in any jurisdiction where Alpaca is not registered (Alpaca is registered only in the United States).