Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

COMP226: Intro to backtester_2022

This document gives an introduction to the backtester_2022 framework, which is used in

assignment 2. As a first step, download backtester_2022 .zip from Canvas and unzip it:


backtester_2022

── DATA

│    ├── A2

│    ├── 01 .csv

│    ├── 02 .csv

│    ├── 03 .csv

│    └── 04 .csv

└── EXAMPLE

├── 01 .csv

├── 02 .csv

├── 03 .csv

├── 04 .csv

└── 05 .csv

── a2_main_template .R

├── a2_periods .R

├── a2_test_checks_and_getTMA .R

├── a2_yamls

├── rsjs

│    └── results .yaml

├── x1xxx

│    └── results .yaml

├── x1yyy

│    └── results .yaml

└── x1zzz

│        └── results .yaml

├── example_strategies .R

── framework

│    ├── backtester .R

│    ├── data .R

│    └── processResults .R

── main .R

└── strategies

├─

├─

├─

├─

├─

├─

└─

a2_strategy_template .R

bbands_contrarian .R

bbands_holding_period .R

bbands_trend_following .R

copycat .R

fixed .R

rsi_contrarian .R

10 directories, 28 files


Next, open R and make sure that the working directory is the backtester_2022 directory you just created (use setwd if required). Now try the example code as follows:


source( 'main .R')

If this doesn't work, first make sure you are have set the working directory correctly, and then make sure you have installed all the required packages (see any error messages to see what the problem is). When it works it will produce a plot like the following, with one equity curve for each series (5 in this case), and one aggregate equity curve (at the top):


Let's go through main .R and see what the individual parts do.

Sourcing the framework and example strategies. First we source the framework itself.


source( 'framework/data .R')

source( 'framework/backtester .R')

source( 'framework/processResults .R')

Then we source example_strategies .R, which gives an easy way to run several examples.


source( 'example_strategies .R')

Loading data. Next, we load in data using getData, which is defined in framework/data .R. This function returns a list of xts objects, which will be passed to the function backtester.


dataList <- getData(directory="EXAMPLE")

There  are  5  series  in  backtester_2022/DATA/EXAMPLE/,  and therefore  dataList has  5 elements. Every element is an xts series, and all the series have the same start and end dates:


> for (x in dataList) print(paste(class(x)[1],start(x),end(x)))

[1] "xts

[1] "xts

[1] "xts

[1] "xts

[1] "xts

The individual series contain Open, High, Low, Close, and Volume columns:


> head(dataList [[1]])

Open High Low Close Volume

1970-01-02 0.7676 0.7698 0.7667 0.7691   3171

1970-01-03 0.7689 0.7737 0.7683 0.7729   6311




1970-01-04 0.7725 0.7748 0.7718 0.7732

1970-01-05 0.7739 0.7756 0.7739 0.7751

1970-01-06 0.7760 0.7770 0.7754 0.7757

1970-01-07 0.7738 0.7744 0.7728 0.7743

Subsetting the data. Next we choose to only use the first 200 days:


# subset data: just use first 200 days

dataList <- lapply(dataList , function(x) x [1 :200])

Loading a strategy. example_strategies .R provides helper functions to load and set the parameters for the following example strategies:


example_strategies <- c("fixed" ,

"copycat" ,

"rsi_contrarian" ,

"bbands_trend_following" ,

"bbands_contrarian" ,

"bbands_holding_period")

Returning to main .R, we see where we picked one (and then checked that the choice is valid):


# choose strategy from example_strategies

strategy <- "fixed"

# check that the choice is valid

stopifnot(is_valid_example_strategy(strategy))

Now we load the strategy and its parameters using a helper function:


load_strategy(strategy) # function from example_strategies .R

The structure of a strategy. Here's the source code for strategies/fixed .R, which we just loaded:


# In period 1, use market orders to take positions according to params$sizes

# No further orders are placed by getOrders

# The backtester automatically exits all positions when the data runs out

getOrders <- function(store , newRowList , currentPos , info , params) {

allzero <- rep(0 ,length(newRowList))

marketOrders <- allzero

if (is .null (store)) {

marketOrders <- params$sizes

store <- 1 # not null

}

return(list(store=store ,marketOrders=marketOrders ,

limitOrders1=allzero ,

limitPrices1=allzero ,

limitOrders2=allzero ,

limitPrices2=allzero))

}

The backtester runs a strategy by calling getOrders, which always has the same arguments:


store: contains all data you choose to save from one period to the next

newRowList: new day's data (a list of single rows from the series)







currentPos: the vector of current positions in each series

info: not needed for assignment 2

params: a list of parameters that are sent to the function


In fixed .R, getOrders is the only function. Here's how strategy fixed .R works. In period 1, the backtester always passes store to getOrders with NULL as its value. Thus in period 1 (and only in period 1) marketOrders will be set as params$sizes. In example_strategies .R we see params$sizes set as 1 for all series, i.e., we buy and hold one unit in every series:


list(sizes=rep(1 ,5))

Changing the parameters. We can change params to stay flat in some series and go short in others, e.g., with the following in example_strategies .R or main .R:


params <- list(sizes=c(1 ,2 ,0 ,0 ,-1))