ATM Strategies Not Loading or Triggering When Called From Custom Add-On

I’m working on a custom NinjaTrader 8 add-on called Command Terminal XL, which functions as a full trading command center. The add-on uses a WPF/XAML window (instead of a standard NinjaScript AddOn window) so that I can expose the ATM Strategy selection UI directly inside the panel.

I was able to successfully load the ATM Strategy Configuration dialog inside the add-on using XAML in combination with C#. The “Custom” button opens the ATM creation window correctly, and I am able to save new ATM templates from within my add-on. This part works fine.

However, I’m running into two issues:


1. ATM templates only populate after pressing Save

When the ATM dialog opens, the list of ATM strategies only updates after I press the “Save” button.
During normal loading of the add-on window, none of my ATM templates appear in the dropdown until a save is performed, which tells me the add-on is only communicating with the ATM subsystem for a brief moment.


2. Calling the ATM from the add-on does not trigger any trades

Even when I select an ATM and call:

atmStrategyId = AtmStrategy.StartAtmStrategy(...);

—or—

AtmStrategy.StartAtmStrategy(...)

(NT8 equivalent of atmStrategy.startAtmStrategy)

…no ATM is actually initiated. The ATM window loads fine, the template is selectable, but no ATM strategy triggers a trade when called from the add-on.


Details

  • The add-on is built in Visual Studio 2022 using XAML + C#.
  • Everything loads correctly when I open Command Terminal XL from the “New” menu.
  • Account selection, instrument binding, and UI interactions all function normally.
  • The ATM Strategy dialog opens inside the panel exactly as intended (something indicators and traditional add-ons cannot do without XAML).
  • The issue happens only at runtime: ATM strategies don’t load on startup, and StartAtmStrategy does not execute after selection.

What I’m trying to determine

Is there a specific requirement or initialization call needed when embedding ATM Strategy UI controls inside a custom XAML add-on window?

For example:

  • Does the ATM subsystem require a particular dispatcher context when used inside a custom WPF window?
  • Is there a known issue where ATM templates do not populate unless SaveStrategy() is invoked at least once?
  • Does StartAtmStrategy() require a specific event sequence or dependency when invoked from an AddOn vs. a strategy?
  • Are there limitations with loading ATM templates before the window is fully initialized?

Summary of the behavior

  • ATM window opens and saves correctly (inside the add-on).
  • ATM template list only refreshes after saving from the dialog.
  • StartAtmStrategy() is called but never triggers a trade.
  • ATM strategies do not load automatically when opening a new instance of the add-on.

Any insights from the NinjaTrader team or other developers who have integrated ATM logic into custom XAML add-ons would be greatly appreciated. I’m confident this is solvable since the ATM UI is loading inside the add-on, but it appears something is missing in the initialization pipeline.



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. :joy:

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:

  1. How the ATM selector is supposed to be initialized in a XAML AddOn
  2. What StartAtmStrategy requires to actually fire
  3. 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:

  1. Confirm your main window is an NTWindow and your panel class is an NTTabPage (or at least directly inside one).
  2. Ensure you:
  • set atmStrategySelector.Id = Guid.NewGuid().ToString("N")
  • bind AtmStrategySelector.Account to a valid AccountSelector.SelectedAccount as in the sample
  1. 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)
  2. 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:

  1. Find an account (e.g., Sim101) by scanning Account.All
  2. Create the order using that account and a valid instrument symbol
  3. 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:

  1. Look at Control Center → Orders tab
  • Do you see an order appear?
  • Is its state Initialized, Working, or something else?
  1. Look at Control Center → Log tab
  • Any messages about ATM, templates, routing errors, “Instrument not enabled”, etc.?
  1. 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:

  1. In AddOn:
  • Find an Account
  • CreateOrder(...) with name "Entry"
  • StartAtmStrategy(templateName, entryOrder)
  1. 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.

1 Like

Just FYI, you can also just ask the llm to look at the latest docs too for reference. Context7 - Up-to-date documentation for LLMs and AI code editors

3 Likes

Thanks for getting back to me, dude. I’ll check this out and see what’s up. I think the problem might be how my plugin loads at startup with the account info. Like, if I’m only connected to one account in the control panel, for some reason, when my plugin loads, it pulls every account it sees, even “old no sim 101,” which was the trader’s old name. It even pulls that one. How it’s doing that, I have no idea, but I think I need to put in some kind of filter. But I’ll still have to program it so it can figure out which one to pull. I might be able to filter it, but if I give this to someone else and it tries to filter it by the name I gave it, obviously that wouldn’t work because their demo account would look different than mine. But I’m getting better. I also hooked it up to an API module that lets me connect an AI model to the back of it because I was able to pull all the time and sales and depth of market data and route it through the plugin. That way, I could avoid paying for the order flow, and then I have the AI plotted on a custom chart I made, and I can see how price stacks up tick by tick on a custom candle chart.