I have found this problem twice already in paper trading. It happens rarely, maybe once a month, out of thousands of correctly executed bracket orders. The problem here is not a pattern-day trading restriction, the paper account has > $25K.
The general situation is as follows:
Bracket order to enter a long position executes successfully. It buys 10 shares at $50 each
Exit orders are successfully submitted:
Take-profit order: sell 10 shares at $55 or more (limit order)
Stop-loss order: sell 10 shares immediately if the price falls below $45 (market order)
So far, so good. But then,
the price hits $55 and the take-profit order triggers. However, it only fills partially, and sells 6 shares at $55. I am left with 4 shares.
This is the big problem: the price fluctuates throughout the day, even dropping well below $45. However, Neither the Take-profit nor the Stop-loss orders trigger, and the 4 remaining shares are not sold.
I can only speculate as to what the problem is. The documentation on bracket orders (Understand Orders | Alpaca Docs) states that: “Importantly, only one of the two exit orders can be executed.” I wonder if restrictions around this condition are creating a bug: Maybe once the take-profit order (in my case) executes partially, the code prevents the stop-loss from ever triggering? That, of course, would be a mistake. And, regarding the take-profit, maybe it would still sell the other 4 shares if the price kept rising? I don’t know if this happens, but given that the problem only presents sporadically, I wonder if the bulk of the times when there is a partial execution of an exit order this order fully fills shortly afterward, and the rare cases I have seen are when the price soon reverses direction and hence impedes the completion of the partially executed closing order?
Anyway, the last paragraph is only my guess. But the problem exists.
Thank you, and I really hope that this Topic doesn’t meet the fate of most support requests in this forum (i.e. complete disregard, neglect, or overlook)
@buysell Do you have an order ID (ideally the original parent order but any of the three orders is fine). I may be able to track down the specifics.
However, getting a partial fill is always possible for any order in both paper and live trading. The situation in (3) from the first post can very well happen
3. the price hits $55 and the take-profit order triggers. However, it only fills partially, and sells 6 shares at $55. I am left with 4 shares.
If the price never goes back above $55 then the limit order will never fill any more. That should be expected. If the price never drops below $45 then the stop-loss order will never trigger and it won’t fill. Again, that should be expected.
The statement in (4) above is odd however
4. …the price fluctuates throughout the day, even dropping well below $45. However, Neither the Take-profit nor the Stop-loss orders trigger, and the 4 remaining shares are not sold.
The stop loss order should trigger if the price drops below $45. If you have an order number where it appears the stop-loss didn’t trigger I can do some research.
Yes, the unexpected behavior is under item 4 on the list.
Here are the order IDs from an OCO order (the position was previously opened with an ioc order, and consisted of 4 shares):
take profit order: 589f9f02-4edc-4dc3-828d-ce5be8206fd9
stop-loss order: 6b6b3df2-4d79-417e-aa68-75eb2b376057
Hopefully, you can see that the take profit order was partially filled (1 share), and throughout the day the price fell below the stop-loss price, but the stop-loss order was never executed. In fact, I hope you can see a flurry of replacement orders trying to sell the 3 remaining shares, but they were never executed.
@buysell You were wondering why the stop order never seemed to trigger. I looked at your sequence of orders which included the above sell stop-loss order: 6b6b3df2-4d79-417e-aa68-75eb2b376057. That was the original stop-loss order but then the stop price was updated/replaced over 100 times after that throughout the day. I am assuming the algo did that?
The issue is, most of the time, the new stop price was more than the current bid. For a sell order, the stop price must be lower than the current bid to be accepted.
Regardless of the reason why a trader is using a stop order, buy stop orders are always to be placed at or above the market price (asking price), while sell stop orders are always to be placed at or below the market price (bid). If a trader places a buy stop order below the current asking price it will get rejected. If a trader places a sell stop order above the current bid price, it will get rejected.
The paper trading platform doesn’t reject updates but rather waits until the stop price becomes valid and then effectively submits the change. In live trading, the replace request would be rejected.
Below is a screenshot of a portion of the replaced stop price along with the current bid at the time the replace was requested. Notice in most cases the revised price is greater than the bid. These would have been rejected in live trading.
Ensure the stop sell price is below the current bid price and the stop order will trigger as expected. Hope that helps.
Thank you for looking into this, I really appreciate it.
Regarding the replacement orders, yes, my algo was trying to exit the position–It is something I am still working on. Thank you so much for the explanation on stop orders vs market price. I am very surprised to hear you say that this is managed differently between paper and live trading, I thought the whole idea is that paper functions as live trading (minus the fees) so we can test our code. I was not aware of this difference, and I consider it very significant.
I am a little puzzled at the moment, I was expecting that those orders would be executed if the market price is lower than the stop price. As far as I know, there is no efficient way to know what the market price is (I think the Alpaca docs use the phrase “base price”?). Any insight would be appreciated, but I am getting off-topic!
On the issue I am reporting in this thread: I can guarantee you that I had seen the problem months before I started replacing orders, so I am sure that a replacement stop order is not the problem.
According to my logs, I saw the issue on Oct 12, 2022; and again on Nov 16, 2022. That is around the time I opened this thread, and after that I did not log any new events of this situation. I don’t have the order IDs for those cases, but I am sure those were bracket orders with no replacement. In those cases, the situation was exactly as I described it: the profit order was partially executed, the price dropped well below the stop price, but the stop loss order was never executed.
@buysell Regarding paper trading working a bit different than live. Yes, that’s true. It’s very close but not exact. A large difference is paper trading doesn’t implement any corporate actions like splits and dividends. There are also no margin or stock borrow fees added. However live isn’t always consistent either. Alpaca works with a number of execution parters who actually execute the trades. Each of them have a bit different rules and processes for handling orders. If an order is routed to one venue it may get a bit different errors and codes.
If you want to ensure your stop price is below the current quote one can check the current quote. That is typically what traders do. However, it sounds like you want your order to fill? If that is the case then replace the limit price of the limit order length to a ‘marketable’ price (ie a sell lower than the bid).
If you do see an order that doesn’t seem to trigger, please send an email to firstname.lastname@example.org and include the order number. They will be able to track down the issue. I’ll never say ‘never’ but orders not triggering isn’t a known issue.