Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Since this is the first post on this blog, a quick start up for those who may be reading this who don’t have my exact technical background: this blog will mostly use R, and backtesting will be done in the quantstrat package.
For those of you who follow me from a non-technical background, send me a message, and I’ll help you get started. For those simply not acquainted with the quantstrat package, this is the link to the definitive, comprehensive guide on quantstrat.
http://www.rinfinance.com/agenda/2013/workshop/Humme+Peterson.pdf
To motivate this post, consider some common wisdom about both mean-reverting and trend-following strategies. Mean reverting strategies often sport a high percentage of positive trades, but the few negative trades can hammer the equity curve. On the other side of the equation, trend-following strategies run on a philosophy of “let your winners run and cut your losers”, resulting in many small losses and a few wins that make up for them. However, what if there were an indicator that behaved like the best of both worlds? That is, capitalize on trends, while cutting out a good portion of whipsaws?
The Trend Vigor Indicator, or TVI as I call it in my DSTrading package, available on my github (see my about page for the link), created by Dr. John Ehlers (whom I thank for providing the completed code), attempts to do just that. Here’s a link to the original presentation (code incomplete):
http://www.mesasoftware.com/Seminars/Trend%20Modes%20and%20Cycle%20Modes.pdf
As Dr. Ehlers says on the fifth slide, correctly identifying market mode means a great deal. Something I noticed is that the plot for the trend vigor index seems to be very smooth in general, so when the trend vigor rises, it generally doesn’t whipsaw around very much about any particular quantity (at least at the daily resolution), so there may be a strategy to take advantage of this possible property.
Here’s the corresponding function from the DSTrading package, which I will use in the following demo. There may also be a trend vigor calculation with one of Dr. Ehlers’s adaptive period computation algorithms built in. In any case, the way it works is this: it takes in a time series, and two parameters: a period, which is identical to the n parameter in indicators such as SMA and so on, and a delta, which is a trigonometric parameter to adjust the computation of the bandpass filter (I am not overly familiar with the rationale behind signal processing, so I’ll leave the commentary on the finer points of this parameter to someone more experienced in this field).
TVI then outputs a time series of a 0-centered trend vigor indicator, along with a pair of oscillators (signal and lead), which I may touch on in the future.
"TVI" <- function(x, period = 20, delta = 0.2, triggerLag = 1, ...) { if (period != 0) { # static, length-1 period beta <- cos(2 * pi/period) gamma <- 1/cos(4 * pi * delta/period) alpha <- gamma - sqrt(gamma * gamma - 1) BP <- 0.5 * (1 - alpha) * (x - lag(x, 2)) BP[1] <- BP[2] <- 0 BP <- filter(BP, c(beta * (1 + alpha), -1 * alpha), method = "recursive") BP <- xts(BP, order.by = index(x)) signal <- BP - lag(BP, round(period/2)) lead <- 1.4 * (BP - lag(BP, round(period/4))) BP2 <- BP * BP LBP2 <- lag(BP2, round(period/4)) power <- runSum(BP2, period) + runSum(LBP2, period) RMS <- sqrt(power/period) PtoP <- 2 * sqrt(2) * RMS a1 <- exp(-sqrt(2) * pi/period) b1 <- 2 * a1 * cos(sqrt(2) * pi/period) coef2 <- b1 coef3 <- -a1 * a1 coef1 <- 1 - coef2 - coef3 trend <- coef1 * (x - lag(x, period)) trend[is.na(trend)] <- 0 trend <- filter(trend, c(coef2, coef3), method = "recursive") trend <- xts(trend, order.by = index(x)) vigor <- trend/PtoP vigor[vigor > 2] <- 2 vigor[vigor < -2] <- -2 trigger <- lag(vigor, triggerLag) out <- cbind(vigor, signal, lead, trigger) colnames(out) <- c("vigor", "signal", "lead", "trigger") return(out) } else { stop("Dynamic period computation not implemented yet.") # TODO -- DYNAMIC PERIOD TREND VIGOR } }
So in order to test this indicator, I wrote a quantstrat demo to test its momentum properties. First, we will fetch the data, which consists of some ETFs that have been trading since before 2003. This is the data file I will source for this demo (called demoData.R), along with many others.
require(DSTrading) require(quantstrat) options(width=80) source("demoData.R") #contains all of the data-related boilerplate.
Here are the exact contents of demoData.R
options("getSymbols.warning4.0"=FALSE) rm(list=ls(.blotter), envir=.blotter) initDate='1990-12-31' currency('USD') Sys.setenv(TZ="UTC") symbols <- c("XLB", #SPDR Materials sector "XLE", #SPDR Energy sector "XLF", #SPDR Financial sector "XLP", #SPDR Consumer staples sector "XLI", #SPDR Industrial sector "XLU", #SPDR Utilities sector "XLV", #SPDR Healthcare sector "XLK", #SPDR Tech sector "XLY", #SPDR Consumer discretionary sector "RWR", #SPDR Dow Jones REIT ETF "EWJ", #iShares Japan "EWG", #iShares Germany "EWU", #iShares UK "EWC", #iShares Canada "EWY", #iShares South Korea "EWA", #iShares Australia "EWH", #iShares Hong Kong "EWS", #iShares Singapore "IYZ", #iShares U.S. Telecom "EZU", #iShares MSCI EMU ETF "IYR", #iShares U.S. Real Estate "EWT", #iShares Taiwan "EWZ", #iShares Brazil "EFA", #iShares EAFE "IGE", #iShares North American Natural Resources "EPP", #iShares Pacific Ex Japan "LQD", #iShares Investment Grade Corporate Bonds "SHY", #iShares 1-3 year TBonds "IEF", #iShares 3-7 year TBonds "TLT" #iShares 20+ year Bonds ) #SPDR ETFs first, iShares ETFs afterwards if(!"XLB" %in% ls()) { suppressMessages(getSymbols(symbols, from="2003-01-01", to="2010-12-31", src="yahoo", adjust=TRUE)) } stock(symbols, currency="USD", multiplier=1)
The reason I’m using these symbols is fairly simple: they’re representative of a fairly broad aspect of both the U.S. economy and other developed economies abroad (E.G. Japan, Germany), and contain a fair amount of “staple” ETFs (SPDR sectors, EFA, internationals, etc.).
Let’s begin the demo. The strategy will be simple–the indicator will be the trend vigor calculation, and the strategy will go long on the next open when the trend vigor crosses above 1, sell the next open when it crosses below 1.4, and will stop out on the next open when the trend vigor crosses under 1 if it never crossed 1.4 within the duration of the position.
The general syntax of indicators, signals, and rules in quantstrat (for the uninitiated) is fairly straightforward:
add.indicator/add.signal/add.rule is a function which takes in the name of the strategy as the first argument (which I always use strategy.st for), a name of an R function in the name argument, the arguments to the function as the argument to arguments (that is, arguments=list(x=quote(Cl(mktdata)), period=100, delta=0.2) is the argument to the TVI function which is the value for the name argument in the add.indicator function), and finally, a label. While the labels may seem like so much window dressing, they are critical in terms of linking indicators to signals, signals to rules, and everything to any optimization/robustness testing you may deecide to do. Do not forget them.
While I kept Dr. Ehlers’s default period setting, I found that the strategy works best starting at 60 days for the period, and has a solid performance until the mid-hundreds, at which point it generates too few trades per instrument to really be able to look at any individual statistics.
Here’s the strategy.
#To rerun the strategy, re-run everything from this line down. strategy.st <- portfolio.st <- account.st <- "TVItrendFollowingLong" rm.strat(portfolio.st) rm.strat(strategy.st) initPortf(portfolio.st, symbols=symbols, initDate=initDate, currency='USD') initAcct(account.st, portfolios=portfolio.st, initDate=initDate, currency='USD') initOrders(portfolio.st, initDate=initDate) strategy(strategy.st, store=TRUE) #indicator add.indicator(strategy.st, name="TVI", arguments=list(x=quote(Cl(mktdata)), period=100, delta=0.2), label="TVI") #signals add.signal(strategy.st, name="sigThreshold", arguments=list(threshold=1, column="vigor.TVI", relationship="gte", cross=TRUE), label="longEntry") add.signal(strategy.st, name="sigThreshold", arguments=list(threshold=1.4, column="vigor.TVI", relationship="lt", cross=TRUE), label="longExit") add.signal(strategy.st, name="sigThreshold", arguments=list(threshold=1, column="vigor.TVI", relationship="lt", cross=TRUE), label="wrongExit") #rules add.rule(strategy.st, name="ruleSignal", arguments=list(sigcol="longEntry", sigval=TRUE, orderqty=100, ordertype="market", orderside="long", replace=FALSE, prefer="Open"), type="enter", path.dep=TRUE) add.rule(strategy.st, name="ruleSignal", arguments=list(sigcol="longExit", sigval=TRUE, orderqty="all", ordertype="market", orderside="long", replace=FALSE, prefer="Open"), type="exit", path.dep=TRUE) add.rule(strategy.st, name="ruleSignal", arguments=list(sigcol="wrongExit", sigval=TRUE, orderqty="all", ordertype="market", orderside="long", replace=FALSE, prefer="Open"), type="exit", path.dep=TRUE)
The strategy is then run with the applyStrategy call. I set verbose to FALSE for the purpose of not displaying the order log in this blog post, but by default, quantstrat will start printing out trades at this point. Printing out trades serves two purposes (in my experience): first off, you know your strategy is actually doing something, and secondly, even if it is, the attentive eye will also see if the strategy is not behaving intuitively (that is, is it loading up more lots when you thought it should only be trading 1 lot at a time? This happens often with strategies that crisscross above and below a threshold, such as with simple RSI strategies.)
#apply strategy t1 <- Sys.time() out <- applyStrategy(strategy=strategy.st,portfolios=portfolio.st, verbose=FALSE) t2 <- Sys.time() print(t2-t1) #tradeStats updatePortf(portfolio.st) dateRange <- time(getPortfolio(portfolio.st)$summary)[-1] updateAcct(portfolio.st,dateRange) updateEndEq(account.st)
The last four lines are some more “accounting boilerplate” that are necessary for the following analytics.
Here are the trade statistics:
tStats <- tradeStats(Portfolios = portfolio.st, use = "trades", inclZeroDays = FALSE) print(data.frame(t(tStats[, -c(1:2)])))
Here’s the output:
EFA EPP EWA EWC EWG EWH Num.Txns 11.000 11.000 11.000 13.0000 11.000 15.000 Num.Trades 6.000 6.000 6.000 7.0000 6.000 8.000 Net.Trading.PL 2565.775 1969.314 1286.254 467.3296 814.737 606.872 Avg.Trade.PL 427.629 328.219 214.376 66.7614 135.789 75.859 Med.Trade.PL 406.141 187.906 133.158 134.4598 32.897 98.591 Largest.Winner 848.301 907.877 599.901 349.9296 591.163 180.214 Largest.Loser 0.000 -124.794 -95.424 -256.5205 -59.893 -95.641 Gross.Profits 2565.775 2163.065 1393.249 992.6210 942.630 703.020 Gross.Losses 0.000 -193.750 -106.995 -525.2914 -127.893 -96.148 Std.Dev.Trade.PL 353.537 461.074 285.169 239.4493 257.994 92.620 Percent.Positive 100.000 66.667 66.667 57.1429 66.667 75.000 Percent.Negative 0.000 33.333 33.333 42.8571 33.333 25.000 Profit.Factor Inf 11.164 13.022 1.8897 7.370 7.312 Avg.Win.Trade 427.629 540.766 348.312 248.1553 235.658 117.170 Med.Win.Trade 406.141 584.662 330.518 254.1158 175.014 109.259 Avg.Losing.Trade NaN -96.875 -53.498 -175.0971 -63.947 -48.074 Med.Losing.Trade NA -96.875 -53.498 -143.9421 -63.947 -48.074 Avg.Daily.PL 494.769 407.654 230.788 42.4390 176.547 86.768 Med.Daily.PL 571.279 289.949 134.004 4.8155 64.354 105.539 Std.Dev.Daily.PL 349.896 467.346 315.644 252.6538 265.974 94.326 Ann.Sharpe 22.447 13.847 11.607 2.6665 10.537 14.603 Max.Drawdown -1035.238 -817.160 -519.809 -765.6489 -442.170 -529.427 Profit.To.Max.Draw 2.478 2.410 2.474 0.6104 1.843 1.146 Avg.WinLoss.Ratio NaN 5.582 6.511 1.4172 3.685 2.437 Med.WinLoss.Ratio NA 6.035 6.178 1.7654 2.737 2.273 Max.Equity 3154.421 2386.521 1330.685 536.1786 1115.907 947.518 Min.Equity -1.416 -5.738 0.000 -229.4703 -10.326 -7.227 End.Equity 2565.775 1969.314 1286.254 467.3296 814.737 606.872 EWJ EWS EWT EWU EWY EWZ Num.Txns 15.0000 15.0000 13.00000 15.000 13.0000 13.000 Num.Trades 8.0000 8.0000 7.00000 8.000 7.0000 7.000 Net.Trading.PL 126.0921 527.5159 352.38231 496.885 3903.4781 5650.267 Avg.Trade.PL 15.7615 65.9395 50.34033 62.111 557.6397 807.181 Med.Trade.PL -4.8031 48.6563 15.20059 53.201 507.7895 425.888 Largest.Winner 211.4631 287.4863 181.33002 170.439 1911.0697 3090.026 Largest.Loser -109.4557 -183.5601 -98.93976 -26.825 -645.4187 -762.177 Gross.Profits 369.6269 746.4612 536.96182 572.167 4548.8968 6431.642 Gross.Losses -243.5348 -218.9453 -184.57951 -75.282 -645.4187 -781.375 Std.Dev.Trade.PL 105.5657 156.0082 121.48260 84.271 766.8694 1323.564 Percent.Positive 37.5000 75.0000 57.14286 62.500 85.7143 71.429 Percent.Negative 62.5000 25.0000 42.85714 37.500 14.2857 28.571 Profit.Factor 1.5178 3.4094 2.90911 7.600 7.0480 8.231 Avg.Win.Trade 123.2090 124.4102 134.24045 114.433 758.1495 1286.328 Med.Win.Trade 99.0951 70.0932 170.21560 138.704 522.5712 533.596 Avg.Losing.Trade -48.7070 -109.4727 -61.52650 -25.094 -645.4187 -390.687 Med.Losing.Trade -29.1036 -109.4727 -70.52540 -25.206 -645.4187 -390.687 Avg.Daily.PL 9.5748 69.4619 32.17724 74.305 585.8121 944.911 Med.Daily.PL -5.6972 56.0302 0.04312 63.148 522.5712 479.742 Std.Dev.Daily.PL 112.4465 168.1641 122.22309 83.050 836.0858 1393.859 Ann.Sharpe 1.3517 6.5571 4.17923 14.203 11.1226 10.761 Max.Drawdown -355.7105 -255.8450 -466.69819 -307.027 -1576.6419 -1600.155 Profit.To.Max.Draw 0.3545 2.0619 0.75505 1.618 2.4758 3.531 Avg.WinLoss.Ratio 2.5296 1.1365 2.18183 4.560 1.1747 3.292 Med.WinLoss.Ratio 3.4049 0.6403 2.41354 5.503 0.8097 1.366 Max.Equity 422.7339 547.8001 369.07717 650.692 4695.6618 6644.273 Min.Equity 0.0000 -27.7323 -97.62103 -29.595 -106.6402 -58.404 End.Equity 126.0921 527.5159 352.38231 496.885 3903.4781 5650.267 EZU IEF IGE IYR IYZ LQD Num.Txns 13.000 16.0000 13.00 11.000 19.0000 12.0000 Num.Trades 7.000 8.0000 7.00 6.000 10.0000 6.0000 Net.Trading.PL 1182.003 727.7658 -3.733e+01 1925.684 174.6551 -83.6846 Avg.Trade.PL 168.858 90.9707 -5.333e+00 320.947 17.4655 -13.9474 Med.Trade.PL 116.812 60.5784 1.500e+02 310.430 -36.2849 -43.9321 Largest.Winner 706.295 356.5054 6.172e+02 807.768 447.8273 257.6271 Largest.Loser -21.553 -224.7938 -1.047e+03 -294.785 -158.5646 -278.1925 Gross.Profits 1256.372 1093.0415 1.342e+03 2220.469 707.1572 447.8795 Gross.Losses -74.369 -365.2757 -1.380e+03 -294.785 -532.5021 -531.5641 Std.Dev.Trade.PL 255.791 211.5468 5.380e+02 367.789 179.1449 206.1184 Percent.Positive 71.429 75.0000 5.714e+01 83.333 40.0000 33.3333 Percent.Negative 28.571 25.0000 4.286e+01 16.667 60.0000 66.6667 Profit.Factor 16.894 2.9924 9.729e-01 7.533 1.3280 0.8426 Avg.Win.Trade 251.274 182.1736 3.356e+02 444.094 176.7893 223.9397 Med.Win.Trade 126.562 168.8602 2.875e+02 328.352 113.7095 223.9397 Avg.Losing.Trade -37.184 -182.6379 -4.598e+02 -294.785 -88.7504 -132.8910 Med.Losing.Trade -37.184 -182.6379 -1.881e+02 -294.785 -82.9667 -121.9668 Avg.Daily.PL 205.803 90.9707 -6.897e+01 336.975 1.5594 -13.9474 Med.Daily.PL 121.687 60.5784 2.740e+00 328.352 -39.9546 -43.9321 Std.Dev.Daily.PL 258.938 211.5468 5.598e+02 408.851 182.3684 206.1184 Ann.Sharpe 12.617 6.8265 -1.956e+00 13.084 0.1357 -1.0742 Max.Drawdown -756.388 -753.7337 -1.189e+03 -977.604 -415.3754 -648.4695 Profit.To.Max.Draw 1.563 0.9655 -3.139e-02 1.970 0.4205 -0.1290 Avg.WinLoss.Ratio 6.758 0.9975 7.297e-01 1.507 1.9920 1.6851 Med.WinLoss.Ratio 3.404 0.9246 1.529e+00 1.114 1.3705 1.8361 Max.Equity 1650.980 1400.1652 4.661e+02 1932.684 332.9343 251.3202 Min.Equity -27.256 -321.9691 -7.230e+02 -190.088 -335.9970 -397.1493 End.Equity 1182.003 727.7658 -3.733e+01 1925.684 174.6551 -83.6846 RWR SHY TLT XLB XLE XLF Num.Txns 11.000 13.000 14.0000 15.000 17.0000 12.000 Num.Trades 6.000 7.000 7.0000 8.000 9.0000 6.000 Net.Trading.PL 1995.629 1142.519 1442.2875 980.284 -456.6602 323.884 Avg.Trade.PL 332.605 163.217 206.0411 122.536 -50.7400 53.981 Med.Trade.PL 335.682 61.755 269.8718 113.830 -152.9856 100.260 Largest.Winner 773.739 901.261 809.9610 661.063 1136.1168 223.785 Largest.Loser -292.223 -41.231 -484.5142 -323.312 -1360.1798 -189.485 Gross.Profits 2287.852 1183.751 1926.8017 1620.063 2243.5774 575.037 Gross.Losses -292.223 -41.231 -484.5142 -639.779 -2700.2376 -251.153 Std.Dev.Trade.PL 379.963 330.145 388.5266 334.521 723.7411 153.249 Percent.Positive 83.333 85.714 85.7143 62.500 44.4444 66.667 Percent.Negative 16.667 14.286 14.2857 37.500 55.5556 33.333 Profit.Factor 7.829 28.710 3.9768 2.532 0.8309 2.290 Avg.Win.Trade 457.570 197.292 321.1336 324.013 560.8943 143.759 Med.Win.Trade 359.312 63.647 295.1517 357.324 484.7987 142.446 Avg.Losing.Trade -292.223 -41.231 -484.5142 -213.260 -540.0475 -125.577 Med.Losing.Trade -292.223 -41.231 -484.5142 -229.386 -339.2491 -125.577 Avg.Daily.PL 327.263 179.497 206.0411 88.994 -130.5507 53.981 Med.Daily.PL 312.051 39.657 269.8718 49.687 -198.6073 100.260 Std.Dev.Daily.PL 424.560 358.565 388.5266 346.489 730.1456 153.249 Ann.Sharpe 12.237 7.947 8.4185 4.077 -2.8384 5.592 Max.Drawdown -1078.974 -176.880 -1935.3483 -782.001 -2802.9605 -286.089 Profit.To.Max.Draw 1.850 6.459 0.7452 1.254 -0.1629 1.132 Avg.WinLoss.Ratio 1.566 4.785 0.6628 1.519 1.0386 1.145 Med.WinLoss.Ratio 1.230 1.544 0.6092 1.558 1.4290 1.134 Max.Equity 2007.629 1177.262 3079.6926 983.284 1605.9939 591.275 Min.Equity -387.039 -63.396 -660.0092 -43.384 -1196.9666 -75.179 End.Equity 1995.629 1142.519 1442.2875 980.284 -456.6602 323.884 XLI XLK XLP XLU XLV XLY Num.Txns 11.000 13.000 11.0000 13.000 15.00000 9.000 Num.Trades 6.000 7.000 6.0000 7.000 8.00000 5.000 Net.Trading.PL 1711.104 803.342 323.3662 1004.075 30.93792 1211.524 Avg.Trade.PL 285.184 114.763 53.8944 143.439 3.86724 242.305 Med.Trade.PL 326.887 105.678 65.8982 7.115 -9.87414 147.312 Largest.Winner 519.577 438.553 356.5055 681.636 288.56124 761.154 Largest.Loser 0.000 -107.612 -210.7667 -295.709 -187.12589 -82.008 Gross.Profits 1711.104 972.832 591.8219 1349.316 466.45591 1293.532 Gross.Losses 0.000 -169.490 -268.4557 -345.241 -435.51798 -82.008 Std.Dev.Trade.PL 194.940 190.582 188.6608 346.799 146.85429 330.468 Percent.Positive 100.000 57.143 66.6667 57.143 50.00000 80.000 Percent.Negative 0.000 42.857 33.3333 42.857 50.00000 20.000 Profit.Factor Inf 5.740 2.2045 3.908 1.07104 15.773 Avg.Win.Trade 285.184 243.208 147.9555 337.329 116.61398 323.383 Med.Win.Trade 326.887 214.301 96.6660 330.282 68.64046 247.765 Avg.Losing.Trade NaN -56.497 -134.2278 -115.080 -108.87950 -82.008 Med.Losing.Trade NA -34.689 -134.2278 -27.216 -94.01504 -82.008 Avg.Daily.PL 317.385 116.277 46.7108 171.065 -5.57699 293.669 Med.Daily.PL 405.014 81.035 41.9843 60.238 -60.36201 247.765 Std.Dev.Daily.PL 199.312 208.726 210.0097 371.366 155.97459 357.804 Ann.Sharpe 25.279 8.843 3.5308 7.312 -0.56760 13.029 Max.Drawdown -359.821 -431.415 -309.4029 -577.717 -418.76748 -496.847 Profit.To.Max.Draw 4.755 1.862 1.0451 1.738 0.07388 2.438 Avg.WinLoss.Ratio NaN 4.305 1.1023 2.931 1.07104 3.943 Med.WinLoss.Ratio NA 6.178 0.7202 12.135 0.73010 3.021 Max.Equity 1713.104 852.989 332.3662 1332.267 174.64061 1464.480 Min.Equity 0.000 -124.148 -177.2952 -105.827 -399.20704 -100.523 End.Equity 1711.104 803.342 323.3662 1004.075 30.93792 1211.524
Looking at the statistics on a per-trade basis on a 100-share trade size, the majority of configurations come away with a clear profit. While I did not set any transaction costs/slippage, as this strategy is a long to medium term horizon strategy, I wouldn’t worry too much over it. The statistics that impress me are the percentage correct and the profit factor. Looking at EWJ, even when the percentage correct is less than 50%, the strategy still manages to eke out a profit (profit factor 1.5). A few instruments lose), but on a whole, for an indicator that’s supposed to be a mere filter, this isn’t a particularly bad start.
For those wondering about the annualized “Sharpe Ratio” as it is calculated with trade statistics, this is my interpretation of it: if you aggregated every single trade’s profit and loss into one day apiece, averaged them, and divided by the standard error, which is the standard deviation divided by the square root of 252 (trading days in a year).
Here are the daily statistics:
dStats <- dailyStats(Portfolios = portfolio.st, use = "Equity") rownames(dStats) <- gsub("\\.DailyEndEq", "", rownames(dStats)) print(data.frame(t(dStats[, -1]))) EFA EPP EWA EWC EWG EWH Total.Days 886.00 669.00 636.00 566.00 675.00 842.00 Winning.Days 490.00 370.00 359.00 300.00 370.00 442.00 Losing.Days 396.00 299.00 277.00 266.00 305.00 400.00 Avg.Day.PL 2.90 2.94 2.02 0.83 1.21 0.72 Med.Day.PL 5.96 5.06 4.63 2.26 1.81 1.65 Largest.Winner 196.41 164.03 123.88 113.03 99.29 120.60 Largest.Loser -275.87 -234.28 -135.60 -126.79 -117.34 -122.37 Gross.Profits 19050.85 13211.44 8517.36 6635.32 7027.38 7348.06 Gross.Losses -16485.08 -11242.12 -7231.10 -6167.99 -6212.64 -6741.19 Std.Dev.Daily.PL 54.62 50.83 34.68 30.69 27.08 24.61 Percent.Positive 55.30 55.31 56.45 53.00 54.81 52.49 Percent.Negative 44.70 44.69 43.55 47.00 45.19 47.51 Profit.Factor 1.16 1.18 1.18 1.08 1.13 1.09 Avg.Win.Day 38.88 35.71 23.73 22.12 18.99 16.62 Med.Win.Day 30.35 26.11 17.14 16.54 14.44 11.84 Avg.Losing.Day -41.63 -37.60 -26.11 -23.19 -20.37 -16.85 Med.Losing.Day -28.57 -23.21 -15.90 -15.08 -13.21 -11.00 Avg.Daily.PL 2.90 2.94 2.02 0.83 1.21 0.72 Med.Daily.PL 5.96 5.06 4.63 2.26 1.81 1.65 Std.Dev.Daily.PL.1 54.62 50.83 34.68 30.69 27.08 24.61 Ann.Sharpe 0.84 0.92 0.93 0.43 0.71 0.46 Max.Drawdown -1035.24 -817.16 -519.81 -765.65 -442.17 -529.43 Profit.To.Max.Draw 2.48 2.41 2.47 0.61 1.84 1.15 Avg.WinLoss.Ratio 0.93 0.95 0.91 0.95 0.93 0.99 Med.WinLoss.Ratio 1.06 1.12 1.08 1.10 1.09 1.08 Max.Equity 3154.42 2386.52 1330.69 536.18 1115.91 947.52 Min.Equity -1.42 -5.74 0.00 -229.47 -10.33 -7.23 End.Equity 2565.77 1969.31 1286.25 467.33 814.74 606.87 EWJ EWS EWT EWU EWY EWZ Total.Days 569.00 970.00 597.00 763.00 989.00 1075.00 Winning.Days 298.00 536.00 316.00 410.00 546.00 605.00 Losing.Days 271.00 434.00 281.00 353.00 443.00 470.00 Avg.Day.PL 0.22 0.54 0.59 0.65 3.95 5.26 Med.Day.PL 1.87 1.61 1.67 1.68 9.35 7.49 Largest.Winner 44.31 67.76 72.61 67.65 389.70 563.64 Largest.Loser -57.97 -84.06 -116.84 -98.01 -354.19 -623.29 Gross.Profits 3238.75 4779.24 4216.67 5613.57 30944.68 38572.35 Gross.Losses -3112.66 -4251.73 -3864.29 -5116.69 -27041.21 -32922.08 Std.Dev.Daily.PL 14.18 13.75 18.17 18.65 82.68 102.52 Percent.Positive 52.37 55.26 52.93 53.74 55.21 56.28 Percent.Negative 47.63 44.74 47.07 46.26 44.79 43.72 Profit.Factor 1.04 1.12 1.09 1.10 1.14 1.17 Avg.Win.Day 10.87 8.92 13.34 13.69 56.68 63.76 Med.Win.Day 8.64 6.00 11.02 11.24 40.88 36.97 Avg.Losing.Day -11.49 -9.80 -13.75 -14.49 -61.04 -70.05 Med.Losing.Day -8.87 -6.43 -10.08 -10.41 -40.22 -40.02 Avg.Daily.PL 0.22 0.54 0.59 0.65 3.95 5.26 Med.Daily.PL 1.87 1.61 1.67 1.68 9.35 7.49 Std.Dev.Daily.PL.1 14.18 13.75 18.17 18.65 82.68 102.52 Ann.Sharpe 0.25 0.63 0.52 0.55 0.76 0.81 Max.Drawdown -355.71 -255.84 -466.70 -307.03 -1576.64 -1600.16 Profit.To.Max.Draw 0.35 2.06 0.76 1.62 2.48 3.53 Avg.WinLoss.Ratio 0.95 0.91 0.97 0.94 0.93 0.91 Med.WinLoss.Ratio 0.97 0.93 1.09 1.08 1.02 0.92 Max.Equity 422.73 547.80 369.08 650.69 4695.66 6644.27 Min.Equity 0.00 -27.73 -97.62 -29.59 -106.64 -58.40 End.Equity 126.09 527.52 352.38 496.89 3903.48 5650.27 EZU IEF IGE IYR IYZ LQD Total.Days 661.00 670.00 510.00 582.00 715.00 561.00 Winning.Days 366.00 339.00 272.00 307.00 362.00 290.00 Losing.Days 295.00 331.00 238.00 275.00 353.00 271.00 Avg.Day.PL 1.79 1.09 -0.07 3.31 0.24 -0.15 Med.Day.PL 4.40 0.88 3.76 6.55 0.86 1.63 Largest.Winner 173.19 171.24 215.52 235.32 70.10 109.77 Largest.Loser -269.85 -159.58 -227.11 -251.01 -102.91 -125.10 Gross.Profits 12212.18 10589.20 10077.87 15816.00 5627.62 7328.19 Gross.Losses -11030.18 -9861.44 -10115.20 -13890.32 -5452.96 -7411.88 Std.Dev.Daily.PL 48.55 41.28 53.89 65.85 20.72 34.60 Percent.Positive 55.37 50.60 53.33 52.75 50.63 51.69 Percent.Negative 44.63 49.40 46.67 47.25 49.37 48.31 Profit.Factor 1.11 1.07 1.00 1.14 1.03 0.99 Avg.Win.Day 33.37 31.24 37.05 51.52 15.55 25.27 Med.Win.Day 26.82 23.78 31.78 44.00 12.42 19.64 Avg.Losing.Day -37.39 -29.79 -42.50 -50.51 -15.45 -27.35 Med.Losing.Day -24.40 -22.30 -30.05 -38.11 -11.24 -21.70 Avg.Daily.PL 1.79 1.09 -0.07 3.31 0.24 -0.15 Med.Daily.PL 4.40 0.88 3.76 6.55 0.86 1.63 Std.Dev.Daily.PL.1 48.55 41.28 53.89 65.85 20.72 34.60 Ann.Sharpe 0.58 0.42 -0.02 0.80 0.19 -0.07 Max.Drawdown -756.39 -753.73 -1189.16 -977.60 -415.38 -648.47 Profit.To.Max.Draw 1.56 0.97 -0.03 1.97 0.42 -0.13 Avg.WinLoss.Ratio 0.89 1.05 0.87 1.02 1.01 0.92 Med.WinLoss.Ratio 1.10 1.07 1.06 1.15 1.10 0.90 Max.Equity 1650.98 1400.17 466.12 1932.68 332.93 251.32 Min.Equity -27.26 -321.97 -723.05 -190.09 -336.00 -397.15 End.Equity 1182.00 727.77 -37.33 1925.68 174.66 -83.68 RWR SHY TLT XLB XLE XLF Total.Days 574.00 1190.00 614.00 780.00 727.00 471.00 Winning.Days 309.00 668.00 321.00 429.00 398.00 246.00 Losing.Days 265.00 522.00 293.00 351.00 329.00 225.00 Avg.Day.PL 3.48 0.96 2.35 1.26 -0.63 0.69 Med.Day.PL 5.92 1.00 6.03 4.30 8.25 1.82 Largest.Winner 269.45 32.68 471.43 129.97 416.59 83.33 Largest.Loser -293.03 -43.49 -333.98 -162.54 -350.68 -156.62 Gross.Profits 17031.46 4452.86 19634.89 11099.37 22312.96 4470.08 Gross.Losses -15035.83 -3310.34 -18192.61 -10119.09 -22769.62 -4146.20 Std.Dev.Daily.PL 72.55 8.62 86.91 36.57 88.11 24.85 Percent.Positive 53.83 56.13 52.28 55.00 54.75 52.23 Percent.Negative 46.17 43.87 47.72 45.00 45.25 47.77 Profit.Factor 1.13 1.35 1.08 1.10 0.98 1.08 Avg.Win.Day 55.12 6.67 61.17 25.87 56.06 18.17 Med.Win.Day 45.43 5.03 40.71 21.69 39.10 13.76 Avg.Losing.Day -56.74 -6.34 -62.09 -28.83 -69.21 -18.43 Med.Losing.Day -45.55 -4.93 -45.35 -19.65 -46.93 -12.94 Avg.Daily.PL 3.48 0.96 2.35 1.26 -0.63 0.69 Med.Daily.PL 5.92 1.00 6.03 4.30 8.25 1.82 Std.Dev.Daily.PL.1 72.55 8.62 86.91 36.57 88.11 24.85 Ann.Sharpe 0.76 1.77 0.43 0.55 -0.11 0.44 Max.Drawdown -1078.97 -176.88 -1935.35 -782.00 -2802.96 -286.09 Profit.To.Max.Draw 1.85 6.46 0.75 1.25 -0.16 1.13 Avg.WinLoss.Ratio 0.97 1.05 0.99 0.90 0.81 0.99 Med.WinLoss.Ratio 1.00 1.02 0.90 1.10 0.83 1.06 Max.Equity 2007.63 1177.26 3079.69 983.28 1605.99 591.27 Min.Equity -387.04 -63.40 -660.01 -43.38 -1196.97 -75.18 End.Equity 1995.63 1142.52 1442.29 980.28 -456.66 323.88 XLI XLK XLP XLU XLV XLY Total.Days 703.00 806.00 453.00 845.00 632.00 641.00 Winning.Days 396.00 452.00 247.00 469.00 316.00 348.00 Losing.Days 307.00 354.00 206.00 376.00 316.00 293.00 Avg.Day.PL 2.43 1.00 0.71 1.19 0.05 1.89 Med.Day.PL 3.53 2.90 1.91 2.71 0.01 2.96 Largest.Winner 117.17 98.93 76.23 91.19 78.78 165.94 Largest.Loser -105.71 -93.48 -67.43 -144.31 -97.34 -127.92 Gross.Profits 7981.67 7157.63 2899.29 8376.04 5328.55 7759.21 Gross.Losses -6270.56 -6354.29 -2575.92 -7371.96 -5297.62 -6547.68 Std.Dev.Daily.PL 26.72 22.19 15.94 25.64 21.81 30.39 Percent.Positive 56.33 56.08 54.53 55.50 50.00 54.29 Percent.Negative 43.67 43.92 45.47 44.50 50.00 45.71 Profit.Factor 1.27 1.13 1.13 1.14 1.01 1.19 Avg.Win.Day 20.16 15.84 11.74 17.86 16.86 22.30 Med.Win.Day 16.69 12.37 9.31 14.55 14.23 18.28 Avg.Losing.Day -20.43 -17.95 -12.50 -19.61 -16.76 -22.35 Med.Losing.Day -15.22 -12.58 -9.61 -12.72 -13.16 -15.99 Avg.Daily.PL 2.43 1.00 0.71 1.19 0.05 1.89 Med.Daily.PL 3.53 2.90 1.91 2.71 0.01 2.96 Std.Dev.Daily.PL.1 26.72 22.19 15.94 25.64 21.81 30.39 Ann.Sharpe 1.45 0.71 0.71 0.74 0.04 0.99 Max.Drawdown -359.82 -431.41 -309.40 -577.72 -418.77 -496.85 Profit.To.Max.Draw 4.76 1.86 1.05 1.74 0.07 2.44 Avg.WinLoss.Ratio 0.99 0.88 0.94 0.91 1.01 1.00 Med.WinLoss.Ratio 1.10 0.98 0.97 1.14 1.08 1.14 Max.Equity 1713.10 852.99 332.37 1332.27 174.64 1464.48 Min.Equity 0.00 -124.15 -177.30 -105.83 -399.21 -100.52 End.Equity 1711.10 803.34 323.37 1004.07 30.94 1211.52
Looking at the daily statistics, while the statistics aren’t exactly spectacular on the daily time frame, keep in mind that these configurations are ones that hold for very long periods of time, and thus are subject to the usual sloshings of the individual securities over a long period of time. The thing to see here is that this indicator does a good job of creating an edge in most instruments.
Continuing–let’s look at the equity curve of XLB.
tmp <- TVI(Cl(XLB), period = 100) add_TA(tmp$vigor)
Something to note is that the exits I programmed aren’t exactly the best, and suffer from the same weaknesses as the usual trend followers–namely, that unsophisticated trend-following strategies tend to “give back their profts” as the trend they were following winds down. However, looking at the plot of the indicator at the bottom, and given how it does not seem to be something very prone to whipsaws, a potential trading strategy going forward may be to do something Dr. Ehlers has done in another one of his presentations, and create signals on the relationship of the signal compared to its 1-day lagged version.
Finally, out of a tagential interest, let’s look at some portfolio statistics. Note that this probably makes the least sense out of anything presented here since there is no intelligent asset allocation scheme at work here.
portPL <- .blotter$portfolio.TVItrendFollowingLong$summary$Net.Trading.PL (SharpeRatio.annualized(portPL, geometric=FALSE)) Net.Trading.PL Annualized Sharpe Ratio (Rf=0%) 0.623 plot(cumsum(portPL)["2003::"])
From a returns perspective, this doesn’t make too much sense, as there’s no initial equity, but it exists to just get a perspective of the strategy’s performance at a portfolio level. Overall, it seems the system is profitable, but drawdowns come quickly, meaning that as a strategy in and of itself, Trend Vigor is definitely worth looking at. That stated, its original use was as a filter, and odds are, there exist indicators that are probably more dedicated to trend following such as the FRAMA, ichimoku, and so on.
So, overall, this blog post has shown a few things:
1) It is possible to create a trend-following strategy with a win percentage greater than that of 50%.
2) While the trend vigor indicator is a filter, it may be possible to put a dedicated trend-following filter on top of it (such as the FRAMA–more on that in the future), to possibly get even better results.
3) This is (definitely) not a complete trading system. The exit logic definitely leaves something to be desired (for instance, if the trend vigor reaches its maximum (2)–which seems to be every time, waiting for it to drop under 1.4 is definitely suboptimal), and it seems more improvements can be made.
Furthermore, there is more to investigate in the study of this indicator:
1) In this case, given the smoothness of the trend vigor, is it possible to be more aggressive with it? For instance, although it avoided the financial crisis completely, it did not re-enter the market until late 2009, missing a chunk of the trend, and furthermore, it also managed to give back most of those profits (but not all). Can this be rectified?
2) How does the strategy perform on the short end?
3) What can be done to keep strategies built on this indicator from “giving back open equity”?
While I myself have more indicators to write about, I also feel that input from readers may be worth testing as well.
Thanks for reading.
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.