Wednesday, March 31, 2010

Why isn't my 2X Ultra ETF keeping pace with the market and what is path asymmetry (R ex)?

I've been reading a few articles lately, lambasting ultra ETFs for not keeping up with markets and ascribing the problem to weird unexplainable reasons such as portfolio derivative re-balancing and negative drift. I thought it would be nice to revisit the concept of path asymmetry. Although there are many different definitions of price asymmetry (econometrics for example), in this case I'm simply referring to the asymmetrical nature of percentage price movements vs dollar movements and their final cumulative outcome given any arbitrary path.



Fig 1. Example of ultra 2X ETFs and path asymmetry

Many people seem to find it incomprehensible (if not reprehensible) that an underlying series may move a certain direction, yet, both the ultra short and ultra long series both finish below the underlying over the long run. What exactly is path asymmetry? Some traders might be familiar with the notion that if you lose some percentage of your account, like 50%, that you need more than 50% to make up for the loss. That is an example of path asymmetry (I should note someone also mentioned it's an example of Seigel's paradox).

Let's look at a very simple example of how this might affect a stock and it's 2x counterparts. Suppose a stock moves from 100dollars to 80 and back to 100 again-- break-even. The move from 100 to 80 on a percentage basis, was a 20% loss. However, to recoup that amount, we need to solve for 80*(1+x)=100; the answer is 25%, not 20%. This means even though the dollar amount is identical for both moves (20dollars down and up), the %amount is not. That is an example of path asymmetry. How does this affect the 2X ultra Leveraged ETFs? Well, since each ETF is designed to track twice the daily move of the underlying, the the +2x ETF will move 40% down, then it will move 50% back up, for a net dollar ending value of 90 dollars. The -2x ETF will move up 2x or 40% to 140, and then retrace -50% leaving it at only 70 dollars. Notice in both cases, each ultra ETF ends up below the underlying price. It is the simple mechanics of path dependency and asymmetry that account for this, even with perfect 2x leveraging. It is important to take into account path dependencies when dealing with any leveraged product, including hedging.

Now keep in mind, there is additional drag on these products, due to fund expenses, which does add merit to the original question. More on this is explained succinctly in this article by Alpha's Tristan Yates and Lye Kok .

Wednesday, March 24, 2010

Modified Donchian Band Trend Follower using R, Quantmod, TTR -Part 2: Parameter Sweep Sensitivity over long run

Here is a small update to the Donchian Channel type system I displayed in the last post.



Fig 1. Sensitivity of Net Combined L/S Gain to parameter n.

Using the S&P500 index as a proxy for the market, a simulation was run over the lifetime of the index. Notice the system excels in both the very short run, and much longer periods. The short system did very poorly overall and did not perform nowhere near the long side in any of the overall periods (except maybe very short term). A possible explanation is that short side systems do not do very well in the long run due to upward drift of markets. In addition, short side runs do not have the inherent compounding power of long sides as they are asymmetrical. The most you gain on a short run is double your original value, where the long side is unlimited (one way around this limitation is using inverse ETFs). I believe many common simulators err in the effects and method of this computation.



Fig 2. Some long term results of strategy with parameter n=140

The above figure shows the results of choosing a parameter near the optimal region. In light of commissions and limited short strategy performance over longer periods, it might pay to use the long only portion of the strategy. Another observation is to possibly step aside during highly volatile regions in order to capture the beneficial areas of the long strategy. Some of the methods to approach this type of regime switching have been mentioned in earlier posts.

One last comment to think about when hearing detractors regarding 'curve fitting' and optimization, is that as evidenced in the above simulation, you will often find the the local optimal parameter value turns out to be the most robust, as it will perform best over a wide range of sensitivity to parametrization.

Friday, March 12, 2010

Modified Donchian Band Trend Follower using R, Quantmod, TTR

I've been toying around with the examples given on the FOSS trading site for some of the great work they've put together in the Quantmod and TTR packages. Those viewers who are looking for a nice (and free) backtesting suite to possibly complement some of your other results or work in say, Weka, should familiarize yourselves with R. Not only can it serve as a canvas to simulate ideas and concepts, but can process the backend results towards more trader oriented metrics, than using something like Weka as a standalone tool. As you gain more proficiency in data mining and machine learning concepts in Weka, you can also make the move to integrate the tools inside of R, as R contains the majority of machine learning schemes inside of various packages.



Fig 1. Modified Donchian Channel System Simulation

As an example of how to use some of their tools (along with traditional R packages) for fast prototyping, I put together an example of a modified Donchian Channel trend following system along with how you might simulate it using R. The typical Donchian Channel Bands are used as breakout entry and exit signals. I.e. once an n period high has been breached you go long, then exit when the n period low has been breached -- visa versa for short. In this example, however, we simply enter long on the average line break and stay long as long as it is above. A short signal is entered on the average line break to the downside. Unlike a price/moving average type system, there wasn't a lot of choppiness causing false starts around the average line, which is a plus.

I am still trying to familiarize myself more with the tools, and am still at the point where I like how simple and fast the static vector computations work (similar to numpy in Python), but I am wondering how fast more sophisticated entry/exits requiring loops will work. I still expect to work on some of these types of scenarios, as I am really enjoying the capabilities of R along with some of these trading oriented packages.

Although the system (using QQQQ as an example) is in no way optimized nor analyzed for robustness, it returned a respectable 60% versus a buy and hold loss over the past roughly two years (showing a simple example of trend type trading).

Here is the complete code for you to replicate (I used the R version 2.7.10.1).
Note: if some of it looks familiar to the FOSS RSI example, it is exactly because I used that example as a starting point, so there will be some overlap in comments and actions.

# We will need the quantmod package for charting and pulling
# data and the TTR package to calculate Donchian Bands.
# You can install packages via: install.packages("packageName")
# install.packages(c("quantmod","TTR"))
# See Foss Trading Blog for RSI template
library(quantmod)
library(TTR)

tckr<-"QQQQ"
tckr_obj<-QQQQ

start<-"2008-01-01"
end<- "2010-03-08"

# Pull tckr index data from Yahoo! Finance
getSymbols(tckr, from=start, to=end)
QQQQ.cl<-QQQQ[,6]
QQQQ.H<-QQQQ[,2]
QQQQ.L<-QQQQ[,3]
dc<-DonchianChannel(cbind(QQQQ.H,QQQQ.L),n=80)

#Plotting Donchian Channel
ymin=25
ymax=55


par(mfrow=c(2,2), oma=c(2,2,2,2))

# max, avg, min <- red, blue, green
plot(dc[,1],col="red",ylim=c(ymin,ymax),main="")
par(new=T)
plot(dc[,2],col="blue",ylim=c(ymin,ymax),main="")
par(new=T)
plot(dc[,3],col="green",ylim=c(ymin,ymax),main="")
par(new=T)
plot(QQQQ.cl,ylim=c(ymin,ymax),pch=15,main="donchian bands max/avg/min")
lines(QQQQ.cl,ylim(ymin,ymax))
###################################################


# Create the long (up) and short (dn) signals
sigup <-ifelse(QQQQ.cl > dc[,2],1,0)
sigdn <-ifelse(QQQQ.cl < dc[,2],-1,0)

# Lag signals to align with days in market,
# not days signals were generated
sigup <- lag(sigup,1) # Note k=1 implies a move *forward*
sigdn <- lag(sigdn,1) # Note k=1 implies a move *forward*

# Replace missing signals with no position
# (generally just at beginning of series)
sigup[is.na(sigup)] <- 0
sigdn[is.na(sigdn)] <- 0

# Combine both signals into one vector
sig <- sigup + sigdn

# Calculate Close-to-Close returns
ret <- ROC(tckr_obj[,6])
ret[1] <- 0

# Calculate equity curves
eq_up <- cumprod(1+ret*sigup)
eq_dn <- cumprod(1+ret*sigdn)
eq_all <- cumprod(1+ret*sig)

#graphics
mfg=c(1,2)
plot(eq_up,ylab="Long",col="green")
mfg=c(2,2)
plot(eq_all,ylab="Combined",col="blue",main="combined L/S equity")
mfg=c(2,1)
plot(eq_dn,ylab="Short",col="red")
title("Modified Donchian Band Trend Following System (intelligenttradingtech.blogspot.com)", outer = TRUE)

##############################################################################################################


P.S. As always, please use your own due diligence in all work borrowed from this site. There are some areas that I believe are not quite correct in the simulation framework, needless to say, you have a complete script to start your own examples and backtesting.