Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Simulating bracket ordering behavior not working

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

    Simulating bracket ordering behavior not working

    I am trying to simulate bracket ordering by determining entry criteria at a higher timeframe (5min) and capturing the price movement for going short/long (which ever is hit first) using a lower timeframe (1tick). I am trying to avoid the unmanaged approach. However, this does not seem to be working. Orders are being placed multiple bars away from where the entry was identified on the higher timeframe even though there were lower timeframe bars that satisfied the entry criteria just subsequent to the higher timeframe entry point as indicated visually on the chart and through debug statements in the output tab. Here is my test code. Any help in getting this to function as expected is appreciated, thanks!

    P.S. the boolean functions are just a wrapper for the approxcompare logic as a doubles extension (i.e. Close[0].EQ(somevalue)...etc) everything else is native ninjascript.

    // This namespace holds all strategies and is required. Do not change it.
    namespace NinjaTrader.NinjaScript.Strategies.MyStrategies {
    public class MyBrac****rderTestStrategy : Strategy {

    private double _priceLong = 0, _priceShort = 0;
    private int _bi = 0, _biEntry = 0;
    private int _fast = 10, _slow = 25;

    protected override void OnStateChange() {
    if (State == State.SetDefaults) {
    Calculate = Calculate.OnBarClose;
    Name = "MyBrac****rderTestStrategy";
    }

    else if (State == State.Configure) {
    AddDataSeries(Data.BarsPeriodType.Tick, 1);

    AddChartIndicator(EMA(_fast));
    AddChartIndicator(EMA(_slow));

    EMA(_fast).Plots[0].Brush = Brushes.Green;
    EMA(_slow).Plots[0].Brush = Brushes.Blue;

    SetProfitTarget(CalculationMode.Ticks, 4);
    SetStopLoss(CalculationMode.Ticks, 12);
    }
    }

    protected override void OnBarUpdate() {
    if (CurrentBars[0] <= BarsRequiredToTrade || CurrentBars[1] <= BarsRequiredToTrade)
    return;

    if (BarsInProgress == 0) {
    var c = Close[0];
    _bi = CurrentBar;

    if (CrossAbove(EMA(_fast), EMA(_slow), 1)) {
    _biEntry = _bi;
    _priceLong = c + TickSize;
    _priceShort = Low[0] - TickSize;
    BackBrush = Brushes.PowderBlue;
    Print($"MIN Long bi: {_bi} close: {c} entry long: {_priceLong} entry short: {_priceShort}");
    }
    else if (CrossBelow(EMA(_fast), EMA(_slow), 1)) {
    _biEntry = _bi;
    _priceLong = High[0] + TickSize;
    _priceShort = c - TickSize;
    BackBrush = Brushes.PowderBlue;
    Print($"MIN Short bi: {_bi} close: {c} entry short: {_priceShort} entry long: {_priceLong}");
    }

    if (_priceShort.GT(0) && _priceLong.GT(0)) {
    Draw.Line(this, $"longentry" + CurrentBar, true, 1, _priceLong, 0, _priceLong, Brushes.Magenta, DashStyleHelper.Dot, 2);
    Draw.Line(this, $"shortentry" + CurrentBar, true, 1, _priceShort, 0, _priceShort, Brushes.Magenta, DashStyleHelper.Dot, 2);
    }
    }

    var notSameBarIndexAsEmaCrossover = _bi != _biEntry;
    if (BarsInProgress == 1 && notSameBarIndexAsEmaCrossover) {
    var onlyEnterOncePerEmaCrossover = _biEntry != 0;
    if (Position.MarketPosition == MarketPosition.Flat && onlyEnterOncePerEmaCrossover) {
    if (Close[0].EQ(_priceLong)) {
    EnterLong(1, 1, $"EnterLong:{_biEntry}:{_priceLong}");
    Print($"TIC bi: {CurrentBar} close: {Close[0]} MIN bi: {_bi} _priceLong: {_priceLong}");
    _biEntry = 0;
    }
    else if (Close[0].EQ(_priceShort)) {
    EnterShort(1, 1, $"EnterShort:{_biEntry}:{_priceShort}");
    Print($"TIC bi: {CurrentBar} close: {Close[0]} MIN bi: {_bi} _priceShort: {_priceShort}");
    _biEntry = 0;
    }
    }
    }

    }
    }
    }​

    #2
    Hello love2code2trade,

    The term bracket I understand as two opposing entry orders tied with OCO. If the price goes up, one order fills and the other is cancelled, if the price goes down, the other order fills and the first is cancelled.

    Below is a link to an example.


    To use OCO on the entry orders, this would need to use the unmanaged approach.


    To understand behavior of your custom logic, add debugging prints.

    In the strategy add prints (outside of any conditions) that print the date time of the bar and all values compared in every condition that triggers the action being investigated.
    The prints should include the time of the bar and should print all values from all variables and all hard coded values in all conditions that must evaluate as true for this action to be triggered. It is very important to include a text label for each value and for each comparison operator in the print to understand what is being compared in the condition sets.
    The debugging print output should clearly show what the condition is, what time the conditions are being compared, all values being compared, and how they are being compared.

    Prints will appear in the NinjaScript Output window (New > NinjaScript Output window).

    Below is a link to a support article that demonstrates using informative prints to understand behavior and includes a link to a video recorded using the Strategy Builder to add prints.
    https://support.ninjatrader.com/s/ar...nd-TraceOrders

    I am happy to assist you with analyzing the output from the output window.
    Save this by right-clicking the output window and selecting Save As... -> give the output file a name and save -> then attach the output text file to your reply.
    Let me know the date and time the behavior occurred or when you are expecting the behavior to occur.
    Let me know what values you are expecting in the condition.​
    Chelsea B.NinjaTrader Customer Service

    Comment


      #3
      Hi Chelsea, thankyou for your reply. I wanted to stick with the managed approach if possible. Is it possible to get entry criteria on the higher timeframe and monitor the lower timeframe to see if those criteria are met and enter at that point? I will only need to create one order, not two, which would require an OCO approach. However, the code will need to monitor for two price points and whichever gets hit first, at that point issue the relevant order.

      Comment


        #4
        I have added relevant debug print statements in the attached script as well as the output file. For example, on bar 55 of a 5min chart, which is the primary series, a price is determined and used in the secondary series, which is 10sec, and an order is correctly placed when the price identified from the 5min chart is hit in the secondary series at bar 56. however, the order does to show on the chart for bar 56 in the 5min chart but rather on bar 57. I have attached the code and output files for your review. Thanks for your help.
        Attached Files

        Comment


          #5
          Hello love2code2trade,

          When NinjaTrader is running with Calculate set to OnBarClose, orders are placed after the bar closes using logic calculated from that bar.

          Below is a link to the help guide on the Calculate property.


          This means that any orders that are triggered from that bar are submitted after the bar closes as the new bar opens. As the order is placed as the new bar opens and the timestamp of the order is within the time of the next bar, the order will show on the next bar.

          If the strategy were running with Calculate as OnPriceChange or OnEachTick, or if the script has intra-bar granularity and submitted orders on a smaller timeframe, this would cause the timestamp of the order to be within the bar it is triggered on as the order may be submitted intra-bar. This order would show on the same bar as the bar that triggered the order submission.

          In historical data, Calculate will always be OnBarClose unless TickReplay is enabled for the data series.


          Further, TickReplay cannot be used for intra-bar order fills. A 1 tick series must be added for 1-tick intra-bar granularity to increase the accuracy of order fills to the price and time of a specific tick.
          This is outlined in the help guide Discrepancies: Real-Time vs Backtest.


          Also, below is a link to a support article about intra-bar granularity.
          https://support.ninjatrader.com/s/ar...ar-granularity



          With the debugging, add the OnOrderUpdate() override method and print the order.ToString().
          Also, as your inquiry is about order fills, also add the OnExecutionUpdate() override method and print the execution.ToString().

          This gives us information about what is happening with the orders and executions in line with the condition information.

          The condition prints should be for the condition that submits the entry order in question. This should print the values being compared in the condition and the labels for the comparison operators, we can know why the condition evaluated as true or false.

          Temporarily, all other prints should be commented out so these are not appearing in the output. This allows you to focus on the one issue currently being investigated at a time.
          Chelsea B.NinjaTrader Customer Service

          Comment


            #6
            Hi Chelsea,
            I am not making much progress. I can't seem to get my head around the behavior at the tick level vs the onbarclose/isfirsttickofbar level. I have stripped away to just the barebones code to try to fix my issue. I have a fast and slow EMA and want to capture each crossover and set that bar's background color to powderblue and then add order entry code at the more granular tick level once this issue is fixed. The crossovers are identified for some but not others. The values of the EMA's are different when viewed in the DataBox than by print statements to the output window which im assuming is due to the tick variance. What can I do to get this to detect each crossover and function in both historical and realtime data? Thanks for your help.​
            Attached Files
            Last edited by love2code2trade; 11-28-2024, 11:39 PM.

            Comment


              #7
              Hello love2code2trade,

              The debugging prints should give us a sense of what is occurring.

              May I have you provide the requested debugging print output?
              Chelsea B.NinjaTrader Customer Service

              Comment


                #8
                Hi Chelsea,
                When TickReplay is disabled, the script behaves as expected. However, when TickReplay is enabled the EMA crossovers are incorrectly identified. I have attached the output with TickReplay enabled and disabled as well as an updated script.
                Attached Files

                Comment


                  #9
                  Hello love2code2trade,

                  To see when two series have crossed use CrossAbove() and CrossBelow().



                  There are no time stamps in the output so there would not be any way to identify a specific bar.

                  Looking at the first line of output:
                  bi: 1 above: False below: False fast0: 6020.20454545455 slow0: 6020.23076923077 fast1: 6020.25 slow1: 6020.25

                  I believe this is showing the previous EMA(10) was 6020.25 and the EMA(25) was 6020.25 and the current EMA(10) is 6020.20 and the EMA(25) is 6020.23.

                  If CrossAbove() or CrossBelow() had been used, this would not have been a CrossAbove() or CrossBelow().


                  Note, indicators cannot be called from State.Configure. These must be called from State.DataLoaded or later.
                  Chelsea B.NinjaTrader Customer Service

                  Comment


                    #11
                    Hello love2code2trade,

                    To see when two series have crossed use CrossAbove() and CrossBelow().

                    It's helpful to put the timestamp at the beginning of the print, but this will do.

                    You haven't specified a date or time.

                    Looking at the first line of the output (11/27/2024 6:10:00) I see 'above: False' and 'below: False'.

                    Is your inquiry about the first line of output? Are you asking why these values are false?
                    Chelsea B.NinjaTrader Customer Service

                    Comment


                      #12
                      Hi Chelsea,
                      I have made the suggestions you mentioned vis-a-vis crossabove/below and have made the output more friendly to view with the timestamps for troubleshooting. The file that says "TickReplay Disabled" has the correct locations (bar indexes 34, 80, 110, 144, 152, 162, 190) where the crosses occur correctly. The file that says "TickReplay Enabled" has problems where the locations of crossovers are incorrect or don't occur at all (bar indexes 79, 142, 162-missing, 190-missing). My question is how can I get the crossovers to behave the same when TickReplay is enabled so my backtests will be accurate based off of obtaining data associated with entry criteria at the close of each bar (IsFirstTickOfBar) and applying that criteria at the more granular intrabar level for subsequent bars? Right now I don't have any code that enters positions at an intrabar level given that the first part (close of each bar) is not behaving as expected in the different tickreplay modes. I have attached the updated script/output files.
                      Attached Files

                      Comment


                        #13
                        Hello love2code2trade,

                        You haven't specified a date or time.

                        Looking at the first line of the output (11/28/2024 8:10:00) I see​:

                        time0: 11/28/2024 8:10:00 PM
                        fast0: 6021.73581588305 slow0: 6024.32268361651
                        time1: 11/28/2024 8:05:00 PM
                        fast1: 6022.51044163483 slow1: 6024.82874058456​

                        The fast on the previous bar was 6022.51 and the slow on the previous bar was 6024.82, while on the current bar the fast was 6021.73 and the slow was 6024.32.

                        This would not have been a cross. The fast was below the slow on the previous bar and is still below the slow on the current bar.
                        Chelsea B.NinjaTrader Customer Service

                        Comment


                          #14
                          Hi Chelsea,
                          Maybe I am misunderstanding. In the script I have included the Time[0] and Time[1] of the current bar fast0/slow0 and previous bar fast1/slow1. If you mean the time at which the problem is occurring, it would be the times associated with the current bar fast0/slow0 indexes 79, 142, 162-missing, 190-missing.

                          Comment


                            #15
                            Hello love2code2trade,

                            Only a need of the current bar time is necessary.

                            But you have not stated at what date and time the behavior you are wanting investigated occurred.

                            I have no idea where to look in the output, so I am only focusing on the first lines of output.

                            Just as a reminder I have requested in post # 2:
                            "Let me know the date and time the behavior occurred or when you are expecting the behavior to occur.
                            Let me know what values you are expecting in the condition.​​"

                            This information has not been provided.
                            Chelsea B.NinjaTrader Customer Service

                            Comment

                            Latest Posts

                            Collapse

                            Topics Statistics Last Post
                            Started by NullPointStrategies, Today, 05:17 AM
                            0 responses
                            33 views
                            0 likes
                            Last Post NullPointStrategies  
                            Started by argusthome, 03-08-2026, 10:06 AM
                            0 responses
                            124 views
                            0 likes
                            Last Post argusthome  
                            Started by NabilKhattabi, 03-06-2026, 11:18 AM
                            0 responses
                            64 views
                            0 likes
                            Last Post NabilKhattabi  
                            Started by Deep42, 03-06-2026, 12:28 AM
                            0 responses
                            41 views
                            0 likes
                            Last Post Deep42
                            by Deep42
                             
                            Started by TheRealMorford, 03-05-2026, 06:15 PM
                            0 responses
                            46 views
                            0 likes
                            Last Post TheRealMorford  
                            Working...
                            X