Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

NT backtest capabilities - question

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

    NT backtest capabilities - question

    Hi. I'm currently trading through TradeStation and I'm not happy with their back testing methods regarding trailing stops calculation. TS limit your data to only 6 months of tick by tick data, and otherwise calculates your trailing stops (and percent trailing stops) by OHLC. Does ninjatrader offer a superior data availability? are there any limitation on the look-back period, and can I analyze a 5 min bar chart (for example) but have my back test results calculated tick by tick so that my exits are accurate?

    thanks

    #2
    Rambo23,

    Thank you for your post and welcome to the forums!

    NinjaTraders' backtest will calculate using the OHLC and Volume data available as this is the only known values for those bars. Additionally, the only limiting factor is how far back your data provider will provide historical data.

    When running this strategy live you will set the CalculateOnBarClose to False so that your strategy calculates on a tick by tick basis. The Backtest will always have this feature set to true.

    However, you can program an Intrabar Granularity into your script to have the strategy logic calculate on a tick by tick basis for a backtest.

    I am linking a reference sample on how to achieve this in your code -
    http://www.ninjatrader.com/support/f...ead.php?t=6652


    Let me know if I can be of further assistance.
    Cal H.NinjaTrader Customer Service

    Comment


      #3
      Not sure I'm getting your bottom line

      Thank you for replying. I understand how your example would help me submit orders intra-bar when trading live, but for a realistic HISTORICAL trailing stop performance, the analyzing system must look into each bar and understand the chronology of price movement within it. This cannot be done by simply looking at OHLC data. In fact, OHLC data is guaranteed to provide extremely optimistic results if trailing stops.

      It's possible that this is a terminology gap. In TS this is called LIBB, Look Inside-Bar Backtest. My question is, can NT do that, provided my data vendor is providing me with historical tick by tick data?

      Comment


        #4
        Rambo23,

        Look Inside-Bar Back is the same as the Intrabar Granularity that you would use for the backtest. It will use a 1 tick data series that the strategy will then use to calculate on each tick bar.

        When running live you can adjust your strategy to CalculateOnBarClose set to false for the Strategy to run on a tick by tick basis without the Intrabar Granularity.

        I suggested the Intrabar Granularity as this will give the results that you are looking for when running the backtest.

        Let me know if this helps
        Cal H.NinjaTrader Customer Service

        Comment


          #5
          thanks Cal
          Do you know if any of your supported data vendors offers tick by tick data without limitations? do you have any recommendations? I see TS in one of your possible vendor, but I imagine they'd enforce the same limitations (6 months max) in this case as well.

          Comment


            #6
            Rambo23,

            Below is a link on the support Data provider for NinjaTrader and what services they offer.
            http://www.ninjatrader.com/support/h...rical_data.htm
            Cal H.NinjaTrader Customer Service

            Comment


              #7
              Originally posted by NinjaTrader_Cal View Post
              Rambo23,

              Thank you for your post and welcome to the forums!

              NinjaTraders' backtest will calculate using the OHLC and Volume data available as this is the only known values for those bars. Additionally, the only limiting factor is how far back your data provider will provide historical data.

              When running this strategy live you will set the CalculateOnBarClose to False so that your strategy calculates on a tick by tick basis. The Backtest will always have this feature set to true.

              However, you can program an Intrabar Granularity into your script to have the strategy logic calculate on a tick by tick basis for a backtest.

              I am linking a reference sample on how to achieve this in your code -
              http://www.ninjatrader.com/support/f...ead.php?t=6652


              Let me know if I can be of further assistance.
              Cal--

              The SampleIntrabarbacktest strategy that you linked to only deals with how to take a signal from a higher time frame but enter on a lower time frame.

              Has the Support Team pulled together a similar example strategy on how to evaluate the stop or profit levels for backtesting--and more importantly to better reflect how the strategy would have likely performed in real time (as opposed to backtested time)? For instance, let's say we're in a long position, and that the exit bar's High is greater than the profit target (meaning that the profit target may have been hit) but that the Low is also lower than the stop level (meaning that the stop may have been hit). Are there any good examples out there for dealing with backtesting whether or not the profit target or stop was hit first?

              For instance, let's say one was to add a Tick chart with a value of 1 as a secondary data series

              Code:
               protected override void Initialize()
              {
                   Add(PeriodType.Tick, 1);
              }
              Then, within OnBarUpdate(), would you test for the exit (stop or target) on the second data series? For instance, could you do something like this:

              Code:
              protected override void OnBarUpdate()
              		{
              			if(BarsinProgress == 1)
              			{
              				if(Position.MarketPosition == MarketPosition.Flat)
              					return;
              
              				// stop for longs
              				if(Close[0] <= stopPrice)
              				{
              					ExitLong();
              				}
              
              				// stop for shorts
              				else if(Close[0] >= stopPrice)
              				{
              					ExitShort();
              				}
              
              				// profit target for longs
              				else if(Close[0] >= profitPrice)
              				{
              					ExitLong();
              				}
              
              				// profit target for shorts
              				else if(Close[0] <= profitPrice)
              				{
              					ExitShort();
              				}
              			}
              If you are able to use the above concept, can you also confirm that if you use the if(BarsInProgress == 1) condition, that you don't need to be looking at the Closes[1][0] (instead of Close[0])? Does the BarsInProgress == 1 if statement mean that we can just use Close[0]?

              Thanks,

              Aventeren
              Last edited by aventeren; 02-20-2014, 09:00 PM. Reason: Typo and formatting

              Comment


                #8
                Aventeren,

                Your best option would be to use the Market Replay so that you can run as if it was a live situation.

                Additionally, you can use the Intrabar Granularity to take signals from a lower time frame such as a 1 tick data series and then enter your orders from that.
                Cal H.NinjaTrader Customer Service

                Comment


                  #9
                  Originally posted by NinjaTrader_Cal View Post
                  Aventeren,

                  Your best option would be to use the Market Replay so that you can run as if it was a live situation.

                  Additionally, you can use the Intrabar Granularity to take signals from a lower time frame such as a 1 tick data series and then enter your orders from that.
                  I don't see how using Market Replay will help here, as I'm interested in how the backtest engine will evaluate the code--not a forward (i.e., Sim in Live or Market Replay).

                  Does the "exit bar" secondary data series code appear to make sense (below)?

                  Also, if you use the if(BarsInProgress == 1) condition, can you then get away with not having to use Closes[1][0] and instead can just use Close[0] because the if-statement already puts you within the BarsArray[1] data series?

                  Thanks,

                  Aventeren

                  Comment


                    #10
                    Yes it does makes sense, however the BarsInProgess only filters which tick came in. You would still need to use Closes[1] to reference which data series values you want to use.
                    Cal H.NinjaTrader Customer Service

                    Comment


                      #11
                      Originally posted by NinjaTrader_Cal View Post
                      Yes it does makes sense, however the BarsInProgess only filters which tick came in. You would still need to use Closes[1] to reference which data series values you want to use.
                      Cool, thanks.

                      Comment


                        #12
                        Originally posted by NinjaTrader_Cal View Post
                        Yes it does makes sense, however the BarsInProgess only filters which tick came in. You would still need to use Closes[1] to reference which data series values you want to use.
                        Cal, sorry to double back on you here, but from everything I am reading in the NinjaScript documentation, when you call Close[0] within an if(BarsInProgress == 1), the Close[0] should be grabbing the Close from the BarsArray[1] data series and not the BarsArray[0] data series, which your comment (above) states.

                        Since a NinjaScript is truly event driven, the OnBarUpdate() method is called for every bar update event for each Bars object added to a script. This model provides the utmost flexibility. For example, you could have multiple trading systems combined into one strategy dependent on one another. Specifically, you could have a 1 minute MSFT Bars object and a 1 minute AAPL Bars object, process different trading rules on each Bars object and check to see if MSFT is long when AAPL trading logic is being processed.

                        The BarsInProgress property is used to identify which Bars object is calling the OnBarUpdate() method. This allows you to filter out the events that you want to or don't want to process.

                        Continuing our example above, let's take a look at some code to better understand what is happening. Remember, we have three Bars objects working in our script, a primary Bars MSFT 1 minute, MSFT 3 minute and AAPL 1 minute.

                        protected override void OnBarUpdate()
                        {
                        // Checks to ensure all Bars objects contain enough bars before beginning
                        if (CurrentBars[0] <= BarsRequired || CurrentBars[1] <= BarsRequired || CurrentBars[2] <= BarsRequired)
                        return;

                        // Checks if OnBarUpdate() is called from an update on the primary Bars
                        if (BarsInProgress == 0)
                        {
                        if (Close[0] > Open[0])
                        // Do something
                        }

                        // Checks if OnBarUpdate() is called from an update on MSFT 3 minute Bars
                        if (BarsInProgress == 1)
                        {
                        if (Close[0] > Open[0])
                        // Do something
                        }

                        // Checks if OnBarUpdate() is called from an update on AAPL 1 minute Bars
                        if (BarsInProgress == 2)
                        {
                        if (Close[0] > Open[0])
                        // Do something
                        }
                        }

                        What is important to understand in the above sample code is that we have "if" branches that check to see what Bars object is calling the OnBarUpdate() method in order to process relevant trading logic. If we only wanted to process the events from the primary Bars we could write our first statement as follows:

                        if (BarsInProgress != 0)
                        return;

                        What is also important to understand is the concept of context. When the OnBarUpdate() method is called, it will be called within the context of the calling Bars object. This means that if the primary Bars triggers the OnBarUpdate() method, all indicator methods and price data will point to that Bars object's data. Looking at the above example, see how the statement "if (Close[0] > Open[0]" exists under each "if" branch? The values returned by Close[0] and Open[0] will be the close and open price values for the calling Bars object. So when the BarsInProgress == 0 (primary Bars) the close value returned is the close price of the MSFT 1 minute bar. When the BarsInProgress == 1 the close value returned is the close price of the MSFT 3 minute Bars object.


                        Notes
                        1. A multi-series script only processes bar update events from the primary Bars (the series the script is applied to) and any additional Bars objects the script adds itself. Additional Bars objects from a multi-series chart or from other multi-series scripts that may be running concurrently will not be processed by this multi-series script.
                        2. If a multi-series script adds an additional Bars object that already exists on the chart, the script will use the preexisting series instead of creating a new one to conserve memory. This includes that series' session template as applied from the chart. If the Bars object does not exist on the chart, the session template of the added Bars object will be the session template of the primary Bars object. If the primary Bars object is using the "<Use instrument settings>" session template then the additional Bars objects will use the default session templates as defined for their particular instruments in the Instrument Manager.
                        3. In a multi-series script, real-time bar update events for a particular Bars object are only received when that Bars object has satisfied the BarsRequired requirement. To ensure you have satisfied the BarsRequired requirement on all your Bars objects it is recommend you start your OnBarUpdate() method with CurrentBars checks.
                        4. A multi-series indicator will hold the same number of data points for plots as the primary series. Setting values to plots should be done in the primary series in OnBarUpdate(). If you are using calculations based off of a larger secondary series, it may plot like a step ladder because there are more data points available than there are actual meaningful data values.
                        What am I missing? Shouldn't the answer to my previous question be "Yes, if you use the if(BarsInProgress == 1) condition, you can use Close[0] to access the Close of the BarsArray[1] data series?

                        Also, if you use the if(BarsInProgress == 1) condition, can you then get away with not having to use Closes[1][0] and instead can just use Close[0] because the if-statement already puts you within the BarsArray[1] data series?

                        Comment


                          #13
                          aventeren,

                          Apologies, you are correct in this statement.
                          Using the BarsInProgress you can then just use the Close[0] for that tick.
                          Cal H.NinjaTrader Customer Service

                          Comment


                            #14
                            Originally posted by NinjaTrader_Cal View Post
                            aventeren,

                            Apologies, you are correct in this statement.
                            Using the BarsInProgress you can then just use the Close[0] for that tick.
                            Cool--that was a head scratcher for me after I started doing some more research into it.

                            Comment

                            Latest Posts

                            Collapse

                            Topics Statistics Last Post
                            Started by Rooskie, Today, 05:37 AM
                            0 responses
                            5 views
                            0 likes
                            Last Post Rooskie
                            by Rooskie
                             
                            Started by RubenCazorla, Today, 03:23 AM
                            0 responses
                            6 views
                            0 likes
                            Last Post RubenCazorla  
                            Started by Mr Bread, 06-01-2024, 04:14 AM
                            5 responses
                            64 views
                            0 likes
                            Last Post Mr Bread  
                            Started by Jakub, 07-19-2024, 11:06 AM
                            6 responses
                            58 views
                            0 likes
                            Last Post Jakub
                            by Jakub
                             
                            Started by FOMOzombie, 06-26-2024, 08:01 AM
                            8 responses
                            64 views
                            0 likes
                            Last Post DonnieTrader  
                            Working...
                            X