Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

SetTrailStop() yielding unexpected initial stop price

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

    SetTrailStop() yielding unexpected initial stop price

    Hey all,

    Was reviewing a strategy under development and noticed that when using SetTrailStop with a specified number of ticks, the actual stop price being initially placed was much closer to the entry than expected. To isolate the issue from any of my other code, I built a simple strategy (attached) that trades a specific instance where I've observed this and logs the order information obtained through OnOrderUpdate(). It tests SetStopLoss() against SetTrailStop() with the same settings, and highlights a wide difference in initial stop position between the two. My expectation (which may be incorrect) is that these two methods, supplied with the same parameters, should yield roughly the same initial stop price when the associated order is placed.

    Here's what I'm seeing in this test case, using MNQ DEC24 on a 2m chart:

    SetStopLoss(signalName, CalculationMode.Ticks, 150, false);// Expected result
    In this, we can see Mode=Ticks and Value=150, which on this instrument should translate to a stop value $37.5 from entry. And that is what we get, with an short entry at $20084.75 and stop at $20122.25 (20122.25 - 20084.75 = 37.5).

    Code:
    9/23/2024 9:12:00 AM Strategy 'ValidateTrailStopStrategy': Entered internal SetStopTarget() method: Type=Stop FromEntrySignal='test-order' Mode=Ticks Value=150 IsSimulatedStop=False IsMarketIfTouched=False
    9/23/2024 9:12:00 AM Strategy 'ValidateTrailStopStrategy': Entered internal SubmitOrderManaged() method at 9/23/2024 9:12:00 AM: BarsInProgress=0 Action=SellShort OrderType=Market Quantity=1 LimitPrice=0 StopPrice=0 SignalName='test-order' FromEntrySignal=''
    9/23/2024 9:12:00 AM [OnOrderUpdate] Order Name: 'test-order' limitPrice: '0' stopPrice: '0' quantity: '1' filled: '0' averageFillPrice: '0' orderState: 'Submitted' time: '9/23/2024 9:12:00 AM' error: 'NoError' comment: ''
    9/23/2024 9:12:00 AM [OnOrderUpdate] Order Name: 'test-order' limitPrice: '0' stopPrice: '0' quantity: '1' filled: '0' averageFillPrice: '0' orderState: 'Accepted' time: '9/23/2024 9:12:00 AM' error: 'NoError' comment: ''
    9/23/2024 9:12:00 AM [OnOrderUpdate] Order Name: 'test-order' limitPrice: '0' stopPrice: '0' quantity: '1' filled: '0' averageFillPrice: '0' orderState: 'Working' time: '9/23/2024 9:12:00 AM' error: 'NoError' comment: ''
    9/23/2024 9:12:00 AM [OnOrderUpdate] Order Name: 'Stop loss' limitPrice: '0' stopPrice: '20122.25' quantity: '1' filled: '0' averageFillPrice: '0' orderState: 'Submitted' time: '9/23/2024 9:12:00 AM' error: 'NoError' comment: ''
    9/23/2024 9:12:00 AM [OnOrderUpdate] Order Name: 'Stop loss' limitPrice: '0' stopPrice: '20122.25' quantity: '1' filled: '0' averageFillPrice: '0' orderState: 'Accepted' time: '9/23/2024 9:12:00 AM' error: 'NoError' comment: ''
    9/23/2024 9:12:00 AM [OnOrderUpdate] Order Name: 'Stop loss' limitPrice: '0' stopPrice: '20122.25' quantity: '1' filled: '0' averageFillPrice: '0' orderState: 'Working' time: '9/23/2024 9:12:00 AM' error: 'NoError' comment: ''
    9/23/2024 9:12:00 AM [OnOrderUpdate] Order Name: 'test-order' limitPrice: '0' stopPrice: '0' quantity: '1' filled: '1' averageFillPrice: '20084.75' orderState: 'Filled' time: '9/23/2024 9:12:00 AM' error: 'NoError' comment: ''​
    SetTrailStop(signalName, CalculationMode.Ticks, 150, false); // Unexpected result
    Here's the same trade using a trail stop, also using Mode=Ticks and Value=150, which should (I believe) also translate to a stop value $37.5 from entry. However, here we get the same short entry at $20084.75 but a stop at $20090. 20090 - 20084.75 = 5.25, or 21 ticks. Naturally, this results in the trade being stopped out prematurely.

    Code:
    9/23/2024 9:12:00 AM Strategy 'ValidateTrailStopStrategy': Entered internal SetStopTarget() method: Type=TrailStop FromEntrySignal='test-order' Mode=Ticks Value=150 IsSimulatedStop=False IsMarketIfTouched=False
    9/23/2024 9:12:00 AM Strategy 'ValidateTrailStopStrategy': Entered internal SubmitOrderManaged() method at 9/23/2024 9:12:00 AM: BarsInProgress=0 Action=SellShort OrderType=Market Quantity=1 LimitPrice=0 StopPrice=0 SignalName='test-order' FromEntrySignal=''
    9/23/2024 9:12:00 AM [OnOrderUpdate] Order Name: 'test-order' limitPrice: '0' stopPrice: '0' quantity: '1' filled: '0' averageFillPrice: '0' orderState: 'Submitted' time: '9/23/2024 9:12:00 AM' error: 'NoError' comment: ''
    9/23/2024 9:12:00 AM [OnOrderUpdate] Order Name: 'test-order' limitPrice: '0' stopPrice: '0' quantity: '1' filled: '0' averageFillPrice: '0' orderState: 'Accepted' time: '9/23/2024 9:12:00 AM' error: 'NoError' comment: ''
    9/23/2024 9:12:00 AM [OnOrderUpdate] Order Name: 'test-order' limitPrice: '0' stopPrice: '0' quantity: '1' filled: '0' averageFillPrice: '0' orderState: 'Working' time: '9/23/2024 9:12:00 AM' error: 'NoError' comment: ''
    9/23/2024 9:12:00 AM [OnOrderUpdate] Order Name: 'Trail stop' limitPrice: '0' stopPrice: '20090' quantity: '1' filled: '0' averageFillPrice: '0' orderState: 'Submitted' time: '9/23/2024 9:12:00 AM' error: 'NoError' comment: ''
    9/23/2024 9:12:00 AM [OnOrderUpdate] Order Name: 'Trail stop' limitPrice: '0' stopPrice: '20090' quantity: '1' filled: '0' averageFillPrice: '0' orderState: 'Accepted' time: '9/23/2024 9:12:00 AM' error: 'NoError' comment: ''
    9/23/2024 9:12:00 AM [OnOrderUpdate] Order Name: 'Trail stop' limitPrice: '0' stopPrice: '20090' quantity: '1' filled: '0' averageFillPrice: '0' orderState: 'Working' time: '9/23/2024 9:12:00 AM' error: 'NoError' comment: ''
    9/23/2024 9:12:00 AM [OnOrderUpdate] Order Name: 'test-order' limitPrice: '0' stopPrice: '0' quantity: '1' filled: '1' averageFillPrice: '20084.75' orderState: 'Filled' time: '9/23/2024 9:12:00 AM' error: 'NoError' comment: ''
    9/23/2024 9:12:00 AM [OnOrderUpdate] Order Name: 'Trail stop' limitPrice: '0' stopPrice: '20090' quantity: '1' filled: '1' averageFillPrice: '20090' orderState: 'Filled' time: '9/23/2024 9:12:00 AM' error: 'NoError' comment: ''​
    Would welcome any insight into this, particularly if I'm just way off base in one of my assumptions. I've been over the documentation thoroughly, searched the forums, and even tested this on a second machine, and am at a bit of a loss. What am I missing?
    Attached Files

    #2
    Hello ashen,

    As this is historical, it's looking at the entire bar.

    This bar drops from the open of 20084.75 down to 20052.50 at the low, a distance of 32.25 or 129 ticks. This brought the price down to 21 ticks from the entry at 20090.00. The high on that bar is 20090.00 so the order is considered filled.
    Chelsea B.NinjaTrader Customer Service

    Comment


      #3
      Hi Chelsea,

      Thanks for the quick reply. Just to clarify, does that imply that historical evaluations are future-looking? The screenshots I posted weren't zoomed to the level where time markers are clear, but the bar closing at 9:12 has a high of 20090.25 and low of 20078.75. Wouldn't the initial stop price be calculated from those values and not the post-entry 9:14 bar that runs down to 20052.50?

      Or are you saying that the trail stop was originally placed at the appropriate level (and does not fire OnOrderUpdate) and then is presumed to have trailed down until the 21-tick level was reached? In that case, my error would be in looking for OnOrderUpdate events to fire both at the initial level and at the bar-close calculation.

      Just want to make sure that I understand the expected behavior so I can factor it in and avoid the same mistake.

      Thanks,
      -ashen

      Comment


        #4
        Hello ashen,

        The order is submitted at the open of the bar. The stop may fill any time while the bar is open. The low of the bar means the price dropped which will pull the order down as it is a trailing stop loss.
        The entire bar is used all at once for calculating the price as it would have trailed and fill information. Implement 1-tick intra-bar granularity, enable TickReplay, use Calculate.OnPriceChange, and use an Exit order method if you want to see the order change for every change in price for that open bar.


        Yes, this is the expected calculation for a trailing stop when the price falls 129 ticks after the order is submitted.
        Chelsea B.NinjaTrader Customer Service

        Comment


          #5
          Perfect. Appreciate the additional explanation. It sounds like I got wrapped around the axle with the historical event model and was confused about which bar's timestamp to expect in the logs. Will move to a higher-resolution approach going forward, as you suggest.

          Cheers,
          -ashen

          Comment

          Latest Posts

          Collapse

          Topics Statistics Last Post
          Started by NullPointStrategies, Yesterday, 05:17 AM
          0 responses
          56 views
          0 likes
          Last Post NullPointStrategies  
          Started by argusthome, 03-08-2026, 10:06 AM
          0 responses
          133 views
          0 likes
          Last Post argusthome  
          Started by NabilKhattabi, 03-06-2026, 11:18 AM
          0 responses
          73 views
          0 likes
          Last Post NabilKhattabi  
          Started by Deep42, 03-06-2026, 12:28 AM
          0 responses
          45 views
          0 likes
          Last Post Deep42
          by Deep42
           
          Started by TheRealMorford, 03-05-2026, 06:15 PM
          0 responses
          49 views
          0 likes
          Last Post TheRealMorford  
          Working...
          X