Category Archives: EasyLanguage Indicator

Highly Illogical – Best Guess Doesn’t Match Reality

An ES Break-Out System with Unexpected Parameters

I was recently testing the idea of a short term VBO strategy on the ES utilizing very tight stops.  I wanted to see if using a tight ATR stop in concert with the entry day’s low (for buys) would cut down on losses after a break out.  In other words, if the break out doesn’t go as anticipated get out and wait for the next signal.  With the benefit of hindsight in writing this post, I certainly felt like my exit mechanism was what was going to make or break this system.  In turns out that all pre conceived notions should be thrown out when volatility enters the picture.

System Description

  • If 14 ADX < 20 get ready to trade
  • Buy 1 ATR above the midPoint of the past 4 closing prices
  • Place an initial stop at 1 ATR and a Profit Objective of 1 ATR
  • Trail the stop up to the prior day’s low if it is greater than entryPrice – 1 ATR initially, and then trail if a higher low is established
  • Wait 3 bars to Re-Enter after going flat – Reversals allowed

That’s it.  Basically wait for a trendless period and buy on the bulge and then get it out if it doesn’t materialize.  I knew I could improve the system by optimizing the parameters but I felt I was in the ball park.  My hypothesis was that the system would fail because of the tight stops.  I felt the ADX trigger was OK and the BO level would get in on a short burst.  Just from past experience I knew that using the prior day’s price extremes as a stop usually doesn’t fair that well.

Without commission the initial test was a loser: -$1K and -$20K draw down over the past ten years.  I thought I would test my hypothesis by optimizing a majority of the parameters:

  • ADX Len
  • ADX Trigger Value
  • ATR Len
  • ATR BO multiplier
  • ATR Multiplier for Trade Risk
  • ATR Multiplier for Profit Objective
  • Number of bars to trail the stop – used lowest lows for longs

Results

As you can probably figure, I  had to use the Genetic Optimizer to get the job done.  Over a billion different permutations.  In the end here is what the computer pushed out using the best set of parameters.

No Commission or Slippage – Genetic Optimized Parameter Selection

Optimization Report – The Best of the Best

Top Parameters – notice the Wide Stop Initially and the Trailing Stop Look-Back and also the Profit Multiplier – but what really sticks out is the ADX inputs

ADX – Does it Really Matter?

Take a look at the chart – the ADX is mostly in Trigger territory – does it really matter?

A Chart is Worth a 1000 Words

What does this chart tell us?

70% of Profit was made in last 40 trades

Was the parameter selection biased by the heightened level of volatility?  The system has performed on the parameter set very well over the past two or three years.  But should you use this parameter set going into the future – volatility will eventually settle down.

Now using my experience in trading I would have selected a different parameter set.   Here are my biased results going into the initial programming.  I would use a wider stop for sure, but I would have used the generic ADX values.

George’s More Common Sense Parameter Selection – wow big difference

I would have used 14 ADX Len with a 20 trigger and risk 1 to make 3 and use a wider trailing stop.  With trend neutral break out algorithms, it seems you have to be in the game all of the time.  The ADX was supposed to capture zones that predicated break out moves, but the ADX didn’t help out at all.  Wider stops helped but it was the ADX values that really changed the complexion of the system.  Also the number of bars to wait after going flat had a large impact as well.  During low volatility you can be somewhat picky with trades but when volatility increases you gots to be in the game. – no ADX filtering and no delay in re-Entry.  Surprise, surprise!

Alogorithm Code

Here is the code – some neat stuff here if you are just learning EL.  Notice how I anchor some of the indicator based variables by indexing them by barsSinceEntry.  Drop me a note if you see something wrong or want a little further explanation.

Inputs: adxLen(14),adxTrig(25),atrLen(10),atrBOMult(1),atrRiskMult(1),atrProfMult(2),midPtNumBar(3),posMovTrailNumBars(2),reEntryDelay(3);
vars: mp(0),trailLongStop(0),trailShortStop(0),BSE(999),entryBar(0),tradeRisk(0),tradeProf(0);
vars: BBO(0),SBO(0),ATR(0),totTrades(0);

mp = marketPosition;
totTrades = totalTrades;
BSE = barsSinceExit(1);
If totTrades <> totTrades[1] then BSE = 0;
If totalTrades = 0 then BSE = 99;


ATR = avgTrueRange(atrLen);

SBO = midPoint(c,midPtNumBar) - ATR * atrBOMult;
BBO = midPoint(c,midPtNumBar) + ATR * atrBOMult;

tradeRisk = ATR * atrRiskMult;
tradeProf = ATR * atrProfMult;

If mp <> 1 and adx(adxLen) < adxTrig and BSE > reEntryDelay and open of next bar < BBO then buy next bar at BBO stop;
If mp <>-1 and adx(adxLen) < adxTrig AND BSE > reEntryDelay AND open of next bar > SBO then sellshort next bar at SBO stop;

If mp = 1 and mp[1] <> 1 then
Begin
	trailLongStop = entryPrice - tradeRisk;
end;

If mp = -1 and mp[1] <> -1 then
Begin
	trailShortStop = entryPrice + tradeRisk;
end;
	
if mp = 1 then sell("L-init-loss") next bar at entryPrice - tradeRisk[barsSinceEntry] stop;
if mp = -1 then buyToCover("S-init-loss") next bar at entryPrice + tradeRisk[barsSinceEntry] stop;


if mp = 1 then 
begin
	sell("L-ATR-prof") next bar at entryPrice + tradeProf[barsSinceEntry] limit;
	trailLongStop = maxList(trailLongStop,lowest(l,posMovTrailNumBars));
	sell("L-TL-Stop") next bar at trailLongStop stop;
end; 
if mp =-1 then 
begin
	buyToCover("S-ATR-prof") next bar at entryPrice -tradeProf[barsSinceEntry] limit;
	trailShortStop = minList(trailShortStop,highest(h,posMovTrailNumBars));
//	print(d, " Short and trailStop is : ",trailShortStop);
	buyToCover("S-TL-Stop") next bar at trailShortStop stop;
end;
Please follow and like us:

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

 

Please follow and like us:

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.

Please follow and like us:

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.

Please follow and like us:

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
Please follow and like us:

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.

 

Please follow and like us:

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

 

Please follow and like us:

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.

Please follow and like us:

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

 

Please follow and like us:

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.
Please follow and like us: