From 046ab47727be11b55c78276ab39bc8aa5843637e Mon Sep 17 00:00:00 2001
From: Serkan Korkmaz <77464572+serkor1@users.noreply.github.com>
Date: Sun, 7 Jul 2024 17:50:42 +0200
Subject: [PATCH] Updated vignette :arrow_up: :arrow_up:
The custom chart vignette is now more user-friendly. It was targeted developers before
---
vignettes/custom_indicators.Rmd | 460 ++++++++------------------------
1 file changed, 117 insertions(+), 343 deletions(-)
diff --git a/vignettes/custom_indicators.Rmd b/vignettes/custom_indicators.Rmd
index 457ec7d8..792cdfea 100644
--- a/vignettes/custom_indicators.Rmd
+++ b/vignettes/custom_indicators.Rmd
@@ -1,9 +1,8 @@
---
-title: "A Guide on Custom Indicators"
-subtitle: "How to build and chart it"
+title: "A Guide on Charting and Custom Indicators"
output: rmarkdown::html_vignette
vignette: >
- %\VignetteIndexEntry{A Guide on Custom Indicators}
+ %\VignetteIndexEntry{A Guide on Charting and Custom Indicators}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
@@ -12,6 +11,7 @@ vignette: >
knitr::opts_chunk$set(
collapse = TRUE,
message = FALSE,
+ warning = FALSE,
comment = "#>",
out.width = "100%",
out.height = "620px"
@@ -22,394 +22,168 @@ knitr::opts_chunk$set(
library(cryptoQuotes)
```
-Trading indicators comes in various forms; from the alignment of the moon relative to the sun, to sophisticated trading rules based on neural networks which incorporates classified features - It is not possible to cover them all in an `R` package.
+Trading indicators comes in various forms; from the alignment of the moon relative to the sun, to sophisticated trading rules based on neural networks which incorporates classified features; It is not possible to cover them all in an `R` package.
-In this `vignette` an introduction to the construction of charting indicators are given, and is recommended for those who would want to chart indicators not otherwise found in [{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/).
+In this `vignette` an introduction to the construction of charts and chart indicators are given, and is recommended for those who would want to chart indicators not otherwise found in [{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/). The `vignette` uses the built-in `BTC`-object.
> **Note:** Feel free to make a `PR` with your indicators that you wish to share with the
> rest of the community.
-## Charting indicators
+As the charts in [{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) uses [{plotly}](https://github.com/plotly) as backend, the `chart`-objects complies with it's syntax.
-Below is a chart, with the indicators `macd()` and `bollinger_bands()`. Each indicator is created using [{TTR}](https://github.com/joshuaulrich/TTR).
+## Custom Indicators
+
+We start by creating a simple `chart`-object with `volume` as it's only indicator,
```{r}
-chart(
- ticker = BTC,
- main = kline(),
- sub = list(
- macd()
- ),
- indicator = list(
- bollinger_bands()
- )
+# 1) create a simple chart
+# object
+chart_object <- chart(
+ ticker = BTC,
+ main = kline(),
+ sub = list(
+ volume()
+ ),
+ options = list(
+ dark = FALSE
+ )
)
-```
-### The anatomy of indicators
-
-Each indicator is either a *main chart*- or *subchart*-indicator, lets call them `classes` for consistency. The source code for each `class` of indicator is given below,
-
-
-Main chart indicator (Bollinger Bands)
-```{r, echo=FALSE}
-bollinger_bands
+# 2) display the chart
+chart_object
```
-
-
-Subchart indicator (MACD)
-```{r, echo=FALSE}
-macd
-```
-
+### Sinus-oscillator
-Common for both indicator `classes` is that they are wrapped in `structure`, with `class = c("plotly", "htmlwidget")`,
+Assume a trading strategy that follows a `sin`-curve throughout the period of interest. The starting point is generating the indicator,
-```R
-structure(
- .Data = {
-
- # Indicator Logic
+```{r}
+# 1) generate sin-indicator
+sin_indicator <- data.frame(
+ index = zoo::index(BTC),
+ sin_indicator = sin(seq(0,8*pi,length.out=nrow(BTC)))
- },
- class = c(
- yourclass,
- "plotly",
- "htmlwidget"
- )
)
```
-What differentiates the two `classes` of indicators, is the addition of `indicator` or `subchart` in the `yourclass`-placeholder.
-
-The indicator logic is important for the correct charting of your custom indicator. As
-[{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) uses
-[{plotly}](hhttps://github.com/plotly/plotly.R) as backend for charting, your `class` of indicator has to be consistent with the use of [{plotly}](hhttps://github.com/plotly/plotly.R)-functions. More specifically; `subchart`-indicators uses `plotly::plot_ly()`-functions, while main chart `indicator` uses the `plotly::add_*`-family of functions.
-
-When creating the custom indicators there is a couple of additional steps needed which will be covered in the examples.
-
-## Donchian Channels (Example)
-
-Assume a trading strategy based on Donchian Channels (`TTR::DonchianChannel()`) is needed to optimize your profits. This indicator is a main chart indicator, similar to that of `TTR::BBands()`,
+The `sin_indicator` in it's basic form can be charted as follows,
```{r}
-tail(
- TTR::DonchianChannel(
- HL = BTC[,c("high", "low")]
+# 1) create a plotly-object
+# with the sin-indicator
+sin_indicator <- plotly::layout(
+ margin= list(l = 5, r = 5, b = 5),
+ p = plotly::plot_ly(
+ data = sin_indicator,
+ y = ~sin_indicator,
+ x = ~index,
+ type = "scatter",
+ mode = "lines",
+ name = "sin"
+ ),
+ yaxis = list(
+ title = NA
+ ),
+ xaxis = list(
+ title = NA
)
)
+# 2) display the
+# indicator
+sin_indicator
```
-This indicator has three features; `high`, `mid` and `low`. To chart this indicator, we would need to call the `plotly::add_lines()`-function three times to chart it properly. Each of these features are defined as `layers` in [{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/). All layers get built with the `cryptoQuotes:::build()`-function.
-
-```{r}
-## define custom TA
-## donchian_channel
-donchian_channel <- function(
- ## these arguments are the
- ## available arguments in the TTR::DonchianChannel
- ## function
- n = 10,
- include.lag = FALSE,
- ## the ellipsis
- ## is needed to interact with
- ## the chart-function
- ...
-) {
-
- structure(
- .Data = {
-
- ## 1) define args
- ## as a list from the ellipsis
- ## which is how the chart-function
- ## communicates with the indicators
- args <- list(
- ...
- )
-
- ## 2) define the data, which in this
- ## case is the indicator. The indicator
- ## function streamlines the data so it works
- ## with plotly
- data <- cryptoQuotes:::indicator(
- ## this is just the ticker
- ## that is passed into the chart-function
- x = args$data,
-
- ## columns are the columns of the ohlc
- ## which the indicator is calculated on
- columns = c("high", "low"),
-
- ## the function itself
- ## can be a custom function
- ## too.
- .f = TTR::DonchianChannel,
-
- ## all other arguments
- ## passed into .f
- n = n,
- include.lag = FALSE
- )
-
- ## each layer represents
- ## each output from the indicator
- ## in this case we have
- ## high, mid and low.
- ##
- ## The lists represents a plotly-function
- ## and its associated parameters.
- layers <- list(
- ## high
- list(
- type = "add_lines",
- params = list(
- showlegend = FALSE,
- legendgroup = "DC",
- name = "high",
- inherit = FALSE,
- data = data,
- x = ~index,
- y = ~high,
- line = list(
- color = "#d38b68",
- width = 0.9
- )
- )
- ),
-
- ## mid
- list(
- type = "add_lines",
- params = list(
- showlegend = FALSE,
- legendgroup = "DC",
- name = "mid",
- inherit = FALSE,
- data = data,
- x = ~index,
- y = ~mid,
- line = list(
- color = "#d38b68",
- dash ='dot',
- width = 0.9
- )
- )
- ),
-
- ## low
- list(
- type = "add_lines",
- params = list(
- showlegend = FALSE,
- legendgroup = "DC",
- name = "low",
- inherit = FALSE,
- data = data,
- x = ~index,
- y = ~low,
- line = list(
- color = "#d38b68",
- width = 0.9
- )
- )
- )
- )
-
- ## we can add ribbons
- ## to the main plot to give
- ## it a more structured look.
- plot <- plotly::add_ribbons(
- showlegend = TRUE,
- legendgroup = 'DC',
- p = args$plot,
- inherit = FALSE,
- x = ~index,
- ymin = ~low,
- ymax = ~high,
- data = data,
- fillcolor = cryptoQuotes:::as_rgb(alpha = 0.1, hex_color = "#d38b68"),
- line = list(
- color = "transparent"
- ),
- name = paste0("DC(", paste(c(n), collapse = ", "), ")")
- )
-
- ## the plot has to be build
- ## using the cryptoQuotes::build-function
- invisible(
- cryptoQuotes:::build(
- plot,
- layers = layers
- )
- )
-
- }
- )
-
-}
-```
-
-The indicator function can be passed into the appropriate argument in the `chart()`-function, which will handle everything else,
+The `sin_indicator` can be added to the `chart_object` using `plotly::subplot` which also handles the theming,
```{r}
-chart(
- ticker = BTC,
- main = kline(),
- sub = list(
- volume()
+# 1) append the sin_indicator
+# to the chart object
+chart_object <- plotly::subplot(
+ # ensures that plots are
+ # vertically aligned
+ nrows = 2,
+ heights = c(
+ 0.7,
+ 0.2
),
- indicator = list(
- bollinger_bands(),
- donchian_channel()
- )
+ chart_object,
+ sin_indicator,
+ shareX = FALSE,
+ titleY = FALSE
)
+
+# 2) display the chart
+# object
+chart_object
```
-## Commodity Channel Index (Example)
+### Linear Regression Line
-Assume a trading strategy based on Commodity Channel Indices (`TTR::CCI()`) is needed to optimize your profits. This indicator is subchart indicator similar to that of `TTR::RSI()`,
+Assume a trading strategy that goes long (short) every time the price is below (above) the linear regression line. This indicator can be defined as follows,
```{r}
-tail(
- TTR::CCI(
- HLC = BTC[,c("high", "low", "close")]
- )
+# 1) linear regression
+# line
+lm_indicator <- data.frame(
+ y = fitted(
+ lm(
+ close ~ time,
+ data = data.frame(
+ time = 1:nrow(BTC),
+ close = BTC$close
+ )
+ )
+ ),
+ index = zoo::index(BTC)
)
```
-This indicator has a single feature; `cci`. As this indicator is a subchart indicator with a single feature, we only need a single `layer` built with `plot_ly()`,
-
+The `lm_indicator` in it's basic form can be charted as follows,
```{r}
-## define custom TA
-## Commodity Channel Index (CCI)
-cc_index <- function(
- ## these arguments are the
- ## available arguments in the TTR::CCI
- ## function
- n = 20,
- maType,
- c = 0.015,
- ## the ellipsis
- ## is needed to interact with
- ## the chart-function
- ...
-) {
-
- structure(
- .Data = {
-
- ## 1) define args
- ## as a list from the ellipsis
- ## which is how the chart-function
- ## communicates with the indicators
- args <- list(
- ...
- )
-
- ## 2) define the data, which in this
- ## case is the indicator. The indicator
- ## function streamlines the data so it works
- ## with plotly
- data <- cryptoQuotes:::indicator(
- ## this is just the ticker
- ## that is passed into the chart-function
- x = args$data,
-
- ## columns are the columns of the ohlc
- ## which the indicator is calculated on
- columns = c("high", "low", "close"),
-
- ## the function itself
- ## can be a custom function
- ## too.
- .f = TTR::CCI,
-
- ## all other arguments
- ## passed into .f
- n = n,
- maType = maType,
- c = c
- )
-
-
- layer <- list(
- list(
- type = "plot_ly",
- params = list(
- name = paste0("CCI(", n,")"),
- data = data,
- showlegend = TRUE,
- x = ~index,
- y = ~cci,
- type = "scatter",
- mode = "lines",
- line = list(
- color = cryptoQuotes:::as_rgb(alpha = 1, hex_color = "#d38b68"),
- width = 0.9
- )
- )
-
- )
- )
-
- cryptoQuotes:::build(
- plot = args$plot,
- layers = layer,
- annotations = list(
- list(
- text = "Commodity Channel Index",
- x = 0,
- y = 1,
- font = list(
- size = 18
- ),
- xref = 'paper',
- yref = 'paper',
- showarrow = FALSE
- )
- )
- )
-
-
-
- }
- )
-
-}
+# 1) display the linear
+# regression line on
+# an empty chart
+plotly::add_lines(
+ p = plotly::plotly_empty(),
+ data = lm_indicator,
+ y = ~y,
+ x = ~index,
+ inherit = FALSE,
+ xaxis = "x1",
+ yaxis = "y2",
+ name = "regression"
+)
```
+The `lm_indicator` can be added to the `chart_object` using `plotly::add_lines` which also handles the theming,
```{r}
-chart(
- ticker = BTC,
- main = kline(),
- sub = list(
- volume(),
- cc_index()
+# 1) add the regression
+# line to the chart_object
+plotly::layout(
+ margin = list(l = 5, r = 5, b = 5, t = 65),
+ plotly::add_lines(
+ p = chart_object,
+ data = lm_indicator,
+ y = ~y,
+ x = ~index,
+ inherit = FALSE,
+ xaxis = "x1",
+ yaxis = "y2",
+ name = "regression"
),
- indicator = list(
- bollinger_bands(),
- donchian_channel()
+ yaxis = list(
+ title = NA
+ ),
+ xaxis = list(
+ title = NA
)
)
```
## Summary
-Creating custom indicators for the `chart()`-functions can be daunting. Two examples of how these are developed in [{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) have been covered.
+Creating custom indicators for the `chart()`-functions follows standard [{plotly}](https://github.com/plotly) syntax. Two examples of how these are charted in [{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) have been covered.
> **Note:** A full pipeline of charting indicators, custom and built-in, will be released sometime in the future.
-
-To summarise the example,
-
-1. Define the `indicator`-function (e.g `TTR::CCI()`)
-2. Define the `chart`-function for the indicator (e.g `cc_index()`)
- 1. Wrap the `indicator`-function in `cryptoQuotes:::indicator()`
- 2. Define the `layers` according to features, and wether its a subchart or main chart indicator
- 3. Build the chart using `cryptoQuotes:::build()`
-3. Add the `chart`-function for the indicator in the appropriate argument in the `chart()`-function
-
-