Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Incorrect SetStopLoss usage/behaviour

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

    Incorrect SetStopLoss usage/behaviour

    Hi

    I'm a bit stuck with my own NT8 stratagy realization. I have a Tradingivew version, which I'm trying to replicate into NT8.
    Sadly, NT8 doesn't have inbuilt logic called "Profit Trailing" (trailing stop is enabling only after reaching the specific profit target instead, not from the initial entry), so I'm working on my own version of this code.

    Basically, I'm tracking the amont of ticks in profit (ES/NQ futures in my case) using global variable, and when the needed point is reached, I'm calling my function each tick (Strategy.OnEachTick + Tick Replay enabled), checking how much I'm in profit, and trying to move stoploss with a little offset (1-2 ticks. based on input)

    I'm also using Output to check each tick calculation results and can see that all my variables are correct, but, when I'm trying to update stoploss using SetStopLoss with the my price level (SetStopLoss(CalculationMode.Price, newStopAbsolutePrice) - the whole trade is closed at unexpected place - at the OPEN of current bar (for all trades that were profitable enough and triggered my logic), for longs and shorts the situation is the same.
    TF: 1m, and I checked on 1s TF later to be sure that price wasn't even so low/high to be executed at this level


    TLDR:
    I'm calling SetStopLoss(CalculationMode.Price, newStopAbsolutePrice);​ with 15375.25 value
    But for some reason (based on logs from OnExecutionUpdate method) it receives the OPEN[0] as value, which is incorrect

    Thanks in advance!










    I know that it could be hard to understand what I'm talking about, so will try to add as much as possible info and screenshots about this behaviour:
    - NQ 1m TF
    - Strategy.OnEachTick + Tick Replay enabled

    Code:
    Code:
    void updateTrailingStop(double currentPrice) {
        // only when we're already in some trade
        if (Position.MarketPosition != MarketPosition.Flat) {
             Print("currentPrice: " + currentPrice + " Position.MarketPosition: " + Position.MarketPosition + " ToTime(Time[0]) " + Time[0] );
    
             // If no double argument is provided in the call, the current (real-time) Last price will be substituted in.
             // But for back-testing a double price to compare against should be provided.
             double currentProfitTicks = Position.GetUnrealizedProfitLoss(PerformanceUnit.Ticks, currentPrice);
    
             Print("currentProfitTicks " + currentProfitTicks + " highestProfitTicks " + highestProfitTicks);
    
             // Convert profit target and trailing stop loss to ticks
             // TickSize for ES/NQ Futures is 0.25, so 1 offest tick = 0.25 points
    
             double trailingStopLossPoints = trailingStopLossTicks * TickSize;
    
             // when we're reached the point of target profit, we should enable our logic for custom trail
             if (currentProfitTicks >= profitTargetTicks)  {
                   // update trail via SetStopLoss ONLY if current profit is more than was already reached
                   if (currentProfitTicks > highestProfitTicks) {
                         // update the highest reached profit
                         highestProfitTicks = currentProfitTicks;
    
                         // calculate new absolute price for stoploss
                         newStopAbsolutePrice = Position.MarketPosition == MarketPosition.Long ? (currentPrice - 0.5) : (currentPrice + 0.5);
    
                         Print("YEY! SET STOP LOSS: highestProfitTicks " + highestProfitTicks + " newStopAbsolutePrice " + newStopAbsolutePrice + "  ");
    
                         // set new stoploss, every other type (ticks, points, etc) works only as an offset from ENTRY, sadly
                         SetStopLoss(CalculationMode.Price, newStopAbsolutePrice);​
               }
          }
    
    } else {
          highestProfitTicks = 0;
       }
    }
    
    protected override void OnExecutionUpdate(Execution execution, string executionId, double price, int quantity, MarketPosition marketPosition, string orderId, DateTime time) {
        Print("Execution Order Name  " + execution.Order.Name + " and Size " + quantity + " and Price  " + price);
    }
    ​

    1st image - NT8 Output from backtest, as you can see, currentPrice is 15375.75, newStopAbsolutePrice is 15375.25 (2 ticks lower), but in OnExecutionUpdate it's somehow become 15370
    2nd image - part of code (already attached)
    3rd image - how it went on NT8 backtest
    4th image - how it should be (Tradingview backtest)


    Click image for larger version

Name:	photo_2023-08-07_13-53-15.jpg
Views:	148
Size:	141.9 KB
ID:	1263346

    Click image for larger version

Name:	photo_2023-08-06_19-06-40.jpg
Views:	160
Size:	193.9 KB
ID:	1263345
    Click image for larger version

Name:	photo_2023-08-06_19-06-39 (2).jpg
Views:	146
Size:	37.5 KB
ID:	1263344

    Click image for larger version

Name:	photo_2023-08-06_19-06-39.jpg
Views:	323
Size:	26.9 KB
ID:	1263343

    #2
    UPD:

    I even tried to use entry-specified usage of SetStopLoss, no success



    Code:
    EnterLong("LongEntry");
    ​EnterShort("ShortEntry");
    
    .....
    
    void resetToDefaults() {
        highestProfitTicks = 0;
        SetStopLoss("LongEntry", CalculationMode.Ticks, stopLossTicks, false);
        SetStopLoss("ShortEntry", CalculationMode.Ticks, stopLossTicks, false);
        SetProfitTarget(CalculationMode.Ticks, profitTargetTicks * 5 );
    }
    ​
    ......
    
    if (Position.MarketPosition == MarketPosition.Long) {
          SetStopLoss("LongEntry", CalculationMode.Price, newStopAbsolutePrice, false);
    } else {
         SetStopLoss("ShortEntry", CalculationMode.Price, newStopAbsolutePrice, false);
    }
    Click image for larger version

Name:	photo_2023-08-07_17-02-36.jpg
Views:	144
Size:	110.7 KB
ID:	1263395

    Comment


      #3
      Hello wendigooooor,

      Set methods are updated with the bar update information, but TickReplay cannot be used for fill prices. This means any set methods will fill with end-of-bar information in historical data.

      This means if you want accurate intra-bar order submissions and fills in historical data, you will need to use Exit orders or the unmanaged approach and actually submit these orders to the barsInProgressIndex of an added 1 tick series.

      See the forum post below that discusses 1-tick intra-bar granularity and TickReplay.
      https://ninjatrader.com/support/foru...377#post773377

      As well as the example 'ProfitChaseStopTrailExitOrdersExample_NT8' which demonstrates a profit chase as well as a stop trail.
      https://ninjatrader.com/support/foru...269#post802269
      Chelsea B.NinjaTrader Customer Service

      Comment


        #4
        Got it, thank you so much, I lost a lot of time trying to find out the reason of this behaviour.

        In general case, my code *might* work as intended (in Live), but for correct backtesting results I still need to rewrite my code, especially updateTrailingStop method.
        Basically, I need to stop moving stops via SetStopLoss method, and calculate the exact moment of closing by myself, and close the trade using ExitLong or ExitLongLimit (preferred)?
        I hope, ExitLongLimit​ is fast enough to being set and executed in the 1-2 ticks period

        One more question - is it possible to backtest current code using Market Replay? Does Market Replay prodive intrabar calculations (ticks) at all?

        Comment


          #5
          Hello wendigooooor,

          You can use any of the various exit methods in place of SetStopLoss/SetProfitTarget depending on your specific needs. The Set methods are just a convenience method where at the core its just submitting the type of order to match the entry and its direction. A stop loss or trailing stop is generally a stop market order but you can use any order type as long as it is valid for the situation. ExitLong or ExitShort will submit market orders, the other orders like ExitLongLimit specify the order type in the name.

          When you use the exit methods you can do that in two ways. The first is by calling the exit on each OnBarUpdate call, that keeps the exit working until filled and also allows you to provide a variable for the price, if that variable changes the order also changes.
          Orders can also be set to live until cancelled where you don't have to keep calling the order on each OnBarUpdate, you would instead use the Change method to update the orders later. Depending on your overall logic one of those paths would need to be used to submit the exit orders.

          We have a strategy builder sample that uses the first approach which is a variable for the order price and a set which remains true until the order fills. That would be a good starting point for moving away from the Set methods for a trailing stop. This sample only submits a trailing stop so it limits what you are learning in that sample down to that specific concept. You can use the code from that sample in a manually coded script as well, its mainly the concept you would want to focus on with this sample.



          To go beyond that in your own code you can also combine that with the intrabar granularity sample in the help guide, that shows how to submit orders to a 1 tick series to help with fill granularity in backtesting. You can use the overload set with the exit methods that include a BarsInProgress to submit the order to a specific sereis. https://ninjatrader.com/support/help...ipt_strate.htm

          You cannot backetest with market replay also knows as the playback connection. To use market replay (playback) data you need to connect to the playback connection. The strategy analyzer backtest uses Historical data, the same as if you apply a strategy to a chart it does a historical backtest. Playback uses recorded live data and moves forward in time through that data just like it did in realtime. That allows for realtime testing over recorded data but you need to use the playback connection to do that.





          JesseNinjaTrader Customer Service

          Comment


            #6
            Originally posted by NinjaTrader_Jesse View Post
            Hello wendigooooor,

            You can use any of the various exit methods in place of SetStopLoss/SetProfitTarget depending on your specific needs. The Set methods are just a convenience method where at the core its just submitting the type of order to match the entry and its direction. A stop loss or trailing stop is generally a stop market order but you can use any order type as long as it is valid for the situation. ExitLong or ExitShort will submit market orders, the other orders like ExitLongLimit specify the order type in the name.

            When you use the exit methods you can do that in two ways. The first is by calling the exit on each OnBarUpdate call, that keeps the exit working until filled and also allows you to provide a variable for the price, if that variable changes the order also changes.
            Orders can also be set to live until cancelled where you don't have to keep calling the order on each OnBarUpdate, you would instead use the Change method to update the orders later. Depending on your overall logic one of those paths would need to be used to submit the exit orders.

            We have a strategy builder sample that uses the first approach which is a variable for the order price and a set which remains true until the order fills. That would be a good starting point for moving away from the Set methods for a trailing stop. This sample only submits a trailing stop so it limits what you are learning in that sample down to that specific concept. You can use the code from that sample in a manually coded script as well, its mainly the concept you would want to focus on with this sample.

            https://ninjatrader.com/support/foru...rategy-builder

            To go beyond that in your own code you can also combine that with the intrabar granularity sample in the help guide, that shows how to submit orders to a 1 tick series to help with fill granularity in backtesting. You can use the overload set with the exit methods that include a BarsInProgress to submit the order to a specific sereis. https://ninjatrader.com/support/help...ipt_strate.htm

            You cannot backetest with market replay also knows as the playback connection. To use market replay (playback) data you need to connect to the playback connection. The strategy analyzer backtest uses Historical data, the same as if you apply a strategy to a chart it does a historical backtest. Playback uses recorded live data and moves forward in time through that data just like it did in realtime. That allows for realtime testing over recorded data but you need to use the playback connection to do that.






            After few more hours I'm must admin that I don't understand how it should/may work

            I saw your examples, but neither ExitLongLimit nor ExitLongStopLimit work in my code. I can't see even logs, both OnExecutionUpdate and OnOrderUpdate doesn't show anything in that case, that can mean only one thing - the order is incorrect (but I somehow cannot see the reason of this?)

            I can close the open long/short trade only using ExitLong/ExitShort method, I see changes in both OnExecutionUpdate and OnOrderUpdate methods, but, again, with incorrect price (OPEN bar price)

            ​​
            my updateTrailingStop() function is called each tick from OnBarUpdate()

            Code:
            protected override void OnBarUpdate() {
            ​    // If you are using, say, a 1 minute data series with Calculate.OnEachTick,
                // Close[1] would refer to the close of the previous 1 minute bar to the one currently forming.
                // Close[0] would be the current price of the forming bar, based on the tick it's calculating on.
                updateTrailingStop(Close[0]);
            ​    
                ....
            }
            
            void updateTrailingStop(double currentPrice) {
                ....
            
                if (currentProfitTicks <= highestProfitTicks - trailingStopLossTicks) {
                        Print("its time to close trade at price: " + currentPrice);
                        //ExitLongLimit(currentPrice);
                        //ExitShortLimit(currentPrice);
                        //ExitLongStopMarket(currentPrice);
                        //ExitShortStopMarket(currentPrice);
            
                        ExitLong();
                        ExitShort();
            }
            ​
            Based on output logs, I'm receiving my log message "its time to close trade at price: " at correct time, but ExitLongLimit/ExitShortLimit/ExitLongStopMarket/ExitShortStopMarket are not triggering any orders at all


            Sorry for disturbing, hope you'll help with some new links. I'm upset that I can't make so basic functional at all

            Thanks

            Comment


              #7
              Hello wendigooooor,

              ExitLong and ExitShort are market orders which mean they will be filled at the next best price.

              That may be due to the price you are using. Limit and or StopMarket orders generally have a fixed price or in the case of trailing stops have an offset and frequency of trailing. The sample that I linked for the strategy builder shows a way to limit trailing to a frequency giving the order a chance to fill and also has an offset which means its a fixed distance away from the price.

              Another item is that you should generally surround your exit methods with a position check instead of calling both at once. Calling multiple direction methods in the same event is not suggested.

              Code:
              if(Position.MarketPosition == MarketPosition.Long)
              {
                  ExitLong();
              }

              JesseNinjaTrader Customer Service

              Comment


                #8
                Finally found the main reason of all my fails.

                I had SetProfitTarget in my code, and that's why ExitLongLimit and ExitShortLimit wasn't working. They were completly *ignored* becase of Set() methods, that's why I didn't even saw it in OnExecutionUpdate method logs.
                I cannot stress enough how hard to understand that info in NT8 documentation, because it's doesn't make a lot of sense

                found the answer here - https://forum.ninjatrader.com/forum/...er-in-strategy
                "That is correct. You cannot mix Set() and an explicit ExitLongLimit() for the same position because of the potential to have overfills when both get filled."

                Thanks, the issue is closed

                Comment


                  #9
                  Hi

                  I have one more question about the exit trade operation. I'm almost 100% sure that I'm just using the ExitLong() at a wrong place, but still need to know.

                  Situation: NQ! futures, default long operation, I have stoploss, which I'm executing manually after the price is going under my stoploss target.
                  But on backtest (1m, with 'Tick Replay' and 'Fill Limit Order on touch' enabled) all trades are closing on a correct bar (the bar where the condition for stoploss was triggered), but on Open value from that bar

                  Is that possible? Or just bug of backtest engine? ExitLongLimit(currentSlPrice) is works correct, but I need to know if ExitLong() (which is market exit) is working incorrectly on historical bars


                  Code:
                  Code:
                  if (someLongCondition) {
                     EnterLong("entry");
                  
                     currentSlPrice = Close[0] - stopLossTicks * TickSize;
                  ​}
                  
                  ...
                  
                  if (Close[0] <= currentSlPrice) {
                    ExitLong();
                  
                     // ExitLongLimit(currentSlPrice);
                  ​}
                  ​

                  Here's the example of backtest. Long entry from 14794.00. Stoploss (70 ticks <=> 17.5 points) will be at the 14776.5 price level.
                  But exit trade via ExitLong() (again, the exit on market price) was executed at 14784.5, which is Open price level of that bar, and the stoploss was triggered at that bar

                  Click image for larger version

Name:	photo_2023-08-20_15-09-30.jpg
Views:	109
Size:	47.3 KB
ID:	1265361


                  Thanks,
                  Igor
                  Attached Files

                  Comment


                    #10
                    Hello wendigooooor,

                    In the future once you have had your question answered and ask to close the post please make sure to make a new thread for any new questions that you have.

                    You can learn about how the historical fill algorithm works in the following page. Using the open of the bar is part of the process to fill an order. https://ninjatrader.com/support/help...istorical+fill






                    ​​​​​​​
                    JesseNinjaTrader Customer Service

                    Comment

                    Latest Posts

                    Collapse

                    Topics Statistics Last Post
                    Started by jxs_xrj, 01-12-2020, 09:49 AM
                    6 responses
                    3,290 views
                    1 like
                    Last Post jgualdronc  
                    Started by Touch-Ups, Today, 10:36 AM
                    0 responses
                    7 views
                    0 likes
                    Last Post Touch-Ups  
                    Started by geddyisodin, 04-25-2024, 05:20 AM
                    8 responses
                    61 views
                    0 likes
                    Last Post NinjaTrader_Gaby  
                    Started by Option Whisperer, Today, 09:55 AM
                    0 responses
                    8 views
                    0 likes
                    Last Post Option Whisperer  
                    Started by halgo_boulder, 04-20-2024, 08:44 AM
                    2 responses
                    24 views
                    0 likes
                    Last Post halgo_boulder  
                    Working...
                    X