## Learn how to constrain trading between a Start and End Time – not so “easy-peasy”

Why waste time on this?

**Is Time > StartTime and Time <= EndTime then… ** Right?

This is definitely valid when **EndTime** > **StartTime**. But what happens when **EndTime** < **StartTime**. Meaning that you start trading yesterday, prior to midnight, and end trading after midnight (today.) Many readers of my blog know I have addressed this issue before and created some simple equations to help facilitate trading around midnight. The lines of code I have presented work most of the time. Remember when the ES used to close at 4:15 and re-open at 4:30 eastern? As of late June 2021, this gap in time has been removed. The ES now trades between 4:15 and 4:30 continuously. I discovered a little bug in my code for this small gap when I was optimizing a “get out time.” I wanted to create a user function that uses the latest session start and end times and build a small database of valid times for the 24-hour markets. Close to 24 hours – most markets will close for an hour. With this small database you can test your time to see if it is a valid time. The construction of this database will require a little TIME math and require the use of arrays and loops. It is a good tutorial. However, it is not perfect. If you optimize time and you want to get out at 4:20 in 2020 on the ES, then you still run into the problem of this time not being valid. This requires a small workaround. Going forward with automated trading, this function might be useful. Most markets trade around the midnight hour – I think meats might be the exception.

## Time Based Math

How many 5-minute bars are between 18:00 (prior day) and 17:00 (today)? We can do this in our heads 23 hours X (60 minutes / 5 minutes) or 23 X 12 = 276 bars. But we need to tell the computer how to do this and we also should allow users to use times that include minutes such as 18:55 to 14:25. Here’s the math – btw you may have a simpler approach.

Using **startTime** of 18:55 and **endTime** of 14:25.

**1. Calculate the difference in hours and minutes from startTime to midnight and then in terms of minutes only.**

**a. timeDiffInHrsMins** = 2360 – 1855 = 505 or 5 hours and 5 minutes. We use a little short cut hear. 23 hours and 60 minutes is the same as 2400 or midnight.

**b. timeDiffInMinutes = intPortion(timeDiffInHrsMins/100) * 60** + mod(timeDiffInHrsMins,100). This looks much more complicated than it really is because we are using two helper functions – intPortion and mod:

**I) intPortion **– returns the whole number from a fraction. If we divide 505/100 we get 5.05 and if we truncate the decimal we get 5 hours.

**II) mod** – returns the modulus or remainder from a division operation. I use this function a lot. Mod(505/100) gives 5 minutes.

**III) Five hours** * 60 minutes + Five minutes = 305 minutes.

**2. Calculate the difference in hours and minutes from midnight to endTime and then in terms of minutes only.**

**a. timeDiffInHrsMins = endTime** – 0 = 1425 or 14 hours and 25 minutes. We don’t need to use our little, short cut here since we are simply subtracting zero. I left the zero in the calculation to denote midnight.

**b. timeDiffInMinutes = timeDiffInMinutes** + intPortion(timeDiffInHrsMins/100) * 60 + mod(timeDiffInHrsMins,100). This is the same calculation as before, but we are adding the result to the number of minutes derived from the startTime to midnight.

**I) intPortion** – returns the whole number from a fraction. If we divide 1425/100, we get 14.05 and if we truncate the decimal, we get 14.

**II) mod** – returns the modulus or remainder from a division operation. I use this function a lot. Mod(1425/100) gives 25.

**III)** 14* 60 + 25 = 865 minutes.

**iv)** Now add 305 minutes to 865. This gives us a total of 1165 minutes between the start and end times.

**3. Now divide the timeDiffInMinutes by the barInterval. This gives 1165 minutes/5 minutes or 233 five-minute bars.**

## Build Database of all potential time stamps between start and end time

We now have all the ingredients to build are simple array-based database. Don’t let the word array scare you away. Follow the logic and you will see how easy it is to use them. First, we will create the database of all the time stamps between the regular session start and end times of the data on the chart. We will use the same time-based math (and a little more) to create this benchmark database. Check out the following code.

// You could use static arrays

// reserve enough room for 24 hours of minute bars

// 24 * 60 = 1440

// arrays: theoTimes[1440](0),validTimes[1440](0);

// syntax - arrayName[size](0) - the zero sets all elements to zero

// this seems like over kill because we don't know what

// bar interval or time span the user will be using

// these arrays are dynamic

// we dimension or reserve space for just what we need

arrays: theoTimes[](0),validTimes[](0);

// Create a database of all times stamps that potentiall could

// occur

numBarsInCompleteSession = timeDiffInMinutes/barInterval;

// Now set the dimension of the array by using the following

// function and the number of bars we calculated for the entire

// regular session

Array_setmaxindex(theoTimes,numBarsInCompleteSession);

// Load the array from start time to end time

// We know the start time and we know the number of X-min bars

// loop from 1 to numBarsInCompleteSession and

// use timeSum as the each and every time stamp

// To get to the end of our journey we must use Time Based Math again.

timeSum = startTime;

for arrayIndex = 1 to numBarsInCompleteSession

Begin

timeSum = timeSum + barInterval;

if mod(timeSum,100) = 60 Then

timeSum = timeSum - 60 + 100; // 1860 - becomes 1900

if timeSum = 2400 Then

timeSum = 0; // 2400 becomes 0000

theoTimes[arrayIndex] = timeSum;

print(d," theo time",arrayIndex," ",theoTimes[arrayIndex]);

end;

Create a dynamic array with all possible time stamps

This is a simple looping mechanism that continually adds the **barInterval** to **timeSum** until** numBarsInCompleteSession** are exhausted. Reade about the difference between **static** and **dynamic** arrays in the code, please. Here’s how it works with a session start time of 1800:

theoTimes[01] = 1800 + 5 = 1805

theoTimes[02] = 1805 + 5 = 1810

theoTimes[04] = 1810 + 5 = 1815

theoTimes[05] = 1815 + 5 = 1820

theoTimes[06] = 1820 + 5 = 1830

...

//whoops - need more time based math 1860 is not valid

theoTimes[12] = 1855 + 5 = 1860

Insert bar stamps into our theoTimes array

### More time-based math

Our loop hit a snag when we came up with 1860 as a valid time. We all know that 1860 is really 1900. We need to intervene when this occurs. All we need to do is use our modulus function again to extract the minutes from our time.

If mod(timeSum,100) = 60 then **timeSum** = **timeSum** – 60 + 100. Her we remove the sixty minutes from the time and add an hour to it.

1860 – 60 + 100 = 1900 // a valid time stamp

That should fix everything right? What about this:

theoTimes[69] = 2340 + 5 = 2345

theoTimes[70] = 2345 + 5 = 2350

theoTimes[71] = 2350 + 5 = 2355

theoTimes[72] = 2355 + 5 = 2400 // whoops

2400 is okay in Military Time but not in TradeStation

This is a simple fix with. All we need to do is check to see if **timeSum = 2400 **and if so, just simply reset to **zero.**

### Build a database on our custom time frame.

Basically, do the same thing, but use the user’s choice of start and end times.

//calculate the number of barInterval bars in the

//user defined session

numBarsInSession = timeDiffInMinutes/barInterval;

Array_setmaxindex(validTimes,numBarsInSession);

startTimeStamp = calcTime(startTime,barInterval);

timeSum = startTime;

for arrayIndex = 1 to numBarsInSession

Begin

timeSum = timeSum + barInterval;

if mod(timeSum,100) = 60 Then

timeSum = timeSum - 60 + 100;

if timeSum = 2400 Then

timeSum = 0;

validTimes[arrayIndex] = timeSum;

//print(d," valid times ",arrayIndex," ",validTimes[arrayIndex]," ",numBarsInSession);

end;

Create another database using the time frame chose by the user

### Don’t allow weird times!

Good programmers don’t allow extraneous values to bomb their functions. TRY and CATCH the erroneous input before proceeding. If we have a database of all possible time stamps, shouldn’t we use it to validate the user entry? Of course, we should.

//Are the users startTime and endTime valid

//bar time stamps? Loop through all the times

//and validate the times.

for arrayIndex = 1 to numBarsInCompleteSession

begin

if startTimeStamp = theoTimes[arrayIndex] then

validStartTime = True;

if endTime = theoTimes[arrayIndex] Then

validEndTime = True;

end;

Validate user's input

Once we determine if both time inputs are valid, then we can determine if the any bar’s time stamp during a back-test is a valid time.

if validStartTime = false or validEndTime = false Then

error = True;

//Okay to check for bar time stamps against our

//database - only go through the loop until we

//validate the time - break out when time is found

//in database. CanTradeThisTime is the name of the function.

//It returns either True or False

if error = False Then

Begin

for arrayIndex = 1 to numBarsInSession

Begin

if t = validTimes[arrayIndex] Then

begin

CanTradeThisTime = True;

break;

end;

end;

end;

This portion of the code is executed on every bar of the back-test

## Once and only Once!

The code that creates the theoretical and user defined time stamp database is only done on the very first bar of the chart. Also, the validation of the user’s input in only done once as well. This is accomplished by encasing this code inside a **Once – begin – end**.

Now this code will test any time stamp against the current regular session. If you run a test prior to June 2021, you will get a theoretical database that includes a 4:20, 4:25, and 4:30 on the ES futures. However, in actuality these bar stamps did not exist in the data. This might cause a problem when working with a start or end time prior to June 2021, that falls in this range.

Function Name: CanTradeThisTime

Complete code:

// Function to determine if time is in acceptable

// set of times

inputs:startTime(numericSimple),endTime(numericSimple);

vars: sessStartTime(0),sessEndTime(0),

startTimeStamp(0),timeSum(0),timeDiffInHrsMins(0),timeDiffInMinutes(0),

validStartTime(False), validEndTime(False);

vars: error(False),arrayIndex(0),

numBarsInSession(0),numBarsInCompleteSession(0);

arrays: theoTimes[](0),validTimes[](0);

vars: arrCnt(0),seed(0);

canTradeThisTime = false;

once

Begin

sessStartTime = sessionStartTime(0,1);

sessEndTime = sessionEndTime(0,1);

if sessStartTime > sessEndTime Then

Begin

timeDiffInHrsMins = 2360 - sessStartTime;

timeDiffInMinutes = intPortion(timeDiffInHrsMins/100) * 60 + mod(timeDiffInHrsMins,100);

timeDiffInHrsMins = sessEndTime - 0;

timeDiffInMinutes += intPortion(timeDiffInHrsMins/100) * 60 + mod(timeDiffInHrsMins,100);

end;

if sessStartTime <= sessEndTime Then

Begin

timeDiffInHrsMins = (intPortion(sessEndTime/100) - 1)*100 + mod(sessEndTime,100) + 60 - sessEndTime;

timeDiffInMinutes = intPortion(timeDiffInHrsMins/100) * 60 + mod(timeDiffInHrsMins,100);

end;

numBarsInCompleteSession = timeDiffInMinutes/barInterval;

Array_setmaxindex(theoTimes,numBarsInCompleteSession);

timeSum = startTime;

for arrayIndex = 1 to numBarsInCompleteSession

Begin

timeSum = timeSum + barInterval;

if mod(timeSum,100) = 60 Then

timeSum = timeSum - 60 + 100;

if timeSum = 2400 Then

timeSum = 0;

theoTimes[arrayIndex] = timeSum;

print(d," theo time",arrayIndex," ",theoTimes[arrayIndex]);

end;

if startTime > endTime Then

Begin

timeDiffInHrsMins = 2360 - startTime;

timeDiffInMinutes = intPortion(timeDiffInHrsMins/100) * 60 + mod(timeDiffInHrsMins,100);

timeDiffInHrsMins = endTime - 0;

timeDiffInMinutes += intPortion(timeDiffInHrsMins/100) * 60 + mod(timeDiffInHrsMins,100);

end;

if startTime <= endTime Then

Begin

timeDiffInHrsMins = (intPortion(endTime/100) - 1)*100 + mod(endTime,100) + 60 - startTime;

timeDiffInMinutes = intPortion(timeDiffInHrsMins/100) * 60 + mod(timeDiffInHrsMins,100);

end;

numBarsInSession = timeDiffInMinutes/barInterval;

Array_setmaxindex(validTimes,numBarsInSession);

startTimeStamp = calcTime(startTime,barInterval);

timeSum = startTime;

for arrayIndex = 1 to numBarsInSession

Begin

timeSum = timeSum + barInterval;

if mod(timeSum,100) = 60 Then

timeSum = timeSum - 60 + 100;

if timeSum = 2400 Then

timeSum = 0;

validTimes[arrayIndex] = timeSum;

print(d," valid times ",arrayIndex," ",validTimes[arrayIndex]," ",numBarsInSession);

end;

for arrayIndex = 1 to numBarsInCompleteSession

begin

if startTimeStamp = theoTimes[arrayIndex] then

validStartTime = True;

if endTime = theoTimes[arrayIndex] Then

validEndTime = True;

end;

end;

if validStartTime = False or validEndTime = false Then

error = True;

if error = False Then

Begin

for arrayIndex = 1 to numBarsInSession

Begin

if t = validTimes[arrayIndex] Then

begin

CanTradeThisTime = True;

break;

end;

end;

end;

__Complete CanTradeThisTime function code__

### Sandbox Strategy function driver

inputs: startTime(1800),endTime(1500);

if canTradeThisTime(startTime,endTime) Then

if d = 1231206 or d = 1231207 then

print(d," ",t," can trade this time");

I hope you find this useful. Remember to purchase by Easing into EasyLanguage books at amazon.com. The **DayTrade edition** is still on sale. Email me with any question or suggestions or bugs or anything else.

>>By George Pruitt from blog georgepruitt.com

Why not just use and optimize the TimeToMinutes function?

Hi GP (love the initials) – you could incorporate TimeToMinutes for sure! TimeToMinutes returns the number of minutes between midnight and the users’ input (HHMM format.) In any programming language there is more than one way to get the job done. This tutorial, like my books, was designed to introduce multiple programming constructs such as time math, loops, arrays and a simple database. This following code should work when trading around midnight with time-based constraints.

Thanks, GP, for the clever insight!

// Trading around midnight using TimeToMinutes

inputs: startTime(2300),endTime(500);

vars: numMinutes(0),canTrade(False);

if t = startTime then

begin

numMinutes = 0;

end;

canTrade = False;

if numMinutes < TimeToMinutes(endTime) + (TimeToMinutes(2359) – TimeToMinutes(startTime)) then

canTrade = True;

numMinutes += barInterval;

Great stuff! Thanks for the article!

Ah! Same initials! Just noticed! lol