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

COMP226 Assignment 2: Strategy Development

First, let's recall the contents of the backtester_2023.zip:

In the above listing, the following files/directories are specifically there for assignment 2:

a2_main_template.R

a2_periods.R

a2_test_checks_and_getTMA.R

• strategies/a2_strategy_template.R

a2_example_yamls

• DATA/A2

The relevance of these files and directories will be explained below. The rest of the document is split into three parts:

• Part  1 describes the  10 functions that should be implemented to fully complete  strategy.R; you should start from a2_strategy_template.R;

Part 2 describes how to create (the optional) results.yaml;

Part 3 describes submission via CodeGrade and the available pre-deadline tests.

In addition to pre-deadline tests on CodeGrade, example outputs are provided (in this document and as files) so that you can test whether you have implemented things correctly.

As for assignment 1, the pre-deadline tests will determine your mark for the first part, corresponding to 70% of the overall marks that are available. Assuming that you have achieved full marks on the first part, the pre-deadline tests will check that the form of results.yaml is correct, and that it uses the expected student username  (i.e.,  your  one)  and  corresponding  time  periods;  the  pre-deadline  tests  do not check  the correctness of the other fields in results.yaml, which will be checked post deadline only if you pass the pre-deadline test for results.yaml. For those other fields, you should use the examples provided (which are in the subdirectory a2_example_yamls).

Part 1: strategy implementation (70%)

The trading strategy that you should implement is a triple moving average (TMA) momentum strategy, which is described in slides 4.7. The specification of the strategy and the functions that it should comprise are given

in full detail, so the correctness of your code can and will be checked automatically.

Two template files are provided to get you started:

• strategies/a2_strategy_template.R,  which  should  become  the  file  strategy.R that  you eventually submit;

• a2_main_template.R, which uses DATA/A2 and strategies/a2_strategy_template.R. If you source a2_main_template.R with no edits to these two files you will get an error:

This is because the strategy requires a parameter called lookbacks that you will need to pass in from a2_main_template.R. Read on to see what form this parameter should take, and, more generally, how you should be editing these two files.

a2_strategy_template.R contains  10  incomplete  functions  that  you  need  to  complete.  The  first  6 functions (checkE01,..., checkE06) are error checks for the inputs to getTMA. These error checks are all one-liners, worth 3% each. They are intentionally meant to be straightforward to implement. The next three functions   compute   the   moving   averages   (getTMA),   use   them   to   compute   the   position   sign (getPosSignFromTMA),   and   compute  the   position   size   (getPosSize).  The  final,  tenth  function, getOrders combines the last three to implement that actual trading strategy. Recall that every strategy in the backtester framework has a getOrders function.

The  TMA  momentum  strategy  that  you  should  implement  uses  three  moving  averages  with  different lookbacks (window lengths). The short lookback should be smaller than the medium one, which in turn should be smaller than the long lookback. In every trading period, the strategy will compute the value of these three moving averages (for the series that it trades on, which will be determined by params$series). You will achieve this by completing the implementation of the function getTMA.

The following table indicates the position that the strategy will take depending on the relative values of the three moving averages (MAs). You will compute this position (sign, but not size) by completing the function getPosSignFromTMA. The system is out of the market (i.e., flat) when the relationship between the short MA and the medium MA does not match the relationship between the medium MA and the long MA.

The function getPosSignFromTMA takes the output of getTMA as input. The position size, i.e., the number of units to be long or short, is determined by getPosSize. As for all strategies in the backtester framework, the positions are given to the backtester by getOrders. Here are the detailed specification and marks available for these 10 functions.


All-or-nothing tests

Since the check functions and getPosSignFromTMA function will only return a small number of possible correct values (2 for the check functions, and 3 for getPosSign), these are implemented as "all-or-nothing" tests where you either get full marks for passing all tests or no marks if you fail at least


one test. As a very simple function, getPosSign is also marked with all-or-nothing tests, so from the first 10 functions, partial marks are only available for getTMA and getOrders.


Strategy specification

The strategy should apply the following logic independently to only the series in params$series (e.g., params$series could be c(1,3), which would mean trade only on series 1 and 3).

It does nothing until there have been params$lookbacks$long-many periods.

In the (params$lookbacks$long+1)-th period, and in every period after, the strategy computes three simple moving averages with window lengths equal to:

params$lookbacks$short

params$lookbacks$medium

params$lookbacks$long

The corresponding windows always end in the current period. The strategy should in this period send market orders to assume  a  position  (make  sure  you  take  into  account  positions  from  earlier) according to getPosSignFromTMA and getPosSize. (Limit orders are not required at all, and can be left as all zero.)


Hints

You can develop the first 9 functions without running the backtester.

For the checks you may find the following functions useful:

The operator ! means not, and can be used to negate a boolean.

sapply allows one to apply a function element-wise to a vector or list (e.g., to c("short","medium","long")).

• all is a function that checks if all elements of a vector are true (for example, it can be used on the result of sapply).

• %in% can be used to check if an element exists inside a vector.

To compute the moving average in getTMA you can use SMA from the TTR package. For getPosSize, you can use the function floor.

For getOrders some instructions are given as comments in a2_strategy_template.R.

If an error occurs within a function and you would like to inspect the contents of a variable that is local to the function, in addition to printing, you can also use global assignment (<<-) for debugging.


Example output for checkE01 ... checkE06 and getTMA

The file a2_test_checks_and_getTMA.R is provided to give you guidance on how you can test the six functions, checkE01 ... checkE06. For each one, two tests are provided: for a correct implementation, one test should produce TRUE and the other FALSE. (You don't need to use these tests, as you can also just rely on the tests on CodeGrade.)

To use these tests, first source a2_test_checks_and_getTMA.R and also source the implementations that you would like to test. The tests that should return TRUE are test_checkE01() ... test_checkE06(); for tests that should return  FALSE, there is single function,  test_pass_all_checks, which takes the function to test as its only argument. Here's an example of both types of test for E01 (where a correct implementation of checkE01 has been sourced):

> test_checkE01 ()

[1] TRUE

> test_pass_all_checks (checkE01)

[1] FALSE

The way these tests work is clear from the source code in a2_test_checks_and_getTMA.R:

###############################################################################

# Source the functions that you would like to test, e .g., with

# source('strategies/a2_strategy_template .R') or source('strategies/strategy.R')

###############################################################################

source('framework/data.R'); dataList <- getData(directory="A2")

prices <- dataList[[1]]

prices_19_rows <- dataList[[1]]$Close[1:19]

prices_20_rows <- dataList[[1]]$Close[1:20]

prices_20_rows_renamed <- prices_20_rows

colnames(prices_20_rows_renamed) <- 'Closed'