Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Strategy historical closes at random price. NT bug or mine?

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

    Strategy historical closes at random price. NT bug or mine?

    I have a pretty simple strategy that opens limit entry orders, and then if they fill, assigns a SL, TP1 & TP2.

    StopLoss initially set to 60 ticks, second target is 96 ticks. First target is 28 ticks, and if it reaches it, then it moves the SL to Breakeven + 1 tick.

    I have NQ 1-min data loaded for 30 days. There are only 3 type of trades I should see.

    When it wins both legs, it should look like this:

    Click image for larger version  Name:	image.png Views:	0 Size:	23.5 KB ID:	1319179

    When it loses both, like this:

    Click image for larger version  Name:	image.png Views:	0 Size:	8.2 KB ID:	1319180

    And when it wins first, and then hits breakeven, like this:

    Click image for larger version  Name:	image.png Views:	0 Size:	5.0 KB ID:	1319178

    And most of the historical shows one of those. But then there are also periodic trades like this:

    Click image for larger version  Name:	image.png Views:	0 Size:	5.7 KB ID:	1319181

    I'll use this last picture as an example.
    I have added a great deal of logging code, and for that trade, it looks like this (comments in red, bold):

    EA #000 - NQ 12-24 - [OnBarUpdate] - 19-Sep-24 11:16:00 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    DOWNWARD CROSS OF 50-LEVEL (20150) on 11:16:00 Candle
    ENTERING LONG LIMIT @ 20126

    Placed the long limit order ok

    EA #000 - NQ 12-24 - [OnExecutionUpdate] - 19-Sep-24 11:17:00 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    execution.IsEntryStrategy = True, execution.Order.OrderAction = Buy, MarketPosition = Long, marketPosition = Long, execution.Order.OrderAction = Buy, quantity = 2

    Setting SL (60) for Entry @ 20126 to 20111
    Setting TP1 (28) for Entry @ 20126 to 20133
    Setting TP2 (96) for Entry @ 20126 to 20150


    EA #000 - NQ 12-24 - [OnExecutionUpdate] - 19-Sep-24 11:17:00 - (hits TP1 on entry candle) - - - - - - - - - -

    execution.IsEntryStrategy = False, execution.Order.OrderAction = Sell, MarketPosition = Long, marketPosition = Short, execution.Order.OrderAction = Sell, quantity = 1

    TRADE CLOSED, price (param) = 20133
    Last trade PnL: $136.9
    Trade Closed; attempting to adjust SL order quantity to 1. stopOrder.StopPrice = 20111

    I re-submit the SL order because one of the two contracts has closed, like this:

    ExitLongStopMarket(0, true, Position.Quantity, stopOrder.StopPrice, "StopLoss", "Long");



    EA #000 - NQ 12-24 - [OnBarUpdate] - 19-Sep-24 11:17:00 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    Before: Stop Price = 20111

    *MoveToBE TRIGGERED* because High[0] (20133.75) >= Trigger price @ 20132.75: newStopPrice set to 20126.25. Old stop price = 20111

    Calling ExitLongStopMarket(), qty = 1, new SL = 20126.25

    After: Stop Price = 20126.25


    EA #000 - NQ 12-24 - [OnOrderUpdate] - 19-Sep-24 11:19:00 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    (calls OnOrderUpdate 3 times cancelling TP2 before closing the second part of the order next)
    OrderState = CancelPending, OrderAction = Sell, OrderType = Limit, limitPrice = 20150
    OrderState = CancelSubmitted, OrderAction = Sell, OrderType = Limit, limitPrice = 20150
    OrderState = Cancelled, OrderAction = Sell, OrderType = Limit, limitPrice = 20150


    EA #000 - NQ 12-24 - [OnExecutionUpdate] - 19-Sep-24 11:19:00 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    execution.IsEntryStrategy = False, execution.Order.OrderAction = Sell, MarketPosition = Flat, marketPosition = Short, execution.Order.OrderAction = Sell, quantity = 1

    TRADE CLOSED, price (param) = 20120.5

    Closes trade at 20120.50; a price which has nothing to do with anything.



    Can any one shed some light on what is happening here?
    I have heard the tester on NT8 wasn't terribly accurate, but surely historical can't have that many flaws...?
    ​​​​​​
    Last edited by DerkWehler; 09-24-2024, 10:51 PM.

    #2
    Hello DarkWehler,

    Thank you for your post.

    Live orders are filled on an exchange with a trading partner on an agreed upon price based on market dynamics. Backtest (historical) orders are not using these market dynamics. Instead these are filled based on logical rules from processing historical data.
    • When in historical data, only the Open, High, Low, and Close will be available and there will be no intra-bar data.
      • This means actions cannot happen intra-bar, fills cannot happen intra-bar. All prices and actions come from and occur when the bar closes as this is all the information that is known
      • Because of this, OnBarUpdate will only update 'On bar close' as it does not have the intra-bar information necessary for 'On price change' or 'On each tick' and the script will not have the intra-bar information to accurately fill an order at the exact price and time.
    Intra-bar granularity adds a second data series such as a 1 tick series using AddDataSeries() so that the strategy or indicator has the individual ticks in the historical data in between the High and Low of the primary series.
    In NinjaTrader 8, there have been two new enhancements so that programmers may not have to manually add this secondary series and code the script for high accuracy fills (Order Fill Resolution) or for intra-bar actions (TickReplay) depending on the needs of the script.
    Note: bar types that are IsRemoveLastBarSupported cannot be used with TickReplay and generally cause inaccurate results when backtesting in historical data.
    Note: High Order Fill Resolution allows for intra-bar order fills with historical processing, but is not compatible with Tick Replay.

    Please see this support article for a detailed explanation:

    https://support.ninjatrader.com/s/ar...ar-granularity
    Gaby V.NinjaTrader Customer Service

    Comment


      #3
      Thank you for the reply Gaby. I will watch it in real time to see if it ever fails. And thanks for the link for granularity.

      Comment


        #4
        I looked at the methods of increasing granularity, but it mentions adding a tick data series, which the code already has, so shouldn't it react correctly to each tick?


        Comment


          #5
          Hello,

          Are you actually submitting the orders to the 1-tick series?

          If your strategy is using Calculate.OnEachTick or Calculate.OnPriceChange, are you using TickReplay?
          Gaby V.NinjaTrader Customer Service

          Comment


            #6
            Originally posted by NinjaTrader_Gaby View Post
            Hello,

            Are you actually submitting the orders to the 1-tick series?

            If your strategy is using Calculate.OnEachTick or Calculate.OnPriceChange, are you using TickReplay?

            No, I was submitting from the chart TF (1 minute).

            Also, I had:

            Calculate = Calculate.OnBarClose;

            Does that need to be OnEachTick or OnPriceChange to work properly (in any strategy which has a tick series)?

            And no, I am not using TickReplay; I don't even have a very clear idea yet what that does or if it would ever be useful to me.

            Comment


              #7
              Hello,

              In order to properly implement 1-tick intrabar granularity, the orders need to actually be submitted to the 1-tick series. Just adding the 1-tick series isn't going to do anything on its own.



              You do not need to use TickReplay if your strategy is running Calculate.OnBarClose.
              Gaby V.NinjaTrader Customer Service

              Comment


                #8
                If one has a 1-tick data series, do I need to set

                Calculate = Calculate.OnEachTick;

                (or Calculate.OnPriceChange) to process each tick?

                I had thought just adding the data series would cause it to call OnBarUpdate each tick.

                And from there I filtered actions by BarsInProgress value.




                Comment


                  #9
                  Hello DarkWehler,

                  Thank you for your post.

                  If you want OnBarUpdate called for every tick in the 1 minute bar, you would need to use Calculate.OnEachTick.



                  However note that just adding a 1-tick series or changing the Calculate setting to OnEachTick isn't implementing intrabar granularity. The orders need to actually be submitted to the 1-tick series to achieve 1-tick intrabar granularity.

                  If you look at the sample script from my previous post, you will see that it's using OnBarClose and only has actions when BIP = 0 (on the primary data series). However, it is submitting the orders to the secondary 1-tick series (BIP 1).
                  Gaby V.NinjaTrader Customer Service

                  Comment


                    #10
                    Yes, I changed entries to 1-tick. Now I just set a flag in the (BarsInProgress == 0), which is checked in the (BarsInProgress == 1), where it places the trade.

                    Oh! And yes, I see, re: the first parameter when placing an order. That is helpful; thanks! I never knew before why that was there. So I don't have to use the flag method.




                    Comment


                      #11
                      Originally posted by NinjaTrader_Gaby View Post
                      Hello DarkWehler,

                      If you want OnBarUpdate called for every tick in the 1 minute bar, you would need to use Calculate.OnEachTick.

                      However note that just adding a 1-tick series or changing the Calculate setting to OnEachTick isn't implementing intrabar granularity. The orders need to actually be submitted to the 1-tick series to achieve 1-tick intrabar granularity.

                      If you look at the sample script from my previous post, you will see that it's using OnBarClose and only has actions when BIP = 0 (on the primary data series). However, it is submitting the orders to the secondary 1-tick series (BIP 1).
                      Wait... you aren't just talking about historical trades are you?

                      One thing I don't understand then... I have another strategy, which uses Calculate.OnBarClose and has 1-tick data series (while running on M1 chart), and at least in real time, it does everything as intended. Things that happen only per-bar are running correctly (BIP=0) and main entry and trailing stop are running correctly from the BIP=1 section.

                      Which, of course, is why the info you have been giving me came as a surprise. But on that strategy, I never run historical, only real time.


                      Last edited by DerkWehler; 10-02-2024, 08:46 AM.

                      Comment


                        #12
                        I am talking about historical. Intrabar granularity isn't necessary for real time tests.

                        But on that strategy, I never run historical, only real time.
                        Your post seems to be talking about historical trades.

                        I have heard the tester on NT8 wasn't terribly accurate, but surely historical can't have that many flaws...?
                        Gaby V.NinjaTrader Customer Service

                        Comment


                          #13
                          Originally posted by NinjaTrader_Gaby View Post
                          I am talking about historical. Intrabar granularity isn't necessary for real time tests.
                          So, I would need to change it to OnEachTick and recompile every time I want to see accurate history?

                          But no need for it in real time?

                          Comment


                            #14
                            No. As previously discussed, it is not necessary to have to change your Calculate setting to see accurate results in backtest / historical.

                            It is however need to implement intrabar granularity. Calculate.OnEachTick does not implement intrabar granularity in backtest.

                            Live orders are filled on an exchange with a trading partner on an agreed upon price based on market dynamics. Backtest (historical) orders are not using these market dynamics. Instead these are filled based on logical rules from processing historical data.
                            • When in historical data, only the Open, High, Low, and Close will be available and there will be no intra-bar data.
                              • This means actions cannot happen intra-bar, fills cannot happen intra-bar. All prices and actions come from and occur when the bar closes as this is all the information that is known
                              • Because of this, OnBarUpdate will only update 'On bar close' as it does not have the intra-bar information necessary for 'On price change' or 'On each tick' and the script will not have the intra-bar information to accurately fill an order at the exact price and time.


                            However note that just adding a 1-tick series or changing the Calculate setting to OnEachTick isn't implementing intrabar granularity. The orders need to actually be submitted to the 1-tick series to achieve 1-tick intrabar granularity.
                            Last edited by NinjaTrader_Gaby; 10-02-2024, 09:41 AM.
                            Gaby V.NinjaTrader Customer Service

                            Comment


                              #15
                              Originally posted by NinjaTrader_Gaby View Post
                              No. As previously discussed, it is not necessary to have to change your Calculate setting to see accurate results in backtest / historical.

                              It is however need to implement intrabar granularity. Calculate.OnEachTick does not implement intrabar granularity in backtest.



                              I'm sorry if I am not getting it...
                              So if I want historical to be accurate (intrabar), as well as real time, how should I set it?
                              I am already submitting all orders to BIP=1.

                              Comment

                              Latest Posts

                              Collapse

                              Topics Statistics Last Post
                              Started by jpkulkarni, Today, 09:27 PM
                              0 responses
                              3 views
                              0 likes
                              Last Post jpkulkarni  
                              Started by Scalper888, Yesterday, 05:09 PM
                              5 responses
                              23 views
                              0 likes
                              Last Post Scalper888  
                              Started by CardozoPeggy, Today, 06:01 PM
                              0 responses
                              3 views
                              0 likes
                              Last Post CardozoPeggy  
                              Started by aaaa7389, Today, 05:33 PM
                              0 responses
                              4 views
                              0 likes
                              Last Post aaaa7389  
                              Started by aaaa7389, Today, 05:32 PM
                              0 responses
                              5 views
                              0 likes
                              Last Post aaaa7389  
                              Working...
                              X