Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

How to keep X bars of distance between trade entries?

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

    How to keep X bars of distance between trade entries?

    Hi all,

    I've just started working with NinjaScript to build an automated trading bot for a strategy I've been trading manually. I have some programming experience, years ago, and I figured the easiest way to jump start this project was to construct as much as I could of the strategy in the Strategy Wizard, then when I hit the limits of what I can do in the Wizard, unlock the code and program it manually from there.

    I'm trying to add a feature whereby my strategy keeps a certain number of bars between trade entries.

    I tried doing this by adding this condition in the Strategy Wizard:
    BarsSinceEntry() >= EntryDistance
    where EntryDistance is a user defined input with default value 6.

    This resulted in the following code:

    Code:
    protected override void OnBarUpdate()       
      {             
    // Condition set 1             
    if (EMA(MA1Shortperiod)[0] > EMA(MA1Longperiod)[0]                 
    && RSI(RSIperiod, 3).Avg[0] > RSIbuylevel                 
    && ToTime(Time[0]) > ToTime(9, 0, 0)                 
    && ToTime(Time[0]) < ToTime(13, 59, 0)                 
    && Position.MarketPosition != MarketPosition.Short                 
    && BarsSinceEntry() >= EntryDistance)            
     {                 
    EnterLongLimit(DefaultQuantity, Close[0], "LongEntry");             }
    When I backtested the strategy, however, all the backtested trades that were previously there disappeared. It was pointed out to me that the reason for this is most likely because BarsSinceEntry has a 0 value to begin with, and it never reaches the required value of 6 because no trade is ever placed, which in turn means BarSinceEntry is always 0, so in turn no trade is placed, etc.

    So, what is the right way to do this?

    Thanks
    Phil
    Last edited by PhillyD; 10-11-2014, 04:58 PM.

    #2
    Hello Phil,

    Thank you for your post.

    You would want to have your first Entry condition without the BarsSinceEntry(), but instead use a bool and when the first trade occurs set it to false
    Code:
    // Condition set 1             
    if (EMA(MA1Shortperiod)[0] > EMA(MA1Longperiod)[0]                 
    && RSI(RSIperiod, 3).Avg[0] > RSIbuylevel                 
    && ToTime(Time[0]) > ToTime(9, 0, 0)                 
    && ToTime(Time[0]) < ToTime(13, 59, 0)                 
    && Position.MarketPosition != MarketPosition.Short                 
    && firstTrade)            
    {                 
         EnterLongLimit(DefaultQuantity, Close[0], "LongEntry");  
         firstTrader = false;
    }
    Let me know if I can be of further assistance.
    Cal H.NinjaTrader Customer Service

    Comment


      #3
      Hi Cal

      Thanks for the quick response.

      I don't mean to be thick, but I'm not sure I follow how the bool is supposed to be used. I declare it, set it to false after a trade entry, and then?

      Also, would this still work if I allow LongEntry to take several trades in the same direction (currently I let it take up to four entries)?

      Comment


        #4
        Hello PhillyD,

        Thank you for your response.

        You would initially set the bool to True when declaring the bool in the variables section of the code. Then set it to False when the first condition returns true.

        However, if you are using multiple entries then the bool is going to be set on the first entry and thus the remaining three in your example would not be processed. So you would need four separate conditions with four separate bools.

        So are all four supposed to go in the same direction all at once? Or are you wishing to wait for the entry distance and then place the next order?

        Comment


          #5
          Hi Patrick,

          I want to wait the entry distance before placing the next trade. I want the trades to be placed sequentially, with X bars of waiting time between entries. I don't have four separate condition sets per direction. I'm only using one condition set per direction (one for long, one for short). Right now I'm getting it to take up to 4 trades per direction by setting the "Order Handling - Entries per direction" parameter to 4.

          If I use a bool variable as suggested, won't that effectively deactivate my condition set after the first trade is placed?

          How about if I declare an integer variable EntryDistance and set the value to 0, then add
          && BarsSinceEntry() >= EntryDistance
          to the condition set, and insert
          EntryDistance = "desired value"
          after EnterLongLimit?

          Comment


            #6
            Hello Phil,

            Thank you for your response.

            Correct, you would wan to create two sets of conditions. One when the bool is false for the first trade and the other when it is true for the remaining trades.

            Comment


              #7
              Hi Patrick,

              In your post before this last one you said:

              However, if you are using multiple entries then the bool is going to be set on the first entry and thus the remaining three in your example would not be processed. So you would need four separate conditions with four separate bools.

              So are all four supposed to go in the same direction all at once? Or are you wishing to wait for the entry distance and then place the next order?
              But in the last post you're saying that I need two sets of conditions. I'm confused now. Are you saying I need 2 or 4 condition sets? To be clear, right now I have one condition set for long entries, and one for short (2 total). I still don't understand how using nothing but a boolean variable can instruct the strategy to keep 6 bars of distance between consecutive trades.

              I tried modifying the code in my script as I suggested above. First I declared a int variable called EntryDistance:

              Code:
              private int entryDistance = 0; // Default setting for EntryDistance
              
                      public int EntryDistance
                      {
                          get { return entryDistance; }
                          set { entryDistance = Math.Max(0, value); }
                      }
              And then modified the condition and action set to this:
              // Condition set 1
              Code:
              if (EMA(MA1Shortperiod)[0] > EMA(MA1Longperiod)[0]
                              && RSI(RSIperiod, 0)[0] < RSIbuylevel
                              && ToTime(Time[0]) > ToTime(9, 0, 0)
                              && ToTime(Time[0]) < ToTime(13, 59, 0)
                              && Position.MarketPosition != MarketPosition.Short
                              && EMA(BarsArray[1],MA2Shortperiod)[0] > EMA(BarsArray[1],MA2Longperiod)[0]
                              && EMA(BarsArray[2],MA3Shortperiod)[0] > EMA(BarsArray[2],MA3Longperiod)[0]
                              && BarsSinceEntry() >= EntryDistance)
                          {
                              EnterLongLimit(DefaultQuantity, Close[0], "LongEntry");
                              EntryDistance = 6;
                          }
              My thinking was that EntryDistance will remain with value 0 until the conditions are all met and the first EnterLongLimit is triggered. Then, EntryDistance is set to 6 and now subsequent long entries won't be triggered unless 6 bars have passed since the last entry.

              However, it doesn't seem to work. When I run the strategy in a backtest, all the trades disappear. It's not taking trades at all any more.

              Comment


                #8
                Hello Phil,

                Thank you for your response.

                Below is a basic strategy using the ideas we have discussed here. I hope this will help to clarify the idea here, and please let me know if you have any questions.
                Code:
                        #region Variables
                		private bool myBool = true;
                        #endregion
                
                        protected override void Initialize()
                        {
                			EntriesPerDirection = 4;
                			EntryHandling = EntryHandling.AllEntries;
                        }
                
                        protected override void OnBarUpdate()
                        {
                			// check that the bool is true and the condition for entry is met
                			if(myBool && Close[0] > Open[0])
                			{
                				EnterLong();
                				myBool = false;
                			}
                			
                			// check that the bool is false indicating the first entry was placed
                			// then check how many bars have passed since the last entry
                			if(!myBool && BarsSinceEntry() > 5)
                			{
                				EnterLong();
                			}
                		}

                Comment


                  #9
                  Ah, OK. I didn't realize you were suggesting bool and BarsSinceEntry(). I was under the impression I was meant to use a bool alone. I'll try this tonight when I get home. I'll let you know if I have trouble.

                  Comment


                    #10
                    Hi Patrick,

                    I've tried working with this over the past couple of days, and it looks like it's sort of working, but not properly

                    What happens is that when I run a backtest the trades will be properly spaced apart for the first day of the backtest only. On subsequent days though, all signals will trigger all at once on the same bar. It's almost as if BarSinceEntry() works on the first day of the backtest and then after that it uses the most recent entry from the previous day as the reference, rather than the most recent entry from the current trading day. I've pasted the short entry signals of my code below for you to take a look at (same thing happens for long entries, but I don't want to waste space on this post). I've also attached two screenshots showing what I'm talking about. The first is the first day of the backtest where I get short entry signals. The second is the next day of the backtest where I get short entry signals.

                    I'm running a 20-day backtest on my strategy on the ES with 5 mins as the base time frame (I also have the 15 min and 60 min as added time frames).

                    Code:
                    #region Variables
                            private int mA1Shortperiod = 8; // Default setting for MA1Shortperiod
                            private int mA1Longperiod = 13; // Default setting for MA1Longperiod
                            private int mA2Shortperiod = 8; //Default setting for MA2Shortperiod
                            private int mA2Longperiod = 13; //Default seting for MA2Longperiod
                            private int mA3Shortperiod = 8; //Default setting for MA3Shortperiod
                            private int mA3Longperiod = 13; //Default seting for MA3Longperiod        
                            private int rSIperiod = 2; // Default setting for RSIperiod
                            private int aTRperiod = 10; // Default setting for ATRperiod
                            private int rSIbuylevel = 15; // Default setting for RSIbuylevel
                            private int rSIselllevel = 90; // Default setting for RSIselllevel
                            private double stopMultiplier = 0.75; // Default setting for StopMultiplier
                            private int entryDistance = 6; // Default setting for EntryDistance
                            private bool shortTradeBool = true; // Default setting for shortTradeBool, which allows first short trade to be taken
                            private bool shortTradeBool2 = true;
                            private bool shortTradeBool3 = true;
                            private int exitTime = 143000; //Default setting for ExitTime, which determines when we exit all positions
                            #endregion
                    
                            /// <summary>
                            /// This method is used to configure the strategy and is called once before any strategy method is called.
                            /// </summary>
                            protected override void Initialize()
                            {
                                TraceOrders = true;
                                Add(PeriodType.Minute,15);
                                Add(PeriodType.Minute,60);
                                
                                CalculateOnBarClose = true;
                            }
                    
                            /// <summary>
                            /// Called on each bar update event (incoming tick)
                            /// </summary>
                            protected override void OnBarUpdate()
                            {
                                //Checks to ensure all Bars objects contain enough bars before beginning
                                if(CurrentBars[0] <= BarsRequired || CurrentBars[1] <= BarsRequired || CurrentBars[2] <= BarsRequired)
                                    return;
                                
                                // Condition set for short trades for the first trade only
                                if (EMA(BarsArray[0],MA1Shortperiod)[0] < EMA(BarsArray[0],MA1Longperiod)[0]
                                    && RSI(BarsArray[0],RSIperiod, 0)[0] > RSIselllevel
                                    && ToTime(Time[0]) > ToTime(9, 0, 0)
                                    && ToTime(Time[0]) < ToTime(13, 59, 0)
                                    && Position.MarketPosition != MarketPosition.Long
                                    && EMA(BarsArray[1],MA2Shortperiod)[0] < EMA(BarsArray[1],MA2Longperiod)[0]
                                    && EMA(BarsArray[2],MA3Shortperiod)[0] < EMA(BarsArray[2],MA3Longperiod)[0]
                                    && shortTradeBool)
                                {
                                    EnterShortLimit(DefaultQuantity, Close[0], "ShortEntry1");
                                    Variable0 = StopMultiplier*4*ATR(BarsArray[2],ATRperiod)[0];
                                    SetStopLoss("ShortEntry1", CalculationMode.Ticks, Variable0, false);
                                    shortTradeBool = false;
                                }
                                
                                // Condition set for short trades for the second trade
                                if (EMA(BarsArray[0],MA1Shortperiod)[0] < EMA(BarsArray[0],MA1Longperiod)[0]
                                    && RSI(BarsArray[0],RSIperiod, 0)[0] > RSIselllevel
                                    && ToTime(Time[0]) > ToTime(9, 0, 0)
                                    && ToTime(Time[0]) < ToTime(13, 59, 0)
                                    && Position.MarketPosition != MarketPosition.Long
                                    && EMA(BarsArray[1],MA2Shortperiod)[0] < EMA(BarsArray[1],MA2Longperiod)[0]
                                    && EMA(BarsArray[2],MA3Shortperiod)[0] < EMA(BarsArray[2],MA3Longperiod)[0]
                                    && !shortTradeBool
                                    && shortTradeBool2
                                    && BarsSinceEntry(0,"ShortEntry1",0) >= EntryDistance)
                                {
                                    EnterShortLimit(DefaultQuantity, Close[0], "ShortEntry2");
                                    Variable0 = StopMultiplier*4*ATR(BarsArray[2],ATRperiod)[0];
                                    SetStopLoss("ShortEntry2", CalculationMode.Ticks, Variable0, false);
                                    shortTradeBool2 = false;
                                }
                                            
                                // Condition set for short trades for the third trade
                                if (EMA(BarsArray[0],MA1Shortperiod)[0] < EMA(BarsArray[0],MA1Longperiod)[0]
                                    && RSI(BarsArray[0],RSIperiod, 0)[0] > RSIselllevel
                                    && ToTime(Time[0]) > ToTime(9, 0, 0)
                                    && ToTime(Time[0]) < ToTime(13, 59, 0)
                                    && Position.MarketPosition != MarketPosition.Long
                                    && EMA(BarsArray[1],MA2Shortperiod)[0] < EMA(BarsArray[1],MA2Longperiod)[0]
                                    && EMA(BarsArray[2],MA3Shortperiod)[0] < EMA(BarsArray[2],MA3Longperiod)[0]
                                    && !shortTradeBool2
                                    && shortTradeBool3
                                    && BarsSinceEntry(0,"ShortEntry1",0) >= EntryDistance
                                    && BarsSinceEntry(0,"ShortEntry2",0) >= EntryDistance)
                                {
                                    EnterShortLimit(DefaultQuantity, Close[0], "ShortEntry3");
                                    Variable0 = StopMultiplier*4*ATR(BarsArray[2],ATRperiod)[0];
                                    SetStopLoss("ShortEntry3", CalculationMode.Ticks, Variable0, false);
                                    shortTradeBool3 = false;
                                }            
                    
                                //Timecheck for exiting of positions, exit positions, and reset bools back to default values
                                if (ToTime(Time[0])>=ExitTime)
                                {
                                        shortTradeBool = true;
                                        shortTradeBool2 = true;
                                        shortTradeBool3 = true;
                                        longTradeBool = true;
                                    
                                    if (Position.MarketPosition == MarketPosition.Long)
                                    {
                                        ExitLong();
                                    }
                                    else if (Position.MarketPosition == MarketPosition.Short)
                                    {
                                        ExitShort();
                    Attached Files

                    Comment


                      #11
                      Hello PhillyD,

                      The reason it only works for the first trades, is because your BarSinceEntry() method is checking for a specific signal name. Since "ShortEntry1" has been entered, your entryDistance condition is always true. Meaning, after the first trade, the bars since entry for ShortEntry1 is always greater than the entry distance.

                      There are a number ways to handle this. Your bools you added will help restrict the trade setup only when those are true, but in order to do specific tracking to the order signal, you will need to use more unique entry signals.

                      The most straightforward to handle this is to add a counter to your signal names;

                      Code:
                      //int counter we will use to increment every time there is a short trade setup
                      private int shortCount = 0;

                      Then under your first condition, you'll simply want to increase that value each time the condition is true, which will help track how many trades it has taken and then can be used for more precise signal tracking:

                      Code:
                      // Condition set for short trades for the first trade only
                      if(... your condition is true  ..)
                      {
                          // make sure to increment this value FIRST so we can we pass it to the signal name
                          shortCount++;  
                      
                          // add the short count to the signal name-> this produces "ShortEntry1: 1", ShortEntry1: 2", etc
                          EnterShortLimit(DefaultQuantity, Close[0], "ShortEntry1: " + shortCount);  
                      
                          Variable0 = stopMultiplier*4*ATR(BarsArray[2],aTRperiod)[0];
                      
                          //we also need to add this shortCount variable to the stop loss...
                          SetStopLoss("ShortEntry1: " + shortCount, CalculationMode.Ticks, Variable0, false);
                          shortTradeBool = false;  
                      }
                      Then under your second condition, where you're checking BarsSinceEntry(), you'll simply want to add the shortCount variable as well, which will ensure we're checking for a unique entry:

                      Code:
                       && BarsSinceEntry(0,"ShortEntry1: "+shortCount,0) >= entryDistance)
                      Now, since we're just using one counter, we do not need to increment this again for these last 2 conditions, however you do need to make sure you're still using unique signal names with the shortCount

                      Code:
                      EnterShortLimit(DefaultQuantity, Close[0], "ShortEntry2: " + shortCount);
                      SetStopLoss("ShortEntry2: "+ shortCount, CalculationMode.Ticks, Variable0, false);
                      The same logic applies to the 3 condition, we just need to check both entries:

                      Code:
                        && BarsSinceEntry(0,"ShortEntry1: "+ shortCount, 0) >= entryDistance
                                      && BarsSinceEntry(0,"ShortEntry2: "+shortCount,0) >= entryDistance)
                      At this point, you do not necessarily need to use a unique entry for short3 since you're not tracking it, but it doesn't hurt for consistency:

                      Code:
                      EnterShortLimit(DefaultQuantity, Close[0], "ShortEntry3: "+shortCount);
                      SetStopLoss("ShortEntry3: "+shortCount, CalculationMode.Ticks, Variable0, false);
                      MatthewNinjaTrader Product Management

                      Comment


                        #12
                        OK, got it. The shortCount variable would be a variable that keeps track of the day. e.g. Short signal 1/day 1, short signal 2/day 1, short signal 3/day 1, then increment again and becomes short signal 1/day 2, short signal 2/day 2, short signal 3/day 2, etc. etc.

                        Comment

                        Latest Posts

                        Collapse

                        Topics Statistics Last Post
                        Started by Geovanny Suaza, 02-11-2026, 06:32 PM
                        0 responses
                        598 views
                        0 likes
                        Last Post Geovanny Suaza  
                        Started by Geovanny Suaza, 02-11-2026, 05:51 PM
                        0 responses
                        343 views
                        1 like
                        Last Post Geovanny Suaza  
                        Started by Mindset, 02-09-2026, 11:44 AM
                        0 responses
                        103 views
                        0 likes
                        Last Post Mindset
                        by Mindset
                         
                        Started by Geovanny Suaza, 02-02-2026, 12:30 PM
                        0 responses
                        556 views
                        1 like
                        Last Post Geovanny Suaza  
                        Started by RFrosty, 01-28-2026, 06:49 PM
                        0 responses
                        555 views
                        1 like
                        Last Post RFrosty
                        by RFrosty
                         
                        Working...
                        X