Orders
An order is the way a trader manages positions in the dYdX markets. Different types of orders exist to support different trading strategies.
Short-term vs Long-term
Short-term orders are short-lived orders that are not stored on-chain unless filled. These orders stay in-memory of the network validators, for up to 20 blocks, with only their fill amount and expiry block height being committed to state. Short-term orders are mainly intended for use by market makers with high throughput or for market orders.
Long-term orders are “stateful orders” that are committed to the blockchain. Long-term orders encompass any order that lives on the orderbook for longer than the short block window. The short block window represents the maximum number of blocks past the current block height that a short-term MsgPlaceOrder
or MsgCancelOrder
message will be considered valid by a validator. Currently the default short block window is 20 blocks.
Comparison
Short-term | Stateful | |
---|---|---|
purpose | Short-lived orders which are meant to placed immediately (in the same block the order was received). These orders stay in-memory up to 20 blocks, with only their fill amount and expiry block height being committed to state. Intended for use by market makers with high throughput, or for market orders. IoC and FoK orders are also considered short-term orders. Short-term orders do not survive a network restart.
| Long-lived orders which may execute far in the future. These orders should not be lost during a validator restart (placed in the block after the order was received). In the event a validator restarts, all stateful orders are placed back onto the in-memory orderbook. Likely to be used primarily by retail traders. The front end would be sending stateful orders for all order types other than market orders. Two types of stateful orders: 1. Long-Term Orders • meant to be added to the orderbook as soon as possible. Due to certain technical limitations, long-term orders are placed in the block after they are written to state. E.g. if MsgPlaceOrder is included in block N, taker order matching would occur for the long-term order in block N+1.• Order types requiring immediate execution such as fill-or-kill / immediate-or-cancel are disallowed as these should be placed as short term orders; Long-term FoK/IoC orders would never be maker orders, so there is no benefit to writing them to state. 2. Conditional Orders • execute when the oracle price becomes either LTE or GTE to specified trigger price, depending on the type of conditional order (e.g. stop loss sell = LTE, take profit buy = GTE) • orders are placed in the block after their condition is met and they become triggered • it is possible for a conditional order to become triggered in the same block they are initially written to state in. Conditional orders are placed in block ≥ N+1. |
placement message | MsgPlaceOrder | MsgPlaceOrder , long term or conditional order flag enabled on MsgPlaceOrder.Order.OrderId.OrderFlags • valid OrderFlags values are 32 (conditional) and 64 (long-term) for stateful orders |
cancellation message | MsgCancelOrder Short term cancellations are handled best-effort, meaning they are only gossiped and not included in MsgProposedOperations | MsgCancelOrder , long term or conditional order flag enabled on MsgCancelOrder.OrderId.OrderFlags |
expirations | Good-Till-Block (GTB) Short term orders have a maximum GTB of current block height + ShortBlockWindow. Currently this value is 20 blocks, or about 30 seconds. Short term orders can only be GTB because in the interest of being resilient to chain halts or slowdowns. | Good-Till-Block-Time (GTBT) Stateful orders have a maximum GTBT of current block time + StatefulOrderTimeWindow. Currently this value is 95 days. GTBT is used instead of GTB to give a more meaningful expiration time for stateful orders. |
inclusion in block | OperationRaw_ShortTermOrderPlacement inside MsgProposedOperations.OperationsQueue which is an app-injected message in the proposal. Included if and only if the short term order is included in a match. | Normal cosmos transaction. The original Tx which included the MsgPlaceOrder or MsgCancelOrder would be included directly in the block. |
signature verification | Short-term orders must undergo custom signature verification because they are included in an app-injected transaction. The memclob stores each short term order placement’s raw transaction bytes in the memclob. When the order is included in a match, an OperationRaw_ShortTermOrderPlacement operation is included in MsgProposedOperations which contains these bytes.During DeliverTx , we decode the raw transaction bytes into a transaction object and pass the transaction through the app’s antehandler which executes signature verification. If signature verification fails, the MsgProposedOperations execution returns an error and none of the operations are persisted to state. Operations for a given block is all-or-nothing, meaning all operations execute or none of them execute. | Normal cosmos transaction signature verification, executed by the app’s antehandler. |
replay prevention | Keep orders in state until after Good-Till-Block aka expiry (even if fully-filled or cancelled) | Cosmos SDK sequence numbers, verified to be strictly increasing in the app’s antehandler. Note that their use of sequence numbers requires stateful orders to be received in order otherwise they would fail. If placing multiple stateful orders they should be sent to the same validator to prevent issues. |
time placed (matching logic) | CheckTx , immediately after placement transaction is received by the validator.Short term orders are only included in a block when matched. See “time added to state” below. | long-term: Block N+1 in PrepareCheckState where MsgPlaceOrder was included in block Nconditional: Block N+1 PrepareCheckState where the order was triggered in EndBlocker of block N |
what is stored in state | OrderAmountFilledKeyPrefix :• key = OrderId • value = OrderFillAmount & PrunableBlockHeight BlockHeightToPotentiallyPrunableOrdersPrefix :• key = block height • value = list of potentially prunable OrderIds PrunableBlockHeight holds the block height at which we can safely remove this order from state. BlockHeightToPotentiallyPrunableOrders stores a list of order ids which we can prune for a certain block height. These are used in conjunction for replay prevention of short term orders | StatefulOrderPlacementKeyPrefix :• key = OrderId • value = Order StatefulOrdersTimeSlice :• key = time • value = list of OrderIds expiring at this GTBT OrderAmountFilledKeyPrefix :• key = OrderId • value = OrderFillAmount & PrunableBlockHeight (prunable block height unused for stateful orders) |
time added to state | DeliverTx when part of a match included in MsgProposedOperations | StatefulOrderPlacementKeyPrefix and StatefulOrdersTimeSlice : DeliverTx , the MsgPlaceOrder is executed for MsgPlaceOrder msgs included in the block. The handler performs stateful validation, a collateralization check, and writes the order to state. Stateful orders are also written to the checkState in CheckTx for spam mitigation purposes.OrderAmountFilledKeyPrefix : DeliverTx, when part of a match included in MsgProposedOperations |
time removed from state | Always in EndBlocker based off of prunable block height | • cancelled by user: removed from state in DeliverTx for MsgCancelOrder • forcefully-cancelled by protocol: removed from state in DeliverTx when processing OperationRaw_OrderRemoval operation. This operation type is included by the proposer in MsgProposedOperations when a stateful order is no longer valid. Removal reasons listed here• fully-filled: removed from state in DeliverTx in the block in which they become fully filled. The order is added to RemovedStatefulOrderIds of processProposerMatchesEvents to be used in EndBlocker to remove from the in-memory orderbook.• expired: pruned during EndBlocker based off of GTBT also removed from state in CheckTx for cancellations. This is for spam mitigation purposes. |
time added to in-memory orderbook | When placed in CheckTx , if not fully-matched | When placed in PrepareCheckState , if not fully-matched |
time removed from in-memory orderbook | • when fully-filled: removed in PrepareCheckState where invalid memclob state is purged via fully filled orders present in OrderIdsFilledInLastBlock • when cancelled: (CheckTx) • when expired: PrepareCheckState, removed using memclob.openOrders.blockExpirationsForOrders data structure which stores expiration times for short term orders based off of GTB | • when fully-filled: removed in PrepareCheckState where we purge invalid memclob state based off of RemovedStatefulOrderIds • when cancelled: removed in PrepareCheckState based off of PlacedStatefulCancellations • when expired: removed in PrepareCheckState by PurgeInvalidMemclobState , using the list of ExpiredStatefulOrderIds produced in EndBlocker |
Types
Currently, dYdX supports 6 different order types:
- Market Order
- Limit Order
- Stop Market Order
- Stop Limit Order
- Take Profit Market Order
- Take Profit Limit Order
Market Order
A Market Order is an order to buy or sell a given asset and will execute immediately at the best price dependent on the liquidity on the other side of the order book. By default, the front end submits market orders as Immediate-or-Cancel orders, meaning the order will fill immediately (matched against the other side of the order book) and any part that isn’t filled will be canceled. Market orders are also used to close positions. For closing positions, the order is submitted as an Immediate-or-Cancel order.
Limit Order
A Limit Order is an order to buy or sell a given asset at a specified (or better) price. A limit order to buy will only execute at the limit price or lower, and a limit order to sell will only execute at the limit price or higher.
Stop Market Order
A Stop Market Order protects against losses by closing a trader’s position once the Oracle Price or the last traded price* crosses the trigger price. The trigger price can be triggered by either the Oracle Price or the last traded price*. Stop market orders can be used to limit losses on a trader’s positions by automatically closing them when the price falls below (for longs) or rises above (for shorts) the trigger price.
Once triggered, the resulting market order will be immediately filled at the best price on the books.
Stop Limit Order
A Stop Limit Order will execute only when the Oracle Price or the last traded price* crosses a specified Trigger Price. The trigger price can be triggered by either the Oracle Price or the last traded price*. Stop limit orders can be used to limit losses on a trader’s positions by automatically closing them when the price falls below (for longs) or rises above (for shorts) the trigger price.
Once triggered, the resulting limit order may either be immediately filled or may rest on the orderbook at the limit price. The limit price operates exactly the same as for normal limit orders.
Take Profit Market Order
Take Profit Market orders allow traders to set targets and protect profits on positions by specifying a price at which to close an open position for profit. Take profit market orders lock in profits by closing a trader’s position once the Oracle Price or last traded price* crosses the trigger price.
For a long position, a trader places a stop above the current market price. For a short position, a trader places the stop below the current market price. Stop limit orders can be used to limit losses on a trader’s positions by automatically closing them when the price falls below (for longs) or rises above (for shorts) the trigger price.
Take Profit Limit Order
Take Profit Limit orders allow traders to set targets and protect profits on positions by specifying a price at which to close an open position for profit. Take profit limit orders enable profit taking like take profit market orders, but with the versatility and control of a limit order.
For a long position, a trader places a take profit limit above the current market price. For a short position, a trader places the trigger below the current market price. If the Oracle Price or last traded price* rises/drops to take-profit point, the T/P order changes from 'Untriggered' -> 'Open', and then behaves as a traditional limit order. Take-profit orders are best used by short-term traders interested in managing their risk. This is because they can get out of a trade as soon as their planned profit target is reached and not risk a possible future downturn in the market.