I have never used a custom window and don’t want to really look at this long post, but I got you. I mean ChatGPT got you. 
You’re actually very close — the missing pieces are mostly wiring and order setup, not the fact that you’re using XAML.
NinjaTrader does support using ATM from an AddOn, but there are a couple of “gotchas” that aren’t obvious until you compare against the official AddOn framework examples.
Below I’ll walk through:
- How the ATM selector is supposed to be initialized in a XAML AddOn
- What StartAtmStrategy requires to actually fire
- Direct answers to your specific questions / hypotheses
1. Why your ATM templates only show after pressing Save
The behavior you describe (templates only appearing after Save) is a classic symptom of the ATM selector not being fully initialized with:
- an Id
- a valid Account binding
- proper hosting in an NTWindow / NTTabPage context
NinjaTrader’s official “Creating Your Own AddOn Window” example includes an ATM Strategy selector and shows exactly what they expect you to do in code-behind. (NT)
Key requirements from that sample:
a. XAML: use the official AtmStrategySelector
<AtmStrategy:AtmStrategySelector
x:Name="atmStrategySelector"
LinkedQuantity="{Binding ElementName=qudSelector, Path=Value, Mode=OneWay}"
Grid.Row="12"
Grid.Column="2">
<AtmStrategy:AtmStrategySelector.Margin>
<Thickness Left="{StaticResource MarginButtonLeft}"
Top="{StaticResource MarginControl}"
Right="{StaticResource MarginBase}"
Bottom="0" />
</AtmStrategy:AtmStrategySelector.Margin>
</AtmStrategy:AtmStrategySelector>
The important part is not the layout — it’s that you’re using AtmStrategySelector from NinjaTrader.NinjaScript.AtmStrategy in a NinjaTrader-themed window (NTWindow).
b. Code-behind: set Id and bind Account
From the same help page: (NT)
private AtmStrategy.AtmStrategySelector atmStrategySelector;
private AccountSelector accountSelector; // NT’s account selector control
void InitControls(object pageContent)
{
// Find ATM selector in visual tree
atmStrategySelector = LogicalTreeHelper.FindLogicalNode(
pageContent, "atmStrategySelector") as AtmStrategy.AtmStrategySelector;
if (atmStrategySelector != null)
{
// 1) Give the selector a unique Id
atmStrategySelector.Id = Guid.NewGuid().ToString("N");
// 2) Wire events *if* you need them
atmStrategySelector.CustomPropertiesChanged += OnAtmCustomPropertiesChanged;
// 3) Bind the Account property to your AccountSelector
atmStrategySelector.SetBinding(
AtmStrategy.AtmStrategySelector.AccountProperty,
new Binding
{
Source = accountSelector,
Path = new PropertyPath("SelectedAccount")
});
}
}
That binding line is not optional – NinjaTrader explicitly says:
“Be sure to bind our account selector to our ATM strategy selector to ensure proper functionality.” (NT)
If Account is null or never bound when the selector is created, it can behave like:
- No templates visible initially
- Templates appear only after doing something that forces the ATM system to re-load state (e.g., saving a new template through the dialog)
c. Host it in an NTWindow / NTTabPage on the NinjaTrader dispatcher
The official AddOn pattern is:
- Custom window class inherits
NTWindow
- Tab content inherits
NTTabPage
- The Control Center launches your window via
Core.Globals.RandomDispatcher.BeginInvoke(() => new AddOnFrameworkWindow().Show()); so it is created on the correct UI dispatcher (NT)
If you instead created a bare WPF Window or are showing your XAML on a non-NT dispatcher, the controls may not be fully integrated with the platform’s services (workspaces, linking, ATM template manager, etc.).
Action items to fix template loading:
- Confirm your main window is an
NTWindow and your panel class is an NTTabPage (or at least directly inside one).
- Ensure you:
- set
atmStrategySelector.Id = Guid.NewGuid().ToString("N")
- bind
AtmStrategySelector.Account to a valid AccountSelector.SelectedAccount as in the sample
- Make sure you’re launching the window using the NT pattern (e.g. from
OnWindowCreated with RandomDispatcher.BeginInvoke) rather than with new Window().Show() from an arbitrary WPF thread. (NT)
- Verify that you’re connected to a data provider and that a real account is selected – NinjaTrader explicitly notes that accounts/templates in AddOns only populate when connected. (NinjaTrader Forum)
Once those pieces are correct, the ATM selector will normally show all existing templates immediately, just like SuperDOM / Chart Trader.
2. Why StartAtmStrategy() isn’t actually starting anything
Here are the hard requirements from the StartAtmStrategy AddOn reference: (NT)
NinjaTrader.NinjaScript.AtmStrategy.StartAtmStrategy(
AtmStrategy atmStrategyTemplate,
Order entryOrder);
NinjaTrader.NinjaScript.AtmStrategy.StartAtmStrategy(
string atmStrategyTemplateName,
Order entryOrder);
a. The entryOrder.Name must be exactly "Entry"
The docs are very explicit:
“Critical: The name argument on the CreateOrder() method MUST be named Entry for the ATM Strategy to be started successfully.” (NT)
So if you’re doing something like:
account.CreateOrder(instr, OrderAction.Buy, OrderType.Market,
TimeInForce.Day, 1, 0, 0, string.Empty, "LongEntry", null);
and then passing that order to StartAtmStrategy(), the ATM will never start, and the order will likely just sit there in an “Initialized” state.
You need:
entryOrder = account.CreateOrder(
myInstrument,
OrderAction.Buy,
OrderType.Market,
TimeInForce.Day,
1, // quantity
0, 0, // limit/stop prices for market order
string.Empty, // oco
"Entry", // <-- MUST be exactly "Entry"
null);
and then:
NinjaTrader.NinjaScript.AtmStrategy.StartAtmStrategy("MyAtmTemplateName", entryOrder);
The official AddOn example does exactly that (CreateOrder with name "Entry", then StartAtmStrategy("myAtmStrategyName", entryOrder)). (NT)
b. You must use an Order created from a valid Account and Instrument
From the same example, they:
- Find an account (e.g.,
Sim101) by scanning Account.All
- Create the order using that account and a valid instrument symbol
- Immediately pass that
entryOrder into StartAtmStrategy (NT)
So in your AddOn:
account must not be null
instrument must not be null (and should be the same as your UI / chart you intend to trade)
- The account should be connected; otherwise orders can also stall in non-working states.
c. You do not manually call Submit() on the Order when using StartAtmStrategy
StartAtmStrategy() itself is what submits the entry order together with the ATM logic. If you’re doing:
account.Submit(entryOrder);
AtmStrategy.StartAtmStrategy(..., entryOrder);
you’re now in undefined territory – the ATM engine expects to own that submission call.
d. Differences AddOn vs. Strategy
- In a strategy, you usually use
AtmStrategyCreate() / AtmStrategyStart() style methods and work inside OnBarUpdate. (NT)
- In an AddOn, you use
Account.CreateOrder(...) + AtmStrategy.StartAtmStrategy(...) as shown above. (NT)
The ATM core itself is the same – there is no special dispatcher or AddOn restriction documented, beyond using the correct API.
e. Debugging checklist for your case
When you click whatever button calls StartAtmStrategy:
- Look at Control Center → Orders tab
- Do you see an order appear?
- Is its state
Initialized, Working, or something else?
- Look at Control Center → Log tab
- Any messages about ATM, templates, routing errors, “Instrument not enabled”, etc.?
- Confirm at runtime:
entryOrder.Name == "Entry"
entryOrder.Account is the account you think it is
entryOrder.Instrument is the right instrument
- The ATM template name you pass exists exactly as saved (case-sensitive).
If the order appears but stays in Initialized, almost always it’s either:
- wrong name (
"Entry" requirement), or
- no valid connection/account/instrument routing.
3. Direct answers to your specific questions
Is there a specific requirement or initialization call needed when embedding ATM Strategy UI controls inside a custom XAML add-on window?
Yes, but not a “global ATM init” – it’s about control wiring:
- Use
AtmStrategySelector inside an NTWindow / NTTabPage
- Set
atmStrategySelector.Id = Guid.NewGuid().ToString("N") (NT)
- Bind
AtmStrategySelector.Account to your AccountSelector.SelectedAccount
- Optionally bind linked quantity, TIF selector, and instrument linking as per the AddOn framework sample (NT)
If any of those are missing, you can get partial or delayed behavior like you’re seeing.
Does the ATM subsystem require a particular dispatcher context when used inside a custom WPF window?
- NinjaTrader expects UI to be created on its own dispatcher; the official pattern is
Core.Globals.RandomDispatcher.BeginInvoke(() => new AddOnFrameworkWindow().Show()); from OnWindowCreated. (NT)
- If you spin up your own arbitrary WPF
Window from a background thread, that is not supported and can cause subtle issues (including controls not talking to platform services correctly).
So: stick to NTWindow / NTTabPage and the RandomDispatcher pattern and you’re fine.
Is there a known issue where ATM templates do not populate unless SaveStrategy() is invoked at least once?
Not as an official, documented bug.
What is documented is:
- ATM selector relies on proper Account binding and context (see sample). (NT)
- You must be connected and have accounts available; otherwise templates/accounts may not populate in an AddOn. (NinjaTrader Forum)
If Save makes them appear, that almost always means the selector was not fully initialized with the correct Account/Id when the dialog first loaded.
Does StartAtmStrategy() require a specific event sequence or dependency when invoked from an AddOn vs. a strategy?
The requirements are the same, but the pattern is:
- In AddOn:
- Find an
Account
CreateOrder(...) with name "Entry"
StartAtmStrategy(templateName, entryOrder)
- In Strategy:
- Use strategy-scoped ATM methods (e.g.,
AtmStrategyCreate) inside OnBarUpdate etc.
Critical dependencies:
entryOrder must come from Account.CreateOrder
entryOrder.Name must be "Entry" (NT)
- You must be connected with a valid route for that instrument and account.
No extra dispatcher/event prerequisites beyond that.
Are there limitations with loading ATM templates before the window is fully initialized?
Nothing explicit in the docs, but practical guidelines:
- Don’t try to interact with
atmStrategySelector until after your XAML is loaded and you’ve run the “find & bind” logic (often in the tab’s constructor or Loaded event).
- Ensure
AccountSelector has a selected account by the time the selector is initialized.
- If you rely on workspace restoration, also implement
IWorkspacePersistence on your NTWindow as in the sample. (NT)
4. A minimal “known good” pattern you can compare against
Here’s a stripped-down version that you can compare line-for-line with your Command Terminal XL:
public class CommandTerminalTab : NTTabPage
{
private AccountSelector accountSelector;
private AtmStrategy.AtmStrategySelector atmStrategySelector;
private Account account;
private Instrument instrument;
public CommandTerminalTab()
{
var page = new CommandTerminalPage(); // your XAML root
Content = page;
var pageContent = page.Content as DependencyObject;
// Account selector
accountSelector = LogicalTreeHelper.FindLogicalNode(
pageContent, "accountSelector") as AccountSelector;
// ATM selector
atmStrategySelector = LogicalTreeHelper.FindLogicalNode(
pageContent, "atmStrategySelector") as AtmStrategy.AtmStrategySelector;
if (atmStrategySelector != null && accountSelector != null)
{
atmStrategySelector.Id = Guid.NewGuid().ToString("N");
atmStrategySelector.SetBinding(
AtmStrategy.AtmStrategySelector.AccountProperty,
new Binding
{
Source = accountSelector,
Path = new PropertyPath("SelectedAccount")
});
}
// Instrument can come from an InstrumentSelector or be injected
instrument = Cbi.Instrument.GetInstrument("ES 03-26");
// For demo: fire an ATM on construction
StartSampleAtm();
}
private void StartSampleAtm()
{
if (accountSelector?.SelectedAccount == null || instrument == null)
return;
account = accountSelector.SelectedAccount;
var entryOrder = account.CreateOrder(
instrument,
OrderAction.Buy,
OrderType.Market,
TimeInForce.Day,
1,
0, 0,
string.Empty,
"Entry", // <-- critical
null);
NinjaTrader.NinjaScript.AtmStrategy.StartAtmStrategy(
"MyAtmTemplateName", // must exist in ATM templates
entryOrder);
}
}
If that pattern works in your environment but your full Command Terminal XL doesn’t, it narrows the issue to:
- where your window is hosted / created,
- missing Id / Account binding, or
- how you’re building the
entryOrder you pass into StartAtmStrategy.
If you’d like, you can paste your AtmStrategySelector XAML and the C# block where you:
- locate the selector,
- bind the account, and
- call
StartAtmStrategy,
and I can go through it line-by-line and annotate what to change.