COMP226-R代写-assignment 2
时间:2024-05-07
COMP226: Intro to backtester_2024
This document gives an introduction to the backtester_2024 framework, which is used in assignment 2. As a
first step, download backtester_2024.zip from Canvas and unzip it:
backtester_2024
nnn DATA
n nnn A2
n n nnn 01.csv
n n nnn 02.csv
n n nnn 03.csv
n n nnn 04.csv
n nnn EXAMPLE
n nnn 01.csv
n nnn 02.csv
n nnn 03.csv
n nnn 04.csv
n nnn 05.csv
nnn a2_main_template.R
nnn a2_periods.R
nnn a2_test_checks_and_getTMA.R
nnn a2_yamls
n nnn rsjs
n n nnn results.yaml
n nnn x1xxx
n n nnn results.yaml
n nnn x1yyy
n n nnn results.yaml
n nnn x1zzz
n nnn results.yaml
nnn example_strategies.R
nnn framework
n nnn backtester.R
n nnn data.R
n nnn processResults.R
nnn main.R
nnn strategies
nnn a2_strategy_template.R
nnn bbands_contrarian.R
nnn bbands_holding_period.R
nnn bbands_trend_following.R
nnn copycat.R
nnn fixed.R
nnn rsi_contrarian.R
10 directories, 28 files
Next, open R and make sure that the working directory is the backtester_2024 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_2024/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 1970-01-02 1970-07-20"
[1] "xts 1970-01-02 1970-07-20"
[1] "xts 1970-01-02 1970-07-20"
[1] "xts 1970-01-02 1970-07-20"
[1] "xts 1970-01-02 1970-07-20"
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 4317
1970-01-05 0.7739 0.7756 0.7739 0.7751 3409
1970-01-06 0.7760 0.7770 0.7754 0.7757 2904
1970-01-07 0.7738 0.7744 0.7728 0.7743 3514
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:
getOrders <- function(store, newRowList, currentPos, info, params) {
• 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))
Compare the new and old equity curves: For series 1 they are the same, for series 2 the new one is scaled
by 2, for series 3 and 4 we now don't trade, and for series 5 the equity curve is (essentially) reflected in the
profit and loss axis.
Market orders. fixed.R uses market orders. The backester framework also supports limit orders, but we
will not use them for assignment 2.
In the framework, trading decisions are made after the close of day k, with trades executed on day k+1. Per
day, the framework supports one market order for each series, and two limit orders for each
series. These orders are returned from getOrders as follows:
return(list(store=store,marketOrders=marketOrders,
limitOrders1=limitOrders1,
limitPrices1=limitPrices1,
limitOrders2=limitOrders2,
limitPrices2=limitPrices2))
Market orders will be executed at the open on day k+1. The sizes and directions are encoded in
the element marketOrders of the list returned by getOrders. For example
c(0,-5,0,1,0)
means place a market order for 5 units short in series 2, and 1 unit long in series 4.
Since we will not use limit orders for assignment 2, so you should leave limitOrders1, limitPrices1,
limitOrders2, limitPrices2 as zero vectors when you do assignment 2.
Running the backtest. Finally we do the backtest and plot the results:
# Do backtest
results <- backtest(dataList,getOrders,params,sMult)
plotResults(dataList,results)
cat("Profit:", results$aggProfit, '\n')
The arguments to the function backtest are the following:
• dataList - list of (daily) xts objects (with identical indexes)
• getOrders - the strategy
• params - the parameters for the strategy
• sMult - slippage multiplier (proportion of overnight gap)
Results for individual series are in results$pnlList. The aggregate profit is stored in
results$aggProfit, which we see as the final line of the output when we source main.R (the the original
parameters for fixed.R):
Read 5 series from DATA/EXAMPLE
Sourcing strategies/fixed.R
[1] "Parameters:"
$sizes
[1] 1 1 1 1 1
Profit: 1469.036
In assignment 2 you will use the params argument to getOrders to vary the parameters in order to
optimise the aggregate profit of a trading strategy that you will implement.
plotResults produces the plots above, which is useful during development, but should not be used when
doing the parameter optimisation as it will needlessly slow things down.
essay、essay代写