# Free Trend Following System

Here is a free Trend Following System that I read about on Andreas Clenow’s www.followthetrend.com website and from his book.  This is my interpretation of the rules as they were explained.  However the main impetus behind this post wasn’t to provide a free trading system, but to show how you can program a simple system with a complete input interface and program a tracking indicator.   You might be asking what is a “tracking indicator?”  We use a tracking indicator to help provide insight to what the strategy is doing and what it might do in the near future.  The indicator can let you know that a new signal is imminent and also what the risk is in a graphical form.  The indicator can also plot the indicators that are used in the strategy itself.

## Step 1:  Program the Strategy

This system is very simple.  Trade on a 50 day Donchian in the direction of the trend and use a 3 X ATR trailing stop.  So the trend is defined as bullish when the 50-day exponential moving average is greater than the 100-day exponential moving average.  A bearish trend is defined when the 50-day is below the 100-day.  Long positions are initiated on the following day when a new 50 day high has been established and the trend is bullish.  Selling short occurs when the trend is bearish and a new 50 day low is establish.  The initial stop  is set to 3 X ATR below the high of the day of entry.  I tested using a 3 X ATR stop initially from the entryPrice for protection on the day of entry, but it made very little difference.  As the trade moves more into your favor, the trailing stop ratchets up and tracks the higher intra-trade extremes.  Eventually once the market reverses you get stopped out of a long position 3 X ATR from the highest high since you entered the long trade.  Hopefully, with a big winner.   The Clenow model also uses a position sizing equation that uses ATR to determine market risk and \$2000 for the allocated amount to risk.  Size= 2000 / ATR – this equation will normalize size across a portfolio of markets.

Here is the code.

``````//Based on Andreas Clenow's description from www.followingthetrend.com
//This is my interpretation and may or may not be what Andreas intended
//Check his books out at amazon.com
//
inputs: atrLen(30),trailATRMult(3);
vars: avg1(0),avg2(0),lXit(0),sXit(0),posSize(0),atr(0);

avg1  = xaverage(c,xAvgShortLen);
avg2  = xaverage(c,xAvgLongLen);

atr = avgTrueRange(atrLen);
posSize = maxList(1,intPortion(risk\$Alloc/(atr*bigPointValue)));

If marketPosition <> 1 and avg1 > avg2 and buyTrigPrice = highest(buyTrigPrice,hhllLen) then buy posSize contracts next bar at open;
If marketPosition <> -1 and avg1 < avg2 and shortTrigPrice = lowest(shortTrigPrice,hhllLen) then sellshort posSize contracts next bar at open;

If marketPosition = 0 then
Begin
lXit = o - trailATRMult * atr ;
sXit = o + trailATRMult * atr;
//	if c < lXit then Sell currentcontracts contracts next bar at open;
//	If c > sXit then buyToCover currentcontracts contracts next bar at open;
end;

If marketPosition = 1 then
begin
lXit = maxList(lXit,h - trailATRMult * atr);
If c < lXit then sell currentContracts contracts next bar at open;
end;

If marketPosition = -1 then
begin
sXit = minList(sXit,l + trailATRMult * atr);
If c > sXit then buyToCover currentContracts contracts next bar at open;
end;``````
Cleanow Simple Trend Following System

What I like about this code is how you can use it as a template for any trend following approach.  All the variables that could be optimized are included as inputs.  Many may not know that you can actually change the data series that you want to use as your signal generator right in the input.  Here I have provided two inputs : buyTrigPrice(H), shortTrigPrice(L).  If you want to use the closing price, then all you need to do is change the H and L to C.  The next lines of code performs the calculations needed to calculate the trend.  PosSize is then calculated next.  Here I am dividing the variable risk\$Alloc by atr*bigPointValue.  Basically I am taking \$2000 and dividing the average true range over the past 30 days multiplied by the point value of the market being tested.  Always remember when doing calculations with \$s you have to convert whatever else you are using into dollars as well.  The ATR is expressed in the form of a price difference.  You can’t divide dollars by a price component, hence the multiplication by bigPointValue.  So now we have the trend calcuation and the position sizing taken care of and all we need now is the trend direction and the entry levels.  If avg1 > avg2 then the market is in a bullish posture, and if today’s High = highest(High,50) days back then initiate a long position with posSize contracts at the next bar’s openNotice how I used the keyword contracts after posSize.  This let’s TS know that I want to trade more than one contract.  If the current position is flat I set the lXit and sXit price levels to the open -/+ 3 X ATR.  Once a position (long or short) is initiated then I start ratcheting the trailing stop up or down.  Assuming a long position, I compare the current lXit and the current bar’s HIGH- 3 X ATR and take the larger of the two valuesSo lXit always moves up and never down.  Notice if the close is less than lXit I used the keyword currentContracts and contracts in the directive to exit a long trade.  CurrentContracts contains the current number of contracts currently long and contracts informs TS that more than one contract is being liquidated.  Getting out of a short position is exactly the same but in a different direction.

## Step 2: Program the System Tracking Indicator

Now you cant take the exact code and eliminate all the order directives and use it to create a tracking indicator.  Take a look at this code:

``````//Based on Andreas Clenow's description from www.followingthetrend.com
//This is my interpretation and may or may not be what Andreas intended
//Check his books out at amazon.com
//
inputs: atrLen(30),trailATRMult(3);
vars: avg1(0),avg2(0),lXit(0),sXit(0),posSize(0),atr(0),mp(0);

avg1  = xaverage(c,xAvgShortLen);
avg2  = xaverage(c,xAvgLongLen);

atr = avgTrueRange(atrLen);

plot1(avg1,"stXavg");
plot2(avg2,"ltXavg");

If avg1 > avg2 and buyTrigPrice = highest(buyTrigPrice,hhllLen) then mp = 1;
If avg1 < avg2 and shortTrigPrice = lowest(shortTrigPrice,hhllLen) then mp = -1;

If mp = 0 then
Begin
lXit = o - trailATRMult * atr ;
sXit = o + trailATRMult * atr;
end;

If mp = 1 then
begin
lXit = maxList(lXit,h - trailATRMult * atr);
plot3(lXit,"LongTrail");
If c < lXit then mp = 0;
end;

If mp = -1 then
begin
sXit = minList(sXit,l + trailATRMult * atr);
plot4(sXit,"ShortTrail");
If c > sXit then mp = 0;
end;``````

However, you do need to keep track if the underlying strategy is long or short and you can do this by pretending you are the computer and using the mp variable.  You know if yesterdays avg1 > avg2 and HIGH = highestHigh(HIGH,50), then a long position should have been initiated.  If this happens just set mp to 1You set mp to -1 by checking the trend and lowestLow(LOW,50).  Once you know the mp or implied market position then you can calculate the lXit and sXit.  You will always plot the moving averages to help determine trend direction, but you only plot the lXit and sXit when a position is on.  So plot3 and plot4 should only be plotted when a position is long or short.

Here is a screenshot of the strategy and tracking indicator. Notice how the Yellow and Cyan plots follow the correct market position.  You will need to tell TS not to connect these plot lines when they are not designed to be plotted.

### Turn-Off Auto Plot Line Connection

Do this for Plot3 and Plot4 and you will be good to go. I hope you found this post useful.  Also don’t forget to check out my new book at Amazon.com.  If you really want to learn programming that will help across different platforms I think it would be a great learning experience. # Keith’s Book

Thanks to MJ for planting the seed for this post.  If you were one of the lucky ones to get Keith’s “Building Reliable Trading SystemsTradable Strategies that Perform as They Backtest and Meet Your Risk-Reward Goals”  book by John Wiley 2013 at the list price of \$75 count yourself lucky.  The book sells for a multiple of that on Amazon.com.  Is there anything earth shattering in the book you might ask?  I wouldn’t necessarily say that, but there are some very well thought out and researched topics that most traders would find of interest.

## Bar Scoring

In his book Keith discusses the concept of bar-scoring.  In Keith’s words, “Bar-scoring is an objective way to classify an instrument’s movement potential every bar.  The two parts of the bar-scoring are the criterion and the resultant profit X days hence.”  Keith provides several bar scoring techniques, but I highlight just one. Keith broke these patterns down into the relationship of the close to the open, and close in the upper half of the range; close greater than the open and close in the lower half of the range.  He extended the total number of types to 8 by adding the relationship of the close of the bar to yesterdays bar.

The PatternSmasher code can run through a binary representation

for each pattern and test holding the position for an optimizable number of days.  It can also check for long and short positions.  The original Pattern Smasher code used a for-loop to create patterns that were then compared to the real life facsimile.  In this code it was easier to just manually define the patterns and assign them the binary string.

``````if c> c and c > o and c > (h + l)/2  then patternString = "----";
if c> c and c > o and c < (h + l)/2  then patternString = "---+";
if c> c and c < o and c > (h + l)/2  then patternString = "--+-";
if c> c and c < o and c < (h + l)/2  then patternString = "--++";
if c< c and c > o and c > (h + l)/2  then patternString = "-+--";
if c< c and c > o and c < (h + l)/2  then patternString = "-+-+";
if c< c and c < o and c > (h + l)/2  then patternString = "-++-";
if c< c and c < o and c < (h + l)/2  then patternString = "-+++";``````
Manual Pattern Designations

Please check my code for any errors.  Here I go through the 8 different relationships and assign them to a Patter String.  “-+++”  represents pattern number (7 ) or type (7 + 1 = 8 – my strings start out at 0).  You can then optimize the test pattern and if the test pattern matches the actual pattern, then the Pattern Smasher takes the trade  on the opening of the next bar and holds it for the number of days you specify.  You an also designate long and short positions in the code.  Here I optimized the 8 patterns going long and short and holding from 1-4 days. Here is the equity curve!  Remember these are Hypothetical Results with \$0 commission/slippage and historic performance is not necessarily indicative of future results.  Educational purposes only!  This is tested on ES.D Play around with the code and let me know if you find any errors or any improvements.

``````input: patternTests(8),orbAmount(0.20),LorS(1),holdDays(0),atrAvgLen(10),enterNextBarAtOpen(true);

var: patternTest(""),patternString(""),tempString("");
var: iCnt(0),jCnt(0);
array: patternBitChanger(0);

{written by George Pruitt -- copyright 2019 by George Pruitt
This will test a 4 day pattern based on the open to close
relationship.  A plus represents a close greater than its
open, whereas a minus represents a close less than its open.
The default pattern is set to pattern 14 +++- (1110 binary).
You can optimize the different patterns by optimizing the
patternTests input from 1 to 16 and the orbAmount from .01 to
whatever you like.  Same goes for the hold days, but in this
case you optimize start at zero.  The LorS input can be
optimized from 1 to 2 with 1 being buy and 2 being sellshort.}

patternString = "";
patternTest = "";

patternBitChanger = 0;
patternBitChanger = 0;
patternBitChanger = 0;
patternBitChanger = 0;

value1 = patternTests - 1;

//example patternTests = 0 -- > 0000
//example patternTests = 1 -- > 0001
//example patternTests = 2 -- > 0010
//example patternTests = 3 -- > 0011
//example patternTests = 4 -- > 0100
//example patternTests = 5 -- > 0101
//example patternTests = 6 -- > 0110
//example patternTests = 7 -- > 0111

if(value1 >= 0) then
begin

if(mod(value1,2) = 1) or value1 = 1 then patternBitChanger = 1;
value2 = value1 - patternBitChanger * 1;

if(value2 >= 7) then begin
patternBitChanger = 1;
value2 = value2 - 8;
end;

if(value2 >= 4) then begin
patternBitChanger = 1;
value2 = value2 - 4;
end;
if(value2 = 2) then patternBitChanger = 1;
end;

for iCnt = 3 downto 0  begin
if(patternBitChanger[iCnt] = 1) then
begin
patternTest = patternTest + "+";
end
else
begin
patternTest = patternTest + "-";
end;
end;

patternString = "";

if c> c and c > o and c > (h + l)/2  then patternString = "----";
if c> c and c > o and c < (h + l)/2  then patternString = "---+";
if c> c and c < o and c > (h + l)/2  then patternString = "--+-";
if c> c and c < o and c < (h + l)/2  then patternString = "--++";
if c< c and c > o and c > (h + l)/2  then patternString = "-+--";
if c< c and c > o and c < (h + l)/2  then patternString = "-+-+";
if c< c and c < o and c > (h + l)/2  then patternString = "-++-";
if c< c and c < o and c < (h + l)/2  then patternString = "-+++";

if(barNumber = 1) then print(elDateToString(date)," pattern ",patternTest," ",patternTests-1);
if(patternString = patternTest) then
begin

//   print(date," ",patternString," ",patternTest); //uncomment this and you can print out the pattern
if (enterNextBarAtOpen) then
begin
if(LorS = 2) then SellShort("PatternSell") next bar on open;
end
else
begin
if(LorS = 2) then SellShort("PatternSellBO") next bar at open of tomorrow - avgTrueRange(atrAvgLen) * orbAmount stop;
if(LorS = 1) then buy("PatternBuyBO") next bar at open of tomorrow + avgTrueRange(atrAvgLen) * orbAmount stop;
end;

end;

if(holdDays = 0 ) then setExitonClose;
if(holdDays > 0) then
begin
if(barsSinceEntry = holdDays and LorS = 2) then BuyToCover("xbarLExit") next bar at open;
if(barsSinceEntry = holdDays and LorS = 1) then Sell("xbarSExit") next bar at open;
end;``````
Bar Scoring Testing Template

# Programming a Multi-Time Frame Indicator in EasyLanguage

Take a look at this indictor.

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

# An ES Day Trading Model Explained – Part 2

### This is a continuation post or Part 2 of the development of the ES day trading system with EasyLanguage.

If you can understand this model you can basically program any of your day trading ideas.

#### Inputs Again:

First I want to revisit our list of inputs and make a couple of changes before proceeding.

``````inputs: volCalcLen(10),orboBuyPer(.2),orboSellPer(.2);
inputs: volStopPer(.7),Stop\$(500);
inputs: volThreshPer(.3),ProfThresh\$(250);
inputs: volTrailPer(.2),Trail\$(200);
Modification to our inputs

If we want to optimize these values then we can’t use the keyword bigPointValue in the input variable default value.  So I removed them – also I added an input endTradingTime(1500).  I wanted to cut off our trading at a given time – no use entering a trade five minutes prior to the closing.

#### Disengage the Vol or \$Dollar Trade Management:

I may have muddied the waters a little with having volatility and \$ values simultaneously.  You can use either for the initial protective stop, profit threshold, and trailing stop amount.  You can disengage them by using large values.  If you want to ignore all the \$ inputs just add a couple of 00 to each of the values:

Stop\$(50000), ProfThres\$(25000),Trail\$(50000)

If you want to ignore the volatility trade management stops just put a large number in front of the decimal.

volStopPer(9.7), volThreshPer(9.3), volTrailPer(9.2)

If you make either set large then the algorithm will use the values closest to the current market price.

#### Computations:

Let’s now take a look at the computations that are done on the first bar of the day:

``````If d <> d then
Begin
rangeSum = 0.0;  // range calculation for entry
For iCnt = 1 to volCalcLen
Begin
rangeSum = rangeSum + (highD(iCnt) - lowD(iCnt));
end;
vol = rangeSum/volCalcLen;
sellPoint = openD(0) - vol*orboSellPer;

longStopAmt = vol * volStopPer;
longStopAmt = minList(longStopAmt,Stop\$/bigPointValue);

shortStopAmt = vol *volStopPer;
shortStopAmt = minList(shortStopAmt,Stop\$/bigPointValue);

longThreshAmt = vol  * volThreshPer;
longThreshAmt = minList(longThreshAmt,ProfThresh\$/bigPointValue);

shortThreshAmt = vol * volThreshPer;
shortThreshAmt = minList(shortThreshAmt,ProfThresh\$/bigPointValue);

longTrailAmt = vol * volTrailPer;
longTrailAmt = minList(longTrailAmt,Trail\$/bigPointValue);

shortTrailAmt = vol * volTrailPer;
shortTrailAmt = minList(shortTrailAmt,Trail\$/bigPointValue);

longTrailLevel = 0;
shortTrailLevel = 999999;
shortsToday = 0;
end;``````
Once a day computations

I determine it is the first bar of the day by comparing the current 5-minute bar’s date stamp to the prior 5-minute bar’s date stamp.  If they are not the same then you have the first bar of the day.  The first thing I do is calculate the volatility of the current market by using a for-loop to accumulate the day ranges for the past volCalcLen days.  I start the iterative process using the iCnt index and going from 1 back in time to volCalcLen.  I use iCnt to index into the function calls HighD and LowD.  Indexing is not really the right word here – that is more appropriate when working with arrays.  HighD and LowD are functions and we are passing the values 1 to volCalcLen into the functions and summing their output.  When you do this you will get a warning “A series function should not be called more than once with a given set of parameters.”  Sounds scary but it seems to work just fine.  If you don’t do this then you have to include a daily bar on the chart.  I like to keep things as simple as possible.   Once I sum up the daily ranges I then divide by volCalcLen to get the average range over the few days.  All of the vol based variables will use this value.

#### Entries:

Entry is based off a move away from the opening in terms of volatility.  If we use 0.2 (twenty percent) as orboBuyPer then the algorithm will buy on a stop 20% of the average range above the open tick.  Sell short is just the opposite.   We further calculate the longStopAmt as a function of vol and a pure \$ amount.  I am using the minList function to determine the smaller of the two values  .This is how I disengage either the vol value or the \$ value.  The other variables are also calculated just once a day: shortStopAmt, longThreshAmt, shortThreshAmt, longTrailAmt, shortTrailAmt. You could calculate every bar but that would be inefficient. I am also resetting four values at the beginning of the day:  longTrailLevel, shortTrailLevel, buysToday and shortsToday.

#### The Mighty MP:

``````mp = marketPosition;

If mp = 1 and mp <> 1 then buysToday = buysToday + 1;
If mp = -1 and mp <> -1 then shortsToday = shortsToday + 1;``````
MarketPosition monitoring and determining Buys/Shorts Today

I like using a variable to store each bar’s marketPosition.  In this case I am using MP.  By aliasing the marketPosition function call to a variable allows us to do this:

if mp = 1 and mp <> 1 then buysToday = buysToday + 1;

This little line does a bunch of stuff.  If the current bar’s position is 1 and the prior bars position is not one then we know we have just entered a long position.  So every time this happens throughout the day the buysToday is incremented.  ShortsToday works just the same.  Pitfall warning:  If you strategy enters and exits on the same bar then this functionality will not work!  Neither will the call to the marketPosition function.  It will look like nothing happened.  If you need to keep track of the number of trades make sure you can only enter or exit on different bars.  If you stuff is so tight then drop down to a 1 minute or tick bar.

#### Controlling the Nmber of Buys/Shorts for the Day:

``````if time < endTradingTime and buysToday < 1 then Buy("ORBo-B") next bar at buyPoint stop;
if time < endTradingTime and shortsToday < 1 then Sellshort("ORBo-S") next bar at sellPoint stop;

If marketposition = 1 then
Begin
longExitPoint = entryPrice - longStopAmt;
sell("L-Exit") next bar at longExitPoint stop;
end;

If marketposition = -1 then
Begin
shortExitPoint = entryPrice + shortStopAmt;
buyToCover("S-Exit") next bar at shortExitPoint stop;
end;

If marketPosition = 1 and maxContractProfit/bigPointValue >= longThreshAmt then
Begin
sell("TrailSell") next bar at longTrailLevel stop;
end;

If marketPosition = -1 and maxContractProfit/bigPointValue >= shortThreshAmt then
Begin
buyToCover("TrailCover") next bar at shortTrailLevel stop;
end;

SetExitOnClose;``````

Notice how I am controlling the trade directives using the if statements.  I only want to enter a long position when the time is right and I haven’t already entered a long position for the day.  If you don’t control the trade directives, then these orders are placed on every bar, in our case every 5-minutes.  If you have pyramiding turned off then once you are long the buy directive is ignored.  This is an important concept – let’s say you just want to buy and short only one time per day trade session.  If you don’t control this directive, then it will fire off an order every five minutes.    You don’t want this -at least I hope you don’t. So controlling the time and number of entries is paramount.  If you don’t control the time of entry then the day can arrive at the last bar of the day and fire off an order for the opening of the next day.  A big no, no !

#### Put To Work:

Here are the inputs I used to generate the trades in the graphic that follows. ##### Not Doing Exactly What You Want:

Here is what most day traders are looking for.   I made a comment on the chart – make sure you read it – it is another pitfall. The trailing stop had to wait for the bar to complete to determine if the profit reached the threshold.  A little slippage here.  You can overcome this if you use the BuiltIn Percent Trailing Strategy or by using the SetPercentTrailing function call. However, you lose the ability to really customize your algorithms by using the builtin functionalility.  You could drop down to a one minute bar and probably get out nearer your trailing stop amount.

Here you go!

# Open Range BreakOut with Trade Management

How difficult is it to program a day trading system using an open range break out, protective stop and a trailing stop?  Let’s see.  I started working on this and it got a little more detailed than I wanted so I have now split it up into two posts.  Part 2 will follow very soon.

What inputs do we need?  How about the number of days used in the volatility calculation?  What percentage of the volatility from the open do you want to buy or sell?  Should we have a different value for buys and sells?  Do we want to use a volatility based protective stop or a fixed dollar?  How about a trailing stop?  Should we wait to get to a certain profit level before engaging the trailing stop?  Should it also be based on volatility or fixed dollar amt?  How much should we trail – again an amount of volatility or fixed dollar?

## Proposed inputs:

inputs: volCalcLen(10), orboBuyPer(.2), orboSellPer(.2), volStopPer(.7), \$Stop(500), volProfThreshPer(.5), \$ProfThresh(250),volTrailPer(.2),\$Trail(200);

That should do it for the inputs – we can change later if necessary.

## Calculations:

We need to determine the volatility and a good way do this is calculating the average range over the past N days.   There are two ways to do this: 1) incorporate a daily chart as data2 and use a built-in function for the calculation or 2) use a for-loop and use the built-in functions HighD and LowD and just use one data feed.   Both have their drawbacks.  The first is you need to have a multi-data chart and the second you get a warning that you shouldn’t put a series function call inside the body of a for-loop.   I have done it both ways and I prefer to deal with the warning – so far it has worked out nicely – so let’s go with a single data chart.

## Building the code:

### Inputs:

Since we are combining a volatility and fixed \$ amount in our trade management, you will need to set either the vol or dollar amounts to a high value to disable them.  You can use both but I am taking the smaller of the respective values.

``````inputs: volCalcLen(10),orboBuyPer(.2),orboSellPer(.2);
inputs: volStopPer(.7),\$Stop(500/bigPointValue);
inputs: volThreshPer(.5),\$ProfThresh(250/bigPointValue);
inputs: volTrailPer(.2),\$Trail(200/bigPointValue);``````
Inputs We Will Need - Can Changer Later

### Variables:

``````vars:vol(0),buyPoint(0),sellPoint(0),
longStopAmt(0),shortStopAmt(0),longExitPoint(0),shortExitPoint(0),
longThreshAmt(0),shortThreshAmt(0),
longTrailAmt(0),shortTrailAmt(0),
longTrailLevel(0),shortTrailLevel(0),
hiSinceLong(0),loSinceShort(0),mp(0),
rangeSum(0),iCnt(0),
Variables That We Might Need

### Once A Day Calculations:

Since we will be working with five-minute bars we don’t want to do daily calculations on each bar.  If we do it will slow down the process.  So let’s do these calculation on the first bar of the day only.

``````If d <> d then
Begin
rangeSum = 0.0;  // range calculation for entry
For iCnt = 1 to volCalcLen
Begin
rangeSum = rangeSum + (highD(iCnt) - lowD(iCnt));
end;
vol = rangeSum/volCalcLen;
sellPoint = openD(0) - vol*orboSellPer;

longStopAmt = vol * volStopPer;
longStopAmt = minList(longStopAmt,Stop\$);

shortStopAmt = vol *volStopPer;
shortStopAmt = minList(shortStopAmt,Stop\$);

longThreshAmt = vol  * volThreshPer;
longThreshAmt = minList(longThreshAmt,ProfThresh\$);

shortThreshAmt = vol * volThreshPer;
shortThreshAmt = minList(shortThreshAmt,ProfThresh\$);

longTrailAmt = vol * volTrailPer;
longTrailAmt = minList(longTrailAmt,Trail\$);

shortTrailAmt = vol * volTrailPer;
shortTrailAmt = minList(shortTrailAmt,Trail\$);

longTrailLevel = 0;
shortTrailLevel = 999999;
shortsToday = 0;
end;``````
Do These Just Once A Day

#### For All of You Who Don’t Want To Wait – Beta Version Is Available Below:

In my next post, I will dissect the following code for a better understanding.  Sorry I just ran out of time.

``````inputs: volCalcLen(10),orboBuyPer(.2),orboSellPer(.2);
inputs: volStopPer(.7),Stop\$(500/bigPointValue);
inputs: volThreshPer(.3),ProfThresh\$(250/bigPointValue);
inputs: volTrailPer(.2),Trail\$(200/bigPointValue);

longStopAmt(0),shortStopAmt(0),longExitPoint(0),shortExitPoint(0),
longThreshAmt(0),shortThreshAmt(0),
longTrailAmt(0),shortTrailAmt(0),
longTrailLevel(0),shortTrailLevel(0),
hiSinceLong(0),loSinceShort(0),mp(0),
rangeSum(0),iCnt(0),

If d <> d then
Begin
rangeSum = 0.0;  // range calculation for entry
For iCnt = 1 to volCalcLen
Begin
rangeSum = rangeSum + (highD(iCnt) - lowD(iCnt));
end;
vol = rangeSum/volCalcLen;
sellPoint = openD(0) - vol*orboSellPer;

longStopAmt = vol * volStopPer;
longStopAmt = minList(longStopAmt,Stop\$);

shortStopAmt = vol *volStopPer;
shortStopAmt = minList(shortStopAmt,Stop\$);

longThreshAmt = vol  * volThreshPer;
longThreshAmt = minList(longThreshAmt,ProfThresh\$);

shortThreshAmt = vol * volThreshPer;
shortThreshAmt = minList(shortThreshAmt,ProfThresh\$);

longTrailAmt = vol * volTrailPer;
longTrailAmt = minList(longTrailAmt,Trail\$);

shortTrailAmt = vol * volTrailPer;
shortTrailAmt = minList(shortTrailAmt,Trail\$);

longTrailLevel = 0;
shortTrailLevel = 999999;
shortsToday = 0;
end;

mp = marketPosition;

If mp = 1 and mp <> 1 then buysToday = buysToday + 1;
If mp = -1 and mp <> -1 then shortsToday = shortsToday + 1;

if time < sessionendTime(0,1) and shortsToday < 1 then Sellshort("ORBo-S") next bar at sellPoint stop;

If marketposition = 1 then
Begin
longExitPoint = entryPrice - longStopAmt;
sell("L-Exit") next bar at longExitPoint stop;
end;

If marketposition = -1 then
Begin
shortExitPoint = entryPrice + shortStopAmt;
buyToCover("S-Exit") next bar at shortExitPoint stop;
end;

If marketPosition = 1 and maxContractProfit/bigPointValue >= longThreshAmt then
Begin
sell("TrailSell") next bar at longTrailLevel stop;
end;

If marketPosition = -1 and maxContractProfit/bigPointValue >= shortThreshAmt then
Begin
buyToCover("TrailCover") next bar at shortTrailLevel stop;
end;

SetExitOnClose;``````
Beta Version - I will clean up later and post it

# EasyLanguage Code for Optimal F (Multi-Charts and VBA too!)

## Optimal F in EasyLanguage for TradeStation and MultiCharts

Here is the code for the Optimal F calculation.  For a really good explanation of Optimal f, I refer you to Ralph Vince’s Book Portfolio Management FORMULAS.  We had programmed this years ago for our Excalibur software and I was surprised the EasyLanguage code was not really all that accessible on the internet.  Finding the Optimal f is found through an iterative process or in programmers terms a loop.  The code is really quite simple and I put it into a Function.  I decided to create this function because I wanted to demonstrate the ideas from my last post on how a function can store variable and array data.  Plus this code should be readily available somewhere out there.

``````//OptimalFGeo by George Pruitt
//My interpretation Sept. 2018
//www.georgepruitt.com
//georgeppruitt@gmail.com

vars: iCnt(00),jCnt(00),grandTot(0),highI(0);
vars: optF(0.0),gMean(0.0),fVal(0.0),HPR(0.0),TWR(0.0),hiTWR(0.0);
vars: biggestLoser(0.0),gat(0.0);

begin
end;

// Taken from my Fortran library - GPP and Vince Book PMF

optF = 0.0;
gMean = 1.00;
gat   = 0.00;
Begin
biggestLoser = 0;
grandTot = 0;
For iCnt = 1 to tradeCnt //get the biggest loser
begin
end;
//	print(grandTot," ",biggestLoser);
IF({grandTot > 0 and} biggestLoser <0) then
begin
//		print("Inside TWR Calculations");
highI = 0;
hiTWR = 0.0;
for iCnt = 1 to 100
begin
fVal = .01 * iCnt;
TWR = 1.0;
for jCnt = 1 to tradeCnt // calculate the Terminal Wealth Relative
begin
HPR = 1. + (fVal * (-1*tradesArray[jCnt]) / biggestLoser);
TWR = TWR * HPR;
//   			print(fVal," ",iCnt," " ,jCnt," Trades ",tradesArray[jCnt]," HPR ",HPR:6:4," TWR : ",TWR:6:4," hiTWR",hiTWR:6:4," bl ",biggestLoser);
end;
//			print(iCnt," ",TWR," ",hiTWR);
IF(TWR>hiTWR) THEN
begin
hiTWR = TWR;
optF = fVal;    	// assign optF to fVal in case its the correct one
end
else
break;                     //highest f found - stop looping
end;
If (TWR <= hiTWR or optF >= 0.999999) then
begin
TWR  = hiTWR;
OptimalFGeo = optF;  //assign optF to the name of the function
end;

if(optF<>0) then GAT   = (gMean - 1.0) * (biggestLoser / -(optF));
print(d," gmean ",gmean:6:4," ",GAT:6:4);  // I calculate the GMEAN and GeoAvgTrade
end;
end;``````
Optimal F Calculation by Ralph Vince code by George Pruitt

#### VBA version of Optimal F

For those of you who have a list of trades and want to see how this works in Excel here is the VBA code:

``````Sub OptimalF()

i = 0
biggestLoser = 0#
Do While (Cells(3 + i, 1) <> "")
tradesArray(i) = Cells(3 + i, 1)
i = i + 1
Loop
highI = 0
hiTWR = 0#
rc = 3
For fVal = 0.01 To 1 Step 0.01
TWR = 1#
For jCnt = 0 To tradeCnt
HPR = 1# + (fVal * (-1 * tradesArray(jCnt)) / biggestLoser)
TWR = TWR * HPR
Cells(rc, 5) = jCnt
Cells(rc, 7) = HPR
Cells(rc, 8) = TWR
rc = rc + 1
Next jCnt
Cells(rc, 9) = fVal
Cells(rc, 10) = TWR
rc = rc + 1

If (TWR > hiTWR) Then
hiTWR = TWR
optF = fVal
Else
Exit For
End If

Next fVal
If (TWR <= hiTWR Or optF >= 0.999999) Then
TWR = hiTWR
OptimalFGeo = optF
End If
Cells(rc, 8) = "Opt f"
Cells(rc, 9) = optF
rc = rc + 1
gMean = TWR ^ (1# / (tradeCnt + 1))
If (optF <> 0) Then GAT = (gMean - 1#) * (biggestLoser / -(optF))
Cells(rc, 8) = "Geo Mean"
Cells(rc, 9) = gMean
rc = rc + 1
Cells(rc, 8) = "Geo Avg Trade"
Cells(rc, 9) = GAT

End Sub``````
VBA code for Optimal F

I will attach the eld and .xlsm file a little later.

# Anatomy Of Mean Reversion in EasyLanguage

Look at this equity curve: As long as you are in a bull market buying dips can be very consistent and profitable.  But you want to use some type of entry signal and trade management other than just buying a dip and selling a rally.  Here is the anatomy of a mean reversion trading algorithm that might introduce some code that you aren’t familiar.  Scroll through the code and I will  summarize below.

``````inputs: mavlen(200),rsiLen(2),rsiBuyVal(20),rsiSellVal(80),holdPeriod(5),stopLoss\$(4500);

Condition1 = c > average(c,mavLen);

Condition3 = rsi(c,rsiLen) > rsiSellVal;

Value1 = 0;
Value2 = 0;

For iCnt = 0 to consecUpClose - 1
Begin
value1 = value1 + iff(c[iCnt] > c[iCnt+1],1,0);
end;

For iCnt = 0 to consecDnClose - 1
Begin
Value2 = value2 + iff(c[iCnt] < c[iCnt+1],1,0);
end;

dontCatchFallingKnife = absValue(C - c) < avgTrueRange(10)*2.0;

meanRevBuy = condition1 and condition2 and dontCatchFallingKnife;
meanRevSell =  not(condition1) and condition3 and dontCatchFallingKnife;

If marketPosition = 1 and condition1 and value1 >= consecUpClose then sell("ConsecUpCls") this bar on close;

If meanRevSell then sellShort this bar on close;
If marketPosition = -1 and not(condition1) and value2 >= consecDnClose then buyToCover this bar close;

setStopLoss(stopLoss\$);

Begin
if marketPosition = 1 and not(meanRevBuy) then sell this bar on close;
if marketPosition =-1 and not(meanRevSell) then buytocover this bar on close;
end;``````
Mean Reversion System

I am using a very short term RSI indicator, a la Connors, to initiate long trades.  Basically when the 2 period RSI dips below 30 and the close is above the 200-day moving average I will buy only if I am not buying “a falling knife.”  In February several Mean Reversion algos kept buying as the market fell and eventually got stopped out with large losses.  Had they held on they probably would have been OK.  Here I don’t buy if the absolute price difference between today’s close and yesterday’s is greater than 2 X the ten day average true range.  Stay away from too much “VOL.”

Once a trade is put on I use the following logic to keep track of consecutive closing relationships:

``````For iCnt = 0 to consecUpClose - 1
Begin
value1 = value1 + iff(c[iCnt] > c[iCnt+1],1,0);
end;``````
Using the IFF function in EasyLanguage

Here I am using the IFF function to compare today’s close with the prior day’s.  iCnt is a loop counter that goes from 0 to 1. IFF checks the comparison and if it’s true it returns the first value after the comparison and if false it returns the last value.  Here if I have two consecutive up closes value1 accumulates to 2.  If I am long and I have two up closes I get out.  With this template you can easily change this by modifying the input:  consecUpClose.  Trade management also includes a protective stop and a time based exit.  If six days transpire without two up closes then the system gets out – if the market can’t muster two positive closes, then its probably not going to go anywhere.  The thing with mean reversion, more so with other types of systems, is the use or non use of a protective stop.  Wide stops are really best, because you are betting on the market to revert.  Look at the discrepancy of results using different stop levels on this system: Here an \$1,800 stop only cut the max draw down by \$1,575.  But it came at a cost of \$17K in profit.  Stops, in the case of Mean Reversion, are really used for the comfort of the trader.

This code has the major components necessary to create a complete trading system.  Play around with the code and see if you can come up with a better entry mechanism.

# How to Keep Track of BuysToday and SellsToday

## The Useful MP

We all know how to use the reserved word/function MarketPosition – right?  Brief summary if not – use MarketPosition to see what your current position is: -1 for short, +1 for long and 0 for flat.  MarketPosition acts like a function because you can index it to see what you position was prior to the current position – all you need to do is pass a parameter for the number of positions ago.  If you pass it a one (MarketPosition(1)) then it will return the your prior position.  If you define a variable such as MP you can store each bars MarketPosition and this can come in handy.

``````mp = marketPosition;

If mp <> 1 and mp = 1 then buysToday = buysToday + 1;
If mp <> -1 and mp = -1 then sellsToday = sellsToday + 1;``````
Keeping Track of Buy and Sell Entries on Daily Basis

The code compares prior bar’s MP value with the current bar’s.   If there is a change in the value, then the current market position has changed.   Going from not 1 to 1 indicates a new long position.  Going from not -1 to -1 implies a new short.  If the criteria is met, then the buysToday or sellsToday counters are incremented.  If you want to keep the number of buys or sells to a certain level, let’s say once or twice,  you can incorporate this into your code.

``````If  time >= startTradeTime and t < endTradeTime and
sellsToday < 1 and
rsi(c,rsiLen) crosses below rsiShortVal then sellShort this bar on close;``````
Using MP to Keep Track of BuysToday and SellsToday

This logic will work most of the time, but it depends on the robustness of the builtin MarketPosition function Look how this logic fails in the following chart:

## MarketPosition Failure

Failure in the sense that the algorithm shorted twice in the same day.  Notice on the first trade how the profit objective was hit on the very next bar.  The problem with MarketPosition is that it only updates at the end of the bar one bar after the entry.  So MarketPosition stays 0 during the duration of this trade.  If MarketPosition doesn’t change then my counter won’t work.  TradeStation should update MarketPosition at the end of the entry bar.  Alas it doesn’t work this way.  I figured a way around it though.  I will push the code out and explain it later in more detail.

``````Input: rsiLen(14),rsiBuyVal(30),rsiShortVal(70),profitObj\$(250),protStop\$(300),startTradeTime(940),endTradeTime(1430);

If d <> d then
Begin
sellsToday = 0;
startOfDayNetProfit = netProfit;
end;

{mp = marketPosition;

If mp <> 1 and mp = 1 then buysToday = buysToday + 1;
If mp <> -1 and mp = -1 then sellsToday = sellsToday + 1;}

If entriesToday(date) > buysToday + sellsToday then
Begin
If marketPosition =-1 then sellsToday = sellsToday + 1;
If marketPosition = 0 then
Begin
if netProfit > startOfDayNetProfit then
begin
If exitPrice(1) < entryPrice(1) then sellsToday = sellsToday + 1;
end;;
if netProfit < startOfDayNetProfit then
Begin
If exitPrice(1) > entryPrice(1) then sellsToday = sellsToday + 1;
end;
end;
end;

sellsToday < 1 and
rsi(c,rsiLen) crosses below rsiShortVal then sellShort this bar on close;

SetProfittarget(profitObj\$);
SetStopLoss(protStop\$);

SetExitOnClose;``````
A Better Buy and Short Entries Counter

TradeStation does update EntriesToday at the end of the bar so you can use this keyword/function to help keep count of the different type of entries.  If MP is 0 and EntriesToday increments then you know an entry and an exit has occurred (takes care of the MarketPosition snafu) – all you need to do is determine if the entry was a buy or a sell.  NetProfit is also updated when a trade is closed.   I establish the StartOfDayNetProfit on the first bar of the day (line 9 in the code) and then examine EntriesToday and if NetProfit increased or decreased.  EntryPrice and ExitPrice are also updated at the end of the bar so I can also use them to extract the information I need.   Since MarketPosition is 0  I have to pass 1 to the EntryPrice and ExitPrice functions – prior position’s prices.  From there I can determine if a Long/Short entry occurred.  This seems like a lot of work for what you get out of it, but if you are controlling risk by limiting the number of trades (exposure) then an accurate count is so very important.

An alternative is to test on a higher resolution of data – say 1 minute bars.  In doing this you give a buffer to the MarketPosition function – more bars to catch up.

# 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:
ema1(0),ema2(0,data2),trendUp(false);

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.