-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathREADME.Rmd
184 lines (135 loc) · 4.95 KB
/
README.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
---
output: github_document
editor_options:
chunk_output_type: console
---
<!-- README.md is generated from README.Rmd. Please edit that file -->
```{r setup, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```
![lifecycle](https://img.shields.io/badge/lifecycle-experimental-brightgreen.svg)
# flyingfox
The goal of `flyingfox` is to connect Quantopian's `zipline` financial backtesting package with R.
## Installation
You can install the released version of flyingfox from [CRAN](https://CRAN.R-project.org) with:
``` r
# NO YOU CANNOT
install.packages("flyingfox")
```
And the development version from [GitHub](https://github.com/) with:
``` r
# install.packages("devtools")
devtools::install_github("DavisVaughan/flyingfox")
```
## Setup
(Using reticulate >= 1.7.1)
To get started with `zipline`, you'll need the `zipline` Python module. Install it with:
```{r, eval=FALSE}
install_zipline()
```
By default `zipline` will be installed into the virtualenv, `r-reticulate`,
as recommended by `reticulate`.
Next, you'll need data to run the backtest on. The easiest way
to do this is to:
1) Create a free account on [Quandl](https://www.quandl.com/) and find your API Key in Account Settings.
2) Add the API key as the R environment variable, `QUANDL_API_KEY` (access your `.Renviron` file with `usethis::edit_r_environ()`).
3) "Ingest" the Quandl data with `flyingfox::fly_ingest()`.
```{r, eval=FALSE}
fly_ingest()
```
## Example
`flyingfox` backtests are run using a combination of two main functions. `fly_initialize()` sets up variables you might need during the backtest along with giving you a chance to schedule functions to run periodically. `fly_handle_data()` is called at a daily/minutely frequency and runs your algorithm, orders assets, and records data for future inspection.
Below, we are going to create a basic mean reversion strategy to demonstrate the
basics of running an algorithm.
```{r}
library(flyingfox)
```
First, set up an initialize function. It must take `context` as the argument.
Think of `context` as a persistent environment where you can store variables
and assets that you want to access at any point in the simulation.
```{r}
fly_initialize <- function(context) {
# We want to track what day we are on. The mean reversion algo we use
# should have at least 300 days of data before doing anything
context$i = 0L
# We want to trade apple stock
context$asset = fly_symbol("AAPL")
}
```
Next, create a data handling function that accepts `context` and `data`. Think
of `data` as an environment containing functions for accessing historical and
current price data about the assets you are using in your simulation.
The below implementation of `fly_handle_data()` demonstrates a mean reversion algorithm.
```{r}
fly_handle_data <- function(context, data) {
# Increment day
context$i <- context$i + 1L
# While < 300 days of data, return
if(context$i < 300L) {
return()
}
# Calculate a short term (100 day) moving average
# by pulling history for the asset (apple) and taking an average
short_hist <- fly_data_history(data, context$asset, "price", bar_count = 100L, frequency = "1d")
short_mavg <- mean(short_hist)
# Calculate a long term (300 day) moving average
long_hist <- fly_data_history(data, context$asset, "price", bar_count = 300L, frequency = "1d")
long_mavg <- mean(long_hist)
# If short > long, go 100% in apple
if(short_mavg > long_mavg) {
fly_order_target_percent(asset = context$asset, target = 1)
}
# Else if we hit the crossover, dump all of apple
else if (short_mavg < long_mavg) {
fly_order_target_percent(asset = context$asset, target = 0)
}
# Record today's data
# We record the current apple price, along with the value of the short and long
# term moving average
fly_record(
AAPL = fly_data_current(data, context$asset, "price"),
short_mavg = short_mavg,
long_mavg = long_mavg
)
}
```
Run the algo over a certain time period.
```{r}
performance <- fly_run_algorithm(
initialize = fly_initialize,
handle_data = fly_handle_data,
start = as.Date("2013-01-01"),
end = as.Date("2016-01-01")
)
tail(performance)
```
From the `performance` tibble, we can look at the recorded value of Apple's stock price.
```{r}
library(ggplot2)
library(dplyr)
library(lubridate)
performance <- performance %>%
mutate(date = as.POSIXct(date, "UTC"))
performance %>%
filter(date >= "2014-08-01") %>%
ggplot(aes(x = date, y = AAPL)) +
geom_line()
```
We can also look at the value of our portfolio over time.
```{r}
first_order <- performance %>%
filter(row_number() == 300) %>%
pull(date)
performance %>%
mutate(date = as.POSIXct(date, "UTC")) %>%
ggplot(aes(x = date, y = portfolio_value)) +
geom_line() +
geom_vline(xintercept = first_order, color = "red") +
annotate("text", x = first_order - days(50), y = 10500,
label = "First Order", color = "red")
```