Transaction Cost and Execution Price functionality in the Backtesting library in the Systematic Investor Toolbox
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
I want to introduce the Transaction Cost and Execution Price functionality in the Backtesting library in the Systematic Investor Toolbox.
The Transaction Cost is implemented by a commission parameter in the bt.run() function. You may specify the commissions in $ per share for “share” type backtest and as a percentage of total trade for “weight” type backtest.
Following is a simple example of 50 / 200 day moving average cross over strategy with 10c per share commission:
############################################################################### # Load Systematic Investor Toolbox (SIT) # http://systematicinvestor.wordpress.com/systematic-investor-toolbox/ ############################################################################### con = gzcon(url('http://www.systematicportfolio.com/sit.gz', 'rb')) source(con) close(con) #***************************************************************** # Load historical data #****************************************************************** load.packages('quantmod') tickers = spl('SPY') data <- new.env() getSymbols(tickers, src = 'yahoo', from = '1970-01-01', env = data, auto.assign = T) for(i in ls(data)) data[[i]] = adjustOHLC(data[[i]], use.Adjusted=T) bt.prep(data, align='keep.all', dates='1970::') #***************************************************************** # Code Strategies #****************************************************************** prices = data$prices nperiods = nrow(prices) models = list() #***************************************************************** # Buy & Hold #****************************************************************** data$weight[] = 0 data$execution.price[] = NA data$weight[] = 1 models$buy.hold = bt.run.share(data, clean.signal=T) #***************************************************************** # MA cross-over strategy #****************************************************************** sma.fast = SMA(prices, 50) sma.slow = SMA(prices, 200) signal = iif(sma.fast >= sma.slow, 1, -1) data$weight[] = NA data$weight[] = signal models$ma.crossover = bt.run.share(data, clean.signal=T, trade.summary = TRUE) #***************************************************************** # MA cross-over strategy, add 10c per share commission #***************************************************************** data$weight[] = NA data$weight[] = signal models$ma.crossover.com = bt.run.share(data, commission = 0.10, clean.signal=T)
The transaction costs reduced the total strategy performance from 5.13 to 4.83
The Backtesting library in the Systematic Investor Toolbox was designed with an assumption that there is only one price at which securities are traded each day, by default I used Close prices. The Execution.Price field allows to override this default functionality. In the following example, I modified the 50 / 200 day moving average cross over strategy to Enter trades at the open the next day after the signal.
#***************************************************************** # MA cross-over strategy: # Exit trades at the close on the day of the signal # Enter trades at the open the next day after the signal #****************************************************************** popen = bt.apply(data, Op) signal.new = signal trade.start = which(signal != mlag(signal) & signal != 0) signal.new[trade.start] = 0 trade.start = trade.start + 1 data$weight[] = NA data$execution.price[] = NA data$execution.price[trade.start,] = popen[trade.start,] data$weight[] = signal.new models$ma.crossover.enter.next.open = bt.run.share(data, clean.signal=T, trade.summary = TRUE) #***************************************************************** # Create Report #****************************************************************** # Plot perfromance plotbt(models, plotX = T, log = 'y', LeftMargin = 3) mtext('Cumulative Performance', side = 2, line = 1) # Plot trades plotbt.custom.report.part3(models$ma.crossover, trade.summary = TRUE) plotbt.custom.report.part3(models$ma.crossover.enter.next.open, trade.summary = TRUE)
This modification reduced the total strategy performance from 5.13 to 5.09 and we can double check the logic by comparing trades for each strategy below:
To view the complete source code for this example, please have a look at the bt.execution.price.test() function in bt.test.r at github.
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.