The indicator does not need to exist in the chart. It can be hardcoded into the script that creates the button.
Announcement
Collapse
No announcement yet.
Partner 728x90
Collapse
NinjaTrader
ChartTrader button: new order and attach to an indicator
Collapse
X
-
ChartTrader button: new order and attach to an indicator
I have gone through the forums, and I see a number of solutions and addons that seem to do bit parts of what I want, but I have found it difficult to use their code. I believe what I want to do is really simple, and I just need some sample code to set me off in the right direction. Any assistance will be appreciated.
The indicator does not need to exist in the chart. It can be hardcoded into the script that creates the button.Tags: None
-
Chelsea,
Thanks for the response. I am testing this linked code now. I have follow-up questions:
1. How do I display the buttons in the ChartTrader panel instead of the charts
2. How can I make the orders executed on the currently selected account in the ChartTrader panel
3. When I place an order using this approach, I would like the currently active ATM strategy in the ChartTrader panel to be applied to it. How can I make this possible?Last edited by lanredocemo; 08-15-2024, 11:38 AM.
Comment
-
Hello lanredocemo,
Below is a link to the SampleWPFModifications reference sample which demonstrates adding buttons to the ChartTrader. See the regions labelled 'Use case #5: Custom chart trader buttons variables'.
To get the ChartTrader account selector this can be found by automationID. Below is a link to a support article with direction. See the code sample under the heading 'Getting the ChartTrader Account selector'.
This page also demonstrates getting the ChartTrader AtmSelector value. See the code sample under the heading 'Getting the AtmStrategy selector'.
Also, below is a link to the example.
Chelsea B.NinjaTrader Customer Service
Comment
-
Hi Chelsea,
I have followed instructions in the shared articles so far, but the ATM strategy is not attaching. It worked once and then stopped working subsequently. See the code below. Any help will be appreciated:
Code:{ public class LongEmaNine : Indicator { private Account account; private System.Windows.Controls.Grid buttonsGrid; private System.Windows.Controls.Button longConditionalButton, longLimitButton, longMarketButton; private bool longConditionTriggerEnabled, longLimitEnabled; private Order longLimitOrder; private EMA ema1; private NinjaTrader.Gui.NinjaScript.AtmStrategy.AtmStrategySelector selector; protected override void OnStateChange() { if (State == State.SetDefaults) { Description = @"Example to demonstrate how to submit orders from an indicator's button click event using the Addon approach"; Name = "LongEmaNine"; Calculate = Calculate.OnPriceChange; IsOverlay = true; AddPlot(Brushes.Orange, "EMA"); } else if (State == State.DataLoaded) { Print("State.DataLoaded"); ChartControl.Dispatcher.InvokeAsync((Action)(() => { NinjaTrader.Gui.Tools.AccountSelector chartTraderAccountSelector = Window.GetWindow(ChartControl.Parent).FindFirst("ChartTraderControlAccountSelector") as NinjaTrader.Gui.Tools.AccountSelector; account = Account.All.FirstOrDefault(a => a.Name == chartTraderAccountSelector.SelectedAccount.Name); //selector = Window.GetWindow(ChartControl.Parent).FindFirst("ChartTraderControlATMStrategySelector") as NinjaTrader.Gui.NinjaScript.AtmStrategy.AtmStrategySelector; })); //account = Account.All.FirstOrDefault(a => a.Name == "Sim101"); if (account != null) account.OrderUpdate += Account_OrderUpdate; if (ChartControl != null) CreateWPFControls(); ema1 = EMA(9); } else if (State == State.Terminated) { if (account != null) account.OrderUpdate -= Account_OrderUpdate; if (ChartControl != null) RemoveWPFControls(); } } private void Account_OrderUpdate(object sender, OrderEventArgs orderUpdateArgs) { #region Use case 2, submitting a limit order with limit price updated to indicator plot value if (longLimitOrder != null && longLimitOrder == orderUpdateArgs.Order) { // detect when the limit order is working to provide a message if (longLimitOrder.OrderState == OrderState.Working || longLimitOrder.OrderState == OrderState.Accepted) { Draw.TextFixed(this, "infoBox", "Limit order working at: " + longLimitOrder.LimitPrice, TextPosition.BottomLeft); if (ChartControl != null && longLimitButton != null) { // change the button text to show the limit can be cancelled ChartControl.Dispatcher.InvokeAsync((() => { longLimitButton.Content = "Cancel limit"; })); } } // when the order is no longer active, reset so a new order can be placed else if (longLimitOrder.OrderState == OrderState.Cancelled || longLimitOrder.OrderState == OrderState.Rejected || longLimitOrder.OrderState == OrderState.Filled) { if (longLimitOrder.OrderState == OrderState.Filled) Draw.TextFixed(this, "infoBox", "Limit filled at: " + longLimitOrder.AverageFillPrice, TextPosition.BottomLeft); if (longLimitOrder.OrderState == OrderState.Cancelled) Draw.TextFixed(this, "infoBox", "Limit cancelled", TextPosition.BottomLeft); if (ChartControl != null && longLimitButton != null) { // change the button text so we know we can place a new order ChartControl.Dispatcher.InvokeAsync((() => { longLimitButton.Content = "Long@EMA9"; longLimitButton.Background = Brushes.Green; longLimitButton.Foreground = Brushes.White; })); } longLimitEnabled = false; longLimitOrder = null; } } #endregion } private void CreateWPFControls() { // if the script has already added the controls, do not add a second time. if (UserControlCollection.Contains(buttonsGrid)) return; // when making WPF changes to the UI, run the code on the UI thread of the chart ChartControl.Dispatcher.InvokeAsync((() => { // this buttonGrid will contain the buttons buttonsGrid = new System.Windows.Controls.Grid { Background = Brushes.Red, Name = "ButtonsGrid", HorizontalAlignment = HorizontalAlignment.Right, VerticalAlignment = VerticalAlignment.Top }; // add 3 columns to the grid for (int i = 0; i < 3; i++) buttonsGrid.ColumnDefinitions.Add(new System.Windows.Controls.ColumnDefinition()); #region Use case 1, immediately submitting a market order longMarketButton = new System.Windows.Controls.Button { Name = "LongMarketButton", Content = "Long@Mkt", Foreground = Brushes.White, Background = Brushes.Green }; longMarketButton.Click += OnButtonClick; buttonsGrid.Children.Add(longMarketButton); System.Windows.Controls.Grid.SetColumn(longMarketButton, 0); #endregion #region Use case 2, submitting a limit order with limit price updated to indicator plot value longLimitButton = new System.Windows.Controls.Button { Name = "LongLimitButton", Content = "Long@EMA9", Foreground = Brushes.White, Background = Brushes.Green }; longLimitButton.Click += OnButtonClick; buttonsGrid.Children.Add(longLimitButton); System.Windows.Controls.Grid.SetColumn(longLimitButton, 1); #endregion #region Use case 3, setting a trigger to submit a market order after conditions are met #endregion // add our button grid to the main UserControlCollection over the chart UserControlCollection.Add(buttonsGrid); })); } protected override void OnBarUpdate() { Value[0] = ema1[0]; #region Use case 2, submitting a limit order with limit price updated to indicator plot value // if the order is submitted, continue updating the order to the price of the indicator if plot is below the ask // if the plot is above the ask move below current ask, if (longLimitOrder != null && (longLimitOrder.OrderState == OrderState.Working || longLimitOrder.OrderState == OrderState.Accepted)) { longLimitOrder.LimitPriceChanged = Math.Min(Instrument.MasterInstrument.RoundToTickSize(ema1[0]), GetCurrentAsk() - 1 * TickSize); account.Change(new Order[] { longLimitOrder }); //NinjaTrader.NinjaScript.AtmStrategy.StartAtmStrategy(selector.SelectedAtmStrategy, longLimitOrder); } #endregion #region Use case 3, setting a trigger to submit a market order after conditions are met if (longConditionTriggerEnabled // your custom conditions for entering the trade can go here. I'll use the price crossing the SMA as an example. && (CrossAbove(ema1, Close, 1) || CrossBelow(ema1, Close, 1))) { longConditionTriggerEnabled = false; Order mar****rder = account.CreateOrder(Instrument, OrderAction.Buy, OrderType.Market, OrderEntry.Automated, TimeInForce.Day, 1, 0, 0, string.Empty, "Long conditional", new DateTime(), null); account.Submit(new Order[] { mar****rder }); // its best practice to check for null, however the code cannot get to this point if the button does not exist if (ChartControl != null && longConditionalButton != null) { ChartControl.Dispatcher.InvokeAsync((() => { longConditionalButton.Content = "Long after condition"; longConditionalButton.Background = Brushes.Green; longConditionalButton.Foreground = Brushes.White; })); } Draw.TextFixed(this, "infoBox", "SMA has crossed the market price, order submitted", TextPosition.BottomLeft); } #endregion } private void OnButtonClick(object sender, RoutedEventArgs rea) { Print("Button Clicked"); System.Windows.Controls.Button button = sender as System.Windows.Controls.Button; #region Use case 1, immediately submitting a market order if (button == longMarketButton) { Order mar****rder = account.CreateOrder(Instrument, OrderAction.Buy, OrderType.Market, OrderEntry.Manual, TimeInForce.Day, 1, 0, 0, string.Empty, string.Empty, new DateTime(), null); //Print(selector.SelectedAtmStrategy); //NinjaTrader.NinjaScript.AtmStrategy.StartAtmStrategy(selector.SelectedAtmStrategy, mar****rder); NinjaTrader.NinjaScript.AtmStrategy.StartAtmStrategy("1q4p100s", mar****rder); //Print(selector.SelectedAtmStrategy); account.Submit(new Order[] { mar****rder} ); } #endregion #region Use case 2, submitting a limit order with limit price updated to indicator plot value if (button == longLimitButton) { longLimitEnabled = !longLimitEnabled; // only send a new order if there isn't one already working if (longLimitEnabled && longLimitOrder == null) { // to use a price from a series (such as the SMA) from outside of a data driven method (like OnBarUpdate) the series will need to be synchronized first to update the sma and close price values // buy limit orders must be below the ask. submit to either the sma or the ask minus 1 tick, whichever is lower TriggerCustomEvent(o => { longLimitOrder = account.CreateOrder(Instrument, OrderAction.Buy, OrderType.Limit, OrderEntry.Manual, TimeInForce.Gtc, 1, Math.Min(Instrument.MasterInstrument.RoundToTickSize(ema1[0]), GetCurrentAsk() - 1 * TickSize), 0, string.Empty, "Long limit order", new DateTime(), null); //NinjaTrader.NinjaScript.AtmStrategy.StartAtmStrategy(selector.SelectedAtmStrategy, longLimitOrder); NinjaTrader.NinjaScript.AtmStrategy.StartAtmStrategy("1q4p100s", longLimitOrder); account.Submit(new Order[] { longLimitOrder }); }, null); } // if there one working cancel it else if (!longLimitEnabled && longLimitOrder.OrderState == OrderState.Working || longLimitOrder.OrderState == OrderState.Accepted) { account.Cancel(new Order[] { longLimitOrder }); } // change the button text so we know the order is submitted ChartControl.Dispatcher.InvokeAsync((() => { button.Content = longLimitEnabled ? "Limit submitted" : "Long@9EMA"; button.Background = longLimitEnabled ? Brushes.LightGreen : Brushes.Green; button.Foreground = longLimitEnabled ? Brushes.Black : Brushes.White; })); } #endregion }
Comment
-
Hello lanredocemo,
It looks like you may be submitting the order with account.Submit(new Order[]) instead of NinjaTrader.NinjaScript.AtmStrategy.StartAtmStrate gy().
When using StartAtmStrategy() you will not have to use account.Submit().
Below is a link to an example of starting an Atm Strategy through the addon approach (which would also work in an indicator).
Chelsea B.NinjaTrader Customer Service
Comment
-
Hi Chelsea,
Thanks for sharing.The use case you described above satisfies placing the order the first time. As you can see, the limit order updates with every change in the EMA. Do i need to use startATMStrategy in place of account.change? If no, which method do I use to change the order using ATM strategy approach every time the EMA changes?
Comment
-
Hello lanredocemo,
Using <Account>.Change() on the limit order would be appropriate. Note, any changes may be undone by actions of the Atm such as breakeven, trailing, or chase behavior.
If you are intending to control the price of the limit and/or stop, it may be better suited to submit these orders directly to the account instead of using an Atm.
The ProfitCaseStopTrailIndicatorExample linked below demonstrates this.
Chelsea B.NinjaTrader Customer Service
Comment
-
Hi Chelsea,
Thank you for sharing the alternative approach. I would still prefer to use the Atmstrategy approach as it is more simple and elegant, and it's easier for me to reason about.
The issue that I am facing is that when the order is placed using startAtmStrategy, it's state is stuck in "initialized" and it never changes. Consequently, closing or cancelling all orders results in a "cancel pending" state, which means I then have to reset the sim account.
Something seems to be wrong with how startAtmStrategy processes created orders in this script, and I will appreciate your assistance in getting it resolved
Comment
-
Hello lanredocemo,
The entry order is getting stuck in OrderState.Initialized?
May I confirm you are no longer using <Account>.Submit()?
This may be due to using 1/1/0001 12:00:00 AM as the gtd parameter. Try using Core.Globals.MaxDate as suggested by the help guide instead.
If this does not correct the behavior, may I test the script?
To export a NinjaTrader 8 NinjaScript so this can be shared and imported by the recipient do the following:- Click Tools -> Export -> NinjaScript Add-on...
- Click the 'add' link -> check the box(es) for the script(s) and reference(s) you want to include
- Click the 'Export' button
- Enter the script name in the value for 'File name:'
- Choose a save location -> click Save
- Click OK to clear the export location message
- (My) Documents/NinjaTrader 8/bin/Custom/ExportNinjaScript/<export_file_name.zip>
Once exported, please attach the file as an attachment to your reply.
Chelsea B.NinjaTrader Customer Service
Comment
Latest Posts
Collapse
| Topics | Statistics | Last Post | ||
|---|---|---|---|---|
|
Started by Geovanny Suaza, 02-11-2026, 06:32 PM
|
0 responses
556 views
0 likes
|
Last Post
|
||
|
Started by Geovanny Suaza, 02-11-2026, 05:51 PM
|
0 responses
324 views
1 like
|
Last Post
|
||
|
Started by Mindset, 02-09-2026, 11:44 AM
|
0 responses
101 views
0 likes
|
Last Post
by Mindset
02-09-2026, 11:44 AM
|
||
|
Started by Geovanny Suaza, 02-02-2026, 12:30 PM
|
0 responses
545 views
1 like
|
Last Post
|
||
|
Started by RFrosty, 01-28-2026, 06:49 PM
|
0 responses
547 views
1 like
|
Last Post
by RFrosty
01-28-2026, 06:49 PM
|

Comment