Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

2 entry orders help!

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

  • NinjaTrader_ChelseaB
    replied
    Hello PaulMohn,

    Yes, correct, the CreateWPFControls() method is called from the dispatcher invoke async action.

    (Action)() => { /* your logic here */ } <-- this is the action that is run once the invoke async has allowed access to the thread.

    This ChartOrderButtonsIndicatorExample demonstrates accessing a button label on line 84. The button is on the UI thread and requires a dispatcher invoke.
    https://ninjatrader.com/support/foru...18#post1126818

    Also, note, the ChartTraderCustomButtonsExample is an antiquated example. SampleWPFModifications is now in the help guide. (Read the full post and follow the links)
    https://ninjatrader.com/support/help...ui)-modifi.htm
    Last edited by NinjaTrader_ChelseaB; 06-07-2022, 07:44 AM.

    Leave a comment:


  • PaulMohn
    replied
    Hello Chelsea and thanks for the correction.
    I've found your ChartTraderCustomButtonsExample from the post Modifications to chart WPF elements and tab considerations

    lines 35-38
    PHP Code:
    ChartControl.Dispatcher.InvokeAsync(() =>
    {
         CreateWPFControls();
    }); 
    

    Is this the correct way you meant by "run from the Action of the InvokeAsync, not below it."?
    PHP Code:
    ChartControl.Dispatcher.InvokeAsync(() =>
    {
        for (int index = 0; index < quantity Selector.Value; index++)
        {
           stopLossOrder = myAccount.CreateOrder(orderUpdateArgs.Order.Instrument, OrderAction .Sell, OrderType.StopMarket, OrderEntry.Automated, TimeInForce.Day, orderUpdateArgs.Quantity, 0, currentSlPrice, oco+index, "Stop Loss", Core.Globals.MaxDate, null);
           submitOrdersArray.Add(stopLossOrder);
        }
    }); 
    

    If not what else would it be? Thanks!
    Last edited by PaulMohn; 06-06-2022, 02:31 PM.

    Leave a comment:


  • NinjaTrader_ChelseaB
    replied
    Hello PaulMohn,

    Any code that would need the value from UI would need to be run from the Action of the InvokeAsync, not below it.

    No, freezing the thread is not supported and will cause unexpected and undesired behavior.

    Leave a comment:


  • PaulMohn
    replied
    Hello Chelsea and thanks for the reply and illustrative examples.

    I've found this MSDN explanation Asynchronous programming with async and await

    I've tested your snippets and they do print as you say:

    quantitySelector.Value

    and

    savedIntValue: 9999

    You say because of the asynchronous call the variable value can't immediately pick up the quantitySelector.Value value?

    What would be the fix if that's the cause of the Exception error? I saw and tested adding a
    Task.Delay(3000).Wait(); statement as
    PHP Code:
    private void Account_OrderUpdate(object sender, OrderEventArgs orderUpdateArgs)
    {
      int savedIntValue = 9999;
    
      ChartControl.Dispatcher.InvokeAsync((Action)(() =>
      {
        if (quantitySelector != null)
          savedIntValue = 5;
        else
          Print("quantitySelector is null");
        }));
    
      Task.Delay(3000).Wait();
      Print("savedIntValue: " + savedIntValue);
    } 
    
    But that's slowing it 20+ seconds and the orders are separated by several seconds too.

    I then tested just wrapping the 2 loops with the dispatcher + Task.Delay(1000).Wait(); as

    PHP Code:
          private void Account_OrderUpdate(object sender, OrderEventArgs orderUpdateArgs)
          {
            if (entryBuyMar****rder != null && entryBuyMar****rder == orderUpdateArgs.Order && orderUpdateArgs.Order.OrderState == OrderState.Filled)
            {
              string oco     = Guid.NewGuid().ToString("N");
              submitOrdersArray = new List<Order>();
    
              if (UseProfitTarget)
              {
                currentPtPrice = orderUpdateArgs.AverageFillPrice + ProfitTargetDistance * TickSize;
    
                ChartControl.Dispatcher.InvokeAsync((Action)(() =>
                {
                  Task.Delay(1000).Wait();
                  for (int index = 0; index < quantitySelector.Value; index++)
                  {
                    profitTargetOrder = myAccount.CreateOrder(orderUpdateArgs.Order.Instru ment, OrderAction.Sell, OrderType.Limit, OrderEntry.Automated, TimeInForce.Day, orderUpdateArgs.Quantity, currentPtPrice, 0, oco+index, "Profit Target", Core.Globals.MaxDate, null);
                    submitOrdersArray.Add(profitTargetOrder);
                  }
                }));
              }
    
              if (UseStopLoss)
              {
                currentSlPrice = orderUpdateArgs.AverageFillPrice - StopLossDistance * TickSize;
    
                ChartControl.Dispatcher.InvokeAsync((Action)(() =>
              {
                Task.Delay(1000).Wait();
                  for (int index = 0; index < quantitySelector.Value; index++)
                  {
                    stopLossOrder = myAccount.CreateOrder(orderUpdateArgs.Order.Instru ment, OrderAction.Sell, OrderType.StopMarket, OrderEntry.Automated, TimeInForce.Day, orderUpdateArgs.Quantity, 0, currentSlPrice, oco+index, "Stop Loss", Core.Globals.MaxDate, null);
                    submitOrdersArray.Add(stopLossOrder);
                  }
                }));
              }
    
              myAccount.Submit(submitOrdersArray);
            }
    
            // once the exit orders are closed, reset for a new entry.
            else if ((profitTargetOrder != null && (profitTargetOrder.OrderState == OrderState.Filled
                                || profitTargetOrder.OrderState == OrderState.Rejected
                                || profitTargetOrder.OrderState == OrderState.Cancelled))
              || (stopLossOrder != null && (stopLossOrder.OrderState == OrderState.Filled
                                || stopLossOrder.OrderState == OrderState.Rejected
                                || stopLossOrder.OrderState == OrderState.Cancelled)))
            {
              entryBuyMar****rder   = null;
              profitTargetOrder   = null;
              stopLossOrder     = null;
            }
          } 
    

    Now no more Exception error but the Target and StopLoss orders aren't submitted.

    What fix would you suggest to solve the asynchronous issue? I can't find it in the doc nor in the MSDN examples. Thanks!

    Leave a comment:


  • NinjaTrader_ChelseaB
    replied
    Hello PaulMohn,

    Yes, access is provided by calling the dispatcher invoke (with the action (your logic) supplied) exactly as you are doing in the State.DataLoaded of OnStateChange().

    What you have is correct! but incomplete..

    To complete the idea:
    Code:
    private void Account_OrderUpdate(object sender, OrderEventArgs orderUpdateArgs)
    {
        ChartControl.Dispatcher.InvokeAsync((Action)(() =>
        {
            if (quantitySelector != null)
                Print("quantitySelector.Value: " + quantitySelector.Value);
            else
                Print("quantitySelector is null");
        }));
    }
    Do note that this is an asynchronous call. This means the following code below would not update the variable in time, before the code below the async call evaluates.

    Code:
    private void Account_OrderUpdate(object sender, OrderEventArgs orderUpdateArgs)
    {
        int savedIntValue = 9999;
    
        ChartControl.Dispatcher.InvokeAsync((Action)(() =>
        {
            if (quantitySelector != null)
                savedIntValue = 5;
            else
                Print("quantitySelector is null");
            }));
    
        Print("savedIntValue: " + savedIntValue);
    }
    We get a print of 'savedIntValue: 9999' and not 5 as the value was not changed in time. But if we check it even a second later it now has a value of 5.
    Last edited by NinjaTrader_ChelseaB; 06-02-2022, 02:31 PM.

    Leave a comment:


  • PaulMohn
    replied
    Hello Chelsea and thanks for the reply. Do you have a sample demonstrating what I need? The doc isn't helpful enough, the MSDN example neither as I applied what it states but it's not solving the issue.
    by

    Use dispatcher to access the UI item from the Account thread.
    Use a dispatcher invoke async to access this UI item from the Account update thread.

    do you mean using something like
    Chris example / AccountSelector

    PHP Code:
    ChartControl.Dispatcher.InvokeAsync((Action)(() =>
          {
                //You have to put the stuff below within this ChartControl.Dispatcher.InvokeAsync((Action)(() =>, because you are trying to access something on a different thread.
                xAlselector = Window.GetWindow(ChartControl.Parent).FindFirst("ChartTraderControlAccountSelector") as NinjaTrader.Gui.Tools.AccountSelector;
                Print(xAlselector.SelectedAccount.ToString());
          })); 
    

    if so how would i adapt it to my code?

    PHP Code:
    private void Account_OrderUpdate(object sender, OrderEventArgs orderUpdateArgs)
          {
                ChartControl.Dispatcher.InvokeAsync((Action)(() =>
                {
    
                })); 
    

    How to access the Account thread? I can't find it in the doc . Thanks!
    Last edited by PaulMohn; 06-02-2022, 12:47 PM.

    Leave a comment:


  • NinjaTrader_ChelseaB
    replied
    Hello PaulMohn,

    It now appears you are using in the Account_OrderUpdate() method. You must use a dispatcher to access this UI item on the UI thread from the Account thread.

    Where you have stated:
    "Are you asking if the ChartControl_PreviewKeyDown() contains a dispatcher snippet? No.
    Or if the Account_OrderUpdate() contains a dispatcher snippet? No.
    Or if both the ChartControl_PreviewKeyDown() and Account_OrderUpdate() contains a dispatcher snippet? No."

    Use dispatcher to access the UI item from the Account thread.

    Where you have inquired:
    "I'm not sure I understand. Isn't the quantitySelector.Value already invoked on the UI Thread? How would I check?"

    Any access to a UI item needs to be done with a dispatcher to allow access into the thread.
    Instantiating a new object or finding an object with an AutomationID and assigning this to a variable does not remove the UI item from the UI thread. You will need to use a dispatcher to instantiate, to assign to a variable, to get a value from, to assign a value to, or any use of the UI object.

    You will need to use dispatcher anytime the UI item is referenced from any thread that is not the UI thread.

    Anywhere quantitySelector.Value, or any other UI object like buttons, grids, the UserControlCollection, etc, is used that is not in the UI thread must have a dispatcher invoke into the UI thread or an error will occur.

    Use a dispatcher invoke async to access this UI item from the Account update thread.

    Where you have stated:
    "Which suggest the quantitySelector's thread isn't the UI thread."

    This is incorrect. All UI items are in the UI thread. Buttons, drop-downs, radio buttons, text boxes, grids, stack panels, dock panels, checkboxs, all UI items, all on the UI thread.

    Leave a comment:


  • PaulMohn
    replied
    Hello Cheslea and thanks for the reply and doc and Dispatcher.CheckAccess()) new reference.

    Where is the quantitySelector.Value variable holding the QuantityUpDown object being used?
    In both methods ChartControl_PreviewKeyDown() (lines 139, 175, 211, 227) and Account_OrderUpdate() (lines 263, 274) (script version of post #72 above).

    To confirm, this is now being used in the hotkey press
    and is not being used in Account_OrderUpdate() as you has previously suggested, is this correct?
    Yes it is being used in ChartControl_PreviewKeyDown() (lines 139, 175, 211, 227).
    No, Account_OrderUpdate() (lines 263, 274) does use quantitySelector.Value (it is called in the loops conditions lines 263 and line 274, the purpose being able to set the upper limit value for those loops directly from the quantity selector field in the Chart Toolbar instead of having to manually hardcode and modify the hardcoded value every time in the script).

    The error is happening when you press the key and not when the account order updates right?
    Yes it it happening upon the NumPad1 key press. I don't know if it is also happening or not when the order updates.

    What it happening is:

    Please see the explained below issue in this 4min demo video

    With lines 263 and 274 having the quantitySelector.Value as upper value
    for (int index = 0; index < quantitySelector.Value; index++)
    for (int index = 0; index < quantitySelector.Value; index++)
    when I press the NumPad1 key with say 5 units in the Quantity Selector field inputted in the Chart's toolbar,
    the 6 orders get filled but their expected 5 OCO pairs don't get submitted and the Exception Error is thrown instead.
    What I need is for those 6 OCO pairs to be submitted as well.

    What it happening is:
    With lines 263 and 274 having the hardcoded 3 value as upper value
    for (int index = 0; index < 3; index++)
    for (int index = 0; index < 3; index++)
    when I press the NumPad1 key with say 5 units in the Quantity Selector field inputted in the Chart's toolbar,
    the 6 orders get filled and their expected 3 OCO pairs do get submitted and the Exception Error is not thrown.
    That is what I need, but with the quantitySelector.Value instead of the hardcoded 3 value as the loops upper limits.

    Do you have the quantitySelector.Value in a dispatcher invokeasync from the keypress event handler method where the variable is used?
    Are you asking if the ChartControl_PreviewKeyDown() contains a dispatcher snippet? No.
    Or if the Account_OrderUpdate() contains a dispatcher snippet? No.
    Or if both the ChartControl_PreviewKeyDown() and Account_OrderUpdate() contains a dispatcher snippet? No.
    Can you clarify please what you asked? Thanks!


    Where you have inquired 'Would I need it with the Account_OrderUpdate()'?

    Most definitely YES!! Anywhere quantitySelector.Value, or any other UI object like buttons, grids, the UserControlCollection, etc, is used that is not in the UI thread must have a dispatcher invoke into the UI thread or an error will occur.
    I'm not sure I understand. Isn't the quantitySelector.Value already invoked on the UI Thread? How would I check?
    I found this example which I adapted as
    PHP Code:
        private void Account_OrderUpdate(object sender, OrderEventArgs orderUpdateArgs)
          {
            if (quantitySelector!=null)
            {
              Print("ok");
              // Checking if this thread has access to the object.
              if (quantitySelector.Dispatcher.CheckAccess())
              {
                // This thread has access so it can update the UI thread.
    //           UpdateButtonUI(quantitySelector);
                Print("ok1");
              }
              else
              {
                // This thread does not have access to the UI thread.
                // Place the update method on the Dispatcher of the UI thread.
                // quantitySelector.Dispatcher.BeginInvoke(Dispatcher Priority.Normal,
                //  new UpdateUIDelegate(UpdateButtonUI), quantitySelector);
                Print("ok2"); 
    
    It prints
    ok
    ok2
    Which suggest the quantitySelector's thread isn't the UI thread.
    How would I redirect the quantitySelector on the UI thread?

    the doc give this example
    PHP Code:
    // check if the current object is already on the calling thread
    if (Dispatcher.CheckAccess())
    {
      // execute action directly
      action(args);
    }
    // otherwise run the action from the thread that created the object
    else
    {
      // dispatch action to calling thread
      Dispatcher.InvokeAsync(action, args);
    } 
    
    I think I should modify mine as
    PHP Code:
          private void Account_OrderUpdate(object sender, OrderEventArgs orderUpdateArgs)
          {
            if (quantitySelector!=null)
            {
              Print("ok");
              // Checking if this thread has access to the object.
              if (quantitySelector.Dispatcher.CheckAccess())
              {
                // This thread has access so it can update the UI thread.
    //           UpdateButtonUI(quantitySelector);
                Print("ok1");
              }
              else
              {
                // Use this.Dispatcher to ensure code is executed on the proper thread
                ChartControl.Dispatcher.InvokeAsync((Action)(() =>
                {
    
                }));
              }
            } 
    

    then embed all the remaining in the Dispatcher as
    PHP Code:
    private void Account_OrderUpdate(object sender, OrderEventArgs orderUpdateArgs)
          {
            if (quantitySelector!=null)
            {
              Print("ok");
              // Checking if this thread has access to the object.
              if (quantitySelector.Dispatcher.CheckAccess())
              {
                // This thread has access so it can update the UI thread.
    //           UpdateButtonUI(quantitySelector);
                Print("ok1");
              }
              else
              {
                // Use this.Dispatcher to ensure code is executed on the proper thread
                ChartControl.Dispatcher.InvokeAsync((Action)(() =>
                {
                  if (entryBuyMar****rder != null && entryBuyMar****rder == orderUpdateArgs.Order && orderUpdateArgs.Order.OrderState == OrderState.Filled)
                  {
                    string oco     = Guid.NewGuid().ToString("N");
                    submitOrdersArray = new List<Order>();
    
                    if (UseProfitTarget)
                    {
                      currentPtPrice = orderUpdateArgs.AverageFillPrice + ProfitTargetDistance * TickSize;
    
                      for (int index = 0; index < quantitySelector.Value; index++)
                      {
                        profitTargetOrder = myAccount.CreateOrder(orderUpdateArgs.Order.Instru ment, OrderAction.Sell, OrderType.Limit, OrderEntry.Automated, TimeInForce.Day, orderUpdateArgs.Quantity, currentPtPrice, 0, oco+index, "Profit Target", Core.Globals.MaxDate, null);
                        submitOrdersArray.Add(profitTargetOrder);
                      }
                    }
    
                    if (UseStopLoss)
                    {
                      currentSlPrice = orderUpdateArgs.AverageFillPrice - StopLossDistance * TickSize;
    
                      for (int index = 0; index < quantitySelector.Value; index++)
                      {
                        stopLossOrder = myAccount.CreateOrder(orderUpdateArgs.Order.Instru ment, OrderAction.Sell, OrderType.StopMarket, OrderEntry.Automated, TimeInForce.Day, orderUpdateArgs.Quantity, 0, currentSlPrice, oco+index, "Stop Loss", Core.Globals.MaxDate, null);
                        submitOrdersArray.Add(stopLossOrder);
                      }
                    }
    
                    myAccount.Submit(submitOrdersArray);
                  }
    
                  // once the exit orders are closed, reset for a new entry.
                  else if ((profitTargetOrder != null && (profitTargetOrder.OrderState == OrderState.Filled
                                      || profitTargetOrder.OrderState == OrderState.Rejected
                                      || profitTargetOrder.OrderState == OrderState.Cancelled))
                    || (stopLossOrder != null && (stopLossOrder.OrderState == OrderState.Filled
                                      || stopLossOrder.OrderState == OrderState.Rejected
                                      || stopLossOrder.OrderState == OrderState.Cancelled)))
                  {
                    entryBuyMar****rder   = null;
                    profitTargetOrder   = null;
                    stopLossOrder     = null;
                  }
    
                }));
              }
            } 
    
    That solves the Exception error but now it generates unexpected behavior (it sells instead of buying) and I get those log Tab errors

    Time Category Message
    02/06/2022 17:53:47 Order Sim101, Order '2616282c085944b79879749df33d104e' can't be submitted: order status is CancelPending. affected Order: Sell 1 StopMarket @ -0.1

    Time Category Message
    02/06/2022 17:57:02 Order Sim101, Order '71e83eaca1d14108b6105bf2380696b7' can't be submitted: order status is CancelPending. affected Order: Sell 1 StopMarket @ -0.1

    Time Category Message
    02/06/2022 17:57:01 Order Sim101, Order 'b3405812c3374c2194eb31161b277e4b' can't be submitted: order status is CancelPending. affected Order: Sell 1 StopMarket @ -0.1

    etc.

    What fix would you suggests? hanks!

    Leave a comment:


  • NinjaTrader_ChelseaB
    replied
    Hello PaulMohn,

    We don't need the code where the variable is declared or the QuantityUpDown is found and assigned to a value. Yes, that does need to be in a dispatcher as well, but that's not where the error is occurring and is irrelevant code.

    Where is the quantitySelector.Value variable holding the QuantityUpDown object being used?

    To confirm, this is now being used in the hotkey press and is not being used in Account_OrderUpdate() as you has previously suggested, is this correct?

    The error is happening when you press the key and not when the account order updates right?

    Do you have the quantitySelector.Value in a dispatcher invokeasync from the keypress event handler method where the variable is used?

    Where you have inquired 'Would I need it with the Account_OrderUpdate()'?

    Most definitely YES!! Anywhere quantitySelector.Value, or any other UI object like buttons, grids, the UserControlCollection, etc, is used that is not in the UI thread must have a dispatcher invoke into the UI thread or an error will occur.

    Below is a link to the help guide.
    https://ninjatrader.com/support/help...-threading.htm

    OCO would not cause this issue. I do not expect OCO will be involved in any way.

    Leave a comment:


  • PaulMohn
    replied
    Please find the reduced script ProfitSnipermultiOrders3.zip attached. I kept the minimum Hotkeys and reduced the Account_OrderUpdate() as well.

    Yes a dispatcher, lines 104-107

    PHP Code:
    ChartControl.Dispatcher.InvokeAsync((Action)(() =>
    {
    quantitySelector = (Window.GetWindow(ChartControl.Parent).FindFirst(" ChartTraderControlQuantitySelector") as NinjaTrader.Gui.Tools.QuantityUpDown);
    })); 
    

    and 391-394

    PHP Code:
    ChartControl.Dispatcher.InvokeAsync((Action)(() =>
    {
    if( quantitySelector != null ) chartWindow.MainMenu.Remove(quantitySelector);
    })); 
    

    and 325-336

    PHP Code:
          private void Add_Controls_To_Toolbar()
          {
            // Use this.Dispatcher to ensure code is executed on the proper thread
            ChartControl.Dispatcher.InvokeAsync((Action)(() =>
            {
              //Obtain the Chart on which the indicator is configured
              chartWindow = Window.GetWindow(this.ChartControl.Parent) as Chart;
              if (chartWindow == null)
              {
                Print("chartWindow == null");
                return;
              }
    
              quantitySelector = new NinjaTrader.Gui.Tools.QuantityUpDown();
              //quantitySelector.ValueChanged += On_quantitySelector_ValueChanged;
              quantitySelector.PreviewKeyDown   += On_quantitySelector_PreviewKeyDown;
    
              chartWindow.MainMenu.Add(quantitySelector);
    
              Is_ToolBar_Controls_Added = true;
            }));
          } 
    

    not sure about to invoke into the UI thread from the Account thread. The quantitySelector is for use in the Toolbar. I see post #67 you refer to Chris's snippet with AccountSelector (2nd snippet). I didn't need/use it and it works without it for the Hotkeys/ChartControl_PreviewKeyDown() method and quantitySelector.Value. Would I need it with the Account_OrderUpdate()? If so why and how?

    I suspect the Exception error post #66 might stem from the use of the bools conditions lines 259-270 if (UseProfitTarget)/ if (UseStopLoss) or possibly from the OCO ID generation + index line 265, 276, 255 as those seem to be the only differences in processing the Account_OrderUpdate() method with quantitySelector.Value from the other working method processing ChartControl_PreviewKeyDown() with quantitySelector.Value. Is that right? If so why ad how to fix it? Thanks!
    Attached Files
    Last edited by PaulMohn; 06-02-2022, 05:04 AM.

    Leave a comment:


  • NinjaTrader_ChelseaB
    replied
    Hello PaulMohn,

    Please provide a reduced script if you are wanting someone to look at your code.

    In the code you have not provided, is quantitySelector used inside of a dispatcher to invoke into the UI thread from the Account thread?

    Leave a comment:


  • PaulMohn
    replied
    NinjaTrader.Gui.Tools.QuantityUpDown quantitySelector is declared on line 80 within the action block for OnStateChange(). This variable can only be used in OnStateChange() since it is declared within the scope of OnStateChange().
    Ah yes I had forgot about it being there too, sorry.

    You have previously stated:
    "For some reason the Account_OrderUpdate() method throws this error when using the quantitySelector.Value as upper limit to the loops"

    I am not seeing quantitySelector.Value used anywhere in the Account_OrderUpdate() method from lines 377 to 468.

    I may be overlooking the line. On what line is quantitySelector.Value within the action block for Account_OrderUpdate()?
    You're right
    ProfitSnipermultiOrders1.zip has the hardcoded loops limit lines 392, 406, 431, 445, not the quantitySelector.Value.
    however, post #66 ProfitSnipermultiOrders.zip did have the quantitySelector.Value and not the hardcoded values.

    But if you try substituting the hardcoded value with quantitySelector.Value as

    PHP Code:
    for (int index = 0; index < 3; index++) 
    
    with

    PHP Code:
    for (int index = 0; index < quantitySelector.Value; index++) 
    
    lines 392, 406, 431, 445 in ProfitSnipermultiOrders1.zip script

    you will see the script fails (while it doesn't fail with the hardcoded value. Why? Thanks!).

    Please see attached the new script (ProfitSnipermultiOrders2.zip script) with those substitutions (or if you prefer/faster please try substituting the hardcoded values with quantitySelector.Value lines 392, 406, 431, 445 in ProfitSnipermultiOrders1.zip script) Thanks!


    You will either need to declare it within the scope of the class, or remove all references to this variable outside of OnStateChange() (lines 158, 194, 230, 246, 268, 283, etc).
    I tried declaring it at class level scope (line 65 in ProfitSnipermultiOrders2.zip script) and removing it from the OnStateChange scope (line 82), but it still fails with quantitySelector.Value as upper limit in the loops in the Account_OrderUpdate() (lines 399, 413, 438, 452 in ProfitSnipermultiOrders2.zip script).

    Are you starting a new inquiry?

    Have you resolved your previous inquiry?

    Please reduce the script (or make a test script) to just the line of code you are having an issue with and only the supporting code necessary to run that one line.
    No, still the quantitySelector inquiry
    No, still the quantitySelector inquiry isn't solved

    I need the 151-374 lines ChartControl_PreviewKeyDown() method in ProfitSnipermultiOrders2.zip script to show that those work with using quantitySelector.Value in the Hotkeys loops snippets (lines 151-374) and the hardcoded loops snippets of your Account_OrderUpdate() lines 392, 406, 431, 445 in ProfitSnipermultiOrders1.zip script/lines 399, 413, 438, 452 in ProfitSnipermultiOrders2.zip script.
    I also need quantitySelector.Value in the Hotkeys loops snippets so I can use the quantitySelector input value and not the hardcoded values in the Hotkeys snippets to change orders (151-374 lines ChartControl_PreviewKeyDown() method in ProfitSnipermultiOrders2.zip).
    But the script fails with the substitution (i.e. with quantitySelector.Value both in the Hotkeys loops snippets (lines 151-374) and your Account_OrderUpdate() lines 392, 406, 431, 445 in ProfitSnipermultiOrders1.zip script/lines 399, 413, 438, 452 in ProfitSnipermultiOrders2.zip script.).

    I don't understand why quantitySelector.Value works in 151-374 lines ChartControl_PreviewKeyDown() regardless if declared at class level or at OnStateChange level scope but not in your Account_OrderUpdate() method. Thanks!
    Attached Files
    Last edited by PaulMohn; 06-01-2022, 03:51 PM.

    Leave a comment:


  • NinjaTrader_ChelseaB
    replied
    Hello PaulMohn,

    NinjaTrader.Gui.Tools.QuantityUpDown quantitySelector is declared on line 80 within the action block for OnStateChange(). This variable can only be used in OnStateChange() since it is declared within the scope of OnStateChange().

    You will either need to declare it within the scope of the class, or remove all references to this variable outside of OnStateChange() (lines 158, 194, 230, 246, 268, 283, etc).

    I very highly recommend you make a new test script that removes all code that is not relevant to the inquiry at hand so that you are not causing others to debug your code, and only the few lines relevant code is provided.

    You have previously stated:
    "For some reason the Account_OrderUpdate() method throws this error when using the quantitySelector.Value as upper limit to the loops"

    I am not seeing quantitySelector.Value used anywhere in the Account_OrderUpdate() method from lines 377 to 468.

    I may be overlooking the line. On what line is quantitySelector.Value within the action block for Account_OrderUpdate()?

    Are you starting a new inquiry?

    Have you resolved your previous inquiry?

    Please reduce the script (or make a test script) to just the line of code you are having an issue with and only the supporting code necessary to run that one line.

    Leave a comment:


  • PaulMohn
    replied
    New script attached.

    Is quantitySelector null?

    Do you have a print to show that is not null?

    Do you have a check to ensure that quantitySelector is not null before attempting to use it?
    Thanks for the check suggestion, I tested and it prints ok at the top of your Account_OrderUpdate() method

    PHP Code:
    private void Account_OrderUpdate(object sender, OrderEventArgs orderUpdateArgs)
    {
         if (quantitySelector!=null)
         {
              Print("ok");
         } 
    

    Are you using a dispatcher invoke async to access UI thread objects from the Account thread?

    What code is assigning quantitySelector an object?
    Yes
    The below snippets


    Class level QuantitySelector variables

    PHP Code:
    private Chart chartWindow;
    
    NinjaTrader.Gui.Tools.QuantityUpDown quantitySelector = null;
    
    // QS
    private bool Is_ToolBar_Controls_Added;
    
    // QS
    private int qs; 
    

    State.Historical and State.Terminated
    PHP Code:
    
            else if (State == State.Historical)
            {
              //Call the custom addButtonToToolbar method in State.Historical to ensure it is only done when applied to a chart
              // -- not when loaded in the Indicators window
              if (!Is_ToolBar_Controls_Added) Add_Controls_To_Toolbar();
            }
            else if (State == State.DataLoaded)
            {
              // Find our account
              lock (Account.All)
                myAccount = Account.All.FirstOrDefault(a => a.Name == AccountName);
    
              if (myAccount != null)
                myAccount.OrderUpdate += Account_OrderUpdate;
    
              if (ChartControl != null)
              {
                ChartControl.PreviewKeyDown += ChartControl_PreviewKeyDown;
    
    
                ChartControl.Dispatcher.InvokeAsync((Action)(() =>
                {
                  quantitySelector = (Window.GetWindow(ChartControl.Parent).FindFirst(" ChartTraderControlQuantitySelector") as NinjaTrader.Gui.Tools.QuantityUpDown);
                }));      
              }
            }
            else if (State == State.Terminated)
            {
              if (myAccount != null)
                myAccount.OrderUpdate -= Account_OrderUpdate;
    
              if (ChartControl != null)
              {
                ChartControl.PreviewKeyDown -= ChartControl_PreviewKeyDown;    
              }
    
              //Call a custom method to dispose of any leftover objects in State.Terminated
              DisposeCleanUp();
            }
          } 
    

    Add_Controls_To_Toolbar() and On_quantitySelector_PreviewKeyDown() and DisposeCleanUp()
    PHP Code:
        #region Add Controls To Toolbar
    
          private void Add_Controls_To_Toolbar()
          {
            // Use this.Dispatcher to ensure code is executed on the proper thread
            ChartControl.Dispatcher.InvokeAsync((Action)(() =>
            {
    
              //Obtain the Chart on which the indicator is configured
              chartWindow = Window.GetWindow(this.ChartControl.Parent) as Chart;
              if (chartWindow == null)
              {
                Print("chartWindow == null");
                return;
              }
    
              quantitySelector = new NinjaTrader.Gui.Tools.QuantityUpDown();
              //quantitySelector.ValueChanged += On_quantitySelector_ValueChanged;
              quantitySelector.PreviewKeyDown   += On_quantitySelector_PreviewKeyDown;
    
              chartWindow.MainMenu.Add(quantitySelector);
    
              Is_ToolBar_Controls_Added = true;
            }));
          }
    
        #endregion
    
    
        #region QuantitySelector Snippets
    
          private void On_quantitySelector_PreviewKeyDown(object sender, KeyEventArgs p)
          {
            NinjaTrader.Gui.Tools.QuantityUpDown qs = sender as NinjaTrader.Gui.Tools.QuantityUpDown;
    
            if (p.Key == Key.Delete || p.Key == Key.Back)
            {
              p.Handled = true;
              qs.Value = 0;
            }
    
            if ((p.Key >= Key.D0 && p.Key <= Key.D9 || (p.Key >= Key.NumPad0 && p.Key <= Key.NumPad9)))
            {
              p.Handled = true;
    
              string number = p.Key.ToString();
              string newnumber = qs.Value.ToString();
    
              number = number.Replace("NumPad", "");
              number = number.Replace("D", "");
              int num = int.Parse(newnumber + number);
    
              if (qs != null) qs.Value = num;
            }
          }
    
        #endregion
    
    
        #region DisposeCleanUp Snippet
    
          private void DisposeCleanUp()
          {
            //ChartWindow Null Check
            if (chartWindow != null)
            {
              //Dispatcher used to Assure Executed on UI Thread
              ChartControl.Dispatcher.InvokeAsync((Action)(() =>
              {
                if( quantitySelector != null ) chartWindow.MainMenu.Remove(quantitySelector);
              }));
            }
          }
    
        #endregion 
    

    Do you have print to show this is not null after the variable is assigned?

    Does this print appear before or after the print where the variable is attempted to be used in the Account_OrderUpdate method?

    Is this the chartTrader quantity selector?
    Yes (the ok check above)
    Before (at the top of the Account_OrderUpdate method)
    The ChartControl


    quantitySelector.Value works in the ChartControl_PreviewKeyDown() method:
    lines 158, 194, 230, 246, 268, 283, 305, 320, 342, 357.

    But not in your Account_OrderUpdate method
    lines 392, 406, 431, 445

    Thanks!
    Attached Files
    Last edited by PaulMohn; 06-01-2022, 02:47 PM.

    Leave a comment:


  • NinjaTrader_ChelseaB
    replied
    Hello quantitySelector,

    Is quantitySelector null?

    Do you have a print to show that is not null?

    Do you have a check to ensure that quantitySelector is not null before attempting to use it?

    Are you using a dispatcher invoke async to access UI thread objects from the Account thread?

    What code is assigning quantitySelector an object?

    Do you have print to show this is not null after the variable is assigned?

    Does this print appear before or after the print where the variable is attempted to be used in the Account_OrderUpdate method?

    Is this the chartTrader quantity selector?

    Leave a comment:

Latest Posts

Collapse

Topics Statistics Last Post
Started by CarlTrading, 05-11-2026, 05:56 AM
0 responses
56 views
0 likes
Last Post CarlTrading  
Started by CarlTrading, 05-10-2026, 08:12 PM
0 responses
33 views
0 likes
Last Post CarlTrading  
Started by Hwop38, 05-04-2026, 07:02 PM
0 responses
195 views
0 likes
Last Post Hwop38
by Hwop38
 
Started by CaptainJack, 04-24-2026, 11:07 PM
0 responses
359 views
0 likes
Last Post CaptainJack  
Started by Mindset, 04-21-2026, 06:46 AM
0 responses
280 views
0 likes
Last Post Mindset
by Mindset
 
Working...
X