A positive batting average trend follower? Introducing Trend Vigor.
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.