Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Scaling in with ATR not accurate

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

    Scaling in with ATR not accurate

    I have a strategy that targets 2 ATR and adds to the trade when 1 ATR in profit is hit. When this additional entry is hit, the stop for the initial entry is moved to the initial entry price and the profit target for the initial entry stays the same. Also, when the additional entry is hit, the additional entry shares the same profit target as the initial entry and it's stop is the initial entry price. Basically the stop moves to breakeven after I am 1 ATR in profit and the additional entry is hit. I have no issues with the 2 ATR stops, the stops that get hit without touching the additional entry seem to work fine. Below is the script that I have with the entry criteria hidden:

    namespace NinjaTrader.NinjaScript.Strategies
    {
    public class PleaseHelpStrategy : Strategy
    {
    private double initialEntryPrice;
    private double profitTargetPriceInitial;
    private double stopLossPriceInitial;
    private double profitTargetPriceAdd;
    private double stopLossPriceAdd;
    private double profitTargetPrice;
    private double stopLossPrice;
    private double atrValue;


    protected override void OnStateChange()
    {
    if (State == State.SetDefaults)
    {
    Description = @"Trying to use unadjusted atr"; //fading the strategy and using a trailing stop
    Name = "MarkII10PFractal";
    Calculate = Calculate.OnBarClose;
    EntriesPerDirection = 2;
    EntryHandling = EntryHandling.AllEntries;
    IsExitOnSessionCloseStrategy = true;
    ExitOnSessionCloseSeconds = 30;
    IsFillLimitOnTouch = false;
    MaximumBarsLookBack = MaximumBarsLookBack.TwoHundredFiftySix;
    OrderFillResolution = OrderFillResolution.Standard;
    Slippage = 0;
    StartBehavior = StartBehavior.WaitUntilFlat;
    TimeInForce = TimeInForce.Gtc;
    TraceOrders = false;
    RealtimeErrorHandling = RealtimeErrorHandling.StopCancelClose;
    StopTargetHandling = StopTargetHandling.PerEntryExecution;
    BarsRequiredToTrade = 20;
    IsInstantiatedOnEachOptimizationIteration = true;
    }

    }

    protected override void OnBarUpdate()
    {
    if (BarsInProgress != 0)
    return;

    if (CurrentBar < 20)
    return;

    // Calculate ATR
    atrValue = ATR(14)[0];

    bool goLongSignal = //(my long entry criteria)
    bool goShortSignal = //(my short entry criteria)
    bool market_open = ToTime(Time[0]) >= 093000 && ToTime(Time[0]) <= 160000;

    if (Position.MarketPosition == MarketPosition.Flat)
    {

    if (goShortSignal&& market_open)
    {
    // Initial entry short logic
    EnterShort("InitialEntryShort");
    double stopLimitPrice = Close[0] - atrValue;
    // Submit or re-submit additional entry short order
    EnterShortStopLimit(1, stopLimitPrice, stopLimitPrice, "AdditionalEntryShort");
    }

    if (goLongSignal && market_open)
    {
    // Initial entry long logic
    EnterLong("InitialEntryLong");
    double stopLimitPrice = Close[0] + atrValue;
    // Submit or re-submit additional entry long order
    EnterLongStopLimit(1, stopLimitPrice, stopLimitPrice, "AdditionalEntryLong");
    }
    }
    if (Position.MarketPosition == MarketPosition.Short && Position.Quantity == 1)
    {
    double stopLimitPrice = initialEntryPrice - atrValue;
    // Submit or re-submit additional entry short order
    EnterShortStopLimit(1, stopLimitPrice, stopLimitPrice, "AdditionalEntryShort");
    }

    if (Position.MarketPosition == MarketPosition.Long && Position.Quantity == 1)
    {
    double stopLimitPrice = initialEntryPrice + atrValue;
    // Submit or re-submit additional entry long order
    EnterLongStopLimit(1, stopLimitPrice, stopLimitPrice, "AdditionalEntryLong");
    }

    }

    protected override void OnExecutionUpdate(Execution execution, string executionId, double price, int quantity, MarketPosition marketPosition, string orderId, DateTime time)
    {
    if (execution.Order != null && execution.Order.OrderState == OrderState.Filled)
    {
    if (execution.Order.Name == "InitialEntryLong")
    {
    initialEntryPrice = execution.Price;
    profitTargetPrice = initialEntryPrice + (atrValue * 2);
    stopLossPrice = initialEntryPrice - (atrValue * 2);
    SetProfitTarget("InitialEntryLong", CalculationMode.Price, profitTargetPrice);
    SetStopLoss("InitialEntryLong", CalculationMode.Price, stopLossPrice, false);
    }
    else if (execution.Order.Name == "InitialEntryShort")
    {
    initialEntryPrice = execution.Price;
    profitTargetPrice = initialEntryPrice - (atrValue * 2);
    stopLossPrice = initialEntryPrice + (atrValue * 2);
    SetProfitTarget("InitialEntryShort", CalculationMode.Price, profitTargetPrice);
    SetStopLoss("InitialEntryShort", CalculationMode.Price, stopLossPrice, false);
    }
    else if (execution.Order.Name == "AdditionalEntryLong")
    {
    SetStopLoss("InitialEntryLong", CalculationMode.Price, initialEntryPrice, false);
    SetStopLoss("AdditionalEntryLong", CalculationMode.Price, initialEntryPrice, false);
    SetProfitTarget("AdditionalEntryLong", CalculationMode.Price, profitTargetPrice);
    }
    else if (execution.Order.Name == "AdditionalEntryShort")
    {
    SetStopLoss("InitialEntryShort", CalculationMode.Price, initialEntryPrice, false);
    SetStopLoss("AdditionalEntryShort", CalculationMode.Price, initialEntryPrice, false);
    SetProfitTarget("AdditionalEntryShort", CalculationMode.Price, profitTargetPrice);
    }
    }
    }
    }
    }

    The problem is that around 50% of the time in backtesting on the NQ futures the additional entries are off by 0.50 - 0.75, maybe that's just slippage, I don't know. And about 10% of the time the adds are off by multiple points. I included some pictures of when the additional entries are off by 1.0 or more. In the pictures, the ATR that the trade is using is hovered over and shown in the data box in the top left so you can see that the add spots are off if you use the ATR that is given. Please tell me how I can fix the script so that it always adds right where it should. Thank you.
    Last edited by josiahTrader193541_; 06-07-2024, 10:36 AM.

    #2
    Hello,

    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 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.

    To know why the strategy is trading at a different time/price in the backtest vs realtime would require adding debugging to the strategy and then running it in both of those use cases. Based on the output you see you could adjust logic or settings in the strategy to change how it operates going forward.

    We have a guide that goes over comparing realtime vs historical results in the following link, that page also links to some samples of how to debug your strategy.

    https://support.ninjatrader.com/s/article/Developer-Guide-Comparing-Strategy-Results



    Please let me know if you need further guidance.​

    Comment


      #3
      If I ran it live in a simulation account would the results be more accurate?

      Comment


        #4
        Hello,

        Running the strategy on live data would reflect the actual live performance of your strategy, regardless of whether you are using your actual brokerage account or a simulation account (Sim101).

        Increasing the accuracy when backtesting would require implementing intrabar granularity (or High Order Fill Resolution) and Tick Replay as detailed in my previous reply.

        Please let us know if you have any further questions.

        Comment

        Latest Posts

        Collapse

        Topics Statistics Last Post
        Started by Geovanny Suaza, 02-11-2026, 06:32 PM
        0 responses
        648 views
        0 likes
        Last Post Geovanny Suaza  
        Started by Geovanny Suaza, 02-11-2026, 05:51 PM
        0 responses
        369 views
        1 like
        Last Post Geovanny Suaza  
        Started by Mindset, 02-09-2026, 11:44 AM
        0 responses
        108 views
        0 likes
        Last Post Mindset
        by Mindset
         
        Started by Geovanny Suaza, 02-02-2026, 12:30 PM
        0 responses
        572 views
        1 like
        Last Post Geovanny Suaza  
        Started by RFrosty, 01-28-2026, 06:49 PM
        0 responses
        573 views
        1 like
        Last Post RFrosty
        by RFrosty
         
        Working...
        X