Announcement

Collapse

Looking for a User App or Add-On built by the NinjaTrader community?

Visit NinjaTrader EcoSystem and our free User App Share!

Have a question for the NinjaScript developer community? Open a new thread in our NinjaScript File Sharing Discussion Forum!
See more
See less

Partner 728x90

Collapse

TriggerCustomEvent & pointer alignment

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

    TriggerCustomEvent & pointer alignment

    Hello fellow humans,
    I'm left confused. I'll try my best to provide a clear explanation.
    So, I've developed an indicator. The troublesome & important parts are, that this indicator is reading values from ChartTrader elements & custom added elements. It also does provide buttons for custom functions. Both things work fine. I'm also using the TriggerCustomEvent method for pointer alignment when the buttons are pressed (I use OHLC price values inside these functions). For the most part, everything is read and triggered fine. Since I couldn't find a better solutions, I'm reading the ChartTrader values in the OnStateChange when state is dataloaded, and onbarupdate.
    Now the issue happens actually at the very start when adding this indicator to the chart. If I add this indicator to a chart which doesn't update because e.g. I'm not connected, using the playback & on pause or the chart simply doesn't update that frequent, these ChartTrader values (or from custom elements) are not read inside the TriggerCustomEvent functions. To be more precise:
    I used prints throughout each step and the values themselves are perfectly read and set upon adding the indicator to the chart, only inside the TriggerCustomEvent functions they are not. Not until any update to the chart happens that is.
    Is there something I've misunderstood or missed about these functions? I assume that the issue is that these functions require some update to align/update their pointers. If that is the case, can I somehow force that to happen initially?

    #2
    Hello Human#102,

    Thank you for your post.

    What items are you trying to access from Chart Trader? Please note that something like the AccountSelector from ChartTrader will not be populated unless you are connected.

    If you are not connected or Playback is paused there is no data for OnBarUpdate() to update on (or if it is a slow moving chart, OnBarUpdate() will not execute until there is an update).

    TriggerCustomEvent() isn't typically used to access Chart Trader items this way, it can be used to access NinjaScript values like Close[0] outside of event driven methods like OnBarUpdate().

    I forward to your response.
    Gaby V.NinjaTrader Customer Service

    Comment


      #3

      TriggerCustomEvent should only be run from Event handlers such as UI or timer events. It shouldn't be run from OnBarUpdate().

      It sounds like both your OnBarUpdate and your event handler are calling TriggerCustomEvent, something like this:

      Code:
      private double GetLastestHigh()
      {
           var high = 0d;
          TriggerCustomEvent(o =>
          {
               high = High[0];
      
          }, null);
      }
      
      private void OnClick(Object sender, EventArgs args)
      {
            var high = GetLastestHigh();
      }​
      
      
      protected override void OnBarUpdate()
      {​
             var high = GetLatestHigh();
      }

      You need to make sure TriggerCustomEvent is only used in EventHandlers, like this:


      Code:
      private double GetLastestHigh()
      {
           var high = High[0];
      }
      
      private void OnClick(Object sender, EventArgs args)
      {
          TriggerCustomEvent(o =>
          {​
            var high = GetLastestHigh();
           }, null);
      }​
      
      
      protected override void OnBarUpdate()
      {​
             var high = GetLatestHigh();
      }



      Here are some useful Extension methods for Trigger custom event:

      Code:
          public static class NinjaScriptExtensionMethods
          {​
              public static void TriggerCustomEvent(this NinjaScriptBase  ninjaScript, Action myFunc)
              {
                  Exception failureException = null;
                  ninjaScript.TriggerCustomEvent(t =>
                  {
                      try
                      {
                          myFunc();
                      }
                      catch (Exception ex)
                      {
                          failureException = ex;
                      }
                    
      
                  },null);
      
                  if (failureException != null)
                  {
                      if (ninjaScript.GetChartControl() != null)
                      {
                          NTMessageBoxSimple.Show(ninjaScript.GetChartControl().OwnerChart, failureException.Message,
                              "TriggerCustomEvent failure", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                      }
      
                      throw failureException;
                  }
              }
      
              public static T TriggerCustomEvent<T>(this NinjaScriptBase ninjaScript, Func<T> myFunc)
              {
                  T output = default(T);
                  Exception failureException = null;
                  ninjaScript.TriggerCustomEvent(t =>
                  {
                      try
                      {
                          output = myFunc();
                      }
                      catch (Exception ex)
                      {
                          failureException = ex;
                      }
                      
                  }, null);
                  if (failureException != null)
                  {
                      if (ninjaScript.GetChartControl() != null)
                      {
                          NTMessageBoxSimple.Show(ninjaScript.GetChartControl().OwnerChart, failureException.Message,
                              "TriggerCustomEvent failure", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                      }
      
                      throw failureException;
                  }
                  return output;
              }​
      }
      These methods are more robust and make it easier to return things from TiggerCustomEvent, e.g.:

      Code:
      private void OnClick(Object sender, EventArgs args)
      {
          var high = this.TriggerCustomEvent(() => High[0]);
      
      
          var range = this.TriggerCustomEvent(() => High[0] - Low[0]);
      }​​

      Last edited by kevinenergy; 01-12-2024, 09:34 AM.

      Comment


        #4
        Thank you both for the responses, but it seems I wasn't clear enough with my description.
        I have a method like:
        Code:
        private void ReadChartTraderVals()
                {
                    ChartControl.Dispatcher.InvokeAsync((Action)(() =>
                    {
                        NinjaTrader.Gui.Tools.TifSelector tifSelector = (Window.GetWindow(ChartControl.Parent).FindFirst("ChartTraderControlTIFSelector") as NinjaTrader.Gui.Tools.TifSelector);
                        NinjaTrader.Gui.Tools.QuantityUpDown quantitySelector = (Window.GetWindow(ChartControl.Parent).FindFirst("ChartTraderControlQuantitySelector") as NinjaTrader.Gui.Tools.QuantityUpDown);
                        NinjaTrader.Gui.Tools.AccountSelector accountSelector = (Window.GetWindow(ChartControl.Parent).FindFirst("ChartTraderControlAccountSelector") as NinjaTrader.Gui.Tools.AccountSelector);
                        NinjaTrader.Gui.NinjaScript.AtmStrategy.AtmStrategySelector ATMselector = (Window.GetWindow(ChartControl.Parent).FindFirst("ChartTraderControlATMStrategySelector") as NinjaTrader.Gui.NinjaScript.AtmStrategy.AtmStrategySelector);
                        
                        TIF = tifSelector.SelectedTif;
                        Qty = quantitySelector.Value;
                        SelectedAccount = accountSelector.SelectedAccount;
                        SelectedAtmStrategy = ATMselector.SelectedAtmStrategy;
                        
                        if (OffsetInput != null)
                            OrderOffset = OffsetInput.Value;
                    }));
                }​
        This method is called initially in the state dataloaded block and OnBarUpdate. The TriggerCustomEvent functions are only called with button click or mouseclick events and after calculating some entry prices each calls a common method to submit an order. Now the issue is that these TIF, Qty etc. variables are correctly read and set once the indicator is added to the chart, even without any updates. But inside the TriggerCustomEvent callbacks these variables are all still null, until something updates the chart. Ironically, the price data they're accessing is correct. And just as a simple example these methods look something like:

        Code:
        protected void MyButtonClick(object sender, RoutedEventArgs e)
                {
                    TriggerCustomEvent(o =>
                    {
                        MySubmitOrderMethod(High[1]);
                    }, null);
                    ForceRefresh();
                }​
        And inside SubmitOrder() I'm accessing/reading the TIF, Qty etc. variables.

        Comment


          #5
          Hello,

          We would suggest instead implementing it this way, you instead get a value at the time of the button press and then give that to your method as parameters. You can do this by moving the code into a button event directly.

          Since you are accessing values that can be changed, like the TIF, selected account, selected ATM, etc. the script in its current state won't see those changes after they have been set in State.DataLoaded. Moving the code into a button event will allow the script to access any manually updated values at the time the button is clicked which can then be supplied to your MySubmitOrderMethod().

          As a courtesy, attached is an example script demonstrating. When testing the script, make sure you are connected and have Chart Trader open, as well as a custom ATM saved as a template selected so the script is able to access those values.

          Please let us know if you have any further questions.
          Attached Files
          Gaby V.NinjaTrader Customer Service

          Comment


            #6
            Originally posted by Human#102 View Post
            Thank you both for the responses, but it seems I wasn't clear enough with my description.
            I have a method like:
            Code:
            private void ReadChartTraderVals()
            {
            ChartControl.Dispatcher.InvokeAsync((Action)(() =>
            {
            NinjaTrader.Gui.Tools.TifSelector tifSelector = (Window.GetWindow(ChartControl.Parent).FindFirst("ChartTraderControlTIFSelector") as NinjaTrader.Gui.Tools.TifSelector);
            NinjaTrader.Gui.Tools.QuantityUpDown quantitySelector = (Window.GetWindow(ChartControl.Parent).FindFirst("ChartTraderControlQuantitySelector") as NinjaTrader.Gui.Tools.QuantityUpDown);
            NinjaTrader.Gui.Tools.AccountSelector accountSelector = (Window.GetWindow(ChartControl.Parent).FindFirst("ChartTraderControlAccountSelector") as NinjaTrader.Gui.Tools.AccountSelector);
            NinjaTrader.Gui.NinjaScript.AtmStrategy.AtmStrategySelector ATMselector = (Window.GetWindow(ChartControl.Parent).FindFirst("ChartTraderControlATMStrategySelector") as NinjaTrader.Gui.NinjaScript.AtmStrategy.AtmStrategySelector);
            
            TIF = tifSelector.SelectedTif;
            Qty = quantitySelector.Value;
            SelectedAccount = accountSelector.SelectedAccount;
            SelectedAtmStrategy = ATMselector.SelectedAtmStrategy;
            
            if (OffsetInput != null)
            OrderOffset = OffsetInput.Value;
            }));
            }​
            This method is called initially in the state dataloaded block and OnBarUpdate. The TriggerCustomEvent functions are only called with button click or mouseclick events and after calculating some entry prices each calls a common method to submit an order. Now the issue is that these TIF, Qty etc. variables are correctly read and set once the indicator is added to the chart, even without any updates. But inside the TriggerCustomEvent callbacks these variables are all still null, until something updates the chart. Ironically, the price data they're accessing is correct. And just as a simple example these methods look something like:

            Code:
            protected void MyButtonClick(object sender, RoutedEventArgs e)
            {
            TriggerCustomEvent(o =>
            {
            MySubmitOrderMethod(High[1]);
            }, null);
            ForceRefresh();
            }​
            And inside SubmitOrder() I'm accessing/reading the TIF, Qty etc. variables.
            You're saying they're still null?

            Maybe that's because they're all local variables inside that method.

            Comment


              #7
              Originally posted by NinjaTrader_Gaby View Post
              Hello,

              We would suggest instead implementing it this way, you instead get a value at the time of the button press and then give that to your method as parameters. You can do this by moving the code into a button event directly.

              Since you are accessing values that can be changed, like the TIF, selected account, selected ATM, etc. the script in its current state won't see those changes after they have been set in State.DataLoaded. Moving the code into a button event will allow the script to access any manually updated values at the time the button is clicked which can then be supplied to your MySubmitOrderMethod().

              As a courtesy, attached is an example script demonstrating. When testing the script, make sure you are connected and have Chart Trader open, as well as a custom ATM saved as a template selected so the script is able to access those values.

              Please let us know if you have any further questions.
              Sometimes it's the easy solutions. Thank you, that solved that issue. Though I still believe that the issue I experienced should not happen. It doesn't seem like a bug but rather an unclear or unintuitive technicality.

              Comment

              Latest Posts

              Collapse

              Topics Statistics Last Post
              Started by fx.practic, 10-15-2013, 12:53 AM
              5 responses
              5,406 views
              0 likes
              Last Post Bidder
              by Bidder
               
              Started by Shai Samuel, 07-02-2022, 02:46 PM
              4 responses
              98 views
              0 likes
              Last Post Bidder
              by Bidder
               
              Started by DJ888, Yesterday, 10:57 PM
              0 responses
              8 views
              0 likes
              Last Post DJ888
              by DJ888
               
              Started by MacDad, 02-25-2024, 11:48 PM
              7 responses
              160 views
              0 likes
              Last Post loganjarosz123  
              Started by Belfortbucks, Yesterday, 09:29 PM
              0 responses
              9 views
              0 likes
              Last Post Belfortbucks  
              Working...
              X