# TODO: # - add support for dynamic position sizing # - add param to trades to specify single position vs. multiple positions # - add support for trading costs/slipage # - test with different trading rules (TTR's) # - add support for adding to positions (pyramiding) # - add relative returns (R = (P - (P - 1)) / P)? # - expand stats for analysis of results # - add support for derivatives # - check and/or add support for intraday data # - create test data sets and tests #library("TTR") library("quantmod") #library("PerformanceAnalytics") #library("blotter") crosses_over <- function(data, indicator, value) { co_r = cbind(data, indicator) co_r[lag(co_r[, "..2"], 1) <= value & co_r[, "..2"] > value] } crosses_under <- function(data, indicator, value) { cu_r = cbind(data, indicator) cu_r[lag(cu_r[, "..2"], 1) > value & cu_r[, "..2"] <= value] } # when_to_trade: 0 = at the start of the period # 1 = at the end of the period trades <- function(data, open_long=NULL, close_long=NULL, open_short=NULL, close_short=NULL, long_amount=1, short_amount=1, when_to_trade=0) { data$Position = 0 data$LongTrades = 0 data$ShortTrades = 0 # Handle longs if(!is.null(open_long)) { ol = open_long ol$Trade = long_amount clc = close_long clc$Trade = -long_amount cl = clc[paste(index(first(ol)), '::', sep="")] longs = rbind(ol, cl) longs = longs[ (longs [, "Trade"] + lag(longs [, "Trade"], 1) == 0)] longs = rbind(ol[1], longs) data[index(longs), "LongTrades"] = longs$Trade for(row in 2:nrow(longs)) { if(row %% 2 == 0) { if(when_to_trade == 1) { data[paste(index(data[grep(index(longs[row-1]), index(data))+1]), "::", index(longs[row]), sep=""), "Position"] = long_amount } else { data[paste(index(longs[row-1]), "::", index(data[grep(index(longs[row]), index(data)) - 1]), sep=""), "Position"] = long_amount } } } if(nrow(longs) %% 2 == 1) { if(when_to_trade == 1) { data[paste(index(data[grep(index(longs[nrow(longs)]), index(data))+1]), "::", sep=""), "Position"] = long_amount } else { data[paste(index(longs[nrow(longs)]), "::", sep=""), "Position"] = long_amount } } } # Handle shorts if(!is.null(open_short)) { os = open_short os$Trade = -short_amount csc = close_short csc$Trade = short_amount cs = csc[paste(index(first(os)), '::', sep="")] shorts = rbind(os, cs) shorts = shorts[ (shorts [, "Trade"] + lag(shorts [, "Trade"], 1) == 0)] shorts = rbind(os[1], shorts) data[index(shorts), "ShortTrades"] = shorts$Trade for(row in 2:nrow(shorts)) { if(row %% 2 == 0) { if(when_to_trade == 1) { data[paste(index(data[grep(index(shorts[row-1]), index(data))+1]), "::", index(shorts[row]), sep=""), "Position"] = data[paste(index(data[grep(index(shorts[row-1]), index(data))+1]), "::", index(shorts[row]), sep=""), "Position"] - short_amount } else { data[paste(index(shorts[row-1]), "::", index(data[grep(index(shorts[row]), index(data))-1]), sep=""), "Position"] = data[paste(index(shorts[row-1]), "::", index(data[grep(index(shorts[row]), index(data))-1]), sep=""), "Position"] - short_amount } } } if(nrow(shorts) %% 2 == 1) { if(when_to_trade == 1) { data[paste(index(data[grep(index(shorts[nrow(shorts)]), index(data))+1]), "::", sep=""), "Position"] = data[paste(index(data[grep(index(shorts[nrow(shorts)]), index(data))+1]), "::", sep=""), "Position"] - short_amount } else { data[paste(index(shorts[nrow(shorts)]), "::", sep=""), "Position"] = data[paste(index(shorts[nrow(shorts)]), "::", sep=""), "Position"] - short_amount } } } data } abs_returns <- function(data) { data$AbsReturn = (data$Price - lag(data$Price, 1)) * data$Position data } #compound_returns <- function(data) { # Do we also need comparable simple/compound and/or log() returns, i.e.: # data = cbind(data, Return.calculate(data$Price, method="compound")) #} wealth <- function(data, start=10000.0) { # data$Wealth = lag(data$Wealth, 1) + data$Return data$Wealth = 0 # TODO: handle NA value in first row more elegant data[1, "Wealth"] = start + 0 prevWealth = matrix(data[1, "Wealth"]) for(row in 2:nrow(data)) { #print(row) data[row, "Wealth"] = data[row, "AbsReturn"] + prevWealth prevWealth = matrix(data[row, "Wealth"]) } data } stats <- function(data) { stats=0 stats$pl = 0 stats$pl$all = sum(data[(data$Position != 0), "AbsReturn"]) stats$pl$longs = sum(data[(data$Position > 0), "AbsReturn"]) stats$pl$shorts = sum(data[(data$Position < 0), "AbsReturn"]) stats }