Category Archives: TradingSimula18

Trading the Equity Curve – Part 1 of N?

Only Trade the Best Segments of the Equity Curve – Cut Out Drawdown and Take Advantage of Run Ups! Really?

Equity curve feedback has been around for many years and seems highly logical, but one can’t get an industry-wide agreement on its benefit.  The main problem is to know when to turn trading off and then back on as you track the equity curve.  The most popular approach is to use a moving average of the equity curve to signal system participation.   When the equity curve moves below 30, 60, or 90 period-moving average of equity, then just turn it off and wait until the curve crosses back above the average.  This approach will be investigated in Part 2 of this series.  Another approach is to stop trading once the curve enters a drawdown that exceeds a certain level and then start back up once the equity curve recovers.  In this post, this method will be investigated.

Programmers Perspective

How do you go about programming this tool to start with.  There are probably multiple ways of accomplishing this task, but the two I have most often observed were the two pass process and the inline simultaneous tracking of the synthetic and actual equity curves.  The two pass process generates an unadulterated equity curve and stores the equity and trades either in memory or in a file.  The second part of the process monitors the external equity curve along with the external trades synchronously and while trading is turned on, the trades are executed as they occur chronologically.  When trading is turned off, the synthetic equity curve and trades are processed along the way.   The second method is to create, which I have coined (maybe others too!), a synthetic equity curve and synthetic trades.  I have done this in my TradingSimula_18 software by creating a SynthTrade Class.  This class contains all the properties of every trade and in turn can use this information to create a synthetic equity curve.  The synthetic equity curve and trades are untouched by the real time trading.

Start Simple

The creation of an equity curve monitor and processor is best started using a very simple system.  One market algorithm that enters and exits on different dates, where pyramiding and scaling in or out are not allowed.  The first algorithm that I tested was a mean reversion system where you buy after two consecutive down closes followed by an up close and then waiting one day.  Since I tested the ES over the past 10 years you can assume the trend is up. I must admit that the day delay was a mistake on my behalf.  I was experimenting with a four bar pattern and somehow forgot to look at the prior day’s action.  Since this is an experiment it is OK!

if marketPosition <> 1 and 
(c[2] < c[3] and c[3] < c[4] and c[1]  > =  c[2]) then
buy next bar at open;

//The exit is just as simple -
//get out after four days (includeing entry bar) on the next bars open - no stops or profit objectives.  

If barsSinceEntry > 2 then sell next bar at open;
Simple Strategy to test Synthetic Trading Engine

Here is the unadulterated equity curve using $0 for execution costs.

Non adjusted equity curve of our simple mean reversion system. Wait for a pull back and then a rally before entering.

The Retrace and Recover Method

In this initial experiment, trading is suspended once you reach a draw down of 10% from the peak of the equity curve and then resumes trading once a rally of 15% of the subsequent valley.  Here is an intriguing graphic.

Green means ON. Red means OFF. The lower curve is the resultant curve.

I did this analysis by hand with Excel and it is best case scenario.  Meaning that when trading is turned back on any current synthetic position is immediately executed in the real world.  This experiment resulted in nearly the same drawdown but a large drop in overall equity curve growth – $75K.

Put the Synthetic Equity Curve Engine to the Test

Now that I had the confirmed results of the experiment, I used them as the benchmark against my TS-18 Synthetic Trade Engine.  But before I installed the Equity Curve algorithm, I needed to make sure my synthetic trades lined up exactly with the real equity curve.  The synthetic curve should align 100% with the real equity curve.  If it doesn’t, then there is a problem.  This is another reason to start with a simple trading strategy.

Take a look here where I print out the Synthetic Equity curve on  a daily basis and compare it with the end result of the analysis.

Synth. matches Reality

Now let’s see if it worked.

Testing with Synth. Equity Curve Trading Turned ON!

The equity curves are very similar.  However, there is a difference and this is caused by how one re-enters after trading is turned back on.  In this version I tested waiting for a new trade signal which might take a few days.  You could re-enter in three different ways:

  1. Automatically enter synthetic position on the next bar’s open
  2. Wait for a new trade signal
  3. Enter immediately if you can get in at a better price

Using the 10% Ret. and 15% Rec. algorithm didn’t help at all.  What if we test 10% and 10%.

10% Ret. and 10% Rec.

Now that performed better – more profit and less draw down.  Now that I have the synthetic engine working on simple algorithms we can do all sorts of equity curve analysis.  In the next installment in this series I will make sure the TS-18 Synthetic Engine can handle more complicated entry and exit algorithms.  I have already tested a simple longer term trend following strategy on a medium sized portfolio and the synthetic engine worked fine.  The retracement/recovery algorithm at 10%/15% did not work and I will go into the “whys” in my next post.

Another Good Year For Trend Following

Take a Look at the Last Two Years

Simple Donchian on a one contract basis.  $100 Commission/slippage.  Tested from 2000 thru December 31, 2021.  Do you see why most trend followers failed after the 2008 monstrous year.   Many funds caught the 2008 move and more funds were added soon thereafter.  Promises of similar performance came to fruition in 2011.  This kept much of the “new money” on the board.  However, reality set in and weak handed funds left for greener pastures.  Those that stuck it out were rewarded in 2014.  The trend drought of 2014 -2019 eroded most of the confidence in managed futures.  The rationalization that limited resources would eventually rise in price sounded good initially, but then fell on deaf ears after months of draw down.  Well known CTAs and hedge funds shut their doors forever.   The long awaited promise of 2008 came in the form of a pandemic – but it was too late.   Maybe now the deluge that ended the drought will persevere (hopefully not in the form of a pandemic) into the future.  Prices do not need to rise endlessly, but they need to move one direction or another without many hiccups.   

Simple Donchian Caught Most of the Commodities Up Moves

Which Sectors Pushed this Curve through the Roof

These reports were generated by my Python based Trading Simula-18 using Pinnacle continuous data – rollover triggered by date.  This is my new sector analysis report where I graph the last four years performance.  The tabular data is for the entire 21 year history.  The best sectors were energy, grains, financials and metals.  Lumber was extraordinary

Sector Analysis Report
################################################
Currency -------------------------------------
BN -28012 44681
SN -26925 55337
AN 6560 34350
DX 16284 24387
FN 67463 31737
JN -22212 50362
CN -25355 44110
------------------------------------------------
Totals: -12198 141445
------------------------------------------------
Currency Last 4 Years ---------------------
|
||| |
||||||
| ||||||||
| |||||||||
| ||||||||||
|||||||||||||
||||||||||||||
|||||||||||||| |
|||||||||||||||||||
||||||||||||||||||||| |
|||||||||||||||||||||| | |
|||||||||||||||||||||| | |
|||||||||||||||||||||| | || | | |
------------------------------------------------ 0
||||||||||||||||||||||||| ||| |||| ||| |
||||||||||||||||||||||||| |||| |||||||||||
||||||||||||||||||||||||| | |||| ||||||||||||
||||||||||||||||||||||||||| |||||||||||||||||
|||||||||||||||||||||||||||| ||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||
2018--------2019--------2020--------2021--------
################################################
Energies -------------------------------------
ZU 180750 38330
ZH 155696 85541
ZN 70630 74400
ZB 131874 66651
------------------------------------------------
Totals: 538951 154434
------------------------------------------------
Energies Last 4 Years ---------------------
| |
|| || ||
||| || |||
| ||||||||||
| |||||||||||
||| |||||||||||
|||| | ||||||||||||
||||||| ||||||||||||
|||||||||||||||||||||
|||||||||||||||||||||
|||||||||||||||||||||
|||||||||||||||||||||
| || |||||||||||||||||||||
|| || |||||||||||||||||||||
|| |||| |||||||||||||||||||||
||||||||| ||||||||||||||||||||||
| |||||||||| |||||||||||||||||||||||
|| || |||||||||||||||||||||||||||||||||||||
|||||| |||||||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||
2018--------2019--------2020--------2021--------
################################################
Metals -------------------------------------
ZG -17070 43540
ZI 68395 146885
ZK 101888 29475
ZP 82885 27600
ZA 174955 83910
------------------------------------------------
Totals: 411052 166703
------------------------------------------------
Metals Last 4 Years ---------------------
|
| | |
|| || |
|| |||| |||
| ||| | |||||||||
|| |||||||||||||||||
|| |||||||||||||||||||
|||||||||||||||||||||||
|||||||||||||||||||||||
|||||||||||||||||||||||
| | ||||||||||||||||||||||||
||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||
|| |||||||||||||||||||||||||||||||
|||||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||
|| |||||||||||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||
2018--------2019--------2020--------2021--------
################################################
Grains -------------------------------------
ZS 79175 20312
ZW -43438 51975
ZC 5238 26688
ZL 13248 24588
ZM 29860 28810
------------------------------------------------
Totals: 84083 88850
------------------------------------------------
Grains Last 4 Years ---------------------
|
|
||
||
|||||||||
|||||||||||
|||||||||||
|||||||||||
||||||||||||
| ||||||||||||
| | ||||||||||||
| || ||| ||||||||||||
||||| ||||| |||||||||||||
|||||||||||| |||||||||||||
|||||||||||| ||| | |||||||||||||
||||||||||||| ||||||| || ||||||||||||||
|||||||||||||||||||||||||||| ||||||||||||||
|||||||||||||||||||||||||||||| |||||||||||||||
||||||||||||||||||||||||||||||| |||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||
2018--------2019--------2020--------2021--------
################################################
Financials -------------------------------------
US 35991 24959
TY -350 29175
TU 1473 23969
EC 4700 9650
------------------------------------------------
Totals: 41813 56453
------------------------------------------------
Financials Last 4 Years ---------------------
| | ||||
||| | |||||
||| | || ||||||
||||| ||||||||||
|||||| ||||||||||
|||||||| ||||||||||
|||||||| ||||||||||
||||||||| |||||||||||
||||||||||||||||||||||
| ||||||||||||||||||||||
| ||||||||||||||||||||||
| | ||||||||||||||||||||||
| | || ||||||||||||||||||||||
|| |||||| |||||||||||||||||||||||
||| |||||||||||||||||||||||||||||||
|||| || | |||||||||||||||||||||||||||||||
||||| |||| |||||||||||||||||||||||||||||||
||||||| ||||||||||||||||||||||||||||||||||||
|||||||| ||||||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||
2018--------2019--------2020--------2021--------
################################################
Softs -------------------------------------
SB 25927 15035
KC -49775 94069
CC -72140 76660
CT 16785 45470
Lumber 218513 51745
JO 2588 15760
------------------------------------------------
Totals: 141898 128540
------------------------------------------------
Softs Last 4 Years ---------------------
| ||
||||
|||||
|||||
||||||
| ||||||
||||||||
||||||||
||||||||
||||||||
------------------------------------------------ 0
| | |||||||||
| | ||||||||||
||||||||||||||||
||||||||||||||||
|||||||||||||||||
|||||||||||||||||
|| | ||||||||||||||||||
| ||||||||||| | |||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||
2018--------2019--------2020--------2021--------
################################################
Meats -------------------------------------
ZT -29940 57680
ZZ 38480 15080
ZF 18413 57550
------------------------------------------------
Totals: 26952 66515
------------------------------------------------
Meats Last 4 Years ---------------------
| ||
| || ||
|| | || ||
||| | || ||
||||||||| ||||
| |||||||||| ||||
| | ||||||||||| |||||
| | ||||||||||| |||||| |
| || |||||||||||||||||| |
| ||| | |||||||||||||||||||||
|| ||| | |||||||||||||||||||||
|||||| || | ||||||||||||||||||||| |
|||||| || |||||||||||||||||||||||| |
|||||| || ||||||||||||||||||||||||||
|||||||| | || ||||||||||||||||||||||||||
|||||||| | ||| ||||||||||||||||||||||||||
|||||||||| | |||||||||||||||||||||||||||||||
||||||||||| | |||||||||||||||||||||||||||||||
|||||||||||| || ||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||
2018--------2019--------2020--------2021--------

How Do You Program this in Python

Here is the module for TS-18.  There is a little extra code to keep track of sectors in case you want to limit sector exposure.  However, this code takes every trade on a one contract basis.  This code reflects my latest version of TS-18, which will be released shortly.

#  Define Long, Short, ExitLong and ExitShort Levels - mind your indentations
buyLevel = highest(myHigh,40,curBar,1)
shortLevel = lowest(myLow,40,curBar,1)
longExit = lowest(myLow,20,curBar,1)
shortExit = highest(myHigh,20,curBar,1)
ATR = sAverage(myTrueRange,30,curBar,1)
stopAmt = 2000/myBPV

ATR = sAverage(myTrueRange,30,curBar,1)

posSize = 1
mmLxit = 99999999
mmSxit = -99999999
if mp == 1 : mmLxit = entryPrice[-1] - stopAmt
if mp ==-1 : mmSxit = entryPrice[-1] + stopAmt



# Long Exit
if mp == 1 and myLow[curBar] <= mmLxit and mmLxit > longExit and barsSinceEntry > 1:
price = min(myOpen[curBar],mmLxit)
tradeName = "LxitMM"
numShares = curShares
exitPosition(price, curShares, tradeName, sysMarkDict)
unPackDict(sysMarkDict)
# Long Exit
if mp == 1 and myLow[curBar] <= longExit and barsSinceEntry > 1:
price = min(myOpen[curBar],longExit)
tradeName = "Lxit"
numShares = curShares
exitPosition(price, curShares, tradeName, sysMarkDict)
unPackDict(sysMarkDict)
# Short Exit
if mp == -1 and myHigh[curBar] >= shortExit and barsSinceEntry > 1:
price = max(myOpen[curBar],shortExit)
tradeName = "Sxit"
numShares = curShares
exitPosition(price, curShares, tradeName, sysMarkDict)
unPackDict(sysMarkDict)
# Short Exit
if mp == -1 and myHigh[curBar] >= entryPrice[-1] + stopAmt and barsSinceEntry > 1:
price = max(myOpen[curBar],entryPrice[-1] + stopAmt)
tradeName = "SxitMM"
numShares = curShares
exitPosition(price, curShares, tradeName,sysMarkDict)
unPackDict(sysMarkDict)
# Long Entry
if myHigh[curBar] >= buyLevel and mp !=1:
price = max(myOpen[curBar],buyLevel)
tradeName = "Simple Buy"
numShares = posSize
enterLongPosition(price,numShares,tradeName,sysMarkDict)
unPackDict(sysMarkDict)
# Short Entry
if myLow[curBar] <= shortLevel and mp !=-1 :
price = min(myOpen[curBar],shortLevel)
if mp == 0 : sectorTradesTodayList[curSector] +=1
tradeName = "Simple Sell"
numShares = posSize
enterShortPosition(price, numShares, tradeName, sysMarkDict)
unPackDict(sysMarkDict)
Python within Trading Simula-18

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.

 

The Cure for the Common Trend Follower – SOTF Part 2

Clenow’s algorithm is definitely an indicator for the current State of Trend Following (SOTF).  However, the 3 X ATR trailing stop mechanism actually dampens the profit/draw down ratio.  Take a look at this chart.

Battle of Titans

All Trend Following mechanisms have a very common thread in their entry mechanisms.   The thing that separates them is the preemptive exit.  Do you allow the the algorithm to exit on a purely market defined method or do you overlay trade management?  Here the best approach was to let the Bollinger Band system run unfettered; even though it seems somewhat illogical.  Many times  trade management actually increases draw down.   Is there a solution?  What about this – keep risk down by trading a small, yet diverse portfolio of high volume markets and overlay it with a stock index mean reversion algo.  Take a look.

Bollinger Marries ES Reversion

 

Should’ve, Would’ve , Could’ve.

This could be scaled up.  The mean reversion helped lift  the chart out of the flat and draw down periods of late.  However, the smaller portfolio did OK during this time period too!  Can four or five high volume markets replicate a much larger portfolio?  All tests were carried out with TradingSimula18 – the software that comes with my latest book.

State of Trend Following – Part 1

Clenow’s Trend Following System

Its a new decade! Time to see what’s up with Trend Following.

I am a huge fan of Andreas Clenow’s books, and how he demonstrated that a typical trader could replicate the performance of most large Trend Following CTAs and not pay the 2% / 20% management/incentive combo fees.  So. I felt the system that he described in his book would be a great representation of The State of Trend Following.  At the same time I am going to demonstrate TradingSimula18 (the software included in my latest book).

System Description

Take a look at my last post.  I provide the EasyLanguage and a pretty good description of Clenow’s strategy.

TradingSimula18 Code [Python]

#---------------------------------------------------------------------------------------------------
# Start programming your great trading ideas below here - don't touch stuff above
#---------------------------------------------------------------------------------------------------
# Define Long, Short, ExitLong and ExitShort Levels - mind your indentations
ATR = sAverage(myTrueRange,30,curBar,1)
posSize = 2000/(ATR*myBPV)
posSize = max(int(posSize),1)
posSize = min(posSize,20)
avg1 = xAverage(myClose,marketVal5[curMarket],50,curBar,1)
avg2 = xAverage(myClose,marketVal6[curMarket],100,curBar,1)
marketVal5[curMarket] = avg1
marketVal6[curMarket] = avg2
donchHi = highest(myHigh,50,curBar,1)
donchLo = lowest(myLow,50,curBar,1)

if mp == 1 : marketVal1[curMarket] = max(marketVal1[curMarket],myHigh[curBar-1]- 3 * ATR)
if mp ==-1 : marketVal2[curMarket] = min(marketVal2[curMarket],myLow[curBar-1]+ 3 * ATR)
# Long Entry
if avg1 > avg2 and myHigh[curBar-1] == donchHi and mp !=1:
price = myOpen[curBar]
tradeName = "TFClenowB";numShares = posSize
marketVal1[curMarket] = price - 3 * ATR
if mp <= -1:
profit,curShares,trades = bookTrade(entry,buy,price,myDate[curBar],tradeName,numShares)
barsSinceEntry = 1
marketMonitorList[curMarket].setSysMarkTrackingInfo(tradeName,cumuProfit,mp,barsSinceEntry,curShares,trades)
# Long Exit
if mp == 1 and myClose[curBar-1] <= marketVal1[curMarket] and barsSinceEntry > 1:
price = myOpen[curBar]
tradeName = "Lxit";numShares = curShares
profit,curShares,trades = bookTrade(exit,ignore,price,myDate[curBar],tradeName,numShares)
todaysCTE = profit;barsSinceEntry = 0
marketMonitorList[curMarket].setSysMarkTrackingInfo(tradeName,cumuProfit,mp,barsSinceEntry,curShares,trades)
# Short Entry
if avg1 < avg2 and myLow[curBar-1] == donchLo and mp !=-1:
price = myOpen[curBar];numShares = posSize
marketVal2[curMarket] = price + 3 * ATR
if mp >= 1:
tradeName = "TFClenowS"
profit,curShares,trades = bookTrade(entry,sell,price,myDate[curBar],tradeName,numShares)
barsSinceEntry = 1
marketMonitorList[curMarket].setSysMarkTrackingInfo(tradeName,cumuProfit,mp,barsSinceEntry,curShares,trades)
# Short Exit
if mp == -1 and myClose[curBar-1] >= marketVal2[curMarket] and barsSinceEntry > 1:
price = myOpen[curBar]
tradeName = "Sxit"; numShares = curShares
profit,curShares,trades = bookTrade(exit,ignore,price,myDate[curBar],tradeName,numShares)
todaysCTE = profit;barsSinceEntry = 0
marketMonitorList[curMarket].setSysMarkTrackingInfo(tradeName,cumuProfit,mp,barsSinceEntry,curShares,trades)
#----------------------------------------------------------------------------------------------------------------------------
# - Do not change code below - trade, portfolio accounting - our great idea should stop here
#----------------------------------------------------------------------------------------------------------------------------
TradingSimula18 Python System Testing Environment

I am going to go over this very briefly.   I know that many of the readers of my blog have attempted to use Python and the various packages out there and have given up on it.  Quantopia and QuantConnect are great websites, but I feel they approach back-testing with a programmer in mind.  This was the main reason I created TS-18 – don’t get me wrong its not a walk in the park either, but it doesn’t rely on external libraries to get the job done.  All the reports I show here are generated from the data created solely by TS-18.  Plus it is very modular – Step 1 leads to Step2 and on and on.   Referring to the code I calculate the ATR (average true range) by calling the simple average function sAverage.  I pass it myTrueRanges, 30, curBar and 1.   I am looking for the average true range over the last 30 days.  I then move onto my position sizing – posSize = $2,000 / ATR in $s.  PosSize must fit between 1 and 20 contracts.  The ATR calculation can get rather small for some markets and the posSize can get rather large.  Avg1 and Avg2 are exponential moving averages of length 50 and 100DonchHi and donchLo are the highest high and lowest low of the past 50 days.   If mp == 1 (long position) then a trailing stop (marketVal1) is set to whichever is higher – the current marketVal1 or the yesterday’s High – 3 X ATR;  the trailing stop tracks new intra-trade highs.  The trailing stop for the short side, marketVal2 is calculated in a similar manner, but low prices are used as well as a positive offset of 3 X ATR.  

Now the next section of code is quite a bit different than say EasyLanguage, but parallels some of the online Python paradigms. Here you must test the current bar’s extremes against the donchHi if you are flat and marketVal1 (the trailing stop variable) if you are long.  If flat you also test the low of the bar against donchLo.  The relationship between avg1 and avg2 are also examined.  If the testing criteria is true, then its up to you to assign the correct price, posSize and tradeName.  So you have four independent if-then constructs:

  • Long Entry – if flat test to see if a long position should be initiated
  • Long Exit – if Long then test to see if a liquidation should be initiated
  • Short Entry – if flat test to see if a short position should be initiated
  • Short Exit – if Short then test to see if a liquidation should be initiated

That’s it – all of the other things are handled by TS-18.  Now that I have completely bored you out of your mind, let’s move onto some results.

Results from 2000 – risking $2,000 per trade:

Roller Coaster Ride for most CTAs, Last one out turn off the lights!

Sector Performance from 2000

Sector Performance from 2000

From this chart it doesn’t make much sense to trade MEATS, SOFTS or GRAINS with a Trend Following approach or does it?

In the next post, I will go over the results with more in depth and possibly propose some ideas that might or might not help.  Stay Tuned!