The overnight trading anomaly in SPY is well-known to many traders. In this article, this anomaly is backtested in R and I also make some general comments about backtesting in that language.
A few days ago, Ilya Kipnis and I had a conversation in twitter about backtesting the overnight trading anomaly in R. Ilya is an expert in R programming and strategy backtesting. He provided a few lines of code to backtest the overnight trading anomaly in R. We discussed in detail some of the issues that relate to the calculation of performance parameters in this language. I backtest mostly in Amibroker AFL and also in other platforms, including my own when it comes to data-mined price patterns, but this was an opportunity to get some more exposure in R.
The overnight trading anomaly in SPY causes asymmetry of returns from the close of a day to the open of the next day and from the open of a day to its close. As it is shown below, buying at the close of a day and selling at the next open is a theoretically profitable strategy. In practice, any excess alpha is gone after commission is included, except during some random periods of time.
The R code for testing the overnight trading anomaly in R is shown below:
require(quantmod) require(PerformanceAnalytics) getSymbols('SPY', from = '1900-01-01') adSPY <- adjustOHLC(SPY, use.Adjusted=TRUE) overnightRets <- na.omit(Op(adSPY)/lag(Cl(adSPY)) - 1) table.AnnualizedReturns(overnightRets) maxDrawdown(overnightRets) (avgTrade <- mean(overnightRets)) (avgWin <- mean(overnightRets[overnightRets > 0])) (avgLoss <- mean(overnightRets[overnightRets < 0])) (profitFactor <- -sum(overnightRets[overnightRets > 0])/sum(overnightRets[overnightRets < 0])) SharpeRatio.annualized(overnightRets, Rf = 0, scale = NA, geometric = FALSE) charts.PerformanceSummary(overnightRets)
(Code is courtesy of Ilya Kipnis and includes a few minor changes I made):
Below is the R console output:
The period of the test is from SPY inception to 10/23/2015. No commission is included. Below are the generated charts:
A few things to notice here:
- The R backtest assumes fractional shares. This means that equity is fully invested at each new position. This is important because it affects drawdown calculations.
- When calculating the Sharpe ratio, the “geometric = FALSE” option must be used otherwise the result may not be correct. It took some time to figure that out.
- The profit factor result in R does not reconcile with results from other platforms or even from excel. PF in R is shown as 1.23 but the correct value is 1.17. Actually, the profit factor is calculated on a per share basis in R, although returns are geometric.
Below are results from Amibroker for the same period, no commission is included:
It may be seen that for geometric growth, the profit factor is 1.17. Drawdown levels, CAR and Sharpe values match those generated by the R backtest.
Below is a backtest in Amibroker for one share per position with initial capital equal to the cost of the first share:
In this case the profit factor of 1.22 is close to the 1.23 result from R. But drawdown is -19.53% versus -32.78% in the case of fully invested equity.
Therefore, there is an issue with the profit factor calculations in R. There may be ways to fix that I am not aware of. Regardless, unless one is familiar with the way backtests are performed in R, the results can be misleading. There are a few different libraries for doing backtest in that language and probably some offer more flexibility than others. Since in the past I have identified serious flaws in commercially available backtesting platforms, I would not be surprised if some of the R libraries have some flaws. If you are backtesting a strategy to use in actual trading, it is a good idea to get results from at least two different backtesting platforms for validation purposes.
Finally, the overnight anomaly in SPY deteriorates significantly after the inclusion of commission charges, as shown below:
After including commission of $0.01 per share, CAR drops to 3.76% and the maximum drawdown increases to -40.45%. Surprisingly enough, year-to-date this anomaly has generated a high return, as shown below:
With commission of $0.01 per share, the year-to-date return is 8.20% at a maximum drawdown of just -4.53%. Sharpe is 1.07. But this has been a strange year anyway, with the longest range-bound action in stocks in the last 65 years. Therefore, the high return may be a random result.
There are certain other issues with this type of anomaly and also related strategies. One is that performance is sensitive to commission and slippage. These are analyzed in more detail in my new book, Fooled by Technical Analysis.
You can subscribe here to notifications of new posts by email.
Charting program: Amibroker
Detailed technical and quantitative analysis of Dow-30 stocks and popular ETFs can be found in our Weekly Premium Report.
New book release
© 2015 Michael Harris. All Rights Reserved. We grant a revocable permission to create a hyperlink to this blog subject to certain terms and conditions. Any unauthorized copy, reproduction, distribution, publication, display, modification, or transmission of any part of this blog is strictly prohibited without prior written permission.