Testing Seasonal Tendencies with an EasyLanguage Template

Have you discovered a seasonal tendency but can’t figure out how to test it?

Are there certain times of the year when a commodity increases in price and then recedes?  In many markets this is the case.  Crude oil seems to go up during the summer months and then chills out in the fall.  It will rise once again when winter hits.  Early spring might show another price decline.  Have you done your homework and recorded certain dates of the year to buy/sell and short/buyToCover.  Have you tried to apply these dates to a historical back test and just couldn’t figure it out?  In this post I am going to show how you can use arrays and loops to cycle through the days in your seasonal database (database might be too strong of a term here) and apply long and short entries at the appropriate times during the past twenty years of daily bar data.

Build the Quasi-Database with Arrays

If you are new to EasyLanguage  you may not yet know what arrays are or you might just simply be scared of them.  Now worries here!  Most people bypass arrays because they don’t know how to declare them, and if they get passed that, how to manipulate them to squeeze out the data they need. You may not be aware of it, but if you have programmed in EasyLanguage the least bit, then you have already used arrays.  Check this out:

if high > high[1] and low > low[1] and
average(c,30) > average(c,30)[1] then
buy next bar at open

In reality the keywords high and low are really arrays.  They are lists that contain the entire history of the high and low prices of the data that is plotted on the chart.  And just like with declared arrays, you index these keywords to get historic data.  the HIGH[1] means the high of yesterday and the HIGH[2] means the high of the prior day.   EasyLanguage handles the management of these array-like structures.  In other words, you don’t need to keep track of the indexing – you know the [1] or [2] stuff.  The declaration of an array is ultra-simple once you do it a few times.  In our code we are going to use four arrays:

  1. Buy array
  2. SellShort array
  3. Sell array
  4. BuyToCover array

Each of these arrays will contain the month and day of month when a trade is to be entered or exited.  Why not the year?  We want to keep things simple and buy/short the same time every year to see if there is truly a seasonal tendency.  The first thing we need to do is declare the four arrays and then fill them up.


// use the keyword arrays and : semicolon
// next give each array a name and specify the
// max number of elements that each array can hold
// the [100] part. Each array needs to be initialized
// and we do this by placing a zero (0) in parentheses
arrays: buyDates[100](0),sellDates[100](0),
shortDates[100](0),buyToCoverDates[100](0);

// next you want the arrays that go together to have the same
// index value - take a look at this

buyDates[1] = 0415;sellDates[1] = 0515;
buyDates[2] = 0605;sellDates[2] = 0830;

shortDates[1] = 0915;buyToCoverDates[1] = 1130;
shortDates[2] = 0215;buyToCoverDates[2] = 0330;

// note the buyDates[1] has a matching sellDates[1]
// buyDates[2] has a matching sellDates[2]
// -- and --
// shortDates[1] has a matching buyToCoverDates[1]
// shortDates[2] has a matching buyToCoverDates[2]

Our simple database has been declared, initialized and populated.  This seasonal strategy will buy on:

  • April 15th and Exit on May 15th
  • June 5th and Exit on August 30th

It will sellShort on:

  • September 15th and Cover on November 30th
  • February 15th and Cover on March 30th

You could use this template and follow the pattern to add more dates to your database.  Just make sure nothing overlaps.

Now, each chart has N dates of history plotted from the left to right.  TradeStation starts out the test from the earliest date to the last date.  It does this by looping one day at a time.  The first thing we need to do is convert the bar date (TradeStation represents dates in a weird format – YYYMMDD – Jan 30, 2022 is represented by the number 1220130 – don’t ask why!!) to a format like the data that is stored in our arrays.   Fortunately, we don’t have to deal with the year and EasyLanguage provides two functions to help us out.

  • Month(Date) = the month (1-12) of the current bar
  • DayOfMonth(Date) = the day of the month of the current bar

All we need to do is use these functions to convert the current bar’s date into terms of our database, and then test that converted date against our database.  Take a look:


//convert the date into our own terms
//say the date is December 12
//the month function returns 12 and the day of month returns 12
// 12*100 + 12 = 1212 --> MMDD - just waht we need
//notice I look at the date of tomorrow because I want to take
//action on the open of tomorrow.

currentMMDD = month(d of tomorrow)*100 + dayOfMonth(d of tomorrow);


//You might need to study this a little bit - but I am looping through each
//array to determine if a trade needs to be entered.
//Long Seasonal Entries toggle
buyNow = False;
for n = 1 to numBuyDates
Begin
if currentMMDD[1] < buyDates[n] and currentMMDD >= buyDates[n] Then
Begin
buyNow = True;
end;
end;

//Short Seasonal Entries toggle
shortNow = False;
for n = 1 to numshortDates
Begin
if currentMMDD[1] < shortDates[n] and currentMMDD >= shortDates[n] Then
Begin
shortNow = True;
end;
end;
Date conversion and looping thru Database

This code might look a little daunting, but it really isn’t.  The first for-loop starts at 1 and goes through the number of buyDates.  The index variable is the letter n. The loop starts at 1 and goes to 2 in increments of 1.  Study the structure of the for-loop and let me know if you have any questions.  What do you think this code is doing.

if currentMMDD[1] < buyDates[n] and
currentMMDD >= buyDates[n] Then

As you know the 15th of any month may fall on a weekend.  This code basically says, ” Okay if today is less than the buyDate and tomorrow is equal to or greater than buyDate, then tommorrow is either going to be the exact day of the month or the first day of the subsequent week (the day of month fell on a weekend.)  If tomorrow is a trade date, then a conditional buyNow is set to True.  Further down in the logic the trade directive is issued if buyNow is set to True.

Total of 4 loops – 2 for each long/short entry and 2 for each long/short exit.

Here is the rest of the code:

inputs: dollarProfit(5000),dollarLoss(3000);
arrays: buyDates[100](0),sellDates[100](0),
shortDates[100](0),buyToCoverDates[100](0);

vars: n(0),mp(0),currentMMDD(0),
numBuyDates(0),numshortDates(0),
numSellDates(0),numBuyToCoverDates(0);

vars: buyNow(False),shortNow(False),
sellNow(False),buyToCoverNow(False);


// fill the arrays with dates - remember we are not pyramiding here
// use mmdd format
buyDates[1] = 0415;sellDates[1] = 0515;
buyDates[2] = 0605;sellDates[2] = 0830;
numBuyDates = 2;
numSellDates = 2;


shortDates[1] = 0915;buyToCoverDates[1] = 1130;
shortDates[2] = 0215;buyToCoverDates[2] = 0330;
numshortDates = 2;
numbuyToCoverDates = 2;

mp = marketPosition;
currentMMDD = month(d of tomorrow)*100 + dayOfMonth(d of tomorrow);

//Long Seasonal Entries toggle
buyNow = False;
for n = 1 to numBuyDates
Begin
if currentMMDD[1] < buyDates[n] and currentMMDD >= buyDates[n] Then
Begin
buyNow = True;
end;
end;

//Short Seasonal Entries toggle
shortNow = False;
for n = 1 to numshortDates
Begin
if currentMMDD[1] < shortDates[n] and currentMMDD >= shortDates[n] Then
Begin
shortNow = True;
end;
end;

//Long Seasonal Exits toggle
sellNow = False;
if mp = 1 Then
Begin
for n = 1 to numSellDates
Begin
if currentMMDD[1] < sellDates[n] and currentMMDD >= sellDates[n] Then
Begin
sellNow = True;
end;
end;
end;

//Short Seasonal Exits toggle
buyToCoverNow = False;
if mp = -1 Then
Begin
for n = 1 to numBuyToCoverDates
Begin
if currentMMDD[1] < buyToCoverDates[n] and currentMMDD >= buyToCoverDates[n] Then
Begin
buyToCoverNow = True;
end;
end;
end;


// Long entry execution
if buyNow = True then
begin
buy("Seas-Buy") next bar at open;
end;
// Long exit execution
if mp = 1 then
begin
if sellNow then
begin
sell("Long Exit") next bar at open;
end;
end;

// Short entry execution
if shortNow then
begin
sellShort("Seas-Short") next bar at open;
end;
// short exit execution
if mp = -1 then
begin
if buyToCoverNow then
begin
buyToCover("short Exit") next bar at open;
end;
end;




setStopLoss(dollarLoss);
setProfitTarget(dollarProfit);
Complete Seasonal Template EasyLanguage Code

Does it work?  It does – please take my word for it.  IYou can email me with any questions.  However, TS 10 just crashed on me and is wanting to update, but I need to kill all the processes before it can do a successful update.  Remember to always export your new code to an external location.  I will post an example on Monday Jan 30th.