Category Archives: EasyLanguage Indicator

Converting A String Date To A Number – String Manipulation in EasyLanguage

EasyLanguage Includes a Powerful String Manipulation Library

I thought I would share this function.  I needed to convert a date string (not a number per se) like “20010115” or “2001/01/15” or “01/15/2001” or “2001-01-15” into a date that TradeStation would understand.  The function had to be flexible enough to accept the four different formats listed above.

String Functions

Most programming languages have functions that operate strictly on strings and so does EasyLanguage.  The most popular are:

  • Right String (rightStr) – returns N characters from the right side of the string.
  • Left String (leftStr) – returns N character starting from the left side of the string
  • Mid String (midStr) – returns the middle portion of a string starting at a specific place in the string and advance N characters
  • String Length (strLen) – returns the number of characters in the string
  • String To Number (strToNum) – converts the string to a numeric representation.  If the string has a character, this function will return 0
  • In String (inStr) – returns location of a sub string inside a larger string ( a substring can be just one character long)

Unpack the String

If the format is YYYYMMDD format then all you need to do is remove the dashes or slashes (if there are any) and then convert what is left over to a number.   But if the format is MM/DD/YYYY format then we are talking about a different animal.  So how can you determine if the date string is in this format?  First off you need to find out if the month/day/year separator is a slash or a dash.  This is how you do this:

whereIsAslash = inStr(dateString,”/”);
whereIsAdash = inStr(dateString,”-“);

If either is a non zero then you know there is a separator.  The next thing to do is locate the first “dash or slash” (the search character or string).  If it is located within the first four characters of the date string then you know its not a four digit year.  But, lets pretend the format is “12/14/2001” so if the first dash/slash is the 3rd character you can extract the month string by doing this:

firstSrchStrLoc = inStr(dateString,srchStr);
mnStr= leftStr(dateString,firstSrchStrLoc-1);

So if firstSrchStrLoc = 3 then we want to leftStr the date string and extract the first two characters and store them in mnStr.  We then store what’s left of the date string in tempStr by using rightStr:

strLength = strLen(dateString);

tempStr = rightStr(dateString,strLength-firstSrchStrLoc);

Here I pass dateString and the strLength-firstSrchStrLoc – so if the dateString is 10 characters long and the firstSrchStrLoc is 3, then we can create a tempstring by taking [10 -3  = 7 ] characters from right side of the string:

“12/14/2001” becomes “14/2001” – once that is done we can pull the first two characters from the tempStr and store those into the dyStr [day string.]  I do this by searching for the “/” and storing its location in srchStrLoc.  Once I have that location I can use that information and leftStr to get the value I need.   All that is left now is to use the srchStrLoc and the rightStr function.

srchStrLoc = inStr(tempStr,srchStr);
dyStr = leftStr(tempStr,srchStrLoc-1);
yrStr = rightStr(tempStr,strLen(tempStr)-srchStrLoc);

Now convert the strings to numbers and multiply their values accordingly.

DateSTrToYYYMMDD = strToNum(yrStr) X 10000-19000000 + strToNum(mnStr) X 100 + strToNum(dyStr)

To get the date into TS format I have to subtract 19000000 from the year.  Remember TS represents the date in YYYMMDD  format.

Now what do  you do if the date is in the right format but simply includes the dash or slash separators.  All you need to do here is loop through the string and copy all non dash or slash characters to a new string and then convert to a number.  Here is the loop:

        tempStr = "";
iCnt = 1;
While iCnt <= strLength
Begin
If midStr(dateString,iCnt,1) <> srchStr then
tempStr += midStr(dateString,iCnt,1);
iCnt+=1;
end;
tempDate = strToNum(tempStr);
DateStrToYYYMMDD = tempDate-19000000;

Here I use midStr to step through each character in the string.  MidStr requires a string and the starting point and how many characters you want returned from the string.  Notice I step through the string with iCnt and only ask for 1 character at a time.  If the character is not a dash or slash I concatenate tempStr with the non dash/slash character.  At the end of the While loop I simply strToNum the string and subtract 19000000.  That’s it!  Remember EasyLanguage is basically a full blown programming language with a unique set of functions that relate directly to trading.

Here is the function and testFunc caller.

STRINGFUNCANDFUNCCALLER

 

How To Program A Ratcheting Stop in EasyLanguage

30 Minute Break Out utilizing a Ratchet Stop [7 point profit with 6 point retention]
I have always been a big fan of trailing stops.  They serve two purposes – lock in some profit and give the market room to vacillate.  A pure trailing stop will move up as the market makes new highs, but a ratcheting stop (my version) only moves up when a certain increment or multiple of profit has been achieved.  Here is a chart of a simple 30 minute break out on the ES day session.  I plot the buy and short levels and the stop level based on whichever level is hit first.

When you program something like this you never know what is the best profit trigger or the best profit retention value.  So, you should program this as a function of these two values.  Here is the code.

inputs: ratchetAmt(6),trailAmt(6);
vars:longMult(0),shortMult(0),myBarCount(0);
vars:stb(0),sts(0),buysToday(0),shortsToday(0),mp(0);
vars:lep(0),sep(0);

If d <> d[1] then
Begin
longMult = 0;
shortMult = 0;
myBarCount = 0;
mp = 0;
lep = 0;
sep = 0;
buysToday = 0;
shortsToday = 0;
end;

myBarCount = myBarCount + 1;

If myBarCount = 6 then // six 5 min bars = 30 minutes
Begin
stb = highD(0); //get the high of the day
sts = lowD(0); //get low of the day
end;

If myBarCount >= 6 and buysToday + shortsToday = 0 and high >= stb then
begin
mp = 1; //got long - illustrative purposes only
lep = stb;

end;
If myBarCount >=6 and buysToday + shortsToday = 0 and low <= sts then begin
mp = -1; //got short
sep = sts;
end;

If myBarCount >=6 then
Begin
plot3(stb,"buyLevel");
plot4(sts,"shortLevel");
end;
If mp = 1 then buysToday = 1;
If mp =-1 then shortsToday = 1;


// Okay initially you want a X point stop and then pull the stop up
// or down once price exceeds a multiple of Y points
// longMult keeps track of the number of Y point multipes of profit
// always key off of lep(LONG ENTRY POINT)
// notice how I used + 1 to determine profit
// and - 1 to determine stop level
If mp = 1 then
Begin
If h >= lep + (longMult + 1) * ratchetAmt then longMult = longMult + 1;
plot1(lep + (longMult - 1) * trailAmt,"LE-Ratchet");
end;

If mp = -1 then
Begin
If l <= sep - (shortMult + 1) * ratchetAmt then shortMult = shortMult + 1;
plot2(sep - (shortMult - 1) * trailAmt,"SE-Ratchet");
end;
Ratcheting Stop Code

So, basically I set my multiples to zero on the first bar of the trading session.  If the multiple = 0 and you get into a long position, then your initial stop will be entryPrice + (0 – 1) * trailAmt.  In other words your stop will be trailAmt (6 in this case) below entryPrce.  Once price exceeds or meets 7 points above entry price, you increment the multiple (now 1.)  So, you stop becomes entryPrice + (1-1) * trailAmt – which equals a break even stop.  This logic will always move the first stop to break even.  Assume the market moves 2 multiples into profit (14 points), what would your stop be then?

stop = entryPrice + (2 – 1) * 6 or entryPrice + 6 points.

See how it ratchets.  Now you can optimized the profit trigger and profit retention values.  Since I am keying of entryPrice your first trailing stop move will be a break-even stop.

This isn’t a strategy but it could very easily be turned into one.

Question on Multiple Time Indicator [Discrete Bars]

A reader of this blog proffered an excellent question on this indicator.  I hope this post answers his question and I am always open to any input that might improve my coding!

Because I use BarNumber in my MODULUS calculation the different time frames that I keep track of may not align with the time frames on the chart; your 10-minute bar O, H, L, and C values may not align with the values I am storing in my 10-minute bar container.    Take a look at this snapshot of a spreadsheet.

Here I  print out a 5-minute bar of the ES.D.  Because I use BarNumber in my Modulus calculation, I don’t get to a zero remainder until  9:50 in the 10, 15, and 20 minute time frames.  At 9:50 I start building fresh 10, 15, 20 minute bars by resetting the O, H, L and C to those of the 5-minute bars.  From there I keep track of the highest highs and lowest lows by extracting the data from the 5-minute bar.  I always set the close of the different time frames to the current 5-minute bar’s close.   Once the modulus for the different time frames reaches zero I close out the bar and start fresh again.  The 25-minute bar didn’t reach zero until the 10:05 bar.

I will see if I can come up with some code that will sync with the data on the chart.

MULTI-TIME FRAME – KEEPING TRACK OF DISCRETE TIME FRAMES

Just a quick post here.  I was asked how to keep track of the opening price for each time frame from our original Multi-Time Frame indicator and I was answering the question when I thought about modifying the indicator.  This version keeps track of each discrete time frame.  The original simply looked back a multiple of the base chart to gather the highest highs and lowest lows and then would do a simple calculation to determine the trend.  So let’s say its 1430 on a five-minute bar and you are looking back at time frame 2.  All I did was get the highest high and lowest low two bars back and stored that information as the high and low of time frame 2.  Time frame 3 simply looked back three bars to gather that information.  However if you tried to compare these values to a 10-minute or 15-minute chart they would not match.

In this version, I use the modulus function to determine the demarcation of each time frame.  If I hit the border of the time frame I reset the open, high, low and carry that value over until I hit the next demarcation.  All the while collecting the highest highs and lowest lows.  In this model, I am working my way from left to right instead of right to left.  And in doing so each time frame is discrete.

Let me know which version you like best.

 

Inputs:tf1Mult(2),tf2Mult(3),tf3Mult(4),tf4Mult(5);



vars: mtf1h(0),mtf1l(0),mtf1o(0),mtf1c(0),mtf1pvt(0),diff1(0),
mtf2h(0),mtf2l(0),mtf2o(0),mtf2c(0),mtf2pvt(0),diff2(0),
mtf3h(0),mtf3l(0),mtf3o(0),mtf3c(0),mtf3pvt(0),diff3(0),
mtf4h(0),mtf4l(0),mtf4o(0),mtf4c(0),mtf4pvt(0),diff4(0),
mtf0pvt(0),diff0(0);

If barNumber = 1 then
Begin
mtf1o = o;
mtf2o = o;
mtf3o = o;
mtf4o = o;
end;


If barNumber > 1 then
Begin

Condition1 = mod((barNumber+1),tf1Mult) = 0;
Condition2 = mod((barNumber+1),tf2Mult) = 0;
Condition3 = mod((barNumber+1),tf3Mult) = 0;
Condition4 = mod((barNumber+1),tf4Mult) = 0;

mtf1h = iff(not(condition1[1]),maxList(high,mtf1h[1]),high);
mtf1l = iff(not(condition1[1]),minList(low,mtf1l[1]),low);
mtf1o = iff(condition1[1],open,mtf1o[1]);
mtf1c = close;


mtf0pvt = (close + high + low) / 3;
diff0 = close - mtf0pvt;

mtf2h = iff(not(condition2[1]),maxList(high,mtf2h[1]),high);
mtf2l = iff(not(condition2[1]),minList(low,mtf2l[1]),low);
mtf2o = iff(condition2[1],open,mtf2o[1]);
mtf2c = close;


mtf1pvt = (mtf1h+mtf1l+mtf1c) / 3;
diff1 = mtf1c - mtf1pvt;

mtf2pvt = (mtf2h+mtf2l+mtf2c) / 3;
diff2 = mtf2c - mtf2pvt;

mtf3h = iff(not(condition3[1]),maxList(high,mtf3h[1]),high);
mtf3l = iff(not(condition3[1]),minList(low,mtf3l[1]),low);
mtf3o = iff(condition3[1],open,mtf3o[1]);
mtf3c = close;

mtf3pvt = (mtf3h+mtf3l+mtf3c) / 3;
diff3 = mtf3c - mtf3pvt;

mtf4h = iff(not(condition4[1]),maxList(high,mtf4h[1]),high);
mtf4l = iff(not(condition4[1]),minList(low,mtf4l[1]),low);
mtf4o = iff(condition4[1],open,mtf4o[1]);
mtf4c = close;

mtf4pvt = (mtf4h+mtf4l+mtf4c) / 3;
diff4 = mtf4c - mtf4pvt;


Condition10 = diff0 > 0;
Condition11 = diff1 > 0;
Condition12 = diff2 > 0;
Condition13 = diff3 > 0;
Condition14 = diff4 > 0;

If condition10 then setPlotColor(1,Green) else SetPlotColor(1,Red);
If condition11 then setPlotColor(2,Green) else SetPlotColor(2,Red);
If condition12 then setPlotColor(3,Green) else SetPlotColor(3,Red);
If condition13 then setPlotColor(4,Green) else SetPlotColor(4,Red);
If condition14 then setPlotColor(5,Green) else SetPlotColor(5,Red);

condition6 = condition10 and condition11 and condition12 and condition13 and condition14;
Condition7 = not(condition10) and not(condition11) and not(condition12) and not(condition13) and not(condition14);

If condition6 then setPlotColor(7,Green);
If condition7 then setPlotColor(7,Red);

If condition6 or condition7 then plot7(7,"trend");

Plot6(5,"line");
Plot1(4,"t1");
Plot2(3,"t2");
Plot3(2,"t3");
Plot4(1,"t4");
Plot5(0,"t5");

end;
Multi-Time Frame with Discrete Time Frames

Multi-Time Frame – Using Built-in Indicators and Multi Data Charts

A reader of this blog wanted to be able to use different time frames and some built-in indicators and output the information in a similar fashion as I did in the original MTF post.  There are numerous ways to program this but the two easiest are to use data structures such as arrays or vectors or use TradeStation’s own multi data inputs.  The more complicated of the two would be to use arrays and stay compliant with Multicharts.  Or in that same vein use vectors and not stay compliant with Multicharts.  I chose, for this post, the down and dirty yet compliant method.  [NOTE HERE! When I started this post I didn’t realize it was going to take the turn I ended up with.  Read thoroughly before playing around with the code to see that it is what you are really, really looking for.]  I created a multi data chart with five-time frames: 5,10,15,30 and 60 minutes.  I then hid data2 thru data5.  I created an MTF indicator that plots the relationship of the five time frames applied to the ADX indicator with length 14.  If the ADX > 20 then the plot will be green else it will be red.  If all plots align, then the composite plot will reflect the alignment color.

Using the MTF indicator with ADX
{EasyLanguage MultiTime Frame Indicator)
written by George Pruitt - copyright 2019 by George Pruitt
}


Inputs:adxLen(14),adxTrendVall(20);

vars: adxData1(0),adxData2(0),adxData3(0),adxData4(0),adxData5(0);


If barNumber > 1 then
Begin

adxData1 = adx(adxLen) of data1;
adxData2 = adx(adxLen) of data2;
adxData3 = adx(adxLen) of data3;
adxData4 = adx(adxLen) of data4;
adxData5 = adx(adxLen) of data5;

Condition10 = adxData1 > adxTrendVall;
Condition11 = adxData2 > adxTrendVall;
Condition12 = adxData3 > adxTrendVall;
Condition13 = adxData4 > adxTrendVall;
Condition14 = adxData5 > adxTrendVall;

If condition10 then setPlotColor(1,Green) else SetPlotColor(1,Red);
If condition11 then setPlotColor(2,Green) else SetPlotColor(2,Red);
If condition12 then setPlotColor(3,Green) else SetPlotColor(3,Red);
If condition13 then setPlotColor(4,Green) else SetPlotColor(4,Red);
If condition14 then setPlotColor(5,Green) else SetPlotColor(5,Red);

condition6 = condition10 and condition11 and condition12 and condition13 and condition14;
Condition7 = not(condition10) and not(condition11) and not(condition12) and not(condition13) and not(condition14);

If condition6 then setPlotColor(7,Green);
If condition7 then setPlotColor(7,Red);

If condition6 or condition7 then plot7(7,"trend");

Plot6(5,"line");
Plot1(4,"t1");
Plot2(3,"t2");
Plot3(2,"t3");
Plot4(1,"t4");
Plot5(0,"t5");

end;
MTF with 5 data streams and ADX

This code is very similar to the original MTF indicator, but here I simply pass a pointer to the different time frames to the ADX function.  Since the ADX function only requires a length input I had assumed I could use the following format to get the result for each individual time frame:

adxData1 = adx(14) of data1;

adxData2 = adx(14) of data2;

This assumption worked out.

But are we really getting what we really, really want?  I might be putting too much thought into this but of the five-time frame indicator dots, only the 5-minute will change on a 5-minute basis.  The 10-min dot will stay the same for two 5-min bars.  The dots will reflect the closing of the PRIOR time frame and the current 5-min bar is ignored in the calculation.  This may be what you want, I will leave that up to you.  Here is an illustration of the delay in the different time frames.

So when you look at each dot color remember to say to yourself – this is the result of the prior respective time frame’s closing price.  You can say to yourself, “Okay this is the ADX of the current 5-minute bar and this is the ADX of the prior 10-minute close and this is the ADX of the prior 15 minutes close and so on and so on.   We all know that the last 5 minutes will change all of the time frames closing tick, but it may or may not change the price extremes of those larger time frames.   I will show you how to do this in the next post.   If you want to see the impact of the last 5- minutes, then you must build your bars internally and dynamically.

 

Programming a Multi-Time Frame Indicator in EasyLanguage

Take a look at this indictor.

MTF indicator EasyLanguage

This indicator plots five different time frames as a stacked chart. The circles or dots at the bottom represent the difference between the closing price of each time frame and its associated pivot price  [(high + low + close)/3].  The value plotted at 4, in this case, represents the 5 minute time frame.  The 10-minute time frame is represented by the plot at 3 and so on.  The value plotted at 7 represents the composite of all the time frames.  It is only turned on if all times are either red or green.  If there is a disagreement then nothing is plotted.

This indicator is relatively simple even though the plot looks complicated.  You have to make sure the indicator is plotted in a separate pane.  The y – axis has 0 and 8 as its boundaries.  All you have to do is keep track of the highest highs/lowest lows for each time frame.  I use a multiplier of the base time frame to create different time frames.  TimeFrame1Mult = 2 represents 10 minutes and TimeFrame2Mult = 3 and that represents 15 minutes.  The indicator shows how strong the current swing is across five different time frames.  When you start getting a mix of green and red dots this could indicate a short term trend change.  You can use the EasyLanguage to plug in any indicator over the different time frames.  Here’s the code.  Just email me with questions or if you see a mistake in the coding.

{EasyLanguage MultiTime Frame Indicator)
written by George Pruitt - copyright 2019 by George Pruitt
}


Inputs:tf1Mult(2),tf2Mult(3),tf3Mult(4),tf4Mult(5);

vars: mtf1h(0),mtf1l(0),mtf1o(0),mtf1c(0),mtf1pvt(0),diff1(0),
mtf2h(0),mtf2l(0),mtf2o(0),mtf2c(0),mtf2pvt(0),diff2(0),
mtf3h(0),mtf3l(0),mtf3o(0),mtf3c(0),mtf3pvt(0),diff3(0),
mtf4h(0),mtf4l(0),mtf4o(0),mtf4c(0),mtf4pvt(0),diff4(0),
mtf0pvt(0),diff0(0);


If barNumber > 1 then
Begin

mtf0pvt = (close + high + low) / 3;
diff0 = close - mtf0pvt;

mtf1h = highest(h,tf1Mult);
mtf1l = lowest(l,tf1Mult);
mtf1c = close;

mtf1pvt = (mtf1h+mtf1l+mtf1c) / 3;
diff1 = mtf1c - mtf1pvt;

mtf2h = highest(h,tf2Mult);
mtf2l = lowest(l,tf2Mult);
mtf2c = close;

mtf2pvt = (mtf2h+mtf2l+mtf2c) / 3;
diff2 = mtf2c - mtf2pvt;

mtf3h = highest(h,tf3Mult);
mtf3l = lowest(l,tf3Mult);
mtf3c = close;

mtf3pvt = (mtf3h+mtf3l+mtf3c) / 3;
diff3 = mtf3c - mtf3pvt;

mtf4h = highest(h,tf4Mult);
mtf4l = lowest(l,tf4Mult);
mtf4c = close;

mtf4pvt = (mtf4h+mtf4l+mtf4c) / 3;
diff4 = mtf4c - mtf4pvt;

Condition10 = diff0 > 0;
Condition11 = diff1 > 0;
Condition12 = diff2 > 0;
Condition13 = diff3 > 0;
Condition14 = diff4 > 0;

If condition10 then setPlotColor(1,Green) else SetPlotColor(1,Red);
If condition11 then setPlotColor(2,Green) else SetPlotColor(2,Red);
If condition12 then setPlotColor(3,Green) else SetPlotColor(3,Red);
If condition13 then setPlotColor(4,Green) else SetPlotColor(4,Red);
If condition14 then setPlotColor(5,Green) else SetPlotColor(5,Red);

condition6 = condition10 and condition11 and condition12 and condition13 and condition14;
Condition7 = not(condition10) and not(condition11) and not(condition12) and not(condition13) and not(condition14);

If condition6 then setPlotColor(7,Green);
If condition7 then setPlotColor(7,Red);

If condition6 or condition7 then plot7(7,"trend");

Plot6(5,"line");
Plot1(4,"t1");
Plot2(3,"t2");
Plot3(2,"t3");
Plot4(1,"t4");
Plot5(0,"t5");

end;
MTF in EasyLanguage

 

Using TradeStation’s COT Indicator to Develop a Trading System

TradeStation’s COT (Commitment of Traders) Indicator:

TradeStation COT Indicator

TradeStation now includes the historic COT (Commitment of Traders) report in the form of an indicator.

If you can plot it then you can use it in a Strategy.  The following code listing takes the Indicator code and with very few modifications turns it into a trading system.

{
Net positions of various groups of traders from the CFTC's weekly Commitments of
Traders report. "Net" positions are calculated by taking the number of contracts
that a group of traders is long and subtracting the number of contracts that that
group of traders is short.

The user input "FuturesOnly_Or_FuturesAndOptions_1_or_2" determines whether the
CFTC's "Futures Only" report is used, or the "Futures and Options" report is
used to determine the positions of the various groups of traders. By default, the
"Futures Only" report is used.

Plot1: Commercial traders' net position
Plot2: Non-commercial traders' net position
Plot3: Speculators' net positions, for speculators not of reportable size
Plot4: Zero line

If an error occurs retrieving one of the values used by this study, or if the value
is not applicable or non-meaningful, a blank cell will be displayed in RadarScreen or
in the OptionStation assets pane. In a chart, no value will be plotted until a value
is obtained without generating an error when retrieved.
}

input: FuturesOnly_Or_FuturesAndOptions_1_or_2( 1 ) ; { set to 1 to use the CFTC's
"Futures Only" report, set to 2 (or to any value other than 1) to use the "Futures
and Options" report }

variables:
Initialized( false ),
FieldNamePrefix( "" ),
CommLongFieldNme( "" ),
CommShortFieldNme( "" ),
NonCommLongFieldNme( "" ),
NonCommShortFieldNme( "" ),
SpecLongFieldNme( "" ),
SpecShortFieldNme( "" ),
CommLong( 0 ),
oCommLongErr( 0 ),
CommShort( 0 ),
oCommShortErr( 0 ),
NonCommLong( 0 ),
oNonCommLongErr( 0 ),
NonCommShort( 0 ),
oNonCommShortErr( 0 ),
SpecLong( 0 ),
oSpecLongErr( 0 ),
SpecShort( 0 ),
oSpecShortErr( 0 ),
CommNet( 0 ),
NonCommNet( 0 ),
SpecNet( 0 ) ;

if Initialized = false then
begin
if Category > 0 then
RaiseRuntimeError( "Commitments of Traders studies can be applied only to" +
" futures symbols." ) ;
Initialized = true ;
FieldNamePrefix = IffString( FuturesOnly_Or_FuturesAndOptions_1_or_2 = 1,
"COTF-", "COTC-" ) ;
CommLongFieldNme = FieldNamePrefix + "12" ;
CommShortFieldNme = FieldNamePrefix + "13" ;
NonCommLongFieldNme = FieldNamePrefix + "9" ;
NonCommShortFieldNme = FieldNamePrefix + "10" ;
SpecLongFieldNme = FieldNamePrefix + "16" ;
SpecShortFieldNme = FieldNamePrefix + "17" ;
end ;

CommLong = FundValue( CommLongFieldNme, 0, oCommLongErr ) ;
CommShort = FundValue( CommShortFieldNme, 0, oCommShortErr) ;
NonCommLong = FundValue( NonCommLongFieldNme, 0, oNonCommLongErr ) ;
NonCommShort = FundValue( NonCommShortFieldNme, 0, oNonCommShortErr );
SpecLong = FundValue( SpecLongFieldNme, 0, oSpecLongErr ) ;
SpecShort = FundValue( SpecShortFieldNme, 0, oSpecShortErr ) ;

if oCommLongErr = fdrOk and oCommShortErr = fdrOk then
begin
CommNet = CommLong - CommShort ;
Print ("CommNet ",commNet);
end ;

if oNonCommLongErr = fdrOk and oNonCommShortErr = fdrOk then
begin
NonCommNet = NonCommLong - NonCommShort ;
end ;

if oSpecLongErr = fdrOk and oSpecShortErr = fdrOk then
begin
SpecNet = SpecLong - SpecShort ;
end ;
If CommNet < 0 then sellShort tomorrow at open;
If CommNet > 0 then buy tomorrow at open;


{ ** Copyright (c) 2001 - 2010 TradeStation Technologies, Inc. All rights reserved. **
** TradeStation reserves the right to modify or overwrite this analysis technique
with each release. ** }
COT Indicator Converted To Strategy

Line numbers 90 and 91 informs TS to take a long position if the Net Commercial Interests are positive and a short position if the Commercials are negative.  I kept the original comments in place in  case you wanted to see how the indicator and its associated function calls work.  The linchpin of this code lies in the function call FundValue.  This function call pulls fundamental data from the data servers and provides it in an easy to use format.  Once you have the data you can play all sorts of games with it.  This is just a simple system to see if the commercial traders really do know which direction the market is heading.

if you test this strategy on the ES you will notice a downward sloping 45 degree equity curve.  This leads me to believe the commercials are trying their best to  use the ES futures to hedge other market positions.  If you go with the non Commercials you will see  a totally different picture.  To do this just substitute the following two lines:

If CommNet < 0 then sellShort tomorrow at open;
If CommNet > 0 then buy tomorrow at open;

With:

If NonCommNet < 0 then sellShort tomorrow at open;
If NonCommNet > 0 then buy tomorrow at open;

I said a totally different picture not a great one.  Check out if the speculators know better.

How to Create a Dominant Cycle Class in Python

John Ehlers used the following EasyLanguage code to calculate the Dominant Cycle in a small sample of data.  If you are interested in cycles and noise reduction, definitely check out the books by John Ehlers – “Rocket Science for Traders” or “Cybernetic Analysis for Stocks and Futures.”  I am doing some research in this area and wanted to share how I programmed the indicator/function in Python.  I refer you to his books or online resources for an explanation of the code.  I can tell you it involves an elegantly simplified approach using the Hilbert Transform.

 

Inputs:	Price((H+L)/2);

Vars: Imult(.635),
Qmult (.338),
InPhase(0),
Quadrature(0),
count(0),
Re(0),
Im(0),
DeltaPhase(0),
InstPeriod(0),
Period(0);

If CurrentBar > 8 then begin
Value1 = Price - Price[7];
Inphase = 1.25*(Value1[4] - Imult*Value1[2]) + Imult*InPhase[3];

// print(price," ",price[7]," ",value1," ",inPhase," ",Quadrature," ",self.im[-1]," ",self.re[-1])
// print(d," ",h," ",l," ",c," ",Value1[4]," ",Imult*Value1[2]," ", Imult*InPhase[3]," ",Inphase);
Quadrature = Value1[2] - Qmult*Value1 + Qmult*Quadrature[2];
Re = .2*(InPhase*InPhase[1] + Quadrature*Quadrature[1]) + .8*Re[1];
Im = .2*(InPhase*Quadrature[1] - InPhase[1]*Quadrature) + .8*Im[1];
print(d," ",o," ",h," ",l," ",c," ",value1," ",inPhase," ",Quadrature," ",Re," ",Im);
If Re <> 0 then DeltaPhase = ArcTangent(Im/Re);

{Sum DeltaPhases to reach 360 degrees. The sum is the instantaneous period.}
InstPeriod = 0;
Value4 = 0;
For count = 0 to 50 begin
Value4 = Value4 + DeltaPhase[count];
If Value4 > 360 and InstPeriod = 0 then begin
InstPeriod = count;
end;
end;

{Resolve Instantaneous Period errors and smooth}
If InstPeriod = 0 then InstPeriod = InstPeriod[1];
Period = .25*InstPeriod + .75*Period[1];

Plot1(Period, "DC");
EasyLanguage Code For Calculating Dominant Cycle

In my Python based back tester an indicator of this type is best programmed by using a class.  A class is really a simple construct, especially in Python, once you familiarize yourself with the syntax.   This indicator requires you to refer to historical values to calculate the next value in the equation:  Value1[4], inPhase[1], re[2], etc.,.  In EasyLanguage these values are readily accessible as every variable is defined as a BarArray – the complete history of a variable is accessible by using indexing.  In my PSB I used lists to store values for those variables most often used such as Open, High, Low, Close.  When you need to store the values of let’s say the last five bars its best to just create a list on the fly or build them into a class structure.  A Class stores data and data structures and includes the methods (functions) that the data will be pumped into.  The follow code describes the class in two sections:  1) data declaration and instantiation and 2) the function to calculate the Dominant Cycle.  First off I create the variables that will hold the constant values: imult and qmult.  By using the word self I make these variables class members and can access them using “.” notation.  I will show you later what this means.  I also make the rest of the variables class members, but this time I make them lists and instantiate the first five values to zero.  I use list comprehension to create the lists and zero out the first five elements – all in one line of code.  This is really just a neat short cut, but can be used for much more powerful applications.  Once you create a dominantCycleClass object the object is constructed and all of the data is connected to this particular object.  You can create many dominantCycleClass objects and each one would maintain its own data.  Remember a class is just a template that is used to create an object.

class dominantCycleClass(object):
def __init__(self):
self.imult = 0.635
self.qmult = 0.338
self.value1 = [0 for i in range(5)]
self.inPhase = [0 for i in range(5)]
self.quadrature = [0 for i in range(5)]
self.re = [0 for i in range(5)]
self.im = [0 for i in range(5)]
self.deltaPhase = [0 for i in range(5)]
self.instPeriod = [0 for i in range(5)]
self.period = [0 for i in range(5)]
Data Portion of Class

 

The second part of the class template contains the method or function for calculating the Dominant Cycle.  Notice how I index into the lists to extract prior values.  You will also see the word self. preceding the variable names used in the calculations Initially I felt like this redundancy hurt the readability of the code and in this case it might.  But by using self. I know I am dealing with a class member.  This is an example of the ” . ” notation I referred to earlier.  Basically this ties the variable to the class.

def calcDomCycle(self,dates,hPrices,lPrices,cPrices,curBar,offset):
tempVal1 = (hPrices[curBar - offset] + lPrices[curBar-offset])/2
tempVal2 = (hPrices[curBar - offset - 7] + lPrices[curBar-offset - 7])/2
self.value1.append(tempVal1 - tempVal2)
self.inPhase.append(1.25*(self.value1[-5] - self.imult*self.value1[-3]) + self.imult*self.inPhase[-3])
self.quadrature.append(self.value1[-3] - self.qmult*self.value1[-1] + self.qmult*self.quadrature[-2])
self.re.append(.2*(self.inPhase[-1]*self.inPhase[-2]+self.quadrature[-1]*self.quadrature[-2])+ 0.8*self.re[-1])
self.im.append(.2*(self.inPhase[-1]*self.quadrature[-2] - self.inPhase[-2]*self.quadrature[-1]) +.8*self.im[-1])
if self.re[-1] != 0.0: self.deltaPhase.append(degrees(atan(self.im[-1]/self.re[-1])))
if len(self.deltaPhase) > 51:
self.instPeriod.append(0)
value4 = 0
for count in range(1,51):
value4 += self.deltaPhase[-count]
if value4 > 360 and self.instPeriod[-1] == 0:
self.instPeriod.append(count)
if self.instPeriod[-1] == 0: self.instPeriod.append(self.instPeriod[-1])
self.period.append(.25*self.instPeriod[-1]+.75*self.period[-1])
return(self.period[-1])
Dominant Cycle Method

Okay we now have the class template to calculate the Dominant Cycle but how do we us it?

#---------------------------------------------------------------------------------
#Instantiate Indicator Classes if you need them
#---------------------------------------------------------------------------------
# rsiStudy = rsiClass()
# stochStudy = stochClass()
domCycle = dominantCycleClass()
#---------------------------------------------------------------------------------
#Call the dominantCycleClass method using " . " notation.
tempVal1 = domCycle.calcDomCycle(myDate,myHigh,myLow,myClose,i,0)
#Notice how I can access class members by using " . " notation as well!
tempVal2 = domCycle.imult
Dominant Cycle Object Creation

Here I assign domCycle the object created by calling the dominantCycleClass constructor.  TempVal1 is assigned the Dominant Cycle when the function or method is called using the objects name (domCycle) and the now familiar ” . ” notation.  See how you can also access the imult variable using the same notation.

Here is the code in its entirety.  I put this in the indicator module of the PSB.

class dominantCycleClass(object):
def __init__(self):
self.imult = 0.635
self.qmult = 0.338
self.value1 = [0 for i in range(5)]
self.inPhase = [0 for i in range(5)]
self.quadrature = [0 for i in range(5)]
self.re = [0 for i in range(5)]
self.im = [0 for i in range(5)]
self.deltaPhase = [0 for i in range(5)]
self.instPeriod = [0 for i in range(5)]
self.period = [0 for i in range(5)]

def calcDomCycle(self,dates,hPrices,lPrices,cPrices,curBar,offset):
tempVal1 = (hPrices[curBar - offset] + lPrices[curBar-offset])/2
tempVal2 = (hPrices[curBar - offset - 7] + lPrices[curBar-offset - 7])/2
self.value1.append(tempVal1 - tempVal2)
self.inPhase.append(1.25*(self.value1[-5] - self.imult*self.value1[-3]) + self.imult*self.inPhase[-3])
self.quadrature.append(self.value1[-3] - self.qmult*self.value1[-1] + self.qmult*self.quadrature[-2])
self.re.append(.2*(self.inPhase[-1]*self.inPhase[-2]+self.quadrature[-1]*self.quadrature[-2])+ 0.8*self.re[-1])
self.im.append(.2*(self.inPhase[-1]*self.quadrature[-2] - self.inPhase[-2]*self.quadrature[-1]) +.8*self.im[-1])
if self.re[-1] != 0.0: self.deltaPhase.append(degrees(atan(self.im[-1]/self.re[-1])))
if len(self.deltaPhase) > 51:
self.instPeriod.append(0)
value4 = 0
for count in range(1,51):
value4 += self.deltaPhase[-count]
if value4 > 360 and self.instPeriod[-1] == 0:
self.instPeriod.append(count)
if self.instPeriod[-1] == 0: self.instPeriod.append(self.instPeriod[-1])
self.period.append(.25*self.instPeriod[-1]+.75*self.period[-1])
return(self.period[-1])
Dominant Cycle Class - Python

 

Learn to Program Pyramiding Algorithm

Would you like to learn how to do this?  Check back over the next few days and I will show you to do it.  Warning:  its not straightforward as it seems – some tricks are involved.  Remember to sign up for email notifications of new posts.

UPDATE[1]:  I have recorded an introductory webcast on how to program this pyramiding scheme.  This webcast is Part 1 and illustrates how to brainstorm and start thinking/programming about a problem.  Part 1 introduces some concepts that show how you can use and adapt some of EasyLanguage built-in reserved words and functions.  I start from the perspective of a somewhat beginning EasyLanguage programmer  – one that knows enough to maybe not get the problem solved, but at least get the ball rolling.  The final code may not look anything like the code I present in Part 1.  However it is sometimes important to go down the wrong trail so that you can learn the limitations of a programming language.  Once you know the limitations, you can go about programming workarounds and fixes.  I hope you enjoy Part 1  I should have Part 2 up soon.  Don’t be too critical, this is really the first webcast I have recorded.  You’ll notice I repeat myself and I refer  to one function input as a subscript.  Check it out:  https://youtu.be/ip-DyyKpOTo

Adding positions at fixed intervals.

Utilizing Indicator Functions with Multi-Data on MultiCharts

A good portion of my readers use MultiCharts and the similarities between their PowerLanguage and EasyLanguage is almost indistinguishable.  However, I came across a situation where one my clients was getting different values between an indicator function call and the actual plotted indicator when using Multi-Data.

Here is the code that didn’t seem to work, even though it was programmed correctly in TradeStation.

vars:
oDMIPlus1(0),oDMIMinus1(0),oDMI1(0),oADX1(0),oADXR1(0),oVolty1(0),
oDMIPlus2(0,data2),oDMIMinus2(0,data2),oDMI2(0,data2),oADX2(0,data2),oADXR2(0,data2),oVolty2(0,data2),
ema1(0),ema2(0,data2),trendUp(false);



Value1 = DirMovement( H, L, C , Data1ADXLen, oDMIPlus1, oDMIMinus1, oDMI1, oADX1, oADXR1, oVolty1 ) ;
Value2 = DirMovement( H of data2, L of data2, C of data2, Data2ADXLen, oDMIPlus2, oDMIMinus2, oDMI2, oADX2, oADXR2, oVolty2 );

 

Pretty simple – so what is the problem.  Data aliasing was utilized in the Vars: section – this keeps the indicator from being calculated on the time frame of data1.  Its only calculated on the data2 time frame – think of data1 being a 5 min. chart and data2 a 30 min. chart.  I discovered that you have to also add data aliasing to not just the variables used in the indicator function but also to the function call itself.  This line of code fixed the problem:


DirMovement( H of data2, L of data2, C of data2, Value2, oDMIPlus2, oDMIMinus2, oDMI2, oADX2, oADXR2, oVolty2 )data2;
Add data2 after the function call to tie it to data2.

 

See that!  Just add Data2 to the end of the function call.  This verifies in TradeStation and compiles in MC with no problems.