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

Questions about backtesting and getting price values without typing

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

    Questions about backtesting and getting price values without typing

    Hello, I just started exploring ninja trader and I'd like to backtest my strategy with the playback function. I'd like to manually enter a stop buy order at high[1]+ 1 tick or a stop short at low[1] - 1 tick without having to manually type the values, and to process the order using an atm strategy

    Now I’m not sure I understood correctly but it seems you can’t backtest in playback atm strategies called by a strategy script? because otherwise I’d try to customize the Long Short Toolbar Buttons strategy.

    Alternatively, I thought I could get the value by clicking on the chart at the desired price level, store it into the clipboard and paste it in the basic entry window, but this either doesn’t seem possible?

    Is there any solution for this?
    Thank you

    #2
    Hello Atenlor,

    What you described is possible but due to submitting order manually and using ATM's that would be a realtime only tool. You are correct to use the playback connection, you would have to be playing forward in time to see this type of script working.

    The long/short toolbar would be what is suggested for your manual order actions. You would program a button press to submit the order and at a calculated price. Submitting orders with any other tool in the platform would not be tracked by a NinjaScript strategy.

    The best way forward here would be to first review the SampleATMStrategy script and how it works with ATM's. Once you understand what that is doing you could add the code from the long/short toolbar to make buttons of your own. Instead of using OnBarUpdate to wait for a price condition to submit the ATM you could use one of the buttons events.

    If you are working directly from a button event then you need to surround the code inside the event hander with TriggerCustomEvent. the long/short toolbar avoids this by using bool variables to trigger actions in OnBarUpdate however that is delayed at the rate of OnBarUpdate. Code inside the event handler is executed immediately but requires TriggerCustomEvent for accurate prices.


    Code:
    buttonEventHander() {
       TriggerCustomEvent(o =>
       {
        // your code in here
       }, null);
    }
    JesseNinjaTrader Customer Service

    Comment


      #3
      I'm going to try, Thank you!

      Comment


        #4
        Hi Jesse, I tried to follow your suggestion and I created the script.
        Here's the code:

        Code:
        namespace NinjaTrader.NinjaScript.Strategies
        {
        public class TmpBtn : Strategy
        {
        private bool longButtonClicked;
        private bool shortButtonClicked;
        private string atmStrategyId = string.Empty;
        private string orderId = string.Empty;
        private bool isAtmStrategyCreated = false;
        private System.Windows.Controls.Button longButton;
        private System.Windows.Controls.Button shortButton;
        private System.Windows.Controls.Grid myGrid;
        protected override void OnStateChange()
        {
        if (State == State.SetDefaults)
        {
        Description = @"TmpBtn";
        Name = "TmpBtn";
        Calculate = Calculate.OnEachTick;
        EntriesPerDirection = 3;
        EntryHandling = EntryHandling.AllEntries;
        IsExitOnSessionCloseStrategy = true;
        ExitOnSessionCloseSeconds = 30;
        IsFillLimitOnTouch = false;
        MaximumBarsLookBack = MaximumBarsLookBack.TwoHundredFiftySix;
        OrderFillResolution = OrderFillResolution.Standard;
        Slippage = 0;
        StartBehavior = StartBehavior.WaitUntilFlat;
        TimeInForce = TimeInForce.Gtc;
        TraceOrders = false;
        RealtimeErrorHandling = RealtimeErrorHandling.StopCancelClose;
        StopTargetHandling = StopTargetHandling.PerEntryExecution;
        BarsRequiredToTrade = 0;
        }
        else if (State == State.Configure)
        {
        }
        else if (State == State.Historical)
        {
        if (UserControlCollection.Contains(myGrid))
        return;
        
        Dispatcher.InvokeAsync((() =>
        {
        myGrid = new System.Windows.Controls.Grid
        {
        Name = "MyCustomGrid", HorizontalAlignment = HorizontalAlignment.Right, VerticalAlignment = VerticalAlignment.Top
        };
        
        System.Windows.Controls.ColumnDefinition column1 = new System.Windows.Controls.ColumnDefinition();
        System.Windows.Controls.ColumnDefinition column2 = new System.Windows.Controls.ColumnDefinition();
        
        myGrid.ColumnDefinitions.Add(column1);
        myGrid.ColumnDefinitions.Add(column2);
        
        longButton = new System.Windows.Controls.Button
        {
        Name = "LongButton", Content = "LONG", Foreground = Brushes.White, Background = Brushes.Green
        };
        
        shortButton = new System.Windows.Controls.Button
        {
        Name = "ShortButton", Content = "SHORT", Foreground = Brushes.Black, Background = Brushes.Red
        };
        
        longButton.Click += OnButtonClick;
        shortButton.Click += OnButtonClick;
        
        System.Windows.Controls.Grid.SetColumn(longButton, 0);
        System.Windows.Controls.Grid.SetColumn(shortButton , 1);
        
        myGrid.Children.Add(longButton);
        myGrid.Children.Add(shortButton);
        
        UserControlCollection.Add(myGrid);
        }));
        }
        else if (State == State.Terminated)
        {
        Dispatcher.InvokeAsync((() =>
        {
        if (myGrid != null)
        {
        if (longButton != null)
        {
        myGrid.Children.Remove(longButton);
        longButton.Click -= OnButtonClick;
        longButton = null;
        }
        if (shortButton != null)
        {
        myGrid.Children.Remove(shortButton);
        shortButton.Click -= OnButtonClick;
        shortButton = null;
        }
        }
        }));
        }
        }
        
        private void OnButtonClick(object sender, RoutedEventArgs rea)
        {
        if(State == State.Historical)
        return;
        System.Windows.Controls.Button button = sender as System.Windows.Controls.Button;
        TriggerCustomEvent(o =>
        {
        if (button == longButton && button.Name == "LongButton" && button.Content == "LONG" && orderId.Length == 0 && atmStrategyId.Length == 0)
        {
        isAtmStrategyCreated = false; // reset atm strategy created check to false
        atmStrategyId = GetAtmStrategyUniqueId();
        orderId = GetAtmStrategyUniqueId();
        AtmStrategyCreate(OrderAction.Buy, OrderType.StopMarket, 0, High[1] + TickSize, TimeInForce.Gtc, orderId, "def", atmStrategyId, (atmCallbackErrorCode, atmCallBackId) => {
        //check that the atm strategy create did not result in error, and that the requested atm strategy matches the id in callback
        if (atmCallbackErrorCode == ErrorCode.NoError && atmCallBackId == atmStrategyId)
        isAtmStrategyCreated = true;
        });
        }
        if (button == shortButton && button.Name == "ShortButton" && button.Content == "SHORT" && orderId.Length == 0 && atmStrategyId.Length == 0)
        {
        isAtmStrategyCreated = false; // reset atm strategy created check to false
        atmStrategyId = GetAtmStrategyUniqueId();
        orderId = GetAtmStrategyUniqueId();
        AtmStrategyCreate(OrderAction.Sell, OrderType.StopMarket, 0, Low[1] - TickSize, TimeInForce.Gtc, orderId, "def", atmStrategyId, (atmCallbackErrorCode, atmCallBackId) => {
        //check that the atm strategy create did not result in error, and that the requested atm strategy matches the id in callback
        if (atmCallbackErrorCode == ErrorCode.NoError && atmCallBackId == atmStrategyId)
        isAtmStrategyCreated = true;
        });
        }
        }, null);
        }
        
        
        protected override void OnBarUpdate()
        {
        if (CurrentBar < BarsRequiredToTrade)
        return;
        
        if(State == State.Historical)
        return;
        // Check that atm strategy was created before checking other properties
        if (!isAtmStrategyCreated)
        return;
        
        // Check for a pending entry order
        if (orderId.Length > 0)
        {
        string[] status = GetAtmStrategyEntryOrderStatus(orderId);
        
        // If the status call can't find the order specified, the return array length will be zero otherwise it will hold elements
        if (status.GetLength(0) > 0)
        {
        // Print out some information about the order to the output window
        //Print("The entry order average fill price is: " + status[0]);
        //Print("The entry order filled amount is: " + status[1]);
        //Print("The entry order order state is: " + status[2]);
        
        // If the order state is terminal, reset the order id value
        if (status[2] == "Filled" || status[2] == "Cancelled" || status[2] == "Rejected")
        orderId = string.Empty;
        }
        } // If the strategy has terminated reset the strategy id
        else if (atmStrategyId.Length > 0 && GetAtmStrategyMarketPosition(atmStrategyId) == Cbi.MarketPosition.Flat)
        atmStrategyId = string.Empty;
        }
        }
        }
        It seems to work as intended! Is there any improvement I can make?
        I tried to put the portion below OnBarUpdate inside the TriggerCustomEvent but I didn't notice any difference. I noticed that in either way, if I cancel the strategy using the Basic Entry I have to wait for the tick update (5 seconds?) before being able to initiate a new trade with the same strategy. Is it the normal and unavoidable behaviour?

        I'd like to add more buttons below the two I created. I guess I have to create a new row inside the grid and assign the new buttons to that, but I'm not sure about the correct syntax. Can you help me?

        Thank you

        Comment


          #5
          Hello Atenlor,

          The manual cancellation is the problem, you would need implement another button to handle the cancel. The reason it takes long is because the reset code is inside OnBarUpdate which is linked to the primary series. For the reset to happen immediately you would need to make your own button that both cancels the atm and also resets the atmStrategyId and orderId variable.

          OnBarUpdate shouldn't be needed for anything unless you wanted to use it to monitor something, otherwise that code inside OnBarUpdate needs to be removed and re made in the way you wanted the script to actually work. The main take away is that the atmStrategyId and orderId variable needs set to empty before your button to submit the order works.
          JesseNinjaTrader Customer Service

          Comment

          Latest Posts

          Collapse

          Topics Statistics Last Post
          Started by judysamnt7, 03-13-2023, 09:11 AM
          4 responses
          59 views
          0 likes
          Last Post DynamicTest  
          Started by ScottWalsh, Today, 06:52 PM
          4 responses
          36 views
          0 likes
          Last Post ScottWalsh  
          Started by olisav57, Today, 07:39 PM
          0 responses
          7 views
          0 likes
          Last Post olisav57  
          Started by trilliantrader, Today, 03:01 PM
          2 responses
          21 views
          0 likes
          Last Post helpwanted  
          Started by cre8able, Today, 07:24 PM
          0 responses
          10 views
          0 likes
          Last Post cre8able  
          Working...
          X