Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

ChartTrader button: new order and attach to an indicator

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    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.

    #2
    The Button class in NinjaTrader 8 is derived from Microsoft Windows programming , check Mcrosoft apps on buttons. Microsoft .com

    Comment


      #3
      Hello lanredocemo,

      Below is a link to an example of a button and using an indicator as an order price.
      Chelsea B.NinjaTrader Customer Service

      Comment


        #4
        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


          #5
          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


            #6
            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


              #7
              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


                #8
                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


                  #9
                  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


                    #10
                    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
                    Attached Files

                    Comment


                      #11
                      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:
                      1. Click Tools -> Export -> NinjaScript Add-on...
                      2. Click the 'add' link -> check the box(es) for the script(s) and reference(s) you want to include
                      3. Click the 'Export' button
                      4. Enter the script name in the value for 'File name:'
                      5. Choose a save location -> click Save
                      6. Click OK to clear the export location message
                      By default your exported file will be in the following location:
                      • (My) Documents/NinjaTrader 8/bin/Custom/ExportNinjaScript/<export_file_name.zip>
                      Below is a link to the help guide on Exporting NinjaScripts.


                      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
                      561 views
                      0 likes
                      Last Post Geovanny Suaza  
                      Started by Geovanny Suaza, 02-11-2026, 05:51 PM
                      0 responses
                      325 views
                      1 like
                      Last Post Geovanny Suaza  
                      Started by Mindset, 02-09-2026, 11:44 AM
                      0 responses
                      101 views
                      0 likes
                      Last Post Mindset
                      by Mindset
                       
                      Started by Geovanny Suaza, 02-02-2026, 12:30 PM
                      0 responses
                      547 views
                      1 like
                      Last Post Geovanny Suaza  
                      Started by RFrosty, 01-28-2026, 06:49 PM
                      0 responses
                      547 views
                      1 like
                      Last Post RFrosty
                      by RFrosty
                       
                      Working...
                      X