Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Entry & Profit Target Behavior Change Live VS Strategy Analyzer

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

    Entry & Profit Target Behavior Change Live VS Strategy Analyzer

    The behavior of my entry, profit target, and stop all change when I test my strategy live vs strategy analyzer.

    For example every 2 hours my indicator prints the average price of the previous 2 hour period and my entry 1 is set to trigger only when price closes X ticks under the chosen line:

    Code:
    if (Profit==1)
    line=AV().Av1[0];
    else if (Profit==2)
    line=AV().Av2[0];
    else if (Profit==3)
    line=AV().Av3[0];
    else if (Profit==4)
    line=AV().Av4[0];
    else if (Profit==5)
    line=AV().Av5[0];
    
    
    if (Position.MarketPosition==MarketPosition.Flat && BarsInProgress==0)
    {
    
    //ENTRY 1
    if (Close[0]+MinTickAway*TickSize<line)
    {
    //Print(Time[0]+" - "+line);
    prof=line;
    EnterLong(Lot1,"Entry1");
    SetStopLoss("Entry1",CalculationMode.Ticks,SL,true );
    SetProfitTarget("Entry1",CalculationMode.Price,line,true);
    Today my entry occurred above the selected line and I noticed that it was the correct X ticks under the triggered "Profit Target" which was supposed to be line 1 but was actually a price about 20 ticks higher than all of the drawn indicator lines.

    Does anyone know why the live conditions might distort the codes functionality?

    Please see attached photo to better understand the desired functionality in strategy analyzer and what occurred today. (Green Line is AV1, which is the desired profit target) Click image for larger version  Name:	Entry Issue.png Views:	0 Size:	86.6 KB ID:	1142162
    Last edited by mlprice12; 02-16-2021, 12:58 PM.

    #2
    Hello mlprice12,

    Thanks for your post.

    I would start reviewing the known differences between historical processing and realtime processing.

    Discrepancies between realtime and backtest - https://ninjatrader.com/support/help...ime_vs_bac.htm

    Understanding historical fill processing — https://ninjatrader.com/support/help...ical_fill_.htm

    Please note that the way orders fill will be different (using historical OHLC values to simulate order fills instead of current market data) and the strategy logic will be forced to Calculate.OnBarClose when processing historical data because there is no intrabar movement in a backtest. Tick Replay can be used for historical Calculate.OnPriceChange and Calculate.OnEachTick, but this does not change how the orders fill. You could combine Tick Replay with submitting orders to a single tick data series, but this would require using Exit methods and leaving the Set methods behind. (Exit methods would be needed to have the orders for stop/target submitted to a single tick data series to have them filled intrabar.)

    Note: Even with the above, results will not match live to historical 1:1, but this will be as close as you can get.

    Tick Replay - https://ninjatrader.com/support/help...ick_replay.htm

    Backtesting with intrabar granularity - https://ninjatrader.com/support/help...ipt_strate.htm

    After reviewing the above, I would suggest submitting the Set methods before the entry order is called. Set methods prep NinjaTrader to submit target/stop once an entry order fills. We should then make sure we call the Set method before the associated entry is called, so we ensure that the stop and target are reset to an initial level, so when the entry order fills, the stop and target are submitted where they should be.

    Outside of these differences, I suggest then to reproduce the the different trades and use prints to track how the strategy is using different price levels for order submissions or how the logic is becoming true when you did not expect.

    Debugging Tips - https://ninjatrader.com/support/help...script_cod.htm

    We look forward to assisting.
    JimNinjaTrader Customer Service

    Comment


      #3
      Thanks Jim,

      I understand the order fill differences between historical and live and the inherent discrepancies that will pop up when backtesting vs live.

      I believe my issue has to do with the code logic but I' not figuring it out.

      The issue outlined in the original post is that my "Entry 1" triggered too early and triggered based off an indicator price that isn't visible.

      "Entry 1" was set to trigger when price fell 16 ticks under "AV1" (green line) however it triggered when price was still above the line.

      Issue 2 which is connected to issue 1 and might help debug is that when "Entry 1" triggered it chose a profit target that doesn't correspond to any of the "AV Lines" "Entry 1" is supposed to use "AV1" as the profit target but instead chose a price much higher (about 23 ticks).

      I have setup prints to fire when "Entry 1" is triggered but have to wait for the strategy to be flat and run tonight or tomorrow.

      The reason it is weird is because the logic works perfectly as desired with historical data but not live data.

      Code:
      protected override void OnStateChange()
      {
      if (State == State.SetDefaults)
      {
      Lot1 = 1;
      Lot2 = 1;
      Lot3 = 1;
      Lot4 = 1;
      MinTickAway = 16;
      TFPE2=12;
      TFPE3=12;
      TFPE4=12;
      Profit=1;
      SL=1200;
      }
      else if (State == State.Configure)
      {
      AddDataSeries(BarsPeriodType.Minute, 120);
      AddChartIndicator(AV());
      }
      }
      
      private double line=0;
      private double prof=0;
      private double entry1_price=0;
      
      private double st=0;
      
      private Order ord2=null;
      private Order ord3=null;
      private Order ord4=null;
      
      protected override void OnOrderUpdate(Order order, double limitPrice, double stopPrice, int quantity, int filled, double averageFillPrice, OrderState orderState, DateTime time, ErrorCode error, string nativeError)
      {
      
      if ( (order.Name == "Stop loss" || order.Name == "Profit target") && orderState == OrderState.Filled &&
      order.FromEntrySignal=="Entry1")
      {
      CancelOrder(ord2);
      CancelOrder(ord3);
      CancelOrder(ord4);
      }
      
      
      if (order.Name == "Stop loss" && (orderState == OrderState.Working || orderState == OrderState.Accepted) &&
      order.FromEntrySignal=="Entry1")
      {
      st=order.StopPrice;
      }
      
      if (order.Name == "Entry1" && orderState == OrderState.Filled)
      {
      
      //2
      ord2=EnterLongLimit(0,true,Lot2,averageFillPrice-TFPE2*TickSize,"Entry2");
      SetStopLoss("Entry2",CalculationMode.Price,st,true );
      SetProfitTarget("Entry2",CalculationMode.Price,pro f,true);
      
      //3
      ord3=EnterLongLimit(0,true,Lot3,averageFillPrice-(TFPE2+TFPE3)*TickSize,"Entry3");
      SetStopLoss("Entry3",CalculationMode.Price,st,true );
      SetProfitTarget("Entry3",CalculationMode.Price,pro f,true);
      
      //4
      ord4=EnterLongLimit(0,true,Lot4,averageFillPrice-(TFPE2+TFPE3+TFPE4)*TickSize,"Entry4");
      SetStopLoss("Entry4",CalculationMode.Price,st,true );
      SetProfitTarget("Entry4",CalculationMode.Price,pro f,true);
      }
      
      }
      protected override void OnBarUpdate()
      {
      
      
      if (Profit==1)
      line=AV().Av1[0];
      else if (Profit==2)
      line=AV().Av2[0];
      else if (Profit==3)
      line=AV().Av3[0];
      else if (Profit==4)
      line=AV().Av4[0];
      else if (Profit==5)
      line=AV().Av5[0];
      
      
      
      if (Position.MarketPosition==MarketPosition.Flat && BarsInProgress==0)
      {
      
      //ENTRY 1
      if (Close[0]+MinTickAway*TickSize<line)
      {
      Print(Time[0]+" Entry 1 Trigger line "+line);
      prof=line;
      EnterLong(Lot1,"Entry1");
      SetStopLoss("Entry1",CalculationMode.Ticks,SL,true );
      SetProfitTarget("Entry1",CalculationMode.Price,lin e,true);

      I'll attach the indicator code too because it seems like the strategy code is reading data from the indicator undesirably and that's why the "Entry 1" fired early and the profit target was too high.

      Code:
      protected override void OnStateChange()
      {
      if (State == State.SetDefaults)
      {
      Calculate = Calculate.OnBarClose;
      IsOverlay = true;
      DisplayInDataBox = true;
      DrawOnPricePanel = true;
      DrawHorizontalGridLines = true;
      DrawVerticalGridLines = true;
      PaintPriceMarkers = true;
      ScaleJustification = NinjaTrader.Gui.Chart.ScaleJustification.Right;
      IsSuspendedWhileInactive = true;
      AddPlot(Brushes.Lime, "Av1");
      AddPlot(Brushes.Red, "Av2");
      AddPlot(Brushes.DodgerBlue, "Av3");
      AddPlot(Brushes.Fuchsia, "Av4");
      AddPlot(Brushes.DarkOrange, "Av5");
      }
      else if (State == State.Configure)
      {
      AddDataSeries(BarsPeriodType.Minute, 120);
      }
      }
      
      protected override void OnBarUpdate()
      {
      if (CurrentBars[1]>0)
      {
      double _av1=(Highs[1][0]+Lows[1][0])/2;
      double _av2=(Highs[1][0]+Lows[1][0]+Closes[1][0])/3;
      double _av3=(Highs[1][0]+Lows[1][0]+Closes[1][0]+Closes[1][0])/4;
      double _av4=(Highs[1][0]+Highs[1][0]+Lows[1][0]+Lows[1][0]+Closes[1][0]+Closes[1][0]+Closes[1][0])/7;
      double _av5=(Highs[1][0]+Highs[1][0]+Lows[1][0]+Lows[1][0]+Closes[1][0])/5;
      
      
      
      Av1[0]=Instrument.MasterInstrument.RoundToTickSize(_av1) ;
      Av2[0]=Instrument.MasterInstrument.RoundToTickSize(_av2) ;
      Av3[0]=Instrument.MasterInstrument.RoundToTickSize(_av3) ;
      Av4[0]=Instrument.MasterInstrument.RoundToTickSize(_av4) ;
      Av5[0]=Instrument.MasterInstrument.RoundToTickSize(_av5) ;
      Do you think the indicator is feeding the strategy a dynamic "live" avg. price instead of the static drawn "AV" line avg. price?

      Comment


        #4
        Update: The strategy is now choosing the correct profit target for all 4 entries. (changing the strategy to calculate on bar close instead of on each tick)

        The strategy is producing the wrong stop loss for entries 2,3 and 4

        Comment


          #5
          Hello mlprice,

          Issue 2 which is connected to issue 1 and might help debug is that when "Entry 1" triggered it chose a profit target that doesn't correspond to any of the "AV Lines" "Entry 1" is supposed to use "AV1" as the profit target but instead chose a price much higher (about 23 ticks).
          You may have worked around this, but please consider my suggestion from post #2. Set methods should be called before the associated Enter order is called, and you are calling the Set method after the Enter method. Failure to do so can result in an a previous level being used when NinjaTrader sees the associated entry order fill.

          When you are calling Set methods in OnBarUpdate you will always need to make sure that this level is reset before a new entry is made. For example:

          Code:
          if (Position.MarketPosition == MarketPosition.Flat && YOUR_ENTRY_LOGIC)
          {
              SetStopLoss("EnterLong1", CalculationMode.Ticks, 5, false); // Reset stop to initial level
              EnterLong("EnterLong1");
          }
          As for the other entries that are made that are not expected, understanding why those entries are made will require deeper debugging steps.

          For example, if you can reproduce an unexpected trade, it happens because the logic for that condition became true and allowed the order submission method to be reached and fired. As the condition controlling this action became true, debugging steps will need to be taken to monitor the items used in your conditions, and then also to scale back and track how each item used in the condition is calculated.

          You will then be able to break down any calculation differences and spot specific parts of the logic that are calculating differently.

          This following does not sound to be the case, but will also be helpful to note. If your logic is dependent on order fills, there will always be differences in historical and realtime because the order fills are simulated differently. (historical OHLC used to estimate backtest fills, and current market data used to fill realtime simulated orders.) Ensuring that orders are submitted to a single tick data series can help to get the historical order fills closer to realtime and thus any logic dependent on order fills to be closer to realtime.

          We look forward to assisting.
          JimNinjaTrader Customer Service

          Comment


            #6
            Thanks a lot for your response Jim.

            I simplified the code to only have 1 Entry and moved the set method above.
            Code:
            protected override void OnBarUpdate()
            {
            
            if (Profit==1)
            line=AV().Av1[0];
            else if (Profit==2)
            line=AV().Av2[0];
            else if (Profit==3)
            line=AV().Av3[0];
            else if (Profit==4)
            line=AV().Av4[0];
            else if (Profit==5)
            line=AV().Av5[0];
            
            
            
            if (Position.MarketPosition==MarketPosition.Flat && BarsInProgress==0)
            {
            
            //ENTRY 1
            if (Close[0]+MinTickAway*TickSize<line)
            {
            SetStopLoss("Entry1",CalculationMode.Ticks,SL,false);
            SetProfitTarget("Entry1",CalculationMode.Price,line,false);
            EnterLong(Lot1,"Entry1");
            My only remaining issue is with my custom indicator that is being used as the profit target and entry condition.

            I would like the strategy to use the line value that corresponds to the most recent bar before the current new bar. When I run the strategy through back testing this is happening as desired. When I run the strategy through my sim account the line value being used is from 2 bars behind the current bar.

            Any idea why this change is occurring?

            See attached photos for change reference.

            Thanks Click image for larger version

Name:	Image1.png
Views:	5
Size:	61.3 KB
ID:	1143251Click image for larger version

Name:	Image2.png
Views:	3
Size:	63.7 KB
ID:	1143252

            Comment


              #7
              Update: I figured out the issue was the lines were updating retroactively.

              So my new question is there a way to change the code so the back testing uses the line value from 2 bars back instead of the most recent bar?

              Thanks

              Comment


                #8
                Hello mlprice12,

                If you want to use a value from 2 bars ago, the reference would look like: Close[2] or line=AV().Av1[2];

                Please note that you must ensure the script has processed 2 bars before it makes a reference for 2 bars ago. For example, if you make a Bars Ago reference of 2 when the script starts processing bar 0 in OnBarUpdate, you will receive an error.

                Working with Price Data - https://ninjatrader.com/support/help...ice_series.htm

                Making sure there are enough bars in the data series you are processing - https://ninjatrader.com/support/help...nough_bars.htm

                if you want to have logic specific for historical processing/backtesting, you can create a condition that checks:

                if (State == State.Historical) { }

                We look forward to assisting.
                JimNinjaTrader Customer Service

                Comment

                Latest Posts

                Collapse

                Topics Statistics Last Post
                Started by nutmame1, Today, 08:26 PM
                0 responses
                5 views
                0 likes
                Last Post nutmame1  
                Started by dr0832, Today, 07:02 PM
                0 responses
                11 views
                0 likes
                Last Post dr0832
                by dr0832
                 
                Started by mlurskint8, Today, 05:27 PM
                3 responses
                18 views
                0 likes
                Last Post NinjaTrader_ShawnB  
                Started by SteveTheCPA, Today, 04:54 PM
                0 responses
                10 views
                0 likes
                Last Post SteveTheCPA  
                Started by Unsuitable, Today, 02:42 PM
                2 responses
                14 views
                0 likes
                Last Post Unsuitable  
                Working...
                X