Announcement

Collapse

Looking for a User App or Add-On built by the NinjaTrader community?

Visit NinjaTrader EcoSystem and our free User App Share!

Have a question for the NinjaScript developer community? Open a new thread in our NinjaScript File Sharing Discussion Forum!
See more
See less

Partner 728x90

Collapse

Opening Range based on Open and Close

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

    Opening Range based on Open and Close

    Hello,
    I've downloaded this Opening Range indicator from NT8 Ecosystem (see link below) I have modified the code so it is based on Open and Close of bar rather than High and Low of the bar. (See code below.). Basically I changed lines 136 to 145 to this. (See snippet below)
    The open/close version (My version) works fine on bar close mode and on historical data but when I switch to On Each Tick in Replay Mode or Real time it reverts to High and Close. Not sure if I am missing to modify something? Please advise. Thanks in advance any help will be appreciated. I posted at the bottom the original code and modified versions.

    LINK TO ORIGINAL INDICATOR

    This is a conversion of the Opening Range 4 indicator developed and originally coded for the NinjaTrader 7 platform by sh_daggett. 8/26/2021: Added NinjaScriptProperty attribute to public properties so they can be used in Strategy Builder. Please contact the original author for any questions or comments.


    CODE MODIFICATION Lines 136 to 145 of original code.

    Code:
    // If we're in the range (inclusive), then start tracking highs/lows...
                if (Time[0] >= openDT && Time[0] <= rangeEndDT)
                {
                    //CONDITION HIGHEST CLOSE
                    if (Close[0] > highestHigh)//Changed High to Close
                    {
                        highestHigh = Close[0];//Changed High to Close
                        highBar     = CurrentBar;
                    }
                    //CONDITION HIGHEST OPEN
                    if (Open[0] > highestHigh)//Changed High to Close
                    {
                        highestHigh = Open[0];//Changed High to Close
                        highBar = CurrentBar;
                    }
                    //CONDITION LOWEST OPEN
                    if (Open[0] < lowestLow)//Changed Low to Open
                    {
                        lowestLow     = Open[0];//Changed Low to Open
                        lowBar         = CurrentBar;
                    }
                    //CONDITION LOWEST CLOSE
                    if (Close[0] < lowestLow)//Changed Low to Open
                    {
                        lowestLow = Close[0];//Changed Low to Open
                        lowBar = CurrentBar;
                    }
                }​

    #2
    ORIGINAL CODE

    Code:
    #region Using declarations
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Xml.Serialization;
    using NinjaTrader.Cbi;
    using NinjaTrader.Gui;
    using NinjaTrader.Gui.Chart;
    using NinjaTrader.Gui.SuperDom;
    using NinjaTrader.Gui.Tools;
    using NinjaTrader.Data;
    using NinjaTrader.NinjaScript;
    using NinjaTrader.Core.FloatingPoint;
    using NinjaTrader.NinjaScript.DrawingTools;
    using System.Collections;
    #endregion
    
    //This namespace holds Indicators in this folder and is required. Do not change it.
    namespace NinjaTrader.NinjaScript.Indicators
    {
        public class BzvOpeningRange4 : Indicator
        {
    
            private string openTime                 = @"0930"; // Default setting for OpenTime
            private string rangeEndTime             = @"0932"; // Default setting for RangeEndTime
            private string stopPlotTime             = @"1600"; // When to stop plotting the lines. Must be outside the
                                                            // defined range.
            private TimeSpan openTimeTS;
            public  TimeSpan rangeEndTimeTS;
            private TimeSpan stopPlotTimeTS;
            private bool timeFormatErrorMsgGiven     = false;
            private double highestHigh;
            private double lowestLow;
            private int highBar;
            private int lowBar;
            private bool testMsgGiven                 = false;
            private bool rangeCrosses                 = false;    // True if range crosses date boundary
            private DateTime openDT;
            private DateTime rangeEndDT;
            private DateTime stopPlotDT;
            private DateTime openDate;
            private DateTime endDate;
            private bool daysRangeEndWa****         = false; // Indicates if the day's time range has been put in yet
            private Hashtable openingPriceRanges;
    
            protected override void OnStateChange()
            {
                if (State == State.SetDefaults)
                {
                    Description                                    = @"Enter the description for your new custom Indicator here.";
                    Name                                        = "BzvOpeningRange4";
                    Calculate                                    = Calculate.OnPriceChange;
                    IsOverlay                                    = true;
                    IsAutoScale                                 = false;
                    DisplayInDataBox                            = true;
                    DrawOnPricePanel                            = true;
                    DrawHorizontalGridLines                        = true;
                    DrawVerticalGridLines                        = true;
                    PaintPriceMarkers                            = true;
                    ScaleJustification                            = NinjaTrader.Gui.Chart.ScaleJustification.Right;
                    //Disable this property if your indicator requires custom values that cumulate with each new market data event.
                    //See Help Guide for additional information.
                    IsSuspendedWhileInactive                    = true;
                    AddPlot(Brushes.Orange, "RangeHighSeries");
                    AddPlot(Brushes.Orange, "RangeLowSeries");
    
                }            
    
    
                else if (State == State.Configure)
                {
                     // Use this "unsupported method" to move the drawn lines behind the price bars:
                      // Required for accurate readings; estimate only on historical data
                    openTimeTS             = convertTimeSetting(openTime);
                    rangeEndTimeTS         = convertTimeSetting(rangeEndTime);
    
                    openingPriceRanges  = new Hashtable();
    
                    if (String.IsNullOrEmpty(stopPlotTime))
                    {
                        stopPlotTimeTS     = openTimeTS;
                    }
                    else
                    {
                        stopPlotTimeTS     = convertTimeSetting(stopPlotTime);
                    }
                }
    
                rangeCrosses = (rangeEndTimeTS < openTimeTS);
            }            
            //    Hashtable openingPriceRanges = new Hashtable();
    
            // Used to store range boudaries in a has table....
            private struct BzvPriceRange
            {
                public double RangeHighPrice;
                public double RangeLowPrice;
            }
    
            protected override void OnBarUpdate()
            {
                // If we're on the first bar, do a reset and then get out...
                if (CurrentBar < 1)
                {
                    doReset();
                    return;
                }
                // Wait until we have crossed at least one day boundary...
                if (Time[CurrentBar] >= Time[1])
                {
                    return;
                }
    
                // See if the current time passes over the "next" open time so that we need to
                // reset the "day"...
                openDT         = openDate + openTimeTS;
    
                if (Time[0] >= openDT.AddDays(1))
                {
                    doReset();
                }
    
                openDT         = openDate + openTimeTS;
                rangeEndDT     = endDate + rangeEndTimeTS;
    
                // If we're in the range (inclusive), then start tracking highs/lows...
                if (Time[0] >= openDT && Time[0] <= rangeEndDT)
                {
                    if (High[0] > highestHigh)
                    {
                        highestHigh = High[0];
                        highBar     = CurrentBar;
                    }
                    if (Low[0] < lowestLow)
                    {
                        lowestLow     = Low[0];
                        lowBar         = CurrentBar;
                    }
                }
    
                // If we've passed the time range end, then plot...
                if (Time[0] > rangeEndDT)
                {
                    daysRangeEndWa**** = true;
                    // Handle stop plot time in a way that works with tick charts.
                    if (Time[0] <= stopPlotDT)
                    {
                        // We've past the opening range. Plot the lines...
                        // If previous plots are not set, then take it from the first
                        // bar. Otherwise just do the current bar. (Just need to check
                        // one of the plots.)
    
                        if (RangeHighSeries[0] >= 1)
                        {
                            for (int idx = CurrentBar - highBar; idx >=0; idx--)
                            {
                                RangeHighSeries[idx] = (highestHigh);
                            }
                            for (int idx = CurrentBar - lowBar; idx >=0; idx--)
                            {
                                RangeLowSeries[idx]  = (lowestLow);
                            }
                            // Now set the opening range for the day in the Hashtable.
                            // This only happens once per day.
                            DateTime todayDate             = Times[BarsInProgress][0].Date;
                            BzvPriceRange todayRange     = new BzvPriceRange();
                            todayRange.RangeHighPrice     = highestHigh;
                            todayRange.RangeLowPrice     = lowestLow;
                            openingPriceRanges.Remove(todayDate);
                            openingPriceRanges.Add(todayDate, todayRange);
                        }
                        else
                        {
                            RangeHighSeries[0] = (highestHigh);
                            RangeLowSeries[0]  = (lowestLow);
                        }
                    }
                }
            }

    Comment


      #3
      Hello designer01,

      Thanks for your post.

      There would not be any other code in the indicator that would need to be modified to base the indicator off of the Open and Close instead of the High and Low.

      When testing the code you shared on my end using realtime data and Calculate.OnEachTick, I see the indicator calculating based on the Open and Close. See the attached image. In the image the original BZVOpeningRange4 indicator plots are orange and are based on the High and Low. The modified indicator plots are blue and are based on the Open and Close.

      I have attached the indicator script used to test this on my end. If you test the attached indicator script on your end do you see the same behavior?

      Please let me know if I may assist further.​
      Attached Files
      Brandon H.NinjaTrader Customer Service

      Comment


        #4
        Hi Brandon, I see the image file but not the indicator script. Could you reattach it. A quick question did you test it in replay mode? . Thanks a lot.

        Comment


          #5
          Hello designer01,

          Thanks for your notes.

          It seems the attached indicator was hidden after attaching it to the post. I have edited my previous post so the indicator is visible.

          Yes, I have tested the modified script using Market Replay/Playback and the script seems to work as expected. See the demonstration video below.

          Demonstration video: https://brandonh-ninjatrader.tinytake.com/msc/ODI0MTQ4N18yMTQ2NjkyOQ
          Last edited by NinjaTrader_BrandonH; 05-18-2023, 09:36 AM.
          Brandon H.NinjaTrader Customer Service

          Comment


            #6
            Click image for larger version

Name:	HIST.jpg
Views:	370
Size:	144.9 KB
ID:	1251940
            Click image for larger version

Name:	PLAYBACK.jpg
Views:	367
Size:	157.7 KB
ID:	1251941

            Hi Brandon, I am still having the same issue with the modified version as well. Notice in your video on the Market Replay/Playback mode it plots on High and Low but when you plot it on historical data it plots correctly on Open and Close. It is very strange.

            Click image for larger version  Name:	OpenClose.jpg Views:	0 Size:	194.4 KB ID:	1251931
            Last edited by designer01; 05-18-2023, 09:21 AM.

            Comment


              #7
              Hello designer01,

              Thanks for your notes.

              I was able to reproduce the behavior you are reporting on my end. After investigating this further, I have found that this behavior is expected when using Calculate.OnPriceChange or Calculate.OnEachTick.

              The High and Low acome from the close and are made up of the highest and lowest Close prices. If you use Calculate.OnPriceChange or Calculate.OnEachTick the close will hit those highest and lowest values. This means this code if (Close[0] > highestHigh) highestHigh = Close[0] would be set to the same value that you see as the high of the bar. if you used OnBarClose it is unlikely the close equals the high so you would get different results. The Close[0] == High[0] and Close[0] == Low[0] when a new high or low is made, Close[0] would be different for each price change but as it processes those changes your eventually going to hit the highest and lowest part of that bar then the conditions set the close which is the high or low to the variable.

              If you wanted to use the Close price, you will have to use Calculate.OnBarClose for this indicator so that the Close[0] is not equal to the High[0] or Low[0] when those conditions are checked.
              Brandon H.NinjaTrader Customer Service

              Comment


                #8
                Hi Brandon, Thank you for clarifying. I may do a more granular bar timing like 5 second bars and do on bar close to get a similar effect. I will test it this way and let you know if I have any questions.

                Comment


                  #9
                  Hi Brandon,
                  I was able to find a way around it. I am using a 1 minute chart for the Opening Range Indicator (Modified based on Open/Close) Green and Red horizontal lines in image below. And a 3 second data series for the actual strategy entries. (See code below for strategy) Both indicator and strategy basen on "OnBarClose" . I think it works pretty good in Market Playback as well. (See image below). This way it enters the trade sooner in case the wicks are too long as in this example. Thank you for your help.

                  Click image for larger version  Name:	ORB-open-close.jpg Views:	0 Size:	362.7 KB ID:	1252104

                  Code:
                  #region Using declarations
                  using System;
                  using System.Collections.Generic;
                  using System.ComponentModel;
                  using System.ComponentModel.DataAnnotations;
                  using System.Linq;
                  using System.Text;
                  using System.Threading.Tasks;
                  using System.Windows;
                  using System.Windows.Input;
                  using System.Windows.Media;
                  using System.Xml.Serialization;
                  using NinjaTrader.Cbi;
                  using NinjaTrader.Gui;
                  using NinjaTrader.Gui.Chart;
                  using NinjaTrader.Gui.SuperDom;
                  using NinjaTrader.Gui.Tools;
                  using NinjaTrader.Data;
                  using NinjaTrader.NinjaScript;
                  using NinjaTrader.Core.FloatingPoint;
                  using NinjaTrader.NinjaScript.Indicators;
                  using NinjaTrader.NinjaScript.DrawingTools;
                  #endregion
                  
                  //This namespace holds Strategies in this folder and is required. Do not change it.
                  namespace NinjaTrader.NinjaScript.Strategies
                  {
                      public class FTS230513ORB : Strategy
                      {
                          private FTS230514ORBOpnCls FTS230514ORBOpnCls1;
                  
                  
                          protected override void OnStateChange()
                          {
                              if (State == State.SetDefaults)
                              {
                                  Description                                    = @"Based on BZORB Indicator";
                                  Name                                        = "FTS230513ORB";
                                  Calculate                                    = Calculate.OnBarClose;
                                  EntriesPerDirection                            = 1;
                                  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;
                                  // Disable this property for performance gains in Strategy Analyzer optimizations
                                  // See the Help Guide for additional information
                                  IsInstantiatedOnEachOptimizationIteration    = true;
                              }
                              else if (State == State.Configure)
                              {
                                  AddDataSeries(Data.BarsPeriodType.Minute, 1);
                              }
                              else if (State == State.DataLoaded)
                              {                
                                  FTS230514ORBOpnCls1                = FTS230514ORBOpnCls(Closes[1], @"0931", @"0932", @"1600");
                              }
                          }
                  
                          protected override void OnBarUpdate()
                          {
                              if (BarsInProgress != 0)
                                  return;
                  
                              if (CurrentBars[0] < 1
                              || CurrentBars[1] < 1)
                                  return;
                  
                               // Set 1
                              if (CrossAbove(Close, FTS230514ORBOpnCls1.RangeHighSeries, 1))
                              {
                                  BackBrush = Brushes.CornflowerBlue;
                                  EnterLong(100, "");
                              }
                  
                               // Set 2
                              if (CrossBelow(Close, FTS230514ORBOpnCls1.RangeLowSeries, 1))
                              {
                                  BackBrush = Brushes.IndianRed;
                                  EnterShort(100, "");
                              }
                  
                          }
                      }
                  }​
                  Last edited by designer01; 05-19-2023, 12:41 PM.

                  Comment


                    #10
                    I was able to simplify the code even further (see script below) One question, I'm not sure why there is a portion of the plot showing below (see red arrow area in screenshot) Is there maybe a way to avoid it so that offset portion does not plot? Any suggestions welcomed. Thanks.

                    Code:
                    #region Using declarations
                    using System;
                    using System.Collections.Generic;
                    using System.ComponentModel;
                    using System.ComponentModel.DataAnnotations;
                    using System.Linq;
                    using System.Text;
                    using System.Threading.Tasks;
                    using System.Windows;
                    using System.Windows.Input;
                    using System.Windows.Media;
                    using System.Xml.Serialization;
                    using NinjaTrader.Cbi;
                    using NinjaTrader.Gui;
                    using NinjaTrader.Gui.Chart;
                    using NinjaTrader.Gui.SuperDom;
                    using NinjaTrader.Gui.Tools;
                    using NinjaTrader.Data;
                    using NinjaTrader.NinjaScript;
                    using NinjaTrader.Core.FloatingPoint;
                    using NinjaTrader.NinjaScript.DrawingTools;
                    #endregion
                    
                    //This namespace holds Indicators in this folder and is required. Do not change it.
                    namespace NinjaTrader.NinjaScript.Indicators.TheIndStore
                    {
                        public class FTS230520TisTimeWindowOpnClsInt : Indicator
                        {
                            private double Max_High;
                            private double Min_Low;
                    
                            protected override void OnStateChange()
                            {
                                if (State == State.SetDefaults)
                                {
                                    Description                                = @"Based on TisTimeWindowHighLowInt indicator changed from Low/High to Open/Close";
                                    Name                                        = "FTS230520TisTimeWindowOpnClsInt";
                                    Calculate                                    = Calculate.OnBarClose;
                                    IsOverlay                                    = true;
                                    DisplayInDataBox                        = true;
                                    DrawOnPricePanel                        = true;
                                    DrawHorizontalGridLines            = true;
                                    DrawVerticalGridLines                = true;
                                    PaintPriceMarkers                        = true;
                                    ScaleJustification                        = NinjaTrader.Gui.Chart.ScaleJustification.Right;
                                    //Disable this property if your indicator requires custom values that cumulate with each new market data event.
                                    //See Help Guide for additional information.
                                    IsSuspendedWhileInactive                    = true;
                                    Time_Start                        = 093003;   //DateTime.Parse("10:00", System.Globalization.CultureInfo.InvariantCulture);
                                    Time_Stop                        = 093100; //DateTime.Parse("11:00", System.Globalization.CultureInfo.InvariantCulture);
                    
                                    AddPlot(new Stroke(Brushes.SeaGreen, 2), PlotStyle.Dot, "Max_High");
                                    AddPlot(new Stroke(Brushes.DarkOrchid, 2), PlotStyle.Dot, "Min_Low");
                    
                                }
                                else if (State == State.Configure)
                                {
                                }
                            }
                    
                            protected override void OnBarUpdate()
                            {
                                //Add your custom indicator logic here.
                                if (BarsInProgress != 0)
                                    return;
                    
                                if (CurrentBars[0] < 1)
                                    return;
                    
                                if ((ToTime(Times[0][0]) >= Time_Start)
                                     &&(ToTime(Time[0]) < 160000))
                                {
                    
                                    // Set Open
                                    if ((ToTime(Times[0][0]) >= Time_Start)
                                     && (ToTime(Times[0][1]) < Time_Start))
                                    {
                                        Max_High = Open[0];
                                    }
                    
                                    // Set Close
                                    if ((ToTime(Times[0][0]) >= Time_Stop)
                                         && (ToTime(Times[0][1]) < Time_Stop))
                                    {
                                        Min_Low = Close[0];
                                    }
                    
                                    // Set to Plot Background
                                    if ((ToTime(Times[0][0]) >= Time_Start)
                                         && (ToTime(Times[0][0]) < Time_Stop))
                                    {
                                        BackBrush = Brushes.DarkSlateGray;
                                    }
                    
                                    Max_Hi[0] = Max_High;
                                    Min_Lo[0] = Min_Low;
                                }
                            }
                            #region Properties
                            [NinjaScriptProperty]
                            //[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
                            [Display(Name="Time_Start", Order=1, GroupName="Parameters")]
                            public int Time_Start
                            { get; set; }
                    
                            [NinjaScriptProperty]
                            //[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
                            [Display(Name="Time_Stop", Order=2, GroupName="Parameters")]
                            public int Time_Stop
                            { get; set; }
                    
                                [Browsable(false)]
                            [XmlIgnore]
                            public Series<double> Max_Hi
                            {
                                get { return Values[0]; }
                            }
                    
                            [Browsable(false)]
                            [XmlIgnore]
                            public Series<double> Min_Lo
                            {
                                get { return Values[1]; }
                            }
                            #endregion
                        }
                    }​
                    Click image for larger version

Name:	ORB-open-cl-01.jpg
Views:	466
Size:	215.0 KB
ID:	1252341

                    Comment


                      #11
                      Hello designer01,

                      Thanks for your notes.

                      Debugging steps would need to be taken to understand how the script is processing logic and plotting at that value in the script.

                      Add Prints to the script that print out all the values being used to calculate the plot, the value being assigned to the plot, and the Time.

                      Below is a link to a forum post that demonstrates how to use prints to understand behavior.
                      https://ninjatrader.com/support/foru...121#post791121
                      Brandon H.NinjaTrader Customer Service

                      Comment

                      Latest Posts

                      Collapse

                      Topics Statistics Last Post
                      Started by cmtjoancolmenero, 04-25-2024, 03:58 PM
                      14 responses
                      59 views
                      0 likes
                      Last Post NinjaTrader_ChelseaB  
                      Started by raffu, Yesterday, 11:41 AM
                      1 response
                      9 views
                      0 likes
                      Last Post NinjaTrader_Jesse  
                      Started by cmtjoancolmenero, Yesterday, 11:56 AM
                      1 response
                      13 views
                      0 likes
                      Last Post NinjaTrader_ChelseaB  
                      Started by reynoldsn, 04-21-2024, 07:53 PM
                      3 responses
                      25 views
                      0 likes
                      Last Post NinjaTrader_BrandonH  
                      Started by cmtjoancolmenero, Yesterday, 03:40 PM
                      1 response
                      14 views
                      0 likes
                      Last Post NinjaTrader_Jesse  
                      Working...
                      X