Hello,
I’m building a custom NinjaTrader 8 Indicator has a “Breakeven” button. Clicking it should move the working stop-loss order’s price to the position’s entry price, on demand, at whatever moment I choose — this is meant to be fully discretionary, not the ATM template’s built-in Auto Breakeven
Setup
- Entries go through ChartTrader with an ATM Strategy template selected (e.g. “TP 60 SL 45”, plain static bracket, no Auto Breakeven/Trail). ChartTrader creates the ATM strategy — my script never gets an
atmStrategyId.
- On Breakeven click, I find the working
Stop1 order, set ord.StopPrice to entry price, and call acct.Change(stopOrders).
What I’ve found
- Debug confirms the right order and price are set,
Change() returns with no exception — but ord.StopPrice reverts to the old value immediately after, and the Control Center log never shows a new Accepted at the new price. So the change is silently discarded.
AtmStrategy.ChangeAtmStrategyStopTarget (and related methods) aren’t available from an Indicator (CS0117 on compile).
- Manually dragging the stop or editing its price in Control Center both work fine — only the scripted
Account.Change() fails.
My question
Is Account.Change() simply not meant to work on ATM-owned orders? Is there a supported way to reprice an ATM-owned stop from a script (short of cancelling/resubmitting it as a plain order)?
Thanks for any guidance.
It works for me in some of my scripts, I haven’t looked at ninjascript for a couple months so I’m a bit rusty but here is a snippet from one of mine:
// MODIFY EXISTING STOP ORDER
else if (_order != null && PositionMode(_side) && WorkingMode(_side))
{
if (_order.OrderType == OrderType.StopMarket && _order.OrderState == OrderState.Accepted && // Stop Order = Accepted / Limit Order = Working
((_side == Enum_Side.Long && _order.OrderAction == OrderAction.Buy) || // These 2 lines are extra precaution to make sure
(_side == Enum_Side.Short && _order.OrderAction == OrderAction.SellShort))) // ... a Short Trigger doesn't modify a the Stop of Long Order
{
// New Stop Price
_order.StopPriceChanged = stopPrice;
// Make the Change
myAccount.Change(new[] { _order });
PrintAE("CHANGED STOP ORDER" + _order.Name);
}
}
This works for me on ATM orders, you don’t need to get the ATM Strategy ID, you can if you want but doesn’t seem to be needed. Are you sure your Account variable is set correctly?
Also, there is actually a shortcut in NT prefs that moves stops to BE. You can map this to a shortcut key and then simply have your button mimick this shortcut, if you wanted.
1 Like
your code example help me to make it work, the error was in stop.price instead of stoppricechanged
Thank you!
The important field is StopPriceChanged, not StopPrice. StopPrice is the current acknowledged value. Account.Change() reads the Changed fields as the amendment request.
Round the position entry price to the instrument tick size, assign that value to ord.StopPriceChanged, then pass ord to acct.Change().
Use Account.OrderUpdate as the receipt. Log state, error or comment, StopPrice, StopPriceChanged, account and instrument until the order returns to Accepted or Working at the new price. Do not infer success from Change() returning because the order update is asynchronous.
The NinjaTrader Help Guide’s Account.Change() example uses StopPriceChanged in the same way.
So the immediate revert is consistent with writing StopPrice directly and the next platform update restoring the acknowledged value. It does not by itself show that ATM ownership blocks Account.Change(). I would avoid cancel and resubmit because that can disturb the ATM or OCO relationship.