Frequently, I need to update an initial order multiple times, mostly to catch up with a fast moving market. For the life of me I could not figure out how exactly the update mechanism works in Alpaca. It seems convoluted!
(In another API you would simply send a new limit price with existing order_id and that would be that)
Here are the steps I moved through. Could anyone please fill the rest in the rest?
api.submit_order(), returns Order object with “order_id_1”, “client_order_id_1”, status ACCEPTED
channel trade_updates receives order dictionary with “order_id_1”, “client_order_id_1”, status NEW
– time passes suppose the order does not fill or cancel
api.replace_order(“order_id_1”, new_price) returns “order_id_2”, “client_order_id_2”, status ACCEPTED ?
channel trade_updates receives order dictionary with “order_id_2”, “client_order_id_2”, status REPLACED
price moves fast, no fill, I want to update the order again
- api.replace_order(“order_id_2”, new_price) returns error “… order in replaced status cannot be changed…”
OK - spent more time with paper trading than I would have liked and figured how it works.
When you call
new_order = api.replace_order(order_to_update)
it returns a new order object, with a new unique order_id and order_client_id. Stick to these new ids, as you will refer to your updated order with these. Then a trade_update arrives with status=REPLACED and (order_id, client_order_id) of the ‘order_to_update’. This is formal confirmation that the update executed, you can now safely discard your order_to_update object, if you have not already done so.
Another little thing that threw me off when receiving trade_updates is that, the data.order field that arrives is a dictionary, whereas placing an order returns an object. I wish they were both either dictionary or preferably object. Two different implementations for the same concept. Well, at least the field names are the same.
@ Trader Joe,
I am not able to replace the order as well.
Please elaborate on the order_to_update item and an example with steps.
Rest object looks like it should be straight forward, but it is not.
Ok got it working. As Trader Joe mentioned, every order replacement will create a new client id. Although i didn’t see order_id change. So if your replace_order call has client id filled up, it will throw an error. Here is an example of what I use, and it worked. One pointer though, if using time_in_force make sure it is accepted condition for original order, for example changing ‘day’ to ‘opg’ on extended hours order will result in an error.
Is there a way to omit qty from replace_order and just replace the order for the remaining unfilled qty?
Suggest to pull it from order if you don’t want to update it, like below,
open_orders = api.list_orders()
for order in open_orders:
if order.symbol == your_stock:
This might work only if the order is on the exchange, i don’t know why we can’t change orders if are not on the exchange:
APIError: unable to replace order, order isn't sent to exchange yet