Simple Moving Average Strategy with a Volatility Filter: Follow-Up Part 1
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Analyzing transactions in quantstrat
This post will be part 1 of a follow up to the original post, Simple Moving Average Strategy with a Volatility Filter. In this follow up, I will take a closer look at the individual trades of each strategy. This may provide valuable information to explain the difference in performance of the SMA Strategy with a volatility filter and without a volatility filter.
Thankfully, the creators of the quantstrat package have made it very easy to view the transactions with a simple function and a single line of code.
getTxns(Portfolio, Symbol, Dates)
For the rest of the post, I will refer to the strategies as:
- Strategy 1 = Simple Moving Average Strategy with a Volatility Filter
- Strategy 2 = Simple Moving Average Strategy without a Volatility Filter
It is evident from the equity curves in the last post that neither strategy did much from the year 2000 to 2012. For that reason, I will analyze the period from 1990 to 2000
Strategy 1 Transactions
Txn.Qty Txn.Price Txn.Fees Txn.Value Txn.Avg.Cost Net.Txn.Realized.PL 1900-01-01 00:00:00 0 0.00 0 0.00 0.00 0.00 1992-10-23 00:00:00 410 414.10 0 169781.00 414.10 0.00 1994-04-08 00:00:00 -410 447.10 0 -183311.00 447.10 13530.00 1994-06-10 00:00:00 531 458.67 0 243553.77 458.67 0.00 1994-06-17 00:00:00 -531 458.45 0 -243436.95 458.45 -116.82 1995-05-19 00:00:00 247 519.19 0 128239.93 519.19 0.00 1998-09-04 00:00:00 -247 973.89 0 -240550.83 973.89 112310.90 1999-09-10 00:00:00 45 1351.66 0 60824.70 1351.66 0.00 1999-10-22 00:00:00 -45 1301.65 0 -58574.25 1301.65 -2250.45 1999-11-26 00:00:00 82 1416.62 0 116162.84 1416.62 0.00
Strategy 2 Transactions
Txn.Qty Txn.Price Txn.Fees Txn.Value Txn.Avg.Cost Net.Txn.Realized.PL 1900-01-01 00:00:00 0 0.00 0 0.00 0.00 0.00 1992-10-23 00:00:00 410 414.10 0 169781.00 414.10 0.00 1994-04-08 00:00:00 -410 447.10 0 -183311.00 447.10 13530.00 1994-06-10 00:00:00 531 458.67 0 243553.77 458.67 0.00 1994-06-17 00:00:00 -531 458.45 0 -243436.95 458.45 -116.82 1994-08-19 00:00:00 593 463.68 0 274962.24 463.68 0.00 1994-09-30 00:00:00 -593 462.71 0 -274387.03 462.71 -575.21 1994-10-07 00:00:00 562 455.10 0 255766.20 455.10 0.00 1994-10-14 00:00:00 -562 469.10 0 -263634.20 469.10 7868.00 1994-10-21 00:00:00 560 464.89 0 260338.40 464.89 0.00 1994-12-02 00:00:00 -560 453.30 0 -253848.00 453.30 -6490.40 1995-01-13 00:00:00 548 465.97 0 255351.56 465.97 0.00 1998-09-04 00:00:00 -548 973.89 0 -533691.72 973.89 278340.16 1998-10-02 00:00:00 66 1002.60 0 66171.60 1002.60 0.00 1998-10-09 00:00:00 -66 984.39 0 -64969.74 984.39 -1201.86 1998-10-23 00:00:00 68 1070.67 0 72805.56 1070.67 0.00 1999-10-22 00:00:00 -68 1301.65 0 -88512.20 1301.65 15706.64 1999-10-29 00:00:00 70 1362.93 0 95405.10 1362.93 0.00
For ease of comparison, I exported the transactions for each strategy to excel and aligned the trades as close I could by date.
First, lets look at the trades highlighted by the red rectangle. Strategy 2 executed a trade for 548 units on 1/13/1995 and closed on 9/4/1998 for a total profit of $278340.16. By comparison, Strategy 1 executed a trade for 247 units on 5/19/1995 (about 4 months later) and closed on 9/4/1998 for a total profit of $112,310.90. This is a significant difference of $166,029. It is clear that this single trade is critical to the performance of the strategy.
Now, lets look at the trade highlighted by the yellow rectangle. Both trades were closed on 10/22/1999. Strategy 1 resulted in a loss of $2,250.45 and Strategy 2 resulted in a gain of $15,706.64… a difference of $17,957.09.
The equity curve of Strategy 1 compared with Strategy 2 shows a clearer picture of the outperformance.
Why such a big difference?
For an even closer look, we will need to take a look at the measure of volatility we use as a filter. I will make a few modifications to the RB function so we can see the volatility measure and median.
#Function that calculates the n period standard deviation of close prices. #This is used in place of ATR so that I can use only close prices. SDEV <- function(x, n){ sdev <- runSD(x, n, sample = FALSE) colnames(sdev) <- "SDEV" reclass(sdev,x) } #Custom indicator function RB <- function(x,n){ x <- x roc <- ROC(x, n=1, type="discrete") sd <- runSD(roc,n, sample= FALSE) #sd[is.na(sd)] <- 0 med <- runMedian(sd,n) #med[is.na(med)] <- 0 mavg <- SMA(x,n) signal <- ifelse(sd < med & x > mavg,1,0) colnames(signal) <- "RB" ret <- cbind(x,roc,sd,med,mavg,signal) colnames(ret) <- c("close","roc","sd","med","mavg","RB") reclass(ret,x) } data <- cbind(RB(Ad(GSPC),n=52),SDEV(Ad(GSPC),n=52)) #RB is the volatility signal indicator and SDEV is used for position sizing Created by Pretty R at inside-R.org
> data['1995'] close roc sd med mavg RB SDEV 1995-01-13 00:00:00 465.97 0.0114830251 0.013545475 0.01088292 459.7775 0 8.924008 ... 1995-05-19 00:00:00 519.19 -0.0121016078 0.012412166 0.01259515 472.6006 1 21.161032
The sd for 1995-01-13 is 0.0135 while the SDEV is 8.924. The sd for 1995-05-19 is 0.0124 while the SDEV is 21.16… the SDEV is almost 3 times larger even though our volatility measure is indicating a period of low volatility! (note: SDEV has a direct impact on position sizing)
Perhaps we should take a second look at our choice of volatility measure.
If you want to incorporate a volatility filter into your system, choose the volatility measure wisely…
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.