Hi,
In my strategy while I have set the tp sl, I am still checking for the breach of tp sl on OnMarketUpdate and and if my sl tp is breached I raise an event which the function that runs on the strategy thread catches and calls ExitLong or ExitShort with a new exist signal name and the correct from entry signal.
I notice that sometimes maybe due to race condition, maybe I called ExitLong just when say my stoploss was triggered…I end up getting Filled with volume 1 for both the exit order, my OnOrderUpdate is invoked for the stop loss order I had created while placing the order and also for my ExitLong order that I created to manually close the position.
Is this something specific to demo account, on live is it ever possible to get OnOrderUpdate invoked twice with fill volume 1 when I had only traded Volume 1 to begin with.
Thanks in advance.
Short answer: what you’re seeing is not strictly a “demo-only bug.”
If you have two separate exit orders working (your TP/SL order and a manual ExitLong/ExitShort), it is absolutely possible in live trading for both to fill a 1-lot position, leaving you flat then reversed. You should code as if this can happen and guard against it.
Now the why.
- Why you’re seeing two fills for a 1-lot trade
From what you described:
You submit an entry (qty 1).
You also submit a stop and/or target when you place the order.
Separately, in OnMarketUpdate you watch price, and when price “breaches” SL/TP you raise an event.
That event runs on the strategy thread and calls ExitLong / ExitShort with a new signal name using the correct fromEntrySignal.
So at the moment your stop is hit, you have:
A working stop order (e.g., stopOrder, qty 1), and
A new exit order from ExitLong/ExitShort (qty 1), both in the market at the same time.
When price trades through, both orders may be marketable:
The broker/exchange has no idea you intended only one of them to flatten the same 1-lot position.
It just sees “sell 1 at stop” and “sell 1 market/limit” and is allowed to fill both.
In Ninja’s event model:
Each order will generate its own OnOrderUpdate sequence for state transitions and fills. 
So you can see two OnOrderUpdate calls with orderState == OrderState.Filled and filled == 1 — one for the stop, one for the manual exit.
End result in the account:
Start: +1 long
Stop fills: 1 sell → flat
Manual Exit fills: another sell 1 → now -1 short
On the strategy side you see “but I only traded volume 1,” yet you have 2 fills of size 1, because you had 2 separate exit orders for that same position.
This is not a race condition bug so much as a genuine logic race: you’re letting multiple exits exist simultaneously.
- Demo vs live: can this really happen live?
NinjaTrader has three different “fill worlds”:
Backtest (Strategy Analyzer) – fills are synthetic, based purely on OHLC and internal algorithms. 
Simulation (Sim101 / demo) – fills are simulated from real-time data with an internal model and random delays. 
Live brokerage – fills are whatever the exchange / routing actually does; Ninja just reports executions. 
The docs and support explicitly say:
Multiple executions / partial fills can occur for a single order. 
Event ordering between OnOrderUpdate, OnExecutionUpdate, OnPositionUpdate is not guaranteed for some providers (e.g., Rithmic/IB). 
Given that, there’s nothing in live trading that magically prevents:
Two separate exit orders (each qty 1) from both filling against your one open contract.
Two OnOrderUpdate calls with a filled value of 1 (one per order).
So: Is this something specific to demo?
No. You might see it more often or in slightly different timing in Sim (because of the simulated fill engine), but the core behavior – “if you submit multiple independent exits, you can get multiple fills” – is absolutely possible live. You should assume it can happen and design your strategy to avoid it.
The only thing that prevents this in practice is OCO grouping or careful logic. If your stop and target are placed as an OCO pair, the broker cancels the sibling when one fills. But your extra ExitLong/ExitShort is not part of that OCO; so it’s a free agent and can fill as well.
- Why OnOrderUpdate is a fragile place to drive exit logic
NinjaTrader’s own guidance:
OnOrderUpdate is for tracking order state, errors, etc.
If you want to drive logic based on fills, use OnExecutionUpdate instead — “critical” per the docs. 
There is internal strategy logic that runs after OnOrderUpdate but before OnExecutionUpdate, so using OnOrderUpdate for fill-driven state can bite you. 
Right now you’re:
Watching price in OnMarketUpdate.
Then generating a second exit right when your protective SL/TP order is also about to be triggered.
This is exactly the pattern that creates races and double fills.
- Safer patterns to avoid double fills
You’ve got a couple of good options; all revolve around: never let two independent exits work at the same time for the same quantity.
Option A – Let your broker-side SL/TP do the work
If your TP/SL is already on the book, you usually do not need to watch price and manually exit when breached. The protective orders will fire by themselves.
So:
Place entry.
Submit SetStopLoss / SetProfitTarget or custom stop/target from OnExecutionUpdate once entry fills. 
Do not submit additional ExitLong/ExitShort from OnMarketUpdate at the same levels.
Use OnExecutionUpdate to detect that the stop/target was filled and update your strategy state.
This completely eliminates the race; there is only one exit per side.
Option B – Use a latch / flag so you only ever send one exit
If you do want logic like “if price breaches X, flatten now,” then:
- Add a flag:
private bool exitRequested = false; - In OnMarketUpdate:
if (Position.MarketPosition == MarketPosition.Long
&& !exitRequested
&& ShouldExitNow()) // your price-breach test
{
exitRequested = true;
ExitLong(“ManualExit”, “MyEntry”);
} - In OnExecutionUpdate, when you see the position flat:
if (Position.MarketPosition == MarketPosition.Flat)
{
exitRequested = false;
} - And crucially, if you already have a broker-side SL/TP working, cancel them before sending the manual exit, or don’t place them at all when using this logic.
Option C – Cancel protective orders before manual exit
If you keep the TP/SL orders and also want a manual close, then the sequence should be:
Detect your condition to close.
Cancel the existing stop and target orders (track them as Order objects and call CancelOrder).
After you get their OnOrderUpdate with OrderState.Cancelled, then submit your ExitLong/ExitShort.
That way you never have more than one active exit order with quantity 1.
- Practical takeaway for your question
On live is it ever possible to get OnOrderUpdate invoked twice with fill volume 1 when I had only traded Volume 1 to begin with?
For a single order, you can get multiple OnOrderUpdate calls as it moves through states; the filled parameter may show 1 both when it’s PartFilled and later Filled (depending on how you read it). 
For two different exit orders (stop + manual exit) each qty 1, yes, both can fill in live. There’s nothing in the platform or exchange that guarantees that won’t happen unless you explicitly use OCO groups or cancel one before sending the other. 
So your observation in sim is a very real warning that your current pattern can double execute in live too. It might be rare, but it’s absolutely possible.
Or…don’t mix managed and unmanaged modes.
Thanks for the detailed response, but I am seeing such random behaviour on demo that I am not sure how will i test my strategy before going live, and will these problems occur on live as well.
Today I have a clear statement in my log file that a sell order was filled on ES, but I do not see it at all in trade performance report, and on top of that the previous sell which was filled and on which i invoked SetStopLoss and SetTakeProfit after it was filled in OnOrderUpdate, tp sl was not set, and instead when the sl of the next order that i cant find in the trade performance report was applied to this earlier order which mysteriously stayed naked although i can clearly see that my setstoploss and settakeprofit was invoked. Meanwhile since i have another trader instance that trades these exact same signals on micro instrument on a different demo account…in that case the same code base is running and both orders properly got placed and properly exited according to the sl tp set by me. I am beggining to suspect that the Demo account provided by NinjaTrader that run locally on our machine is as much garbage is the Market replay which we all know is complete garbage. This was the reason I was manually double checking for breach of sl tp but as you correctly pointed out that leads to double exits causing more problems so after reading your response I removed that…but still everything looks rubbing in my trade performance report, Thanks.
SOLVED:
- OnOrderUpdate of my strategy gets invoked with the Filled volume
- an add-on of mine to log slippage throws an exception
- since the OnExecutionUpdate of the addon threw an exception the OnExecutionUpdate of my strategy is never invoked…so although in OnOrderUpdate I logged that my order was filled, I never receive the filled amount in OnExecutionUpdate because between the 2 calls my add on has thrown an exception in its OnExecutionUpdate (a pop up with an error message is also shown).
From this point onwards Trade Performance gets corrupted and shows some nonsense report.