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 on topics such as: visualization (ggplot2, Boxplots, maps, animation), programming (RStudio, Sweave, LaTeX, SQL, Eclipse, git, hadoop, Web Scraping) statistics (regression, PCA, time series,ecdf, trading) and more...



Zero Inflated Models and Generalized Linear Mixed Models with R.
Zuur, Saveliev, Ieno (2012).