Category Archives: EasyLanguage

Turn of the Month Trading Strategy [Stock Indices Only]

The System

This system has been around for several years.  Its based on the belief that fund managers start pouring money into the market near the end of the month and this creates momentum that lasts for just a few days.  The original system states to enter the market on the close of the last bar of the day if the its above a certain moving average value.  In the Jaekle and Tomasini book, the authors describe such a trading system.  Its quite simple, enter on the close of the month if its greater than X-Day moving average and exit either 4 days later or if during the trade the closing price drops below the X-Day moving average.

EasyLanguage or Multi-Charts Version

Determining the end of the month should be quite easy -right?  Well if you want to use EasyLanguage on TradeStation and I think on Multi-Charts you can’t sneak a peek at the next bar’s open to determine if the current bar is the last bar of the month.  You can try, but you will receive an error message that you can’t mix this bar on close with next bar.  In other words you can’t take action on today’s close if tomorrow’s bar is the first day of the month.  This is designed, I think, to prevent from future leak or cheating.  In TradeStation the shift from backtesting to trading is designed to be a no brainer, but this does provide some obstacles when you only want to do a backtest.

LDOM function – last day of month for past 15 years or so

So I had to create a LastDayOfMonth function.  At first I thought if the day of the month is the 31st then it is definitely the last bar of the month.  And this is the case no matter what.  And if its the 30th then its the last day of the month too if the month is April, June, Sept, and November.  But what happens if the last day of the month falls on a weekend.  Then if its the 28th and its a Friday and the month is blah, blah, blah.  What about February?  To save time here is the code:

Inputs: movAvgPeriods(50);
vars: endOfMonth(false),theDayOfWeek(0),theMonth(0),theDayOfMonth(0),isLeapYear(False);

endOfMonth = false;
theDayOfWeek = dayOfWeek(date);
theMonth = month(date);
theDayOfMonth = dayOfMonth(date);
isLeapYear = mod(year(d),4) = 0;

// 29th of the month and a Friday
if theDayOfMonth = 29 and theDayOfWeek = 5 then 
	endOfMonth = True;
// 30th of the month and a Friday
if theDayOfMonth = 30 and theDayOfWeek = 5 then 
	endOfMonth = True;
// 31st of the month 	
if theDayOfMonth = 31 then 
	endOfMonth = True;
// 30th of the month and April, June, Sept, or Nov
if theDayOfMonth = 30 and (theMonth=4 or theMonth=6 or theMonth=9 or theMonth=11) then 
	endOfMonth = True;
// 28th of the month and February and not leap year
if theDayOfMonth = 28 and theMonth = 2 and not(isLeapYear)  then 
	endOfMonth = True;
// 29th of the month and February and a leap year or 28th, 27th and a Friday	
if theMonth = 2 and isLeapYear then
Begin
	If theDayOfMonth = 29 or ((theDayOfMonth = 28 or theDayOfMonth = 27) and theDayOfWeek = 5) then 
	endOfMonth = True;	
end;
// 28th of the month and Friday and April, June, Sept, or Nov
if theDayOfMonth = 28 and (theMonth = 4 or theMonth = 6 or 
	theMonth = 9 or theMonth =11) and theDayOfWeek = 5 then
	endOfMonth = True;
// 27th, 28th of Feb and Friday	
if theMonth = 2 and theDayOfWeek = 5 and theDayOfMonth = 27 then
	endOfMonth = True;
// 26th of Feb and Friday and not LeapYear
if theMonth = 2 and theDayOfWeek = 5 and theDayOfMonth = 26 and not(isLeapYear) then
	endOfMonth = True;	
// Memorial day adjustment
If theMonth = 5 and theDayOfWeek = 5 and theDayOfMonth = 28 then
	endOfMonth = True;
//Easter 2013 adjustment
If theMonth = 3 and year(d) = 113 and theDayOfMonth = 28 then
	endOfMonth = True;
//Easter 2018 adjustment
If theMonth = 3 and year(d) = 118 and theDayOfMonth = 29 then
	endOfMonth = True;	

if endOfMonth and c > average(c,movAvgPeriods) then	
	Buy("BuyDay") this bar on close;

If C <average(c,movAvgPeriods) then 
	Sell("MovAvgExit") this bar on close;
If BarsSinceEntry=4 then 
	Sell("4days") this bar on close;
Last Day Of Month Function and Strategy

All the code is generic except for the hard code for days that are a consequence of Good Friday.

All this code because I couldn’t sneak a peek at the date of tomorrow.  Here are the results of trading the ES futures sans execution costs for the past 15 years.

Last Day Of Month Buy If C > 50 Day Mavg

What if it did the easy way and executed the open of the first bar of the month.

If c > average(c,50) and month(d) <> month(d of tomorrow) then 
	buy next bar at open;

If  barsSinceEntry >=3 then 
	sell next bar at open;

If marketPosition = 1 and c < average(c,50) then 
	sell next bar at open;
Buy First Day Of Month
First Day of Month If C > 50 Day Mavg

The results aren’t as good but it sure was easier to program.

TradingSimula-18 Version

Since you can use daily bars we can test this with my TradingSimula-18 Python platform.  And we will execute on the close of the month.  Here is the snippet of code that you have to concern yourself with.  Here I am using Sublime Text and utilizing their text collapsing tool to hide non-user code:

Small Snippet of TS-18 Code

This was easy to program in TS-18 because I do allow Future Leak – in other words I will let you sneak a peek at tomorrow’s values and make a decision today.  Now many people might say this is a huge boo-boo, but with great power comes great responsibility.  If you go in with eyes wide open, then you will only use the data to make things easier or even doable, but without cheating.  Because you are only going to cheat yourself.  Its in your best interest do follow the rules.  Here is the line that let’s you leak into the future.

If isNewMonth(myDate[curBar+1])

The curBar is today and curBar+1 is tomorrow.  So I am saying if tomorrow is the first day of the month then buy today’s close.  Here you are leaking into the future but not taking advantage of it.  We all know if today is the last day of the month, but try explaining that to a computer.  You saw the EasyLanguage code.  So things are made easier with future leak, but not taking advantage of .

Here is a quick video of running the TS-18 Module of 4 different markets.

 

Please follow and like us:

Ratio Adjusted versus Point Adjusted Contracts in TradeStation Part 2

Thomas Stridsman quote from  his “Trading Systems That Work Book”

The benefits of the RAD contract also become evident when you want to put together a multimarket portfolio…For now we only state that the percentage based calculations do not take into consideration how many contracts you’re trading and, therefore, give each market an equal weighting in the portfolio.

The Stridsman Function I presented in the last post can be used to help normalize a portfolio of different markets.  Here is a two market portfolio (SP – 250price and JY -125Kprice contract sizes) on a PAD contract.

1-Contract SP and JY on PAD data

Here is the performance of the same portfolio on a RAD contract.

Equal rating of SP and JY on RAD data

 

The curve shapes are similar but look at the total profit and the nearly $125K draw down.  I was trying to replicate Thomas’ research so this data is from Jan. 1990 to Dec. 1999.  A time period where the price of the SP increased 3 FOLD!  Initially you would start trading 1 JY to 2 SP but by the time it was over you would be trading nearly 3 JY to 1 SP.  Had you traded at this allocation the PAD numbers would be nearly $240K in profit.  Now this change occurred through time so the percentage approach is applied continuously.  Also the RAD data allows for a somewhat “unrealistic” reinvestment or compounding mechanism.  Its unrealistic because you can’t trade a partial futures contract.  But it does give you a glimpse of the potential.  The PAD test does not show reinvestment of profit.  I have code for that if you want to research that a little bit more.  Remember everything is in terms of Dec. 31 1999 dollars.  That is another beauty of the RAD contract.

Another Stridsman Quote

Now, wait a minute, you say, those results are purely hypothetical.  How can I place all the trades in the same market at presumably the same point in time?  Well, you can’t, so that is a good and valid question; but let me ask you, can you place any of these trades for real, no matter, how you do it?  No, of course not.  They all represent foregone opportunities.  Isn’t it better then to at least place them hypothetically in today’s marketplace to get a feel for what might happen today, rather in a ten-year-old market situation to get a feel for how the situation was back then?  I think wall can agree that it is better to know what might happen today, rather than what happened ten years ago.

That is a very good point.  However, convenience and time is import and when developing an algorithm.  And most platforms, including my TS-18, are geared toward PAD data.  However TS-18 can look at the entire portfolio balance and all the market data for each market up to that point in time and can adjust/normalize based on portfolio and data metrics.  However, I will add a percentage module a little later, but I would definitely use the StridsmanFunc that I presented in the last post to validate/verify your algorithm in today’s market place if using TradeStation.

Email me if you want the ELD of the function.

Please follow and like us:

Ratio Adjusted versus Pointed Adjusted Contracts in TradeStation – Part 1

If you play around with TradeStation’s custom futures capabilities you will discover you can create different adjusted continuous contracts.  Take a look at this picture:

Panama vs Ratio Adjusted

Both charts look the same and the trades enter and exit at the same locations in relation to the respective price charts.   However, take a look at the Price Scale on the right and the following pictures.

As you can see from the P/L from each trade list there is a big difference.  The top list is using RAD and the second is the generally accepted Panama Adjusted Data (PAD.)  Ratio adjusted data takes the percentage difference between the expiring contract and the new contract and propagates the value throughout the entire back history.  This is different than the PAD we have all used, where the actual point difference is propagated.  These two forms of adjustment have their own pros and cons but many industry leaders prefer the RAD.  I will go over a little bit of the theory in my next post, but in the mean time I will direct you to Thomas Stridsman’s excellent work on the subject in his book, “Trading Systems That Work – Building and Evaluating Effective Trading Systems”.

Here is another look at draw down metrics between the two formats.

RAD V PAD DrawDown

Who would want to trade a system on 1 contract of crude and have a $174K draw down?  Well you can’t look at it like that.  Back in 2008 crude was trading at $100 X 1000 = $100,000 a contract.  Today May 11th 2020 it is around $25,000.  So a drawdown of $44K back then would be more like $176K in today’s terms.  In my next post I will go over the theory of  RAD, but for right now you just need to basically ignore TradeStation’s built in performance metrics and use this function that I developed in most part by looking at Thomas’ book.

//Name this function StridsmanFunc1

Vars: FName(""), offset(1),TotTr(0), Prof(0), CumProf(1), ETop(1), TopBar(0), Toplnt(0),BotBar(0), Botlnt(0), EBot(1), EDraw(1), TradeStr2( "" );
Arrays: tradesPerArr[1000](0),drawDownArr[1000](0);
Vars: myEntryPrice(0),myEntryDate(0),myMarketPosition(0),myExitDate(0),myExitPrice(0);
If CurrentBar = 1 Then 
Begin
	FName = "C:\Temp\" + LeftStr(GetSymbolName, 3) + ".csv";
	FileDelete(FName);
	TradeStr2 = "E Date" + "," + "Position" + "," + "E Price" + "," + "X Date" +"," + "X Price" + "," + "Profit" + "," + "Cum. prof." + "," + "E-Top" + "," +"E-Bottom" + "," + "Flat time" + "," + "Run up" + "," + "Drawdown" +NewLine;
	FileAppend(FName, TradeStr2);
End;
TotTr = TotalTrades;
If TotTr > TotTr[1] or (lastBarOnChart and marketPosition <> 0) Then 
Begin

	if TotTr > TotTr[1] then
	begin
		if (EntryPrice(1) <> 0) then Prof = 1 + PositionProfit(1)/(EntryPrice(1) * BigPointValue); 
	End
	else
	begin
		Value99 = iff(marketPosition = 1,c - entryPrice, entryPrice - c);
		Prof = 1 + (Value99*bigPointValue) /(Entryprice *BigPointValue);
//		print(d," StridsmanFunc1 ",Value99," ",Prof," ",(Value99*bigPointValue) /(Entryprice *BigPointValue):5:4);
		TotTr = totTr + 1;
	end;
	tradesPerArr[TotTr] = Prof - 1;
	CumProf = CumProf * Prof;
	ETop = MaxList(ETop, CumProf);
	If ETop > ETop[1] Then 
	Begin
		TopBar = CurrentBar;
		EBot = ETop;
	End;
	
	EBot = MinList(EBot, CumProf);
	
	If EBot<EBot[1] Then BotBar = CurrentBar;
	
	Toplnt = CurrentBar - TopBar;
	
	Botlnt = CurrentBar - BotBar;
	
	if ETop <> 0 then EDraw = CumProf / ETop;
	
	drawDownArr[TotTr] = (EDraw - 1);
	
	myEntryDate = EntryDate(1);
	myMarketPosition = MarketPosition(1);
	myEntryPrice = EntryPrice(1);
	myExitDate = ExitDate(1);
	myExitPrice = ExitPrice(1);
	If lastBarOnChart and marketPosition <> 0 then
	Begin
		myEntryDate = EntryDate(0);
		myMarketPosition = MarketPosition(0);
		myEntryPrice = EntryPrice(0);
		myExitDate = d;
		myExitPrice =c;
	end;
	TradeStr2 = NumToStr(myEntryDate, 0) + "," +NumToStr(myMarketPosition, 0) + "," + NumToStr(myEntryPrice, 2) + "," 
	+ NumToStr(myExitDate, 0) + "," + NumToStr(myExitPrice, 2) + ","+ NumToStr((Prof - 1) * 100, 2) + "," + NumToStr((CumProf - 1) *100, 2) + "," 
	+ NumToStr((ETop - 1) * 100, 2) + "," + NumToStr((EBot - 1) * 100, 2) + "," + NumToStr(Toplnt, 0) + "," + NumToStr(Botlnt, 0) + "," + NumToStr((EDraw - 1) * 100, 2) +
	NewLine;
	
	FileAppend(FName, TradeStr2);
End;
vars: tradeStr3(""),
	  ii(0),avgTrade(0),avgTrade$(0),cumProf$(0),trdSum(0),
	  stdDevTrade(0),stdDevTrade$(0),
	  profFactor(0),winTrades(0),lossTrades(0),perWins(0),perLosers(0),
	  largestWin(0),largestWin$(0),largestLoss(0),largestLoss$(0),avgProf(0),avgProf$(0),
      winSum(0),lossSum(0),avgWin(0),avgWin$(0),avgLoss(0),avgLoss$(0),maxDD(0),maxDD$(0),cumProfit(0),cumProfit$(0);
      
If lastBarOnChart then
begin
    stdDevTrade = standardDevArray(tradesPerArr,TotTr,1);
    stdDevTrade$ = stdDevTrade*c*bigPointValue;
    For ii = 1 to TotTr
    Begin
    	trdSum = trdSum + tradesPerArr[ii];	
//    	print(d," ",ii," ",tradesPerArr[ii]);
    	If tradesPerArr[ii] > 0 then 
    	begin
    		winTrades = winTrades + 1;
    		winSum = winSum + tradesPerArr[ii];
    	end;
    	If tradesPerArr[ii] <=0 then 
    	begin
    		lossTrades = lossTrades + 1;
    		lossSum = lossSum + tradesPerArr[ii];
    	end;
    	If tradesPerArr[ii] > largestWin then 
    	begin
    		largestWin = tradesPerArr[ii];
 //   		print("LargestWin Found ",largestWin);
    	end;
    	If tradesPerArr[ii] < largestLoss then largestLoss = tradesPerArr[ii];
    	If drawDownArr[ii] < maxDD then maxDD = drawDownArr[ii];
    end;
 //   print("TradeSum: ",trdSum);
    if TotTr <> 0 then avgTrade = trdSum/TotTr;
	avgTrade$ = avgTrade*c*bigPointValue;
    largestWin = largestWin;
    largestLoss = largestLoss;
    largestWin$ = largestWin*c*bigPointValue;
    largestLoss$ = largestLoss*c*bigPointValue;
    if TotTr <> 0 then perWins = winTrades/TotTr;
    if TotTr <> 0 then perLosers = lossTrades/TotTr;
    If winTrades <> 0 then avgWin = winSum / winTrades;
    avgWin$ = avgWin*c*bigPointValue;
    if lossTrades <> 0 then avgLoss= lossSum / lossTrades;
    avgLoss$ = avgLoss*c*bigPointValue;
    maxDD$ = maxDD *c*bigPointValue;
    if lossTrades <>0 and avgLoss$ <> 0 then profFactor = (winTrades*avgWin$)/(lossTrades*avgLoss$);
    CumProf = cumProf - 1;
    CumProf$ = cumProf*c*bigPointValue;
    
    TradeStr3 = "Total Trades,,"+NumToStr(TotTr,0)+",Num. Winners,"+NumToStr(winTrades,0)+","+NumToStr(perWins,3)+", Num. Losses,"+NumToStr(lossTrades,0)+","+NumToStr(perLosers,3)+NewLine+
                "Profit Factor,,"+NumToStr(profFactor,3)+",Largest Win ,"+NumToStr(largestWin,3)+","+NumToStr(largestWin$,0)+",Largest Loss,"+NumToStr(largestLoss,3)+","+NumToStr(largestLoss$,0)+NewLine+
                "Avg Profit,"+NumToStr(avgTrade,3)+","+NumToSTr(avgTrade$,0)+",Avg Win,"+NumToStr(avgWin,3)+","+NumToStr(avgWin$,0)+",Avg Loss,"+NumToStr(avgLoss,3)+","+NumToStr(avgLoss$,0)+NewLine+
                "Std. Dev,"+NumToStr(stdDevTrade,3)+","+NumToStr(stdDevTrade$,0)+",Cum Profit,"+NumToStr(cumProf,3)+","+NumToStr(cumProf$,3)+",Draw Down,"+numToStr(maxDD,3)+","+numToStr(maxDD$,0)+NewLine;
 	FileAppend(FName, TradeStr3);
 {  Print("Total Trades  ",totalTrades," Num. Winners ",winTrades," ",perWins," Num. Losses    ",lossTrades," ",perLosers);
    Print("Profit Factor ",profFactor," Largest Win   ",largestWin:5:2," ",largestWin$," Largest Loss ",largestLoss:5:2," ",largestLoss$);
    Print("Avg Profit ",avgTrade," ",avgTrade$," Avg Win ",avgWin," ",avgWin$," Avg Loss ",avgLoss," ",avgLoss$);
    Print("St Dev ",stdDevTrade," ",stdDevTrade$," Cum Profit ",cumProf," ",cumProf$," Drawdown ",maxDD," ",maxDD$);}
    
    
 end;   
    
    

StridsmanFunc1 = 1;
Conversion of Performance Metrics to Percentages Instead of $Dollars

This function will out put a file that looks like this.  Go ahead and play with the code – all you have to do is call the function from within an existing strategy that you are working with.  In part two I will go over the code and explain what its doing and how arrays and strings were used to archive the trade history and print out this nifty table.

Stridsman Function Output.

In this output if you treat the return from each trade as a function of the entry price and accumulate the returns you can convert the value to today’s current market price of the underlying.  In this case a 15 -year test going through the end of last year, ended up making almost $70K.

RAD TradeStation Metrics:

Profit $350K – Draw Down $140K

PAD TradeStation Metrics:

Profit $89K – Draw Down $45K

Stridsman Func on RAD:

Profit $70K – Draw Down $48K

At this point you can definitely determine that the typical RAD/TS metrics are not all that usuable.  The PAD/TS results look very similar to RAD/StridsmanFunc results.  Stay tuned for my next post and I will hopefully explain why RAD/StridsmanFunc is probably the most accurate performance metrics of the three.

Please follow and like us:

Super Combo Day Tradng System A 2020 Redo!

If you have some time on your hands and you want to build your own Frankenstein monster from a parts bin, here is your chance.  The Super Combo Day Trading System was originally published in my “Building Winning Trading Systems” book back in 2001.  I designed it to be more of a tutorial than a pure trading system.    You should be able to get the spare parts you need to create your own day trading system.  Back in 2001, I wanted to show how to control and monitor different entry and exit techniques in one complete algorithm.  The system was designed to day-trade the big SP and the results at the time looked promising.  Since the transition to the ES and the higher levels of volatility that we have seen over the years and the adoption of overnight trading,  the system hasn’t fared that well, but the concepts are still viable as an instructional tool today as they were 20 years ago.  EasyLanguage has been improved over this time period so the coding for the Super Combo can definitely take advantage of the new enhancements.

Here are the main premises of the logic:

  • take advantage of a buyEasier and shortEasier pattern setup
  • incorporate daily and 5-minute time frames in one chart
  • include a breakOut, failedBreakOut and reverseOnLiquidation trade entry techniques
  • monitor which signal is currently online and apply the correct exit signal
  • monitor profit and incorporate a break even stop
  • monitor time and incorporate a trailing stop
  • provide an interface into the logic via inputs

Okay here we go – there is quite a bit of code here so let’s divide an conquer by examining just one module at a time.  This first module includes the inputs and variables section plus once per day calculations.

[LegacyColorValue = true]; 

{Super Combo by George Pruitt - redo 2020
 This intra-day trading system will illustrate the multiple data
 handling capabilities of TradeStation.  All pertinent buy and sell
 calculations will be based on daily bars and actual trades will be
 executed on 5-min bars.  I have made most of the parameters input
 variables}

 Inputs:waitPeriodMins(30),initTradesEndTime(1430),liqRevEndTime(1200),
 	thrustPrcnt1(0.30),thrustPrcnt2(0.60),breakOutPrcnt(0.25),
	failedBreakOutPrcnt(0.25),protStopPrcnt1(0.30),protStopPrcnt2(0.20),
	protStopAmt(3.00),breakEvenPrcnt(0.50),avgRngLength(10);
	
Variables:averageRange(0),canTrade(0),buyEasierDay(FALSE),
	sellEasierDay(FALSE),buyBOPoint(0),sellBOPoint(0),longBreakPt(0),
	shortBreakPt(0),longFBOPoint(0),shortFBOPoint(0),barCount(0),buysToday(0),
	sellsToday(0),mp(0),longLiqPoint(0),shortLiqPoint(0),
	longLiqPoint1(0),shortLiqPoint1(0),intraTradeHigh(0),intraTradeLow(999999);


{Just like we did in the psuedo code -- let's start out with the daily 
 bar calculations.  If Date <> Date[1] -- first bar of day}
if(Date <> Date[1]) then {save time by doing these calculations once per day}
begin
 	averageRange = Average(Range,10) of Data2; {Data 2 points to daily bars}
 	
	canTrade = 0;
    if range of data2 < averageRange then canTrade = 1;

	{use close of data2 - seems to be more accurate than CloseD(1)
	buyEasierDay =Close of Data2 >= Close[1] of Data2;
	sellEasierDay = Close of Data2 <  Close[1] of Data2;

	buyBOPoint = Open + thrustPrcnt1*averageRange;
	sellBOPoint= Open - thrustPrcnt2*averageRange;
	
	if(sellEasierDay) then
	begin
		sellBOPoint= Open - thrustPrcnt1*averageRange;
		buyBOPoint = Open + thrustPrcnt2*averageRange; 
	end;

	longBreakPt = HighD(1) + breakOutPrcnt*averageRange;
	shortBreakPt=  LowD(1) - breakOutPrcnt*averageRange;

	shortFBOPoint = HighD(1) - failedBreakOutPrcnt*averageRange;
	longFBOPoint=  LowD(1) + failedBreakOutPrcnt*averageRange;

{Go ahead and initialize any variables that we may need later on in the day}
	
	barCount = 0;
	buysToday = 0;sellsToday = 0;{You can put multiple statements on one line}	
end;
First Modules of SuperCombo 2020

Here I am just setting up the inputs and variables that I will need to execute the algorithm.  If you are using .D data then the code

if date <> date[1] then

is a valid test for the first bar of the day.  A new date will represent the beginning of the next day.  The code controlled by this if-then construct is only executed one time per day.  So if you can put the lion’s share of daily calculations here, then it should speed stuff up.  The first thing I do is calculate the average range of the last 10 daily bars.  I access this date from data2.  Can you build a loop and accumulate the difference between the HighD and LowD function calls?

  1. for i = 1 to 10 begin
  2.      sum = sum + (HighD(i) – LowD(i));
  3. end;

The HighD() and LowD() functions are EasyLanguage enhancements that can help eliminate the need for a multi-data chart.  However, if you do this, you will get an warning message that its not a good idea.  I have done this and it seems to work, but to be safe just use Data2.    Next I determine if there has been a narrow range or range compression by comparing yesterday’s range to the averageRange.  If so, then I allow trading.  This is an old filter that looks for range expansion after compression.  The concept of a buyDay and sellDay was originated in the 1930s by George W. Cole (correct me if I am wrong here).  I use this idea by comparing the prior two bars closing relationships.  If there has been an up close, then I consider the next day to be a buyEasier day.  If the opposite is true, then its a sellEasier day.   This system isn’t unidirectional and does allow buying  and shorting in the same session – hence the word easier.   Continuing I calculate the levels that if the market reaches will hopefully trigger a short term trend in that direction.  This is the once highly respected open range break out or ORBO.  This methodology has lost its luster over the last 10 years or so due to overnight trading and allowing pent up buying and selling to be expressed in the overnight sessions.  Twenty years ago it was still viable.  The next bit of code creates the break out levels based on the buyEasier or sellEasier days.   The thrust is calculated by multiplying the range by thrustPrcnt1 and thrustPrcnt2.

So that is method 1 – break out.  Hope the market breaks out and continues to the close.  I wish it were this easy.  Since its not, the second methodolgy, FailedBreakOut, is calculated.  This is also known as the “ClearOut” trade.   The market is pushed to take out all the buy stops and then pulled back for the professionals to feast on the amateurs.  SuperCombo tries to take advantage of this by calculating the two points to determine a failed break out.  On the long side, it is the two points the market rises up to and then falls back to.  If the market breaches the longBreakPt, then look to sellShort at the shortFBOPoint.    Here is the next module

{Now lets trade and manage on 5-min bars}

barCount = barCount + 1; {count the number of bars of intraday data}
if(barCount >= waitPeriodMins/BarInterval and canTrade = 1) then {have we waited long enough}
begin
	if(MarketPosition = 1) then buysToday = 1;
	if(MarketPosition =-1) then sellsToday= 1;
	
	if(buysToday = 0 and Time < initTradesEndTime) then
		Buy("LBreakOut") next bar at buyBOPoint stop;
		
	if(sellsToday= 0 and Time < initTradesEndTime) then 
		SellShort("SBreakout") next bar at sellBOPoint stop;
				
	if(highD(0) > longBreakPt and sellsToday = 0 and Time < initTradesEndTime) then
		SellShort("SfailedBO") next bar at shortFBOPoint stop;
	if(lowD(0) < shortBreakPt and buysToday = 0 and Time < initTradesEndTime) then
		Buy("BfailedBO") next bar at longFBOPoint stop;
		
Monitor Market Action and Place Trades Accordingly

 

if(barCount>= waitPeriodMins/BarInterval and canTrade = 1) then

Forces the logic to flow only if canTrade is 1 and we have waited for amateur hour to be completed – well 30 minutes to be accurate.  Is the first hour really amateur hour?  I don’t think this applies, but if you think it does this is how you control trading prior to the completion of this period.  By dividing by BarInterval and counting each bar you can generalize this code for any time resolution.   If MarketPosition is 1 then you know you entered a long position and the opposite is true for short positions.  Only place the break out orders if time is less than initTradesEndTime.  If the market penetrates the long and shortBreakPts, then prepare to take advantage of a failed breakout.  Only go short if a short position has not already been entered – same for longs.  So, this logic places the breakOut and failedBreakOut orders.  Now for the last module.

{The next module keeps track of positions and places protective stops}

	mp = marketPosition;
	if(MarketPosition = 1) then
	begin
		longLiqPoint = EntryPrice-protStopPrcnt1*averageRange;
		longLiqPoint = MinList(longLiqPoint,EntryPrice - protStopAmt);
		longLiqPoint1 = EntryPrice - protStopPrcnt2*averageRange;
		longLiqPoint1 = MinList(longLiqPoint1,EntryPrice - protStopAmt);
		if Maxpositionprofit >= breakEvenPrcnt*averageRange*bigPointValue then
		begin
			longLiqPoint = EntryPrice;  {Breakeven trade}
			longLiqPoint1 = EntryPrice;  {Breakeven trade}
		end;
		if(Time >= initTradesEndTime) then
		begin
			longLiqPoint = MaxList(longLiqPoint,Lowest(Low,3)); {Trailing stop}
			longLiqPoint1 = MaxList(longLiqPoint1,Lowest(Low,3)); {Trailing stop}
		end;
		if(Time < liqRevEndTime and sellsToday = 0 and 
		longLiqPoint <> EntryPrice and BarsSinceEntry >= 4) then
			SellShort("LongLiqRev") next bar at longLiqPoint stop;
			 
		Sell("LongLiq-BO") from entry("LBreakOut") next bar at longLiqPoint stop;
		Sell("LongLiq-FBO") from entry("BFailedBO") next bar at longLiqPoint stop;
		Sell("LongLiq-RLoss") from entry("ShortLiqRev") next bar at longLiqPoint1 stop;
	end;
	if(MarketPosition =-1) then
	begin	
		shortLiqPoint = EntryPrice+protStopPrcnt1*averageRange;
		shortLiqPoint = MaxList(shortLiqPoint,EntryPrice + protStopAmt);
		shortLiqPoint1 = EntryPrice + protStopPrcnt2*averageRange;
		shortLiqPoint1 = MaxList(shortLiqPoint1,EntryPrice + protStopAmt);
		if maxPositionProfit >= breakEvenPrcnt*averageRange*bigPointValue then
		begin
			shortLiqPoint = EntryPrice;  {Breakeven trade}
			shortLiqPoint1 = EntryPrice;
		end;
		if(Time >= initTradesEndTime) then
		begin
			shortLiqPoint = MinList(shortLiqPoint,Highest(High,3)); {Trailing stop}
			shortLiqPoint1 = MinList(shortLiqPoint1,Highest(High,3)); {Trailing stop}
	    end;
		if(Time < liqRevEndTime and buysToday = 0 and 
		shortLiqPoint <> EntryPrice and BarsSinceEntry >= 4) then
			Buy("ShortLiqRev") next bar at shortLiqPoint stop;
			
		BuyToCover("ShortLiq-BO") from entry("SBreakOut") next bar at shortLiqPoint stop;
		BuyToCover("ShortLiq-FBO") from entry("SFailedBO") next bar at shortLiqPoint stop;
		BuyToCover("ShortLiq-RLoss") from entry("LongLiqRev") next bar at shortLiqPoint1 stop;			
	end;
end;
SetExitOnClose;
TradeManagement (Enter on Stop Loss or Not?)

This code looks a little hairy, but its not.  Let’s just look at the long side logic to save time here.  First let’s calculate the LongLiqPoints (1 and 2.)  Twenty years ago I thought it would be better to have a smaller stop for entries that occurred on a LiquidationReversal.  Oh yeah that code is in here to.  Back in the day I wanted to make sure the stop was at least 3 handles – ha, ha, ha – no really I am serious.  Really.  Stop laughing!! That code could be eliminated.  After calculating these two points I start to monitor profit and if it reaches a predetermined level I pull the the longLiqPoints toa  BreakEven stop.  If you are fortunate to still be in a trade after initTradesEndTime, then I start trailing the stop by the lowest low of the last 3 five minute bars – I don’t want to turn a small winner into a loser.  Now this is the fun stuff.

  1. if(Time < liqRevEndTime and sellsToday = 0 and
    longLiqPoint <> EntryPrice and BarsSinceEntry >= 4) then
  2.      SellShort(“LongLiqRev”) next bar at longLiqPoint stop;

If time is less than liqRevEndTime and BarsSinceEntry, then reverse and go short at the longLiqPoint stop.  Do this instead of liquidating.  I thought if the market reversed course quickly, then I wanted to take advantage of this counter trend move.  Eliminating this to see if it has any impact would be where I would start to play around with the template.  Okay now the liquidations based on from Entry take place next.  If I am long from a “ShortLiqRev“, then I use longLiqPoint1 instead of longLiqPoint.  Okay that last part was the kitchen sink.  Now you have enough code to make your own day trading system – really too much code, but you should be able to hobble something together from these parts.  Let me know if you can create your own Frankenstein monster.  I will update the parameters to see if there is any hope to the system as a whole.  Keep checking back for updated performance metrics.  Best to all and be safe!

 

 

Please follow and like us:

A Quant’s ToolBox: Beautiful Soup, Python, Excel and EasyLanguage

Many Times It Takes Multiple Tools to Get the Job Done

Just like a mechanic, a Quant needs tools to accomplish many programming tasks.  In this post, I use a toolbox to construct an EasyLanguage function that will test a date and determine if it is considered a Holiday in the eyes of the NYSE.

Why a Holiday Function?

TradeStation will pump holiday data into a chart and then later go back and take it out of the database.  Many times the data will only be removed from the daily database, but still persist in the intraday database.  Many mechanical day traders don’t want to trade on a shortened holiday session or use the data for indicator/signal calculations.  Here is an example of a gold chart reflecting President’s Day data in the intra-day data and not in the daily.

Holiday Data Throws A Monkey Wrench Into the Works

This affects many stock index day traders.  Especially if automation is turned on.  At the end of this post I provide a link to my youTube channel for a complete tutorial on the use of these tools to accomplish this task.  It goes along with this post.

First Get The Data

I searched the web for a list of historical holiday dates and came across this:

Historic List of Holidays and Their Dates

You might be able to find this in a easier to use format, but this was perfect for this post.

Extract Data with Beautiful Soup

Here is where Python and the plethora of its libraries come in handy.  I used pip to install the requests and the bs4 libraries.  If this sounds like Latin to you drop me an email and I will shoot you some instructions on how to install these libraries.  If you have Python, then you have the download/install tool known as pip.

Here is the Python code.  Don’t worry it is quite short.

# Created:     24/02/2020
# Copyright:   (c) George 2020
# Licence:     <your licence>
#-------------------------------------------------------------------------------

import requests
from bs4 import BeautifulSoup

url = 'http://www.market-holidays.com/'
page = requests.get(url)
soup = BeautifulSoup(page.text,'html.parser')
print(soup.title.text)
all_tables = soup.findAll('table')
#print (all_tables)
print (len(all_tables))
#print (all_tables[0])
print("***")
a = list()
b = list()
c = list()
#print(all_tables[0].find_all('tr')[0].text)
for numTables in range(len(all_tables)-1):
    for rows in all_tables[numTables].find_all('tr'):
        a.append(rows.find_all('td')[0].text)
        b.append(rows.find_all('td')[1].text)

for j in range(len(a)-1):
    print(a[j],"-",b[j])
Using Beautiful Soup to Extract Table Data

As you can see this is very simple code.  First I set the variable url to the website where the holidays are located.  I Googled on how to do this – another cool thing about Python – tons of users.  I pulled the data from the website and stuffed it into the page object.  The page object has several attributes (properties) and one of them  is a text representation of the entire page.  I pass this text to the BeautifulSoup library and inform it to parse it with the html.parser.  In other words, prepare to extract certain values based on html tags.  All_tables contains all of the tables that were parsed from the text file using Soup.  Don’t worry how this works, as its not important, just use it as a tool.  In my younger days as a programmer I would have delved into how this works, but it wouldn’t be worth the time because I just need the data to carry out my objective; this is one of the reasons classically trained programmers never pick up the object concept.  Now that I have all the tables in a list I can loop through each row in each table.  It looked liker there were 9 rows and 2 columns in the different sections of the website, but I didn’t know for sure so I just let the library figure this out for me.  So I played around with the code and found out that the first two columns of the table contained the name of the holiday and the date of the holiday.  So, I simply stuffed the text values of these columns in two lists:  a and b.  Finally I print out the contents of the two lists, separated by a hyphen, into the Interpreter window.  At this point I could simply carry on with Python and create the EasyLanguage statements and fill in the data I need.  But I wanted to play around with Excel in case readers didn’t want to go the Python route.  I could have used a powerful editor such as NotePad++ to extract the data from the website in place of Python.  GREP could have done this.  GREP is an editor tool to find and replace expressions in a text file.

Use Excel to Create Actual EasyLanguage – Really!

I created a new spreadsheet.  I used Excel, but you could use any spreadsheet software.   I first created a prototype of the code I would need to encapsulate the data into array structures.  Here is what I want the code to look like:

Arrays: holidayName[300](""),holidayDate[300](0);

holidayName[1]="New Year's Day ";	holidayDate[1]=19900101;
Code Prototype

This is just the first few lines of the function prototype.  But you can notice a repetitive pattern.  The array names stay the same – the only values that change are the array elements and the array indices.  Computers love repetitiveness.  I can use this information a build a spreadsheet – take a look.

Type EasyLanguage Into the Columns and Fill Down!

I haven’t copied the data that I got out of Python just yet.  That will be step 2.  Column A has the first array name holidayName (notice I put the left square [ bracket in the column as well).  Column B will contain the array index and this is a formula.  Column C contains ]=”.  Column D will contain the actual holiday name and Column E contains theThese columns will build the holidayName array.  Columns G throuh K will build the holidayDates array.    Notice column  H  equals column B.  So whatever we do to column B (Index) will be reflected in Column H (Index).  So we have basically put all the parts of the EasyLanguage into  Columns A thru K. 

Excel provides tools for manipulating strings and text.  I will use the Concat function to build my EasyLanguageBut before I can use Concat all the stuff I want to string together must be in a string or text format.  The only column in the first five that is not a string is Column B.  So the first thing I have to do is convert it to text.  First copy the column and paste special as values.  Then go to your Data Tab and select Text To Columns. 

Text To Columns

It will ask if fixed width or delimited – I don’t think it matters which you pick.  On step 3 select text.

Text To Columns – A Powerful Tool

The Text To Columns button will solve 90% of your formatting issues in Excel.    Once you do this you will notice the numbers will be left justified – this signifies a text format.  Now lets select another sheet in the workbook and past the holiday data.

Copy Holiday Data Into Another Spreadsheet

New Year's Day - January 1, 2021
Martin Luther King, Jr. Day - January 18, 2021
Washington's Birthday (Presidents' Day) - February 15, 2021
Good Friday - April 2, 2021
Memorial Day - May 31, 2021
Independence Day - July 5, 2021
Labor Day - September 6, 2021
Thanksgiving - November 25, 2021
Christmas - December 24, 2021
New Year's Day - January 1, 2020
Martin Luther King, Jr. Day - January 20, 2020
Washington's Birthday (Presidents' Day) - February 17, 2020
Good Friday - April 10, 2020
Memorial Day - May 25, 2020
Holiday Output

 

Data Is In Column A

Text To Columns to the rescue.  Here I will separate the data with the “-” as delimiter and tell Excel to import the second column in Date format as MDY.  

Text To Columns with “-” as the delimiter and MDY as Column B Format

Now once the data is split accordingly into two columns with the correct format – we need to convert the date column into a string.

Convert Date to a String

Now the last couple of steps are really easy.  Once you have converted the date to a string, copy Column A and past into Column D from the first spreadsheet.  Since this is text, you can simply copy and then paste.  Now go back to Sheet 2 and copy Column C and paste special [values] in Column J on Sheet 1.  All we need to do now is concatenate the strings in Columns A thru E for the EasyLanguage for the holidayName array.  Columns G thru K will be concatenated for the holidayDate array.  Take a look.

Concatenate all the strings to create the EasyLanguage

Now create a function in the EasyLanguage editor and name it IsHoliday and have it return a boolean value.  Then all you need to do is copy/paste Columns F and L and the data from the website will now be available for you use.   Here is a portion of the function code.  Notice I declare the holidayNameStr as a stringRef?  I did this so I could change the variable in the function and pass it back to the calling routine.

Inputs : testDate(numericSeries),holidayNameStr(stringRef);

Arrays: holidayName[300](""),holidayDate[300](0);

holidayNameStr = "";

holidayName[1]="New Year's Day ";	holidayDate[1]=19900101;
holidayName[2]="Martin Luther King, Jr. Day ";	holidayDate[2]=19900115;
holidayName[3]="Washington's Birthday (Presidents' Day) ";	holidayDate[3]=19900219;
holidayName[4]="Good Friday ";	holidayDate[4]=19900413;
holidayName[5]="Memorial Day ";	holidayDate[5]=19900528;
holidayName[6]="Independence Day ";	holidayDate[6]=19900704;
holidayName[7]="Labor Day ";	holidayDate[7]=19900903;
holidayName[8]="Thanksgiving ";	holidayDate[8]=19901122;
holidayName[9]="New Year's Day ";	holidayDate[9]=19910101;
holidayName[10]="Martin Luther King, Jr. Day ";	holidayDate[10]=19910121;
holidayName[11]="Washington's Birthday (Presidents' Day) ";	holidayDate[11]=19910218;

// There are 287 holiays in the database.
// Here is the looping mechanism to compare the data that is passed
// to the database

vars: j(0);
IsHoliday = False;
For j=1 to 287
Begin
	If testDate = holidayDate[j] - 19000000 then
	Begin
		holidayNameStr = holidayName[j] + " " + numToStr(holidayDate[j],0);
		IsHoliday = True;
	end;
end;
A Snippet Of The Function - Including Header and Looping Mechanism

This was a pretty long tutorial and might be difficult to follow along.  If you want to watch my video, then go to this link.

I created this post to demonstrate the need to have several tools at your disposal if you really want to become a Quant programmer.  How you use those tools is up to you.  Also you will be able to take bits and pieces out of this post and use in other ways to get the data you really need.  I could have skipped the entire Excel portion of the post and just did everything in Python.  But I know a lot of Quants that just love spreadsheets.  You have to continually hone your craft in this business.   And you can’t let one software application limit your creativity.  If you have a problem always be on the lookout for alternative platforms and/or languages to help you solve it.

 

 

Please follow and like us:

Free Trend Following System with Indicator Tracker

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: xAvgShortLen(50),xAvgLongLen(100),hhllLen(50),buyTrigPrice(h),shortTrigPrice(l),risk$Alloc(2000);
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 can 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: xAvgShortLen(50),xAvgLongLen(100),hhllLen(50),buyTrigPrice(h),shortTrigPrice(l);
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[1] > avg2[1] and buyTrigPrice[1] = highest(buyTrigPrice[1],hhllLen) then mp = 1;
If avg1[1] < avg2[1] and shortTrigPrice[1] = lowest(shortTrigPrice[1],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[1] = highestHigh(HIGH[1],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[1],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.

 

Please follow and like us:

A Christmas Project for TradeStation Day-Traders

Here is a neat little day trader system that takes advantage of what some technicians call a “CLEAR OUT” trade.  Basically traders push the market through yesterday’s high and then when everybody jumps on board they pull the rug out from beneath you.  This strategy tries to take advantage of this.  As is its OK, but it could be made into a complete system with some filtering.  Its a neat base to start your day-trading schemes from.

But first have you ever encountered this one when you only want to go long once during the day.

I have logic that examines marketPosition, and if it changes from a non 1 value to 1 then I increment buysToday.  Since there isn’t an intervening bar to establish a change in marketPosition, then buysToday does not get incremented and another buy order is issued.  I don’t want this.  Remember to plot on the @ES.D.

Here’s how I fixed it and also the source of the CLEAR-OUT day-trade in its entirety.  I have a $500 stop and a $350 take profit, but it simply trades way too often.  Have fun with this one – let me now if you come up with something.

inputs: clearOutAmtPer(0.1),prot$Stop(325),prof$Obj(500),lastTradeTime(1530);

vars: coBuy(false),coSell(false),buysToday(0),sellsToday(0),mp(0),totNumTrades(0);

If d <> d[1] then
Begin
	coBuy = false;
	coSell = false;
	buysToday = 0;
	sellsToday = 0;
	totNumTrades = totalTrades;
end;

 
mp = marketPosition;
If mp[1] <> mp and mp = 1 then buysToday = buysToday + 1;
If mp[1] <> mp and mp = -1 then sellsToday = sellsToday + 1;

If h > highD(1) + clearOutAmtPer * (highD(1) - lowD(1)) then coSell = true;
If l < lowD(1) - clearOutAmtPer * (highD(1) - lowD(1)) then coBuy = true;

If totNumTrades <> totalTrades and mp = 0 and mp[1] = 0 and positionProfit(1) < 0 and entryPrice(1) > exitPrice(1) then buysToday = buysToday + 1;
If totNumTrades <> totalTrades and mp = 0 and mp[1] = 0 and positionProfit(1) < 0 and entryPrice(1) < exitPrice(1) then sellsToday =sellsToday + 1;

totNumTrades = totalTrades;

If buysToday = 0 and t < lastTradeTime and coBuy = true then buy ("COBuy") next bar at lowD(1) + minMove/priceScale stop;
If sellsToday = 0 and t < lastTradeTime and coSell = true then sellShort ("COSell") next bar at highD(1) - minMove/priceScale stop;

setStopLoss(prot$stop);
Setprofittarget(prof$Obj);
setExitOnClose;
Look at lines 22 and 23 - the entry/exit same bar fix

Please follow and like us:

Testing Keith Fitschen’s Bar Scoring with Pattern Smasher

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[0]> c[1] and c[0] > o[0] and c[0] > (h[0] + l[0])/2  then patternString = "----";
if c[0]> c[1] and c[0] > o[0] and c[0] < (h[0] + l[0])/2  then patternString = "---+";
if c[0]> c[1] and c[0] < o[0] and c[0] > (h[0] + l[0])/2  then patternString = "--+-";
if c[0]> c[1] and c[0] < o[0] and c[0] < (h[0] + l[0])/2  then patternString = "--++";
if c[0]< c[1] and c[0] > o[0] and c[0] > (h[0] + l[0])/2  then patternString = "-+--";
if c[0]< c[1] and c[0] > o[0] and c[0] < (h[0] + l[0])/2  then patternString = "-+-+";
if c[0]< c[1] and c[0] < o[0] and c[0] > (h[0] + l[0])/2  then patternString = "-++-";
if c[0]< c[1] and c[0] < o[0] and c[0] < (h[0] + l[0])/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[4](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] = 0;
patternBitChanger[1] = 0;
patternBitChanger[2] = 0;
patternBitChanger[3] = 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[0] = 1;
    value2 = value1 - patternBitChanger[0] * 1;
  
    if(value2 >= 7) then begin
        patternBitChanger[3] = 1;
        value2 = value2 - 8;
    end;
 
    if(value2 >= 4) then begin
        patternBitChanger[2] = 1;
        value2 = value2 - 4;
    end;
    if(value2 = 2) then patternBitChanger[1] = 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[0]> c[1] and c[0] > o[0] and c[0] > (h[0] + l[0])/2  then patternString = "----";
if c[0]> c[1] and c[0] > o[0] and c[0] < (h[0] + l[0])/2  then patternString = "---+";
if c[0]> c[1] and c[0] < o[0] and c[0] > (h[0] + l[0])/2  then patternString = "--+-";
if c[0]> c[1] and c[0] < o[0] and c[0] < (h[0] + l[0])/2  then patternString = "--++";
if c[0]< c[1] and c[0] > o[0] and c[0] > (h[0] + l[0])/2  then patternString = "-+--";
if c[0]< c[1] and c[0] > o[0] and c[0] < (h[0] + l[0])/2  then patternString = "-+-+";
if c[0]< c[1] and c[0] < o[0] and c[0] > (h[0] + l[0])/2  then patternString = "-++-";
if c[0]< c[1] and c[0] < o[0] and c[0] < (h[0] + l[0])/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;
		if(LorS = 1) then buy("PatternBuy") next bar at 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
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: