Yesterday my exit order through API hit a problem: placed a MARKET BUY with market protection of -1 to close a short, price moved against me quickly, the market protection (default ~3% on options ₹10-₹100) clipped it into a stale LIMIT, and the order never filled.
To redesign exits more reliably, I tested LIMIT orders today with my own positions:
LIMIT SELL at ₹0.05 on a NIFTY option with LTP ₹217 → REJECTED with “Price exceeds circuit limits for the instrument. Place an order within the daily range.”
LIMIT SELL at ₹100 on the same option → also REJECTED with the same message (even though the displayed circuit limits in Kite UI were ₹0.05 to ₹785.85, so ₹100 is clearly inside)
LIMIT SELL at ₹135 (~LTP x 0.62) → ACCEPTED, filled at LTP
Premium > ₹50: limit must be within Reference Price ± 40%
Premium ≤ ₹50: limit must be within Reference Price ± ₹20 (absolute)
Reference Price = simple average of trade prices in the last 30 seconds
When orders breach LPP they get rejected, but the error message just says “circuit limits”, which is misleading.
What I’m considering:
Compute the reference price myself from a 30-second rolling window of WebSocket trade ticks, then place LIMIT exits just inside the LPP boundary. For example, for a buy exit on a ₹100 option: LIMIT BUY at RP x 1.38 (slightly inside the RP x 1.40 LPP ceiling).
Questions:
Is computing RP locally overkill? Is there a simpler approximation, like LIMIT BUY at LTP x 1.10 (i.e. 10% buffer), does that works reliably enough in practice?
What buffer values do you actually use? Real numbers from people running live algos would be very helpful.
Does anyone use MARKET orders with explicit market_protection (e.g. 35 or 100) as a fallback? Do those actually bypass LPP at the matching engine, or face the same rejection?
How often do you hit the LPP rejection on liquid index options? During normal hours? On expiry day?
@Zerodha folks, what’s the official recommendation to reliably get into order books and exit? Market order with market protection doesn’t look reliable. Is Limit order with LPP boundary reliable as per the mechanism in NSE circular?
If you’re using default market protection (-1), Zerodha auto-calculates the protection range on the backend.
If you want more control, you can try custom market protection; you just set the % yourself (like 2%, 5%, 10%, etc.). You can check the details here.
Under the hood, it’s pretty similar to placing a limit order with a buffer, since both are basically defining a price range instead of going as a pure market order.
Just keep in mind: This improves the chances of getting filled, but doesn’t guarantee execution.
@nivas_k , what happens when Reference Price drifts significantly from LTP? If the gap is more than 40%, how are we supposed to place the order since any buffer will be already out of LPP range? For instance, let’s say,
At time T, LTP is 10, RP is also 10. I have a Sell position open at 10.
Now say, from T + 20 to T + 30, LTP suddenly moves significantly, let’s say it moves to 50 which can happen with option prices during expiry. RP will be mean average of LTP of rolling 30 seconds window, right? So it will be around 25-35 something depending upon when the extreme movement happened in those 30 seconds. Even if consider it to be 35, the LPP bound will be 35 + 40% = 49. 49 is less than current LTP.
If I place the buy order below LTP i.e. <= 49, my order will be accepted, but it won’t fill. It stays open. My short position is at risk.
If I place the buy order even at LTP or above it i.e. >= 50, it will be rejected since it’s out of bound, right? So how am I supposed to exit my short. I’m essentially stuck with huge risk.
Most traders won’t know this and they will keep getting rejections until the broker or NSE decides to do something about it.
How is this safe then for traders, and especially for Algo traders who might not be near there screens?
@nivas_k , there are also no clear guidelines around custom market protection. The document mentions any value from greater than 0 to 100 is allowed. But if LPP bound is 40%, would you allow custom market protection higher than 40%? Theoretically, the order will be rejected, no?
It will in few cases, if price is 5 rs then 100% protection won’t reject the order but if price is 40 then 100% protection market order will be rejected, so based on price one should send orders as you are aware of these ranges.
@siva , understood. Can this be documented clearly? i.e. market order with 100% protection has to respect the LPP (limit price protection) range.
Also, could you respond to my other concern, that’s way important to know because that touches the order reliability part. Our orders can get rejected plainly because the reference price drifted from LTP and we wouldn’t know exactly how much and what range should we decide on before placing the order through the API? It’s like complete blackbox unless we ourselves calculate reference price and try to get in the order book, but even in that case, the order can just stay Open if the LTP has moved beyond the allowed LPP (limit price protection) range.
But this is same for manual trading also, but here user will see it and place the order again, similarly in API this has to be coded based on rejection.
We are working on to give ranges but even then that is not 100% fool proof as prices can change with in milliseconds.
I have coded the retry logic. The problem is, I’m not sure if that would work when it will be most needed to work. Based on what you know and how this works internally, could you confirm if what I’m doing it right to improve chances of order getting into the order book and fill/
Place order with LPP range 20% (LTP > 50) or flat 15 (LTP <= 50).
If rejected with specific LPP message (i.e. message matches terms like “circuit”, “LPP”, “Limit Price Protection”), retry with narrow LPP 10% (LTP > 50) or flat 8 (LTP <= 50).
If Open or Open with partial fill, modify with LPP 10% (LTP > 50) or flat 8 (LTP <= 50).
I’m doing only one retry. If that fails, the system will alert me and then I’ll have to manually rectify this problem by accessing Kite and working with the order.
You would have noticed I have to rely on error text matching. It’s fragile, but the API doesn’t seem to give any better option. There is no specific error code from Kite API that I can map this logic to. Even the API error text is ambiguous. It indicates Circuit issue, however it’s really the LPP range issue. The error text is not even matching what the NSE circular mentions.
Why is this so unreliable and ambiguous? How are you guys ok with this? Without reliability in place, the API won’t have much takers. If such issues are coming from NSE itself, it has to be taken up.
Not sure how can I automate this reliably given the state of the API.