diff --git a/.Rbuildignore b/.Rbuildignore index 9b396e4b..8b088c76 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -17,3 +17,4 @@ playground ^data-raw$ ^codemeta\.json$ NEWS.Rmd +.vdoc.r \ No newline at end of file diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 24a7f327..80a15b07 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -8,6 +8,8 @@ on: name: R-CMD-check +permissions: read-all + jobs: R-CMD-check: runs-on: ${{ matrix.config.os }} @@ -29,7 +31,7 @@ jobs: R_KEEP_PKG_SOURCE: yes steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-pandoc@v2 @@ -47,3 +49,4 @@ jobs: - uses: r-lib/actions/check-r-package@v2 with: upload-snapshots: true + build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' \ No newline at end of file diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml index cfe937b6..080b236b 100644 --- a/.github/workflows/test-coverage.yaml +++ b/.github/workflows/test-coverage.yaml @@ -2,9 +2,9 @@ # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: push: - branches: [development] + branches: [development, expand-test] pull_request: - branches: [development] + branches: [development, expand-test] name: test-coverage diff --git a/.gitignore b/.gitignore index 09bebba5..830332d4 100644 --- a/.gitignore +++ b/.gitignore @@ -51,4 +51,8 @@ inst/doc /doc/ /Meta/ docs -/playground +/playground/ + +/*.html +.vdoc.r +*.Rproj diff --git a/CRAN-SUBMISSION b/CRAN-SUBMISSION new file mode 100644 index 00000000..4fa0cc51 --- /dev/null +++ b/CRAN-SUBMISSION @@ -0,0 +1,3 @@ +Version: 1.3.2 +Date: 2024-11-07 05:41:59 UTC +SHA: e12973201b0a1173d20ccc6d89b774a4f68b95cf diff --git a/DESCRIPTION b/DESCRIPTION index d5a607f9..db3eac68 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,20 +1,30 @@ Package: cryptoQuotes -Title: A Streamlined Access to Cryptocurrency OHLC-V Market Data and Sentiment Indicators -Version: 1.3.1 +Title: Open Access to Cryptocurrency Market Data, Sentiment Indicators and Interactive Charts +Version: 1.3.2 Authors@R: c( - person("Serkan", "Korkmaz", , "serkor1@duck.com", role = c("cre", "aut", "ctb", "cph"), - comment = c(ORCID = "0000-0002-5052-0982")), - person("Jonas", "Cuzulan Hirani", , "jjh@vive.dk", role = "ctb", - comment = c(ORCID = "0000-0002-9512-1993")) + person( + given = "Serkan", + family = "Korkmaz", + email = "serkor1@duck.com", + role = c("cre", "aut", "ctb", "cph"), + comment = c(ORCID = "0000-0002-5052-0982") + ), + person( + given = "Jonas", + family = "Cuzulan Hirani", + email = "jjh@vive.dk", + role = "ctb", + comment = c(ORCID = "0000-0002-9512-1993") + ) ) -Description: - This high-level API client offers a streamlined access to public cryptocurrency market data and sentiment indicators. It features OHLC-V (Open, High, Low, Close, Volume) that comes - with granularity ranging from seconds to months and essential sentiment indicators to develop and backtest trading strategies, or conduct detailed market analysis. By interacting directly with - the major cryptocurrency exchanges this package ensures a reliable, and stable, flow of market information, eliminating the need for complex, low-level API interactions or webcrawlers. +Description: + This high-level API client provides open access to cryptocurrency market data, sentiment indicators, and interactive charting tools. + The data is sourced from major cryptocurrency exchanges via 'curl' and returned in 'xts'-format. The data comes in open, high, low, and close (OHLC) format with flexible granularity, ranging from seconds to months. + This flexibility makes it ideal for developing and backtesting trading strategies or conducting detailed market analysis. License: GPL (>= 2) Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.1 +RoxygenNote: 7.3.2 Suggests: data.table, knitr, @@ -24,14 +34,14 @@ Suggests: tidyverse Config/testthat/edition: 3 Imports: - cli (>= 3.6.2), + cli (>= 3.6.3), curl (>= 5.2.1), jsonlite (>= 1.8.8), lifecycle (>= 1.0.4), plotly (>= 4.10.4), TTR (>= 0.24.4), utils, - xts (>= 0.13.2), + xts (>= 0.14.0), zoo (>= 1.8-12) Depends: R (>= 4.0.0) diff --git a/NAMESPACE b/NAMESPACE index 423df79e..051c5aea 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -23,6 +23,7 @@ export(lsr) export(macd) export(ohlc) export(pline) +export(read_xts) export(remove_bound) export(rsi) export(sma) @@ -31,6 +32,7 @@ export(split_window) export(volume) export(vwap) export(wma) +export(write_xts) export(zlema) importFrom(TTR,BBands) importFrom(curl,has_internet) diff --git a/NEWS.Rmd b/NEWS.Rmd index 34518eb3..341d6292 100644 --- a/NEWS.Rmd +++ b/NEWS.Rmd @@ -23,7 +23,97 @@ knitr::opts_chunk$set( library(cryptoQuotes) ``` -# cryptoQuotes 1.3.1 +# Version 1.3.2 + +## General + +* `bitmart` has updated their futures API. The backend have been updated accordingly. + +* Unit-tests have been updated and now all `get_quote()`-functions are being tested for equality in passed and inferred interval. + +## Improvements + +## Read and Write `xts`-objects + +* `read_xts()` and `write_xts()` reads and stores `xts`-objects. These functions are essentially just wrappers of `zoo::read.zoo()` and `zoo::write.zoo()`. Thank you @gokberkcan7 for the suggestion. + +### Charting + +* The `chart()`-function are now exported as `.svg`-images in 4k resolution via the `modebar`. +* The `chart()`-function are now more interactive and supports drawing lines and rectangles via the `modebar`. It is also possible to interactively change the `title` and `subtitle` by double clicking these (Thank you @andreltr for the suggestion. See [Discussion](https://github.com/serkor1/cryptoQuotes/discussions/19)). +* The `chart()`-function now has a new option `static` that is equal to `FALSE` by default. If `FALSE` the chart can be edited, annotated and explored interactively. +* The `chart()`-function now has a new option `palette` that is set to "hawaii" by default. See `hcl.pals()` for accepted values. +* The `chart()`-function now has a new option `scale` that is set to 1 by default. Scales all fonts on the chart. +* The `chart()`-function now has a new option `width` that is set to 0.9 by default. Sets the overall `linewidth` of the chart. (Thank you @andreltr for the suggestion. See [Discussion](https://github.com/serkor1/cryptoQuotes/discussions/30)) + +
+Static set to FALSE (Default Palette) +```{r} +# static = FALSE +chart( + ticker = BTC, + main = kline(), + indicator = line( + sma(n = 7), + sma(n = 14), + sma(n = 21) + ), + options = list( + static = FALSE, + palette = "hawaii" + ) +) +``` +
+ +
+Static set to TRUE ("Set 3" palette) +```{r} +# static = TRUE +chart( + ticker = BTC, + main = kline(), + indicator = line( + sma(n = 7), + sma(n = 14), + sma(n = 21) + ), + options = list( + static = TRUE, + palette = "Set 3" + ) +) +``` +
+ +### Supported Exchanges (Issue [#14](https://github.com/serkor1/cryptoQuotes/issues/14)) + +[{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) now supports the following exchanges: + +* Crypto.com +* Huobi +* MEXC + + +## Breaking Changes + +## Bugfixes + +### Charting + +* Fixed a bug in the `chart()`-function where a warning would be given if called using namespace qualified function calls (Issue [#13](https://github.com/serkor1/cryptoQuotes/issues/13)) +* Fixed a bug in the `chart()`-function where a `legend` wouldn't show unless a main-chart indicator +were included. (Issue [#13](https://github.com/serkor1/cryptoQuotes/issues/13)) + +### Quotes + +* Removed `1s` from *Binance spot* +* Removed `3m`, `6h` and `3d` in *Bitmart spot* + +These intervals have been removed as they have either been discontinued, or were non-existent. + + +# Version 1.3.1 ## General @@ -118,7 +208,7 @@ chart( * Removed dependency on `conflicted`-package. -Prior to version `1.3.0` the `get*`-functions were following the syntax of `quantmod` closely, and this goes for the function naming too. With the adoption of the `tidyverse` style guide, there is no conflicts that +Prior to version `1.3.0` the `get*`-functions were following the syntax of [{quantmod}](https://github.com/joshuaulrich/quantmod) closely, and this goes for the function naming too. With the adoption of the `tidyverse` style guide, there is no conflicts that needs to be resolved on `stable`- and `experimental`-functions. ### New developper tools @@ -140,7 +230,7 @@ needs to be resolved on `stable`- and `experimental`-functions. * Fixed a bug in the `get_quote()`-function where if `to = NULL` and `from != NULL` the returned `quote` would be filtered according to `UTC` and not `Sys.timezone()` * Fixed a bug in the `chart()`-function where the inferred intervals would be incorrect for leap years, and months different from 30 days. -# cryptoQuotes 1.3.0 +# Version 1.3.0 ## Improvements @@ -247,10 +337,10 @@ tail( ## Warning -As the `cryptoQuotes`-package has moved to the `tidyverse` style guide, the `getFoo`-functions are now `deprecated`. These will be permanently deleted, and removed from the `cryptoQuotes`-package, at version 1.4.0! +As [{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) has moved to the `tidyverse` style guide, the `getFoo`-functions are now `deprecated`. These will be permanently deleted, and removed from the [{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/), at version 1.4.0! -# cryptoQuotes 1.2.1 +# Version 1.2.1 ### Minor Updates @@ -263,7 +353,7 @@ As the `cryptoQuotes`-package has moved to the `tidyverse` style guide, the `get * All returned Quotes are now in `UTC`, again. * Fixed an error on the `Bitmart` API where weekly candles would throw an error. -# cryptoQuotes 1.2.0 +# Version 1.2.0 * All `from` and `to` arguments are now more flexible, and supports passing `Sys.Date()` and `Sys.time()` directly into the `get`-functions. @@ -271,7 +361,7 @@ As the `cryptoQuotes`-package has moved to the `tidyverse` style guide, the `get The `getQuote()`-function can now be used as follows; -``` +```r ## Specifying from ## date only; ## @@ -283,7 +373,7 @@ getQuote( ) ``` -``` +```r ## Specifying to ## date only; ## @@ -312,7 +402,7 @@ Three new convinience functions are added applicable to some situations, * `splitWindow()` * `calibrateWindow()` -# cryptoQuotes 1.1.0 +# Version 1.1.0 ## Frontend @@ -320,7 +410,7 @@ Three new convinience functions are added applicable to some situations, ## Backend -* All code has been rewritten so its compatible with `httr2`, the package used `httr` at version `1.0.0`. +* All code has been rewritten so its compatible with [{httr2}](https://github.com/r-lib/httr2), the package used [{httr}](https://github.com/r-lib/httr) at version `1.0.0`. ## Future releases @@ -331,6 +421,6 @@ In the next release, three more exchanges will be supported. The returned `quotes` are in local timezone, this is an unintentional feature and will be fixed in a bugfix. -# cryptoQuotes 1.0.0 +# Version 1.0.0 * Initial CRAN submission :rocket: diff --git a/NEWS.md b/NEWS.md index 35fcb76c..e7fe3430 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,125 @@ -# cryptoQuotes 1.3.1 +# Version 1.3.2 + +## General + +- `bitmart` has updated their futures API. The backend have been updated + accordingly. + +- Unit-tests have been updated and now all `get_quote()`-functions are + being tested for equality in passed and inferred interval. + +## Improvements + +## Read and Write `xts`-objects + +- `read_xts()` and `write_xts()` reads and stores `xts`-objects. These + functions are essentially just wrappers of `zoo::read.zoo()` and + `zoo::write.zoo()`. Thank you @gokberkcan7 for the suggestion. + +### Charting + +- The `chart()`-function are now exported as `.svg`-images in 4k + resolution via the `modebar`. +- The `chart()`-function are now more interactive and supports drawing + lines and rectangles via the `modebar`. It is also possible to + interactively change the `title` and `subtitle` by double clicking + these (Thank you @andreltr for the suggestion. See + [Discussion](https://github.com/serkor1/cryptoQuotes/discussions/19)). +- The `chart()`-function now has a new option `static` that is equal to + `FALSE` by default. If `FALSE` the chart can be edited, annotated and + explored interactively. +- The `chart()`-function now has a new option `palette` that is set to + “hawaii” by default. See `hcl.pals()` for accepted values. +- The `chart()`-function now has a new option `scale` that is set to 1 + by default. Scales all fonts on the chart. +- The `chart()`-function now has a new option `width` that is set to 0.9 + by default. Sets the overall `linewidth` of the chart. (Thank you + @andreltr for the suggestion. See + [Discussion](https://github.com/serkor1/cryptoQuotes/discussions/30)) + +
+ +Static set to FALSE (Default Palette) + + +``` r +# static = FALSE +chart( + ticker = BTC, + main = kline(), + indicator = line( + sma(n = 7), + sma(n = 14), + sma(n = 21) + ), + options = list( + static = FALSE, + palette = "hawaii" + ) +) +``` + + +
+
+ +Static set to TRUE (“Set 3” palette) + + +``` r +# static = TRUE +chart( + ticker = BTC, + main = kline(), + indicator = line( + sma(n = 7), + sma(n = 14), + sma(n = 21) + ), + options = list( + static = TRUE, + palette = "Set 3" + ) +) +``` + + +
+ +### Supported Exchanges (Issue [\#14](https://github.com/serkor1/cryptoQuotes/issues/14)) + +[{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) now supports +the following exchanges: + +- Crypto.com +- Huobi +- MEXC + +## Breaking Changes + +## Bugfixes + +### Charting + +- Fixed a bug in the `chart()`-function where a warning would be given + if called using namespace qualified function calls (Issue + [\#13](https://github.com/serkor1/cryptoQuotes/issues/13)) +- Fixed a bug in the `chart()`-function where a `legend` wouldn’t show + unless a main-chart indicator were included. (Issue + [\#13](https://github.com/serkor1/cryptoQuotes/issues/13)) + +### Quotes + +- Removed `1s` from *Binance spot* +- Removed `3m`, `6h` and `3d` in *Bitmart spot* + +These intervals have been removed as they have either been discontinued, +or were non-existent. + +# Version 1.3.1 ## General @@ -49,7 +167,7 @@ chart( ) ``` - + ### Expanded Support @@ -72,12 +190,12 @@ tail( ``` #> open_interest - #> 2024-05-31 15:00:00 3013.342 - #> 2024-05-31 16:00:00 2957.343 - #> 2024-05-31 17:00:00 2960.819 - #> 2024-05-31 18:00:00 2954.668 - #> 2024-05-31 19:00:00 2983.686 - #> 2024-05-31 20:00:00 2996.449 + #> 2024-11-02 10:00:00 2394.876 + #> 2024-11-02 11:00:00 2389.595 + #> 2024-11-02 12:00:00 2396.225 + #> 2024-11-02 13:00:00 2403.175 + #> 2024-11-02 14:00:00 2418.193 + #> 2024-11-02 15:00:00 2398.648 @@ -115,7 +233,7 @@ chart( ) ``` - + ### Documentation @@ -134,9 +252,10 @@ chart( - Removed dependency on `conflicted`-package. Prior to version `1.3.0` the `get*`-functions were following the syntax -of `quantmod` closely, and this goes for the function naming too. With -the adoption of the `tidyverse` style guide, there is no conflicts that -needs to be resolved on `stable`- and `experimental`-functions. +of [{quantmod}](https://github.com/joshuaulrich/quantmod) closely, and +this goes for the function naming too. With the adoption of the +`tidyverse` style guide, there is no conflicts that needs to be resolved +on `stable`- and `experimental`-functions. ### New developper tools @@ -163,7 +282,7 @@ needs to be resolved on `stable`- and `experimental`-functions. - Fixed a bug in the `chart()`-function where the inferred intervals would be incorrect for leap years, and months different from 30 days. -# cryptoQuotes 1.3.0 +# Version 1.3.0 ## Improvements @@ -229,7 +348,7 @@ chart( ) ``` - + ### Exchange Support @@ -258,12 +377,12 @@ tail( ``` #> funding_rate - #> 2024-05-30 02:00:00 0.00010000 - #> 2024-05-30 10:00:00 0.00010000 - #> 2024-05-30 18:00:00 0.00010000 - #> 2024-05-31 02:00:00 0.00014599 - #> 2024-05-31 10:00:00 0.00012268 - #> 2024-05-31 18:00:00 0.00010000 + #> 2024-10-31 17:00:00 1.730390e+12 + #> 2024-11-01 01:00:00 1.730419e+12 + #> 2024-11-01 09:00:00 1.730448e+12 + #> 2024-11-01 17:00:00 1.730477e+12 + #> 2024-11-02 01:00:00 1.730506e+12 + #> 2024-11-02 09:00:00 1.730534e+12 @@ -285,12 +404,12 @@ tail( ``` #> open_interest - #> 2024-05-26 02:00:00 72347.36 - #> 2024-05-27 02:00:00 71077.10 - #> 2024-05-28 02:00:00 71580.71 - #> 2024-05-29 02:00:00 71880.38 - #> 2024-05-30 02:00:00 76232.59 - #> 2024-05-31 02:00:00 74250.55 + #> 2024-10-28 01:00:00 82206.35 + #> 2024-10-29 01:00:00 89115.04 + #> 2024-10-30 01:00:00 90242.98 + #> 2024-10-31 01:00:00 89315.49 + #> 2024-11-01 01:00:00 89544.93 + #> 2024-11-02 01:00:00 84087.60 @@ -311,11 +430,13 @@ tail( ## Warning -As the `cryptoQuotes`-package has moved to the `tidyverse` style guide, -the `getFoo`-functions are now `deprecated`. These will be permanently -deleted, and removed from the `cryptoQuotes`-package, at version 1.4.0! +As [{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) has moved +to the `tidyverse` style guide, the `getFoo`-functions are now +`deprecated`. These will be permanently deleted, and removed from the +[{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/), at version +1.4.0! -# cryptoQuotes 1.2.1 +# Version 1.2.1 ### Minor Updates @@ -331,7 +452,7 @@ deleted, and removed from the `cryptoQuotes`-package, at version 1.4.0! - Fixed an error on the `Bitmart` API where weekly candles would throw an error. -# cryptoQuotes 1.2.0 +# Version 1.2.0 - All `from` and `to` arguments are now more flexible, and supports passing `Sys.Date()` and `Sys.time()` directly into the @@ -343,25 +464,29 @@ deleted, and removed from the `cryptoQuotes`-package, at version 1.4.0! The `getQuote()`-function can now be used as follows; - ## Specifying from - ## date only; - ## - ## Returns 10 pips - getQuote( - ticker = 'BTCUSDT', - interval = '1d' - from = as.character(Sys.Date() - 10) - ) - - ## Specifying to - ## date only; - ## - ## Returns 100 pips - getQuote( - ticker = 'BTCUSDT', - interval = '1d' - to = as.character(Sys.Date()) - ) +``` r +## Specifying from +## date only; +## +## Returns 10 pips +getQuote( + ticker = 'BTCUSDT', + interval = '1d' + from = as.character(Sys.Date() - 10) + ) +``` + +``` r +## Specifying to +## date only; +## +## Returns 100 pips +getQuote( + ticker = 'BTCUSDT', + interval = '1d' + to = as.character(Sys.Date()) + ) +``` ## Market Sentiment @@ -383,7 +508,7 @@ Three new convinience functions are added applicable to some situations, - `splitWindow()` - `calibrateWindow()` -# cryptoQuotes 1.1.0 +# Version 1.1.0 ## Frontend @@ -391,8 +516,9 @@ Three new convinience functions are added applicable to some situations, ## Backend -- All code has been rewritten so its compatible with `httr2`, the - package used `httr` at version `1.0.0`. +- All code has been rewritten so its compatible with + [{httr2}](https://github.com/r-lib/httr2), the package used + [{httr}](https://github.com/r-lib/httr) at version `1.0.0`. ## Future releases @@ -403,6 +529,6 @@ In the next release, three more exchanges will be supported. The returned `quotes` are in local timezone, this is an unintentional feature and will be fixed in a bugfix. -# cryptoQuotes 1.0.0 +# Version 1.0.0 - Initial CRAN submission :rocket: diff --git a/R/api_binance.R b/R/api_binance.R index 59e97c57..9c00afb4 100644 --- a/R/api_binance.R +++ b/R/api_binance.R @@ -9,17 +9,10 @@ binanceUrl <- function( futures = TRUE, ...) { - # 1) define baseURL - # for each API - baseUrl <- base::ifelse( - test = futures, - yes = 'https://fapi.binance.com', - no = 'https://data-api.binance.vision' - ) - - # 2) return the - # baseURL - baseUrl + if (futures) + 'https://fapi.binance.com' + else + 'https://data-api.binance.vision' } @@ -28,18 +21,18 @@ binanceEndpoint <- function( futures = TRUE, top = FALSE) { - endPoint <- switch( + switch( EXPR = type, - ohlc = { - if (futures) 'fapi/v1/klines' else - 'api/v3/klines' - }, - ticker ={ - if (futures) 'fapi/v1/exchangeInfo' else + ticker = { + if (futures) + 'fapi/v1/exchangeInfo' + else 'api/v3/exchangeInfo' }, lsratio = { - if (top) 'futures/data/topLongShortAccountRatio' else + if (top) + 'futures/data/topLongShortAccountRatio' + else 'futures/data/globalLongShortAccountRatio' }, interest = { @@ -47,14 +40,15 @@ binanceEndpoint <- function( }, fundingrate = { 'fapi/v1/fundingRate' + }, + { + if (futures) + 'fapi/v1/klines' + else + 'api/v3/klines' } ) - # 2) return endPoint url - return( - endPoint - ) - } # 2) Available intervals; ##### @@ -67,11 +61,54 @@ binanceIntervals <- function( # 0) wrap all intercals # in switch - all_intervals <- switch( + switch( EXPR = type, 'ohlc' = { - data.frame( - labels = c( + + if (futures) { + + # the labels + interval_label <- c( + '1m', + '3m', + '5m', + '15m', + '30m', + '1h', + '2h', + '4h', + '6h', + '8h', + '12h', + '1d', + '3d', + '1w', + '1M' + ) + + # the actual values + interval_actual <- c( + '1m', + '3m', + '5m', + '15m', + '30m', + '1h', + '2h', + '4h', + '6h', + '8h', + '12h', + '1d', + '3d', + '1w', + '1M' + ) + + + } else { + + interval_label <- c( '1s', '1m', '3m', @@ -88,8 +125,9 @@ binanceIntervals <- function( '3d', '1w', '1M' - ), - values = c( + ) + + interval_actual <- c( '1s', '1m', '3m', @@ -107,30 +145,50 @@ binanceIntervals <- function( '1w', '1M' ) - ) + + + } + }, # default return value - data.frame( - labels = c('5m', '15m', '30m', '1h', '2h', '4h', '6h', '12h', '1d'), - values = c('5m', '15m', '30m', '1h', '2h', '4h', '6h', '12h', '1d') - ) - ) - if (all) { + { + interval_label = c( + '5m', + '15m', + '30m', + '1h', + '2h', + '4h', + '6h', + '12h', + '1d' + ) + + interval_actual = c( + '5m', + '15m', + '30m', + '1h', + '2h', + '4h', + '6h', + '12h', + '1d' + ) + } + - return(all_intervals$labels) + ) - } else { - # Select the specified interval - selectedInterval <- all_intervals$values[ - grepl(paste0('^', interval, '$'), all_intervals$values) - ] + if (all) { return(interval_label) } - return(selectedInterval) + interval_actual[ + interval_label %in% interval + ] - } } # 3) define response object and format; #### @@ -146,30 +204,11 @@ binanceResponse <- function( switch( EXPR = type, - ohlc = { - list( - colum_names = c( - 'open', - 'high', - 'low', - 'close', - 'volume' - ), - colum_location = c( - 2:6 - ), - index_location = c( - 1 - ) - - ) - }, - ticker = { list( foo = function( response, - futures = NULL){ + futures = NULL) { subset( x = response$symbols, grepl( @@ -185,25 +224,39 @@ binanceResponse <- function( fundingrate = { list( colum_names = "funding_rate", - index_location = c(2), - colum_location = c(3) + index_location = 2, + colum_location = 2 ) }, interest = { list( - colum_names = c("open_interest"), - index_location = c(4), - colum_location = c(2) + colum_names = "open_interest", + index_location = 4, + colum_location = 2 ) }, lsratio = { list( - colum_names = c('long', 'short'), - index_location = c(5), + colum_names = c('long', 'short'), + index_location = 5, colum_location = c(2,4) ) + }, + { + list( + colum_names = c( + 'open', + 'high', + 'low', + 'close', + 'volume' + ), + colum_location = 2:6, + index_location = 1 + + ) } ) @@ -229,20 +282,15 @@ binanceDates <- function( } else { - dates <- convert_date( - x = dates, - multiplier = multiplier) - - dates <- vapply( - dates, - format, - scientific = FALSE, - FUN.VALUE = character(1) + dates <- format( + convert_date( + x = dates, + multiplier = multiplier + ), + scientific = FALSE ) - names(dates) <- c('startTime', 'endTime') - - + names(dates) <- c('startTime','endTime') } @@ -265,7 +313,7 @@ binanceParameters <- function( symbol = ticker, interval = binanceIntervals( interval = interval, - futures = futures, + futures = futures, type = type ), limit = if (futures) 1500 else 1000 @@ -274,9 +322,9 @@ binanceParameters <- function( # Add date parameters date_params <- binanceDates( futures = futures, - dates = c( + dates = c( from = from, - to = to + to = to ), is_response = FALSE ) @@ -302,15 +350,13 @@ binanceParameters <- function( params <- c(params, date_params) # Return a structured list with additional common parameters - return( - list( - query = params, - path = NULL, - futures = futures, - source = 'binance', - ticker = ticker, - interval = interval - ) + list( + query = params, + path = NULL, + futures = futures, + source = 'binance', + ticker = ticker, + interval = interval ) } diff --git a/R/api_bitmart.R b/R/api_bitmart.R index 9d6ac225..0961f30a 100644 --- a/R/api_bitmart.R +++ b/R/api_bitmart.R @@ -11,15 +11,10 @@ bitmartUrl <- function( # 1) define baseURL # for each API - baseUrl <- base::ifelse( - test = futures, - yes = 'https://api-cloud.bitmart.com', - no = 'https://api-cloud.bitmart.com' - ) - - # 2) return the - # baseURL - baseUrl + if (futures) + 'https://api-cloud-v2.bitmart.com' + else + 'https://api-cloud.bitmart.com' } @@ -28,21 +23,21 @@ bitmartEndpoint <- function( futures = TRUE, ...) { + if (type == "ohlc") { - endPoint <- switch( - EXPR = type, - ohlc = { - if (futures) 'contract/public/kline' else - 'spot/quotation/v3/lite-klines' - }, - ticker ={ - if (futures) 'contract/public/details' else - 'spot/v1/symbols' - } - ) + if (futures) + 'contract/public/kline' + else + 'spot/quotation/v3/lite-klines' - # 2) return endPoint url - endPoint + } else { + + if (futures) + 'contract/public/details' + else + 'spot/v1/symbols' + + } } @@ -54,8 +49,9 @@ bitmartIntervals <- function( ...) { # Define all intervals in a data frame - allIntervals <- data.frame( - labels = c( + if (futures) { + + interval_label <- c( '1m', '3m', '5m', @@ -69,8 +65,9 @@ bitmartIntervals <- function( '1d', '3d', '1w' - ), - values = c( + ) + + interval_actual <- c( 1, 3, 5, @@ -85,20 +82,49 @@ bitmartIntervals <- function( 4320, 10080 ) - ) - if (all) { + } else { - return(allIntervals$labels) + interval_label <- c( + '1m', + # '3m', + '5m', + '15m', + '30m', + '1h', + '2h', + '4h', + # '6h', + # '12h', + '1d', + # '3d', + '1w' + ) - } else { - # Locate and return the chosen interval value - selectedInterval <- allIntervals$values[ - allIntervals$labels == interval - ] + interval_actual <- c( + 1, + # 3, + 5, + 15, + 30, + 60, + 120, + 240, + # 360, + # 720, + 1440, + # 4320, + 10080 + ) - return(selectedInterval) } + + if (all) { return(interval_label) } + + interval_actual[ + interval_label %in% interval + ] + } # 3) define response object and format; #### @@ -107,46 +133,45 @@ bitmartResponse <- function( futures, ...) { - response <- NULL - # mock response # to avoid check error in # unevaluated expressions response <- NULL - switch( - EXPR = type, - ohlc = { - list( - - colum_names = if (futures) - c('low', 'high', 'open', 'close', 'volume') - else - c('open', 'high', 'low', 'close', 'volume'), + if (type == "ohlc") { - colum_location = if (futures) - 1:5 - else - c(2:5, 7), + if (futures) { - index_location = if (futures) - 6 - else - 1 - ) - }, - ticker = { list( - foo = function(response, futures){ + colum_names = c('low', 'high', 'open', 'close', 'volume'), + colum_location = 1:5, + index_location = 6 + ) - if (futures) response$data$symbol$symbol else - response$data$symbols + } else { - } + list( + colum_names = c('open', 'high', 'low', 'close', 'volume'), + colum_location = c(2:5,7), + index_location = 1 ) + } - ) + } else { + + list( + foo = function(response, futures){ + + if (futures) + response$data$symbol$symbol + else + response$data$symbols + + } + ) + + } } @@ -166,16 +191,12 @@ bitmartDates <- function( } else { - dates <- convert_date( - x = dates, - multiplier = 1 - ) - - dates <- vapply( - dates, - format, - scientific = FALSE, - FUN.VALUE = character(1) + dates <- format( + convert_date( + x = dates, + multiplier = 1 + ), + scientific = FALSE ) names(dates) <- if (futures) diff --git a/R/api_bybit.R b/R/api_bybit.R index ed2ff55b..eb135e20 100644 --- a/R/api_bybit.R +++ b/R/api_bybit.R @@ -9,17 +9,10 @@ bybitUrl <- function( futures = TRUE, ...) { - # 1) define baseURL - # for each API - baseUrl <- base::ifelse( - test = futures, - yes = 'https://api.bybit.com', - no = 'https://api.bybit.com' - ) - - # 2) return the - # baseURL - baseUrl + if (futures) + 'https://api.bybit.com' + else + 'https://api.bybit.com' } @@ -30,34 +23,29 @@ bybitEndpoint <- function( endPoint <- switch( EXPR = type, - - ohlc = { - if (futures) - 'v5/market/kline' - else - 'v5/market/kline' - }, - ticker = { if (futures) 'v5/market/instruments-info?category=linear' else 'v5/market/instruments-info?category=spot' }, - lsratio = { if (top) 'v5/market/account-ratio' else 'v5/market/account-ratio' }, - fundingrate = { 'v5/market/funding/history' }, - interest = { '/v5/market/open-interest' + }, + { + if (futures) + 'v5/market/kline' + else + 'v5/market/kline' } ) @@ -77,79 +65,47 @@ bybitIntervals <- function( ...) { # 0) Define intervals - all_intervals <- switch( - EXPR = type, - - 'lsratio' = { - data.frame( - labels = c('5m', '15m', '30m', '1h', '4h', '1d'), - values = c("5min", "15min", "30min", "1h", "4h", "1d") - ) - }, - - 'interest' = { - data.frame( - labels = c('5m', '15m', '30m', '1h', '4h', '1d'), - values = c("5min", "15min", "30min", "1h" , "4h", "1d") - ) - }, - - data.frame( - labels = c( - '1m', - '3m', - '5m', - '15m', - '30m', - '1h', - '2h', - '4h', - '6h', - '12h', - '1d', - '1M', - '1w' - ), - values = c( - "1" , - "3", - "5", - "15", - "30", - "60", - "120", - "240", - "360", - "720", - "D", - "M", - "W" - ) + if (type == "ohlc") { + interval_label <- c( + '1m', + '3m', + '5m', + '15m', + '30m', + '1h', + '2h', + '4h', + '6h', + '12h', + '1d', + '1M', + '1w' ) - ) - - - - # 2.1) if not ALL - # then return interval - # selected - if (all) { - - # 2) return all - # intervals - interval <- all_intervals$labels - - - - } else { - - interval <- all_intervals$values[ - grepl(pattern = paste0('^', interval, '$'), x = all_intervals$labels) - ] + interval_actual <- c( + "1" , + "3", + "5", + "15", + "30", + "60", + "120", + "240", + "360", + "720", + "D", + "M", + "W" + ) } else { + interval_label <- c('5m', '15m', '30m', '1h', '4h', '1d') + interval_actual <- c("5min", "15min", "30min", "1h", "4h", "1d") } - interval + if (all) { return(interval_label) } + + interval_actual[ + interval_label %in% interval + ] } @@ -176,12 +132,8 @@ bybitResponse <- function( 'close', 'volume' ), - colum_location = c( - 2:6 - ), - index_location = c( - 1 - ) + colum_location = 2:6, + index_location = 1 ) }, @@ -197,25 +149,24 @@ bybitResponse <- function( }, interest = { list( - colum_names = c('open_interest'), - index_location = c(2), - colum_location = c(1) + colum_names = 'open_interest', + index_location = 2, + colum_location = 1 ) }, fundingrate = { list( colum_names = "funding_rate", - index_location = c(3), - colum_location = c(2) + index_location = 3, + colum_location = 2 ) }, - - lsratio <- { + { list( colum_names = c('long', 'short'), - index_location = c(4), - colum_location = c(2:3) + index_location = 4, + colum_location = 2:3 ) } @@ -246,23 +197,16 @@ bybitDates <- function( } else { - dates <- convert_date( - x = dates, - multiplier = multiplier) - - dates <- vapply( - dates, - format, - scientific = FALSE, - FUN.VALUE = character(1) + dates <- format( + convert_date( + x = dates, + multiplier = multiplier + ), + scientific = FALSE ) - - names(dates) <-c('start', 'end') - - } dates @@ -300,32 +244,36 @@ bybitParameters <- function( is_response = FALSE ) + if (type != "ohlc") { - if (type == "fundingrate"){ + switch( + EXPR = type, + "fundingrate" = { - names(date_params) <- c("startTime", "endTime") + names(date_params) <- c("startTime", "endTime") - } + }, + "interest" = { - if (type == "interest") { + names(params)[3] <- 'intervalTime' + names(date_params) <- c("startTime", "endTime") + params$limit <- 200 - names(params)[3] <- 'intervalTime' - names(date_params) <- c("startTime", "endTime") - params$limit <- 200 - } + }, + "lsratio" = { + # 4.1) This is a standalone + # parameter; was called interval + # but is named period in the API calls + names(params)[3] <- 'period' - if (type == 'lsratio') { - # 4.1) This is a standalone - # parameter; was called interval - # but is named period in the API calls - names(params)[3] <- 'period' - - # 4.1) Return only - # 100 such that this function - # aligns with the remaining - # functions which - # also returns 100 - params$limit <- 500 + # 4.1) Return only + # 100 such that this function + # aligns with the remaining + # functions which + # also returns 100 + params$limit <- 500 + } + ) } diff --git a/R/api_cryptocom.R b/R/api_cryptocom.R new file mode 100644 index 00000000..e86708e4 --- /dev/null +++ b/R/api_cryptocom.R @@ -0,0 +1,223 @@ +# script: new_api_crypto.com +# date: 2024-06-07 +# author: Serkan Korkmaz, serkor1@duck.com +# objective: Create all necessary parameters +# for a proper API call +# script start; +# 1) URLs and Endpoint; #### +crypto.comUrl <- function( + futures = TRUE, + ...) { + + # 1) define baseURL + # for each API + if (futures) + 'https://api.crypto.com/exchange/v1/public' + else + 'https://api.crypto.com/exchange/v1/public' + +} + +crypto.comEndpoint <- function( + type = 'ohlc', + futures = TRUE, + ...) { + + switch( + EXPR = type, + ticker ={ + 'get-instruments' + }, + fundingrate = { + 'get-valuations' + }, + # default value: + # klines + { + 'get-candlestick' + } + ) + +} + +# 2) Available intervals; ##### +crypto.comIntervals <- function( + interval, + futures, + all = FALSE, + ...) { + + # interval labels + # user-facing + interval_label <- c( + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "4h", + "12h", + "1d", + "1w", + "2w", + "1M" + ) + + # API intervals + interval_actual <- c( + "M1", + "M5", + "M15", + "M30", + "H1", + "H2", + "H4", + "H12", + "1D", + "7D", + "14D", + "1M" + ) + + + if (all) { return(interval_label) } + + interval_actual[ + interval_label %in% interval + ] + +} + +# 3) define response object and format; #### +crypto.comResponse <- function( + type = 'ohlc', + futures, + ...) { + + # mock response + # to avoid check error in + # unevaluated expressions + response <- NULL + + switch( + EXPR = type, + ticker = { + list( + foo = function(response, futures) { + + subset( + response$result$data, + response$result$data$tradable == TRUE & + response$result$data$inst_type %in% ifelse( + futures, + c("PERPETUAL_SWAP", "FUTURE"), + "CCY_PAIR" + + ) + )$symbol + } + ) + }, + + fundingrate = { + list( + colum_names = "funding_rate", + index_location = c(2), + colum_location = c(1) + ) + }, + { + list( + colum_names = c('open', 'high', 'low', 'close', 'volume'), + colum_location = 1:5, + index_location = 6 + ) + } + ) + +} + +# 4) Dates passed to and from endpoints; #### +crypto.comDates <- function( + futures, + dates, + is_response = FALSE, + ...) { + + # 0) set multiplier based + # on market + multiplier <- 1e3 + + # 1) if its a response + if (is_response) { + + dates <- convert_date( + x = as.numeric(dates), + multiplier = multiplier + ) + + } else { + + # Convert dates and format + dates <- format( + convert_date( + x = dates, + multiplier = multiplier + ), + scientific = FALSE + ) + + names(dates) <- c('start_ts', 'end_ts') + + } + + dates + +} + +# 5) Parameters passed to endpoints; #### +crypto.comParameters <- function( + futures = TRUE, + ticker, + type = NULL, + interval, + from = NULL, + to = NULL, + ...) { + + # Initial parameter setup + params <- list( + instrument_name = ticker, + timeframe = crypto.comIntervals( + interval = interval, + futures = futures + ), + count = 5000 + ) + + if (type == "fundingrate"){ + params$valuation_type <- 'funding_hist' + } + + # Add date parameters + date_params <- crypto.comDates( + futures = futures, + dates = c(from = from, to = to) + ) + + # Combine all parameters + params <- c(params, date_params) + + # Return structured list with additional parameters + list( + query = params, + path = NULL, + futures = futures, + source = 'crypto.com', + ticker = ticker, + interval = interval + ) +} + +# script end; diff --git a/R/api_huobi.R b/R/api_huobi.R new file mode 100644 index 00000000..50643132 --- /dev/null +++ b/R/api_huobi.R @@ -0,0 +1,249 @@ +# script: api_huobi +# date: 2024-06-07 +# author: Serkan Korkmaz, serkor1@duck.com +# objective: Create all necessary parameters +# for a proper API call +# script start; +# 1) URLs and Endpoint; #### +huobiUrl <- function( + futures = TRUE, + ...) { + + # 1) define baseURL + # for each API + if (futures) + 'https://api.hbdm.com' + else + 'https://api.huobi.pro' + +} + +huobiEndpoint <- function( + type = 'ohlc', + futures = TRUE, + top = FALSE) { + + switch( + EXPR = type, + ticker ={ + if (futures) + "linear-swap-api/v1/swap_api_state" + else + "v2/settings/common/symbols" + }, + { + if (futures) + 'linear-swap-ex/market/history/kline' + else + 'market/history/kline' + } + ) +} + +# 2) Available intervals; ##### +huobiIntervals <- function( + futures, + interval, + all = FALSE, + type, + ...) { + + # 0) define intervals + # NOTE: These are common for + # both endpoints + + interval_label <- c( + '1m', + '5m', + '15m', + '30m', + '1h', + '4h', + '1d', + '1w', + '1M' + ) + + interval_actual <- c( + "1min", + "5min", + "15min", + "30min", + "60min", + "4hour", + "1day", + "1week", + "1mon" + ) + + + if (all) { return(interval_label) } + + interval_actual[ + interval_label %in% interval + ] + +} + + +# 3) define response object and format; #### +huobiResponse <- function( + type = 'ohlc', + futures, + ...) { + + # mock response + # to avoid check error in + # unevaluated expressions + response <- NULL + + switch( + EXPR = type, + ticker = { + list( + foo = function( + response, + futures = NULL){ + + if (futures) { + + subset( + response$data + )$contract_code + + } else { + + subset( + response$data, + response$data$state == "online" & response$data$te == TRUE + )$sc + + } + + } + ) + }, + { + + list( + colum_names = if (futures) + c( + 'open', + 'close', + 'high', + 'low', + 'volume' + ) + + else { + c( + 'open', + 'close', + 'low', + 'high', + 'volume' + ) + }, + colum_location = if (futures) c(2:5,7) else c(2:6), + index_location = c( + 1 + ) + + ) + + } + + ) + +} + +# 4) Dates passed to and from endpoints; #### +huobiDates <- function( + futures, + dates, + is_response = FALSE, + ...) { + + # 0) Set multiplier + multiplier <- 1 + + # 1) determine wether + # its a response or request + if (is_response) { + + # NOTE: The API returns + # in GMT+8 time and + # convert_date assumes that its + # UTC + dates <- convert_date( + x = as.numeric(dates), + multiplier = multiplier) + + } else { + + dates <- format( + convert_date( + x = dates, + multiplier = multiplier + ), + scientific = FALSE + ) + + names(dates) <- c('from', 'to') + + } + + dates + +} + +# 5) Parameters passed to endpoints; #### +huobiParameters <- function( + futures = TRUE, + type = 'ohlc', + ticker, + interval, + from = NULL, + to = NULL, + ...) { + + # Basic parameters common to both futures and non-futures + params <- list( + symbol = ticker, + period = huobiIntervals( + interval = interval, + futures = futures, + type = type + ), + size = 2000 + ) + + if (futures) names(params)[1] <- "contract_code" + + # Add date parameters + date_params <- huobiDates( + futures = futures, + dates = c( + from = from, + to = to + ), + is_response = FALSE + ) + + # Combine all parameters + params <- c(params) + + # Return a structured list with additional common parameters + return( + list( + query = params, + path = NULL, + futures = futures, + source = 'huobi', + ticker = ticker, + interval = interval + ) + ) +} + +# script end; #### diff --git a/R/api_kraken.R b/R/api_kraken.R index 78e220a7..ac7e4d4e 100644 --- a/R/api_kraken.R +++ b/R/api_kraken.R @@ -11,15 +11,10 @@ krakenUrl <- function( # 1) define baseURL # for each API - baseUrl <- base::ifelse( - test = futures, - yes = 'https://futures.kraken.com', - no = 'https://api.kraken.com' - ) - - # 2) return the - # baseURL - baseUrl + if (futures) + 'https://futures.kraken.com' + else + 'https://api.kraken.com' } @@ -28,14 +23,12 @@ krakenEndpoint <- function( futures = TRUE, ...) { - endPoint <- switch( + switch( EXPR = type, - ohlc = { - if (futures) 'api/charts/v1/' else - '0/public/OHLC/' - }, ticker ={ - if (futures) 'derivatives/api/v3/instruments/' else + if (futures) + 'derivatives/api/v3/instruments/' + else '0/public/AssetPairs/' }, # Was lsratio @@ -44,12 +37,15 @@ krakenEndpoint <- function( }, interest = { 'api/charts/v1/analytics/' + }, + { + if (futures) + 'api/charts/v1/' + else + '0/public/OHLC/' } ) - # 2) return endPoint url - endPoint - } # 2) Available intervals; ##### @@ -61,49 +57,31 @@ krakenIntervals <- function( ...) { # 0) construct intervals - all_intervals <- switch( - EXPR = type, - 'ohlc' = { - if (futures) { - # For futures, labels and values are the same - data.frame( - labels = c("1m", "5m", "15m", "30m", "1h", "4h", "12h", "1d", "1w"), - values = c("1m", "5m", "15m", "30m", "1h", "4h", "12h", "1d", "1w") - ) - } else { - # For non-futures, labels and values are different - data.frame( - labels = c("1m", "5m", "15m", "30m", "1h", "4h", "1d", "1w", "2w"), - values = c(1 ,5 ,15 ,30 ,60 ,240 , 1440,10080,21600) - ) - } - }, - data.frame( - labels = c("1m", "5m", "15m", "30m", "1h", "4h", "12h", "2d", "8d"), - values = c(60, 300, 900, 1800, 3600, 14400, 43200, 86400, 604800) - ) - ) - - # 2.1) if not ALL - # then return interval - # selected - if (all) { + switch(EXPR = type, 'ohlc' = { + if (futures) { + # For futures, labels and values are the same - # 2) return all - # intervals - interval <- all_intervals$labels + interval_label <- c("1m", "5m", "15m", "30m", "1h", "4h", "12h", "1d", "1w") + interval_actual <- c("1m", "5m", "15m", "30m", "1h", "4h", "12h", "1d", "1w") + } else { + # For non-futures, labels and values are different + interval_label <- c("1m", "5m", "15m", "30m", "1h", "4h", "1d", "1w", "2w") + interval_actual <- c(1 , 5 , 15 , 30 , 60 , 240 , 1440, 10080, 21600) - } else { - - interval <- all_intervals$values[ - grepl(pattern = paste0('^', interval, '$'), x = all_intervals$labels) - ] + } + }, # default values + { + interval_label <- c("1m", "5m", "15m", "30m", "1h", "4h", "12h", "2d", "8d") + interval_actual <- c(60, 300, 900, 1800, 3600, 14400, 43200, 86400, 604800) + }) - } + if (all) { return(interval_label) } - interval + interval_actual[ + interval_label %in% interval + ] } @@ -123,14 +101,8 @@ krakenResponse <- function( ) } - switch( EXPR = type, - ohlc = { - ohlc_structure( - volume_loc = if (!futures) 7 else 6 - ) - }, ticker = { list( foo = function(response, futures) { @@ -144,16 +116,14 @@ krakenResponse <- function( } else { - names( - lapply( - response$result, - function(x) { - if (x$status == 'online'){ - x$altname - } - } - ) - ) + unname( + obj = sapply( + response$result, function(x){ + x$altname}, + simplify = TRUE, + USE.NAMES = FALSE), + force = TRUE) + } } @@ -175,6 +145,11 @@ krakenResponse <- function( index_location = c(1), colum_location = c(2,3,4,5) ) + }, + { + ohlc_structure( + volume_loc = if (futures) 6 else 7 + ) } ) @@ -211,7 +186,7 @@ krakenDates <- function( yes = 1, no = 1 ) - ) + ) if (!futures) { # Adjust for Spot market @@ -276,7 +251,20 @@ krakenParameters <- function( tick_type = "open-interest" ) }, - ohlc = { + lsratio = { + params$symbol <- params$ticker + params$resolution <- params$interval + params$query <- list( + interval = params$interval, + since = date_params[1], + to = date_params[2] + ) + params$path <- list( + symbol = params$symbol, + tick_type = 'long-short-info' + ) + }, + { # Set specific parameters for futures or non-futures if (futures) { params$symbol <- params$ticker @@ -302,22 +290,6 @@ krakenParameters <- function( ) params$path <- NULL } - - - - }, - lsratio = { - params$symbol <- params$ticker - params$resolution <- params$interval - params$query <- list( - interval = params$interval, - since = date_params[1], - to = date_params[2] - ) - params$path <- list( - symbol = params$symbol, - tick_type = 'long-short-info' - ) } ) diff --git a/R/api_kucoin.R b/R/api_kucoin.R index 950440af..82fae38e 100644 --- a/R/api_kucoin.R +++ b/R/api_kucoin.R @@ -11,17 +11,10 @@ kucoinUrl <- function( # 1) define baseURL # for each API - baseUrl <- base::ifelse( - test = futures, - yes = 'https://api-futures.kucoin.com', - no = 'https://api.kucoin.com' - ) - - # 2) return the - # baseURL - return( - baseUrl - ) + if (futures) + 'https://api-futures.kucoin.com' + else + 'https://api.kucoin.com' } @@ -30,25 +23,25 @@ kucoinEndpoint <- function( futures = TRUE, ...) { - endPoint <- switch( + switch( EXPR = type, - ohlc = { - if (futures) 'api/v1/kline/query' else - 'api/v1/market/candles' - }, ticker ={ - if (futures) 'api/v1/contracts/active' else + if (futures) + 'api/v1/contracts/active' + else 'api/v1/market/allTickers' }, fundingrate = { 'api/v1/contract/funding-rates' + }, + { + if (futures) + 'api/v1/kline/query' + else + 'api/v1/market/candles' } ) - # 2) return endPoint url - return( - endPoint - ) } # 2) Available intervals; ##### @@ -59,8 +52,8 @@ kucoinIntervals <- function( ...) { if (futures) { - allIntervals <- data.frame( - labels = c( + + interval_label <- c( '1m', '5m', '15m', @@ -72,12 +65,12 @@ kucoinIntervals <- function( '12h', '1d', '1w' - ), - values = c(1, 5, 15, 30, 60, 120, 240, 480, 720, 1440, 10080) - ) + ) + interval_actual <- c(1, 5, 15, 30, 60, 120, 240, 480, 720, 1440, 10080) + } else { - allIntervals <- data.frame( - labels = c( + + interval_label <- c( '1m', '3m', '5m', @@ -91,8 +84,9 @@ kucoinIntervals <- function( '12h', '1d', '1w' - ), - values = c( + ) + + interval_actual <- c( '1min', '3min', '5min', @@ -107,21 +101,14 @@ kucoinIntervals <- function( '1day', '1week' ) - ) - } - - if (all) { - return(allIntervals$labels) + } - } else { - # Select the specified interval - selectedInterval <- allIntervals$values[ - grepl(paste0('^', interval, '$'), allIntervals$labels, ignore.case = TRUE) - ] + if (all) { return(interval_label) } - return(selectedInterval) - } + interval_actual[ + interval_label %in% interval + ] } # 3) define response object and format; #### @@ -139,16 +126,6 @@ kucoinResponse <- function( switch( EXPR = type, - ohlc = { - list( - colum_names = if (futures) - c('open', 'high', 'low', 'close', 'volume') - else - c('open', 'close', 'high', 'low', 'volume'), - colum_location = 2:6, - index_location = 1 - ) - }, ticker = { list( foo = function(response, futures) { @@ -174,6 +151,16 @@ kucoinResponse <- function( index_location = c(3), colum_location = c(2) ) + }, + { + list( + colum_names = if (futures) + c('open', 'high', 'low', 'close', 'volume') + else + c('open', 'close', 'high', 'low', 'volume'), + colum_location = 2:6, + index_location = 1 + ) } ) @@ -188,7 +175,10 @@ kucoinDates <- function( # 0) set multiplier based # on market - multiplier <- if (futures) 1e3 else 1 + multiplier <- if (futures) + 1e3 + else + 1 # 1) if its a response if (is_response) { @@ -201,7 +191,6 @@ kucoinDates <- function( } else { - # Convert dates and format dates <- convert_date( @@ -209,25 +198,22 @@ kucoinDates <- function( multiplier = multiplier ) - dates <- format( - dates, - scientific = FALSE - ) - - if (!futures) { # Adjust for Kucoin spot and set names dates <- as.numeric(dates) dates[2] <- dates[2] + 15 * 60 names(dates) <- c('startAt', 'endAt') + } else { # Set names for futures names(dates) <- c('from', 'to') } - - + dates <- format( + dates, + scientific = FALSE + ) } dates @@ -254,7 +240,11 @@ kucoinParameters <- function( ) ) # Assign appropriate names based on the futures flag - interval_param_name <- if (futures) 'granularity' else 'type' + interval_param_name <- if (futures) + 'granularity' + else + 'type' + names(params)[2] <- interval_param_name # Add date parameters @@ -269,11 +259,11 @@ kucoinParameters <- function( # Return structured list with additional parameters return( list( - query = params, - path = NULL, - futures = futures, - source = 'kucoin', - ticker = ticker, + query = params, + path = NULL, + futures = futures, + source = 'kucoin', + ticker = ticker, interval = interval ) ) diff --git a/R/api_mexc.R b/R/api_mexc.R new file mode 100644 index 00000000..d7bd210d --- /dev/null +++ b/R/api_mexc.R @@ -0,0 +1,282 @@ +# script: new_api_mexc +# date: 2023-12-18 +# author: Serkan Korkmaz, serkor1@duck.com +# objective: Create all necessary parameters +# for a proper API call +# script start; +# 1) URLs and Endpoint; #### +mexcUrl <- function( + futures = TRUE, + ...) { + + # 1) define baseURL + # for each API + if (futures) + 'https://contract.mexc.com' + else + 'https://api.mexc.com' + +} + +mexcEndpoint <- function( + type = 'ohlc', + futures = TRUE, + ...) { + + switch( + EXPR = type, + ticker = { + if (futures) + 'api/v1/contract/detail' + else + 'api/v3/exchangeInfo' + }, + fundingrate = { + 'api/v1/contract/funding_rate/history' + }, + # Default values is + # the ohlc + { + if (futures) + 'api/v1/contract/kline/' + else + 'api/v3/klines' + } + ) + +} + +# 2) Available intervals; ##### +mexcIntervals <- function( + interval, + futures, + all = FALSE, + ...) { + + if (futures) { + + interval_label <- c( + '1m', + '5m', + '15m', + '30m', + '1h', + '4h', + '8h', + '1d', + '1w', + "1M" + ) + + interval_actual <- c( + "Min1", + "Min5", + "Min15", + "Min30", + "Min60", + "Hour4", + "Hour8", + "Day1", + "Week1", + "Month1" + ) + + } else { + + interval_label <- c( + '1m', + '5m', + '15m', + '30m', + '1h', + '4h', + '1d', + '1w', + '1M' + ) + + interval_actual <- c( + '1m', + '5m', + '15m', + '30m', + '60m', + '4h', + '1d', + '1W', + '1M' + ) + + } + + if (all) { return(interval_label) } + + interval_actual[ + interval_label %in% interval + ] +} + +# 3) define response object and format; #### +mexcResponse <- function( + type = 'ohlc', + futures, + ...) { + + # mock response + # to avoid check error in + # unevaluated expressions + response <- NULL + + switch( + EXPR = type, + ticker = { + list( + foo = function(response, futures) { + if (futures) { + response$data$symbol + + } else { + subset( + x = response$symbols, + response$symbols$status == "1" + )$symbol + + + } + } + ) + }, + + fundingrate = { + list( + colum_names = "funding_rate", + index_location = c(3), + colum_location = c(2) + ) + }, + { + list( + colum_names = if (futures) + c('open', 'close', 'high', 'low', 'volume') + else + c('open', 'high', 'low', 'close', 'volume'), + colum_location = c(2:6), + index_location = 1 + ) + } + ) + +} + +# 4) Dates passed to and from endpoints; #### +mexcDates <- function( + futures, + dates, + is_response = FALSE, + type = "ohlc", + ...) { + # Set multiplier based on market + # and type + # + # If fundingrate the multiplier + # is 1e3 + multiplier <- 1e3 / if (futures & !grepl("fundingrate", type)) 1e3 else 1 + + # Convert and format dates + dates <- convert_date( + x = if (is_response) as.numeric(dates) else dates, + multiplier = multiplier + ) + + if (!is_response) { + # Adjust for mexc spot and set names + dates <- as.numeric(dates) + dates[2] <- dates[2] + 15 * 60 + + if (!futures) { + + names(dates) <- c('startTime', 'endTime') + + } else { + # Set names for futures + names(dates) <- c('start', 'end') + } + + dates <- format(dates, scientific = FALSE) + + } + + dates +} + + + +# 5) Parameters passed to endpoints; #### +mexcParameters <- function( + futures = TRUE, + ticker, + type = NULL, + interval, + from = NULL, + to = NULL, + ...) { + + # Set initial parameters with interval and assign appropriate name + params <- list( + interval = mexcIntervals( + interval = interval, + futures = futures + ) + ) + + # Add date parameters + params <- c( + params, + mexcDates( + futures = futures, + dates = c(from = from, to = to) + ) + ) + + # Handle type-specific parameters + if (type == "fundingrate") { + params$symbol <- ticker + params$page_size <- 100 + } else { + if (futures) { + params$path <- list(ticker) + } else { + params$symbol <- ticker + params$limit <- 1000 + } + } + + # Construct the final parameter list based on type + params <- switch( + EXPR = type, + fundingrate = list( + query = params, + futures = futures, + source = 'mexc', + interval = interval + ), + ohlc = list( + query = params, + path = if (futures) list(ticker) else NULL, + futures = futures, + source = 'mexc', + interval = interval + ), + # Default case to handle unexpected types + list( + query = params, + futures = futures, + source = 'mexc', + interval = interval + ) + ) + + # Return the final structured parameter list + params +} +# script end; diff --git a/R/available_exchanges.R b/R/available_exchanges.R index 90772d44..507ae209 100644 --- a/R/available_exchanges.R +++ b/R/available_exchanges.R @@ -67,14 +67,38 @@ available_exchanges <- function( ) ) - exchanges <- sort( - switch( - type, - ohlc = c('binance', 'kucoin', 'kraken', 'bitmart', 'bybit'), - fundingrate = c('binance', 'bybit', 'kucoin'), - lsratio = c('binance', 'bybit', 'kraken'), - interest = c('binance', 'bybit', 'kraken') - ) + exchanges <- sort(switch( + type, + fundingrate = c( + 'binance', + 'bybit', + 'kucoin', + 'crypto.com', + 'mexc' + ), + lsratio = c( + 'binance', + 'bybit', + 'kraken' + ), + interest = c( + 'binance', + 'bybit', + 'kraken' + ), + { + c( + 'binance', + 'kucoin', + 'kraken', + 'bitmart', + 'bybit', + 'crypto.com', + 'huobi', + 'mexc' + ) + } + ) ) # 1) retun a message diff --git a/R/available_intervals.R b/R/available_intervals.R index 85ea3889..40cd233c 100644 --- a/R/available_intervals.R +++ b/R/available_intervals.R @@ -89,9 +89,9 @@ available_intervals <- function( # 0) extract available # intervals all_intervals <- get(paste0(source, 'Intervals'))( - type = type, - futures = futures, - all = TRUE, + type = type, + futures = futures, + all = TRUE, interval = NULL ) diff --git a/R/available_tickers.R b/R/available_tickers.R index 09c3ac46..f80af47a 100644 --- a/R/available_tickers.R +++ b/R/available_tickers.R @@ -70,17 +70,16 @@ available_tickers <- function( # to ticker-information response <- GET( url = baseUrl( - source = source, + source = source, futures = futures ), endpoint = endPoint( - source = source, + source = source, futures = futures, - type = 'ticker' + type = 'ticker' ) ) - # 2) get source_response # objects source_response <- get( @@ -88,19 +87,17 @@ available_tickers <- function( source, 'Response' ) )( - type = 'ticker', + type = 'ticker', futures = futures ) - ticker <- sort( + sort( source_response$foo( response = response, futures = futures ) ) - ticker - } # script end; diff --git a/R/chart.R b/R/chart.R index 7f7beecf..a5498d27 100644 --- a/R/chart.R +++ b/R/chart.R @@ -31,7 +31,8 @@ #' #' **Sample Output** #' \if{html}{ -#' \out{}\figure{README-chartquote-1.png}{options: style="width:750px;max-width:75\%;"}\out{} +#' \out{} +#' \figure{README-chartquote-1.png}{options: style="width:750px;max-width:75\%;"}\out{} #' } #' \if{latex}{ #' \out{\begin{center}}\figure{README-chartquote-1.png}\out{\end{center}} @@ -42,12 +43,27 @@ #' #' * \code{dark} A <[logical]>-value of [length] 1. [TRUE] by default. #' Sets the overall theme of the [chart()] +#' #' * \code{slider} A <[logical]>-value of [length] 1. [FALSE] by default. -#' If [TRUE], a [plotly::rangeslider()] is added +#' If [TRUE], a [plotly::rangeslider()] is added. +#' #' * \code{deficiency} A <[logical]>-value of [length] 1. [FALSE] by default. #' If [TRUE], all [chart()]-elements are colorblind friendly +#' #' * \code{size} A <[numeric]>-value of [length] 1. The relative size of the -#' main chart. 0.6 by default. Must be between 0 and 1, non-inclusive +#' main chart. 0.6 by default. Must be between 0 and 1, non-inclusive. +#' +#' * \code{scale} A <[numeric]>-value of [length] 1. 1 by default. Scales +#' all fonts on the chart. +#' +#' * \code{width} A <[numeric]>-value of [length] 1. 0.9 by default. Sets +#' the width of all line elements on the chart. +#' +#' * \code{static} A <[logical]>-value of [length] 1. [FALSE] by default. If [FALSE] +#' the chart can be edited, annotated and explored interactively. +#' +#' * \code{palette} A <[character]>-vector of [length] 1. "hawaii" by default. See [hcl.pals()] for +#' all possible color palettes. #' #' ## Charting Events #' @@ -66,9 +82,7 @@ #' @export chart <- function( ticker, - main = list( - kline() - ), + main = kline(), sub = list(), indicator = list(), event_data = NULL, @@ -132,10 +146,14 @@ chart <- function( ## 1) set chart options ## globally (locally) default_options <- list( + static = FALSE, dark = TRUE, slider = FALSE, deficiency = FALSE, - size = 0.6 + palette = "hawaii", + scale = 1, + size = 0.6, + width = 0.9 ) options <- utils::modifyList( @@ -144,13 +162,68 @@ chart <- function( keep.null = TRUE ) - dark <- options$dark - deficiency <- options$deficiency - slider <- options$slider - size <- options$size + dark <- options$dark + deficiency <- options$deficiency + slider <- options$slider + size <- options$size + palette <- options$palette + static <- options$static + candle_color <- movement_color(deficiency = deficiency) + scale <- options$scale + width <- options$width + + if (static) { + + # if the plot is static + # then turn off modebar + # slider and editable + + modebar <- slider <- editable <- FALSE + + } else { + + # the modebar and editable + # part of the plot should + # always be set to true + # for "real" interactivitiy + modebar <- editable <- TRUE + + + } + + # assert inputs and options + assert( + any(grepl(pattern = palette,x = grDevices::hcl.pals(),ignore.case = TRUE)), + error_message = c( + "x" = sprintf( + fmt = "Palette {.val %s} is not valid.", + palette + ), + "i" = paste( + "Run", + cli::code_highlight( + code = "hcl.pals()", + code_theme = "chaos" + ), + "for valid values." + ) + ) + ) + + assert( + size > 0 & size < 1, + error_message = c( + "x" = sprintf( + fmt = "Got {.arg size} %s.", + size + ), + "i" = sprintf( + fmt = "{.arg size} has to be between 0 and 1, non-inclusive." + ) + ) + ) - candle_color <- movement_color(deficiency = deficiency) # 1) generate list # of calls for lazy @@ -171,6 +244,7 @@ chart <- function( .f$interval <- interval .f$candle_color <- candle_color .f$deficiency <- deficiency + .f$scale <- scale eval(.f) }, flatten(list(call_list$main, call_list$sub)) @@ -184,7 +258,7 @@ chart <- function( if (!identical(call_list$indicator, list())) { - plot_list[1] <- list(Reduce( + plot_list[1] <- list(Reduce( f = function(plot, .f) { # Modify the call list .f$data <- ticker @@ -230,7 +304,11 @@ chart <- function( # hcl.colors are colorblind friendly. See: # https://stackoverflow.com/questions/57153428/r-plot-color-combinations-that-are-colorblind-accessible n_colors <- length(unlist(call_list)) - colorway <- grDevices::hcl.colors(n = n_colors) + # colorway <- grDevices::hcl.colors(n = n_colors) + colorway <- grDevices::hcl.colors( + n = n_colors, + palette = palette + ) plot_list <- lapply( X = plot_list, @@ -266,16 +344,55 @@ chart <- function( } ) + ) - bar( - dark = dark, - plot = plot, - name = name, - market = market, - date_range = paste(range(zoo::index(ticker)), collapse = " - ") + scatter_indices <- which( + sapply( + X = plot$x$data, + FUN = function(x) { + x$type == "scatter" + } + ) ) + plot <- plotly::style( + p = plot, + line.width = width, + traces = scatter_indices + ) + + + plot <- plotly::config( + p = bar( + dark = dark, + plot = plot, + name = name, + market = market, + date_range = paste(range(zoo::index(ticker)), collapse = " - "), + modebar = modebar, + scale = scale + ), + staticPlot = static, + editable = editable, + responsive = TRUE, + displayModeBar = modebar, + modeBarButtonsToAdd = c( + "drawline", + "drawrect", + "eraseshape" + ), + toImageButtonOptions = list( + format = "svg", + filename = "chart", + height = 2160, + width = 3840, + scale = 1 + ) + ) + + plot + } # script end; diff --git a/R/chart_fgi.R b/R/chart_fgi.R index 6d0aa7c5..79b27c70 100644 --- a/R/chart_fgi.R +++ b/R/chart_fgi.R @@ -95,7 +95,7 @@ fgi <- function( annotations = list( text = "Fear and Greed Index", font = list( - size = 16 + size = 16 * args$scale ), showarrow = FALSE, x = 0, diff --git a/R/chart_lsr.R b/R/chart_lsr.R index 601b9873..6513a9c2 100644 --- a/R/chart_lsr.R +++ b/R/chart_lsr.R @@ -92,7 +92,7 @@ lsr <- function( annotations = list( text = "Long-Short Ratio", font = list( - size = 16 + size = 16 * args$scale ), showarrow = FALSE, x = 0, diff --git a/R/chart_ma.R b/R/chart_ma.R index a7a60485..432e6aec 100644 --- a/R/chart_ma.R +++ b/R/chart_ma.R @@ -41,7 +41,7 @@ chart_ma <- function( #' `r lifecycle::badge("experimental")` #' #' A high-level [plotly::add_lines()]-wrapper function that -#' interacts with [TTR]'s moving average family of functions. +#' interacts with \{TTR\}'s moving average family of functions. #' The function adds moving average indicators to the main [chart()]. #' #' @usage sma( @@ -52,7 +52,7 @@ chart_ma <- function( #' #' @inheritParams TTR::SMA #' @param price A [character]-vector of [length] 1. "close" by default. -#' The name of the vector to passed into [TTR::SMA]. +#' The name of the vector to passed into [TTR::SMA()]. #' @param ... For internal use. Please ignore. #' #' @example man/examples/scr_MAindicator.R @@ -128,7 +128,7 @@ sma <- function( #' ) #' #' @param price A [character]-vector of [length] 1. "close" by default. -#' The name of the vector to passed into [TTR::EMA]. +#' The name of the vector to passed into [TTR::EMA()]. #' @inheritParams TTR::EMA #' @param ... For internal use. Please ignore. #' @@ -206,7 +206,7 @@ ema <- function( #' ) #' #' @param price A [character]-vector of [length] 1. "close" by default. -#' The name of the vector to passed into [TTR::DEMA]. +#' The name of the vector to passed into [TTR::DEMA()]. #' @inheritParams TTR::DEMA #' @param ... For internal use. Please ignore. #' @@ -286,7 +286,7 @@ dema <- function( #' ) #' #' @param price A [character]-vector of [length] 1. "close" by default. -#' The name of the vector to passed into [TTR::WMA]. +#' The name of the vector to passed into [TTR::WMA()]. #' @inheritParams TTR::WMA #' @param ... For internal use. Please ignore. #' @@ -362,7 +362,7 @@ wma <- function( #' ) #' #' @param price A [character]-vector of [length] 1. "close" by default. -#' The name of the vector to passed into [TTR::EVWMA] +#' The name of the vector to passed into [TTR::EVWMA()] #' @inheritParams TTR::EVWMA #' @param ... For internal use. Please ignore. #' @@ -434,7 +434,7 @@ evwma <- function( #' ) #' #' @param price A [character]-vector of [length] 1. "close" by default. -#' The name of the vector to passed into [TTR::ZLEMA]. +#' The name of the vector to passed into [TTR::ZLEMA()]. #' @inheritParams TTR::ZLEMA #' @param ... For internal use. Please ignore. #' @@ -507,7 +507,7 @@ zlema <- function( #' ) #' #' @param price A [character]-vector of [length] 1. "close" by default. -#' The name of the vector to passed into [TTR::VWAP] +#' The name of the vector to passed into [TTR::VWAP()] #' @inheritParams TTR::VWAP #' @param ... For internal use. Please ignore. #' @@ -583,7 +583,7 @@ vwap <- function( #' ) #' #' @param price A [character]-vector of [length] 1. "close" by default. -#' The name of the vector to passed into [TTR::HMA]. +#' The name of the vector to passed into [TTR::HMA()]. #' @inheritParams TTR::HMA #' @param ... For internal use. Please ignore. #' @@ -654,7 +654,7 @@ hma <- function( #' ) #' #' @param price A [character]-vector of [length] 1. "close" by default -#' The name of the vector to passed into [TTR::ALMA]. +#' The name of the vector to passed into [TTR::ALMA()]. #' @inheritParams TTR::ALMA #' @param ... For internal use. Please ignore. #' diff --git a/R/chart_macd.R b/R/chart_macd.R index e506def6..a0fc5611 100644 --- a/R/chart_macd.R +++ b/R/chart_macd.R @@ -149,7 +149,7 @@ macd <- function( x = 0, y = 1, font = list( - size = 16 + size = 16 * args$scale ), xref = 'paper', yref = 'paper', diff --git a/R/chart_rsi.R b/R/chart_rsi.R index 9ee19906..36b43d25 100644 --- a/R/chart_rsi.R +++ b/R/chart_rsi.R @@ -150,7 +150,7 @@ rsi <- function( list( text = paste0("RSI(", n, ")"), font = list( - size = 16 + size = 16 * args$scale ), x = 0, y = 1, diff --git a/R/chart_smi.R b/R/chart_smi.R index fc0d6e7a..11862bf7 100644 --- a/R/chart_smi.R +++ b/R/chart_smi.R @@ -176,7 +176,7 @@ smi <- function( x = 0, y = 1, font = list( - size = 16 + size = 16 * args$scale ), xref = 'paper', yref = 'paper', diff --git a/R/chart_volume.R b/R/chart_volume.R index 6f756394..13fb3e94 100644 --- a/R/chart_volume.R +++ b/R/chart_volume.R @@ -69,7 +69,7 @@ volume <- function( annotations = list( text = "Volume", font = list( - size = 16 + size = 16 * args$scale ), showarrow = FALSE, x = 0, diff --git a/R/get_fgi.R b/R/get_fgi.R index e56dfeb2..ea801b81 100644 --- a/R/get_fgi.R +++ b/R/get_fgi.R @@ -24,7 +24,7 @@ #' #' @inherit get_quote details #' -#' @returns An [xts]-object containing, +#' @returns An <[\link[xts]{xts}]>-object containing, #' #' \item{index}{<[POSIXct]> the time-index} #' \item{fgi}{<[numeric]> the daily fear and greed index value} @@ -110,7 +110,8 @@ get_fgindex <- function( forced_dates <- default_dates( interval = '1d', from = from, - to = to + to = to, + length = 201 ) # generate from diff --git a/R/get_fundingrate.R b/R/get_fundingrate.R index 73d74bb5..c180562f 100644 --- a/R/get_fundingrate.R +++ b/R/get_fundingrate.R @@ -24,7 +24,7 @@ #' #' @inheritParams get_quote #' -#' @returns An [xts]-object containing, +#' @returns An <[\link[xts]{xts}]>-object containing, #' #' \item{index}{<[POSIXct]> the time-index} #' \item{funding_rate}{<[numeric]> the current funding rate} @@ -87,27 +87,6 @@ get_fundingrate <- function( trimws(ticker) ) - - assert( - source %in% suppressMessages( - available_exchanges(type = "fundingrate") - ), - error_message = c( - "x" = sprintf( - fmt = "Exchange {.val %s} is not supported.", - source - ), - "i" = paste( - "Run", - cli::code_highlight( - code = "cryptoQuotes::available_exchanges(type = 'fundingrate')", - code_theme = "Chaos" - ), - "for supported exhanges" - ) - ) - ) - from <- coerce_date(from); to <- coerce_date(to) # 3) if either of the @@ -136,14 +115,18 @@ get_fundingrate <- function( } - fetch( - ticker = ticker, - source = source, - futures = TRUE, - interval = '1d', - type = "fundingrate", - to = to, - from = from + stats::window( + x = fetch( + ticker = ticker, + source = source, + futures = TRUE, + interval = '1d', + type = "fundingrate", + to = to, + from = from + ), + start = from, + end = to ) } diff --git a/R/get_lsratio.R b/R/get_lsratio.R index db950b72..68306310 100644 --- a/R/get_lsratio.R +++ b/R/get_lsratio.R @@ -27,7 +27,7 @@ #' If [TRUE] it returns the top traders Long-Short ratios. #' #' -#' @returns An [xts]-object containing, +#' @returns An [xts::xts]-object containing, #' #' \item{index}{<[POSIXct]> the time-index} #' \item{long}{<[numeric]> the share of longs} @@ -107,7 +107,7 @@ get_lsratio <- function( available_exchanges( type = 'lsratio' ) - ), + ), error_message = c( "x" = sprintf( fmt = "Exchange {.val %s} is not supported.", @@ -124,28 +124,32 @@ get_lsratio <- function( ) ) + # 2) check wether the + # interval is supported by + # the exchange API assert( interval %in% suppressMessages( available_intervals( - type = 'lsratio', - source = source + source = source, + futures = TRUE, + type = 'lsratio' ) ), error_message = c( "x" = sprintf( - fmt = "Interval {.val %s} is not supported by {.val %s}.", - interval, - source + fmt = "Interval {.val %s} is not supported.", + interval ), "i" = paste( "Run", cli::code_highlight( - code = "cryptoQuotes::available_intervals( - type = 'lsratio', source = source - )", + code = sprintf( + "cryptoQuotes::available_intervals(source = '%s', type = 'lsratio', futures = TRUE)", + source + ), code_theme = "Chaos" ), - "for supported intervals" + "for supported intervals." ) ) ) @@ -201,28 +205,21 @@ get_lsratio <- function( } - response <- fetch( - ticker = ticker, - source = source, - futures= TRUE, - interval = interval, - type = 'lsratio', - to = to, - from = from, - top = top + response <- stats::window( + x = fetch( + ticker = ticker, + source = source, + futures= TRUE, + interval = interval, + type = 'lsratio', + to = to, + from = from, + top = top + ), + start = from, + end = to ) - # Bybit has no to or from - # parameter - so this have to be subsettet - # manually - if (source == "bybit") { - - response <- response[ - paste(c(from, to),collapse = "/") - ] - - } - # Calculate the long # short ratio as not # all APIs provides this by default diff --git a/R/get_openinterest.R b/R/get_openinterest.R index 94a75282..18bcc4cc 100644 --- a/R/get_openinterest.R +++ b/R/get_openinterest.R @@ -27,7 +27,7 @@ #' @inheritParams get_quote #' #' @returns -#' An [xts]-object containing, +#' An <[\link[xts]{xts}]>-object containing, #' #' \item{index}{<[POSIXct]> the time-index} #' \item{open_interest}{<[numeric]> open perpetual contracts on both both sides} @@ -107,28 +107,32 @@ get_openinterest <- function( ) ) + # 2) check wether the + # interval is supported by + # the exchange API assert( interval %in% suppressMessages( available_intervals( - type = 'interest', - source = source - ) + source = source, + futures = TRUE, + type = 'interest' + ) ), error_message = c( "x" = sprintf( - fmt = "Interval {.val %s} is not supported by {.val %s}.", - interval, - source + fmt = "Interval {.val %s} is not supported.", + interval ), "i" = paste( "Run", cli::code_highlight( - code = " - cryptoQuotes::available_intervals(type = 'interest', source = source) - ", + code = sprintf( + "cryptoQuotes::available_intervals(source = '%s', type = 'interest', futures = TRUE)", + source + ), code_theme = "Chaos" ), - "for supported intervals" + "for supported intervals." ) ) ) @@ -172,14 +176,18 @@ get_openinterest <- function( ) } - output <- fetch( - ticker = ticker, - source = source, - futures= TRUE, - interval = interval, - type = "interest", - to = to, - from = from + output <- stats::window( + x = fetch( + ticker = ticker, + source = source, + futures= TRUE, + interval = interval, + type = "interest", + to = to, + from = from + ), + start = from, + end = to ) if (source %in% 'kraken') { diff --git a/R/get_quote.R b/R/get_quote.R index 8af50a2a..ca3fb42f 100644 --- a/R/get_quote.R +++ b/R/get_quote.R @@ -30,7 +30,7 @@ #' @param to An optional [character]-, [date]- or #' [POSIXct]-vector of [length] 1. [NULL] by default. #' -#' @returns An [xts]-object containing, +#' @returns An <[\link[xts]{xts}]>-object containing, #' #' \item{index}{<[POSIXct]> The time-index} #' \item{open}{<[numeric]> Opening price} @@ -71,61 +71,53 @@ get_quote <- function( interval = '1d', from = NULL, to = NULL) { - # This function returns - # the ticker with the desired intervals - # and such - - # 0) check internet connection and passed - # argumnents before anything + # # This function returns + # # the ticker with the desired intervals + # # and such + # + # # 0) check internet connection and passed + # # argumnents before anything check_internet_connection() # 1) check all arguments # what are missing, and are # the classes correct? - {{ - - assert( - " - Argument {.arg ticker} is missing with no default - " = !missing(ticker) & is.character(ticker) & length(ticker) == 1, - - " - Argument {.arg source} has to be {.cls character} of length {1} - " = (is.character(source) & length(source) == 1), - - " - Argument {.arg futures} has to be {.cls logical} of length {1} - " = (is.logical(futures) & length(futures) == 1), - - " - Argument {.arg interval} has to be {.cls character} of length {1} - " = (is.character(interval) & length(interval) == 1), - - " - Valid {.arg from} input is on the form - {.val {paste(as.character(Sys.Date()))}} or - {.val {as.character(format(Sys.time()))}} - " = (is.null(from) || (is.date(from) & length(from) == 1)), - - "Valid {.arg to} input is on the form - {.val {paste(as.character(Sys.Date()))}} or - {.val {as.character(format(Sys.time()))}} - " = (is.null(to) || (is.date(to) & length(to) == 1)) - ) - - }} + assert( + " + Argument {.arg ticker} is missing with no default + " = !missing(ticker) & is.character(ticker) & length(ticker) == 1, + + " + Argument {.arg source} has to be {.cls character} of length {1} + " = (is.character(source) & length(source) == 1), + + " + Argument {.arg futures} has to be {.cls logical} of length {1} + " = (is.logical(futures) & length(futures) == 1), + + " + Argument {.arg interval} has to be {.cls character} of length {1} + " = (is.character(interval) & length(interval) == 1), + + " + Valid {.arg from} input is on the form + {.val {paste(as.character(Sys.Date()))}} or + {.val {as.character(format(Sys.time()))}} + " = (is.null(from) || (is.date(from) & length(from) == 1)), + + " + Valid {.arg to} input is on the form + {.val {paste(as.character(Sys.Date()))}} or + {.val {as.character(format(Sys.time()))}} + " = (is.null(to) || (is.date(to) & length(to) == 1)) + ) # recode the exchange # source to avoid errors # based on capitalization # and whitespace - source <- tolower( - trimws(source) - ) - ticker <- toupper( - trimws(ticker) - ) - + source <- tolower(trimws(source)) + ticker <- trimws(ticker) # 1) check wether # the chosen exchange @@ -151,6 +143,7 @@ get_quote <- function( ) ) ) + # 2) check wether the # interval is supported by # the exchange API @@ -171,17 +164,13 @@ get_quote <- function( "Run", cli::code_highlight( code = sprintf( - "cryptoQuotes::available_intervals( - source = '%s', - type = 'ohlc, - futures = '%s' - )", + "cryptoQuotes::available_intervals(source = '%s', type = 'ohlc', futures = %s)", source, futures - ), + ), code_theme = "Chaos" ), - "for supported intervals" + "for supported intervals." ) ) ) @@ -217,28 +206,29 @@ get_quote <- function( } - ohlc <- fetch( - ticker = ticker, - source = source, - futures= futures, - interval = interval, - type = "ohlc", - to = to, - from = from - )[paste(c(from, to), collapse = "/")] - - # Kraken doesnt have a to - # parameter on spot market - if (source == "kraken") { - - ohlc <- ohlc[paste(c(from, to), collapse = "/")] - - } + ohlc <- stats::window( + x = fetch( + ticker = ticker, + source = source, + futures = futures, + interval = interval, + type = "ohlc", + to = to, + from = from + ), + start = from, + end = to + ) attributes(ohlc)$source <- paste0( to_title(source), if (futures) " (PERPETUALS)" else " (SPOT)" ) + ohlc <- ohlc[ + , + c("open", "high", "low", "close", "volume") + ] + ohlc } diff --git a/R/helper.R b/R/helper.R index caa2ff20..9f5cc8f6 100644 --- a/R/helper.R +++ b/R/helper.R @@ -60,9 +60,7 @@ indicator <- function( zoo::fortify.zoo( x, - names = c( - "index" - ) + names = "index" ) } @@ -237,6 +235,7 @@ infer_interval <- function( "259200" = "3d", "604800" = "1w", "1209600" = "2w", + "1296000" = "2w", "2678400" = "1M", "2592000" = "1M", "2419200" = "1M", @@ -307,7 +306,7 @@ is.date <- function(x){ #' @param ... expressions >= 1. If named the names are used #' as error messages, otherwise R's internal error-messages are thrown #' -#' @param error_message character. An error message, supports [cli]-formatting. +#' @param error_message character. An error message, supports [cli::cli]-formatting. #' @example man/examples/scr_assert.R #' @seealso [stopifnot()], [cli::cli_abort()], [tryCatch()] #' @keywords internal @@ -330,7 +329,7 @@ assert <- function(..., error_message = NULL) { # 2.1) store all conditions # in a list alongside its # names - conditions <- list(...) + conditions <- c(...) # 2.2) if !is.null(condition_names) the # above condition never gets evaluated and @@ -339,32 +338,26 @@ assert <- function(..., error_message = NULL) { # The condition is the names(list()), and is # the error messages written on lhs of the the assert # function - for (condition in named_expressions) { + if (all(conditions)) { - # if TRUE abort - # function - if (!eval.parent(conditions[[condition]])) { + # Stop the funciton + # here if all conditions + # are [TRUE] + return(NULL) - cli::cli_abort( - c("x" = condition), + } else { - # the call will reference the caller - # by default, so we need the second - # topmost caller - call = sys.call( - 1 - length(sys.calls()) - ) + cli::cli_abort( + message = c( + "x" = named_expressions[which.min(conditions)] + ), + call = sys.call( + 1 - length(sys.calls()) ) - - - } + ) } - # stop the function - # here - return(NULL) - } # 3) if there length(...) == 1 then @@ -407,8 +400,6 @@ assert <- function(..., error_message = NULL) { } - - pull <- function( from, what = "Open") { @@ -550,8 +541,9 @@ coerce_date <- function(x){ flatten <- function(x) { if (!inherits(x, "list")) - return(list(x)) else - return(unlist(c(lapply(x, flatten)), recursive = FALSE)) + list(x) + else + unlist(c(lapply(x, flatten)), recursive = FALSE) } @@ -605,7 +597,7 @@ convert_date <- function( # If the values are numeric # it is returned from the # API - scale_factor <- multiplier ** ifelse(is_numeric, -1, 1) + scale_factor <- multiplier ** if (is_numeric) -1 else 1 if (is_numeric) { @@ -943,35 +935,37 @@ bar <- function( name, market, date_range, + modebar, + scale, ...) { # 0) chart theme theme <- chart_theme(dark = dark) - title_text <- ifelse( - !is.null(market), - yes = sprintf( + title_text <- if (!is.null(market)) + sprintf( "Ticker: %s Market: %s
Period: %s", name, market, date_range - ), - no = sprintf( + ) + else + sprintf( "Ticker: %s
Period: %s", name, date_range ) - ) plot <- plotly::layout( p = plot, - margin = list(l = 5, r = 5, b = 5, t = 65), + margin = list(l = 5, r = 5, b = 5, t = if(modebar) 85 else 55), paper_bgcolor = theme$paper_bgcolor, plot_bgcolor = theme$plot_bgcolor, font = list( - size = 14, + size = 14 * scale, color = theme$font_color ), + showlegend = TRUE, legend = list( orientation = 'h', x = 0, @@ -980,14 +974,14 @@ bar <- function( title = list( text = "Indicators:", font = list( - size = 16 + size = 16 * scale ) ) ), title = list( text = title_text, font = list( - size = 20 + size = 20 * scale ), x = 1, xref = "paper", @@ -1099,8 +1093,7 @@ normalize <- function( check_indicator_call <- function( system_calls = sys.calls(), - caller = match.call(envir = parent.frame()) - ) { + caller = match.call(envir = parent.frame())) { # 0) get the entire call stack # to determine the calling function @@ -1110,9 +1103,11 @@ check_indicator_call <- function( # 1) get the calling calling # function, ie. SMA, EMA etc + calling_function <- sys.call(-1) + calling_function <- as.character( - sys.call(-1)[[1]] - ) + calling_function[[1]] + )[length(calling_function)] # 2) check the location # of chart diff --git a/R/store_xts.R b/R/store_xts.R new file mode 100644 index 00000000..9314c2fe --- /dev/null +++ b/R/store_xts.R @@ -0,0 +1,101 @@ +# script: Read and Write XTS +# objects +# author: Serkan Korkmaz, serkor1@duck.com +# date: 2024-07-04 +# objective: These convience functions makes it +# easy to read and write XTS objects. +# script start; + +#' @title +#' Read and Write `xts`-objects +#' +#' @description +#' `r lifecycle::badge("experimental")` +#' +#' The [write_xts()]- and [read_xts()]-functions are [zoo::write.zoo()]- and [zoo::read.zoo()]-wrapper functions. +#' +#' @usage +#' # write XTS-object +#' write_xts( +#' x, +#' file, +#' ... +#' ) +#' +#' @param x An <[\link[xts]{xts}]>-object. +#' @inheritParams zoo::write.zoo +#' @inheritParams zoo::read.zoo +#' +#' @details +#' When reading and writing <[\link[xts]{xts}]>-objects the [attributes] does not follow the object. +#' +#' +#' @author +#' Serkan Korkmaz +#' +#' @family utility +#' +#' @export +write_xts <- function( + x, + file, + ...) { + + assert( + inherits(x = x, what = "xts"), + error_message = c( + "x" = "{.arg x} must be a {.cls xts}-object" + ) + ) + + assert( + is.character(file) & length(file == 1), + error_message = c( + "x" = "{.arg file} has to be a {.cls character} of length 1." + ) + ) + + zoo::write.zoo( + x = x, + file = file, + index.name = "index", + col.names = TRUE, + row.names = FALSE, + ... + ) + +} + +#' @rdname +#' write_xts +#' +#' @usage +#' # read XTS-object +#' read_xts( +#' file +#' ) +#' +#' @family utility +#' @export +read_xts <- function( + file) { + + assert( + is.character(file) & length(file == 1), + error_message = c( + "x" = "{.arg file} has to be a {.cls character} of length 1." + ) + ) + + xts::as.xts( + x = zoo::read.zoo( + file = file, + index.column = 1, + header = TRUE + ) + ) + + +} + +# script end; diff --git a/R/utils.R b/R/utils.R index c948d611..42d38f0b 100644 --- a/R/utils.R +++ b/R/utils.R @@ -57,64 +57,28 @@ GET <- function( # 4) set URL # to handle - curl::handle_setopt( - handle = handle, - url = url - ) + # curl::handle_setopt( + # handle = handle, + # url = url + # ) # 5) store # response in memory # and catch connection # errors - response <- tryCatch( - expr = { - curl::curl_fetch_memory( - url = url, - handle = handle - ) - }, - error = function(error) { - - cli::cli_abort( - message = error$message, - call = sys.call( - 1 - length(sys.calls()) - ) - ) - - } + response <- curl::curl_fetch_memory( + url = url, + handle = handle ) - response <- tryCatch( - expr = { - jsonlite::fromJSON( - txt = rawToChar( - x = response$content - ), - simplifyVector = TRUE, - flatten = TRUE - ) - }, - error = function(error) { - - cli::cli_abort( - message = c( - "x" = rawToChar( - x = response$content - ) - ), - call = sys.call( - 1 - length(sys.calls()) - ) - ) - - } + jsonlite::fromJSON( + txt = rawToChar( + x = response$content + ), + simplifyVector = TRUE, + flatten = TRUE ) - response - - - } @@ -126,8 +90,7 @@ source_parameters <- function( interval, from, to, - ... -) { + ...) { get( paste0( @@ -157,7 +120,7 @@ baseUrl <- function( baseUrl <- get(paste0(source, 'Url'))( futures = futures, ... - ) + ) # 2) return the baseUrl return( @@ -213,7 +176,7 @@ endPoint <- function( #' #' @returns #' -#' It returns an [xts]-object from the desired endpoint. +#' It returns an [xts::xts]-object from the desired endpoint. #' #' #' @author Serkan Korkmaz @@ -313,18 +276,49 @@ fetch <- function( # # This could be done using do.call # maybe - switch (source, - kraken = { - response <- do.call( - data.frame, - response + response <- tryCatch( + expr = { + switch ( + source, + kraken = { + do.call( + data.frame, + response + ) + }, + mexc = { + + tryCatch( + response[[which(idx)]], + error = function(error) { + do.call( + data.frame, + response[ + grepl( + pattern = "data", + x = names(response), + ignore.case = TRUE + ) + ] + ) + + } + ) + + + }, + response[[which(idx)]] ) }, - response <- response[[which(idx)]] + error = function(error) { + assert( + FALSE, + error_message = error_message + ) + } ) - # 3) Extract source specific # response parameters parameters <- get( @@ -339,36 +333,49 @@ fetch <- function( # 3.1) wrap parameters # in tryCatch to check wether # the columns exists - column_list <- tryCatch( - expr = { - list( - index = response[, parameters$index_location], - core = rbind(response[,parameters$colum_location]) - ) - }, - error = function(error) { - - assert( - FALSE, - error_message = error_message - ) + # column_list <- tryCatch( + # expr = { + # list( + # index = response[, parameters$index_location], + # core = rbind(response[,parameters$colum_location]) + # ) + # }, + # error = function(error) { + # + # assert( + # FALSE, + # error_message = error_message + # ) + # + # } + # ) - } - ) + # column_list <- list( + # index = response[, parameters$index_location], + # core = rbind(response[,parameters$colum_location]) + # ) # 3.1.1) extract the values # from the list - index <- column_list$index - core <- column_list$core + + # core <- vapply( + # X = column_list$core, + # FUN = as.numeric, + # FUN.VALUE = numeric(1) + # ) # 3.1.2) convert # all to as.numeric - core <- apply( - X = core, - MARGIN = 2, - FUN = as.numeric + core <- zoo::as.zoo( + apply( + X = rbind(response[,parameters$colum_location]), + MARGIN = 2, + FUN = as.numeric + ) ) + + # 3.1.3) convert dates # to positxct index <- get( @@ -377,23 +384,18 @@ fetch <- function( ) )( futures = futures, - dates = index, + dates = response[, parameters$index_location], is_response = TRUE, type = type ) - - - # 4) convert to xts # from data.frame # NOTE: This throws an error # for KRAKEN no idea why response <- xts::as.xts( - zoo::as.zoo( - core - ), - index + x = core, + order.by = index ) # 4.1) set column # names diff --git a/README.Rmd b/README.Rmd index dff5a4b6..009519fc 100644 --- a/README.Rmd +++ b/README.Rmd @@ -13,11 +13,12 @@ knitr::opts_chunk$set( comment = "#>", fig.path = "man/figures/README-", message = FALSE, - warning = FALSE + warning = FALSE, + echo = FALSE ) ``` -# cryptoQuotes: Open access to cryptocurrency market data cryptocurrency in R +# {cryptoQuotes}: Open access to cryptocurrency market data cryptocurrency in R [![CRAN status](https://www.r-pkg.org/badges/version/cryptoQuotes)](https://CRAN.R-project.org/package=cryptoQuotes) @@ -30,28 +31,63 @@ knitr::opts_chunk$set( ## :information_source: About -The `cryptoQuotes`-package is a high-level API client for accessing public market data endpoints on major cryptocurrency exchanges. It supports open, high, low, close and volume (OHLC-V) data and a variety of sentiment indicators; the market data is high quality and can be retrieved in intervals ranging from *seconds* to *months*. All the market data is accessed and processed without relying on crawlers, or API keys, ensuring an open, and reliable, access for researchers, traders and students alike. There are currently `r length(invisible(cryptoQuotes::available_exchanges(type = "ohlc")))` supported cryptocurrency exchanges, +[{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) is a high-level API client for accessing public market data endpoints on major cryptocurrency exchanges. It supports open, high, low, close and volume (OHLC-V) data and a variety of sentiment indicators; the market data is high quality and can be retrieved in intervals ranging from *seconds* to *months*. All the market data is accessed and processed without relying on crawlers, or API keys, ensuring an open, and reliable, access for researchers, traders and students alike. There are currently `r length(invisible(cryptoQuotes::available_exchanges(type = "ohlc")))` supported cryptocurrency exchanges, -
-```{r, echo=FALSE} -## available exchanges -invisible( - all_exchanges <- cryptoQuotes::available_exchanges() +```{r Exchanges (Raw),include=FALSE, echo=FALSE} +# 1) create a data.table of available +# exchanges and store as dat.table +DT <- data.table::data.table( + value = suppressMessages( + cryptoQuotes::available_exchanges() + ) ) -# Convert the character vector to a single-row data frame -exchanges_df <- data.frame(t(all_exchanges)) +# 2) add labels +# to the data data +DT[ + , + label := data.table::fcase( + value == "binance", "Binance", + value == "kraken", "Kraken", + value == "crypto.com", "Crypto.com", + value == "kucoin", "KuCoin", + value == "bitmart", "BitMart", + value == "huobi", "Huobi (HTX)", + value == "mexc", "MEXC", + value == "bybit", "Bybit" + ) + , +] + +``` -# Set column names to be the exchange names -colnames(exchanges_df) <- all_exchanges + +
+```{r Exchanges (Table), echo=FALSE} +# 1) define all available +# exchanges +all_exchanges <- DT$label + +if (length(DT$label) %% 2 != 0) { + # If odd, append an empty string to make it even + all_exchanges <- c(DT$label, "") +} + +# Convert the character vector to a single-row data frame +all_exchanges <- data.table::data.table( + matrix( + data = all_exchanges, + ncol = 4, + byrow = TRUE) +) # Create a horizontal table kableExtra::kable_styling( knitr::kable( - x = exchanges_df, + x = all_exchanges, digits = 2, col.names = NULL, - caption = 'Supported exchanges', + caption = 'All supported exchanges.', align = 'c', table.attr = "style='width:100%;'", format = 'html' @@ -62,13 +98,15 @@ kableExtra::kable_styling( ```
-All data is returned as [`xts`](https://github.com/joshuaulrich/xts)-objects which enables seamless interaction with with [`quantmod`](https://github.com/joshuaulrich/quantmod) and [`TTR`](https://github.com/joshuaulrich/TTR), for developing and evaluating trading strategies or general purpose cryptocurrency market analysis with a historical or temporal perspective. +All data is returned as [{xts}](https://github.com/joshuaulrich/xts)-objects which enables seamless interaction with with [{quantmod}](https://github.com/joshuaulrich/quantmod) and [{TTR}](https://github.com/joshuaulrich/TTR), for developing and evaluating trading strategies or general purpose cryptocurrency market analysis with a historical or temporal perspective. ## :information_source: Overview -The `cryptoQuotes`-package has *two* main features; retrieving cryptocurrency market data, and charting. The market data consists of *OHLC-V* data and sentiment indicators; including, but not limited to, cryptocurrency *fear and greed index*, *long-short ratio* and *open interest*. All market data is retrieved using the family of `get_*`-functions. To get a full overview of the package and functionality please see the documentation on [pkgdown](https://serkor1.github.io/cryptoQuotes/). +[{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) has *two* main features; retrieving cryptocurrency market data, and charting. The market data consists of *OHLC-V* data and sentiment indicators; including, but not limited to, cryptocurrency *fear and greed index*, *long-short ratio* and *open interest*. All market data is retrieved using the family of `get_*`-functions. To get a full overview of the package and functionality please see the documentation via [{pkgdown}](https://serkor1.github.io/cryptoQuotes/). -> **Note:** Given the nature of crypotcurrency data and general legislative restrictions, some `exchanges` may not work in your geolocation. +> [!WARNING] +> +> Given the nature of crypotcurrency data and general legislative restrictions, some `exchanges` may not work in your geolocation. Below is a quick overview of the package and basic usage examples on retrieving and charting Bitcoin (BTC) *OHLC-V* and *long-short ratio* in 30 minute intervals. @@ -124,7 +162,7 @@ exchange <- firstup( # 2) calculate available # intervals intervals <- sapply( - exchange, + DT$value, function(x){ suppressMessages( { @@ -158,7 +196,7 @@ granularity <- function( ) { sapply( - exchange, + DT$value, function(x){ suppressMessages( { @@ -222,26 +260,33 @@ granularity <- function( # 2) create # table -kableExtra::kable_styling( - knitr::kable( - digits = 2, - caption = 'Supported exchanges, markets and intervals.', - align = 'lccccc', - table.attr = "style='width:100%;'", - col.names = c('Exchange', 'Spot', 'Futures', 'Available Intervals' ,'Smallest Interval', 'Biggest Interval'), - x = data.frame( - row.names = NULL, - Exchange = exchange, - Spot = rep(x = ":white_check_mark:",length(exchange)), - Futures = rep(x = ":white_check_mark:",length(exchange)), - `Available Intervals` = c(intervals), - `Smallest Interval` = c(granularity(TRUE)), - `Biggest Interval` = c(granularity(FALSE)) +gt::as_raw_html( + gt::fmt_markdown( + gt::cols_label( + gt::cols_align( + data = gt::gt( + data.frame( + row.names = NULL, + Exchange = DT$label, + Spot = rep(x = ":white_check_mark:",length(exchange)), + Futures = rep(x = ":white_check_mark:",length(exchange)), + `Available Intervals` = c(intervals), + `Smallest Interval` = c(granularity(TRUE)), + `Biggest Interval` = c(granularity(FALSE)) + ), + auto_align = FALSE, + caption = 'Supported exchanges by spot and futures markets with available intervals.'), + align = "left", + columns = "Exchange" + ), - format = 'html' - ), - full_width = TRUE, - position = 'center' + Available.Intervals = "Available Intervals", + Smallest.Interval = "Smallest Interval", + Biggest.Interval = "Biggest Interval" + ) + + + ) ) ```
@@ -251,7 +296,7 @@ kableExtra::kable_styling( Get USDT denominated Bitcoin (BTC) on the spot market from Binance in `30m`-intervals using the `get_quote()`-function, -```{r cryptocurrency market data in R, eval=TRUE} +```{r cryptocurrency market data in R, eval=TRUE, echo=TRUE} ## BTC OHLC prices ## from Binance spot market ## in 30 minute intervals @@ -260,7 +305,7 @@ BTC <- cryptoQuotes::get_quote( source = 'binance', futures = FALSE, interval = '30m', - from = Sys.Date() - 1 + from = Sys.Date() - 2 ) ``` @@ -289,60 +334,85 @@ __________ #### Sentiment indicators -The sentiment indicators available in the `cryptoQuotes`-package can be divided in two; *derived indicators* and *market indicators*. The former is calculated based on, for example, the price actions such as the *Moving Average Convergence Divergence* (MACD) indicator. The latter are public indicators such as the *long-short ratio* or *fear and greed index*; these are retrieved using the family of `get_*`-functions, while the derived indicators can be created using, for example, [`TTR`](https://github.com/joshuaulrich/TTR). +The sentiment indicators available in [{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) can be divided in two; *derived indicators* and *market indicators*. The former is calculated based on, for example, the price actions such as the *Moving Average Convergence Divergence* (MACD) indicator. The latter are public indicators such as the *long-short ratio* or *fear and greed index*; these are retrieved using the family of `get_*`-functions, while the derived indicators can be created using, for example, [{TTR}](https://github.com/joshuaulrich/TTR). -In this overview we are focusing on *market indicators* made public by the cryptocurrency exchanges. For a full overview of sentiment indicators please refer to the documentation on [pkgdown](https://serkor1.github.io/cryptoQuotes/). All supported *market indicators* by exchange are listed in the table below, +In this overview we are focusing on *market indicators* made public by the cryptocurrency exchanges. For a full overview of sentiment indicators please refer to the documentation via [{pkgdown}](https://serkor1.github.io/cryptoQuotes/). All supported *market indicators* by exchange are listed in the table below,
-```{r, echo = FALSE} -## 1) list all available -## exchanges and the links -available_endpoint <- data.frame( - Endpoint = c( - "Long-Short Ratio", - "Open Interest", - "Funding Rate" - ), - Binance = c( - ":white_check_mark:", - ":white_check_mark:", - ":white_check_mark:" - ), - Bitmart = c( - ":x:", - ":x:", - ":x:" - ), - Bybit = c( - ":white_check_mark:", - ":white_check_mark:", - ":white_check_mark:" - ), - Kraken = c( - ":white_check_mark:", - ":white_check_mark:", - ":x:" - ), - Kucoin = c( - ":x:", - ":x:", - ":white_check_mark:" - ) +```{r Available Endpoints by Exchange, echo = FALSE} +## 0) Get all available +## endpoints +endpoint_label <- c("Long-Short Ratio", "Open Interest", "Fundingrate") +endpoint_value <- c( "lsratio", "interest", "fundingrate") +all_exchanges <- DT$value + +DT_ <- data.table::rbindlist( + lapply( + seq_along(all_exchanges), + FUN = function(i) { + + # 0) extract exchange + exchange <- all_exchanges[i] + + data.table::rbindlist( + lapply( + seq_along(endpoint_value), + FUN = function(j) { + + + # 0) generate table + DT <- data.table::data.table( + order = j, + Exchange = DT$label[i], + Endpoint = endpoint_label[j] + ) + + DT[ + , + available := data.table::fifelse( + test = exchange %in% suppressMessages(cryptoQuotes::available_exchanges(endpoint_value[j])), + yes = ":white_check_mark:", + no = ":x:" + ) + , + ] + + DT + + + } + ) + ) + + + + + } + ) ) +DT_ <- data.table::dcast( + data = DT_, + formula = order + Endpoint ~ Exchange, + value.var = "available" +) +DT_$order <- NULL + ## 4) present table ## for as is -kableExtra::kable_styling( - knitr::kable( - digits = 0, - caption = 'Available sentiment indicators by exchange', - align = 'lccccc', - table.attr = "style='width:100%;'", - x = available_endpoint, - format = 'markdown' - ), - full_width = TRUE, - position = 'center' +gt::as_raw_html( + gt::fmt_markdown( + gt::cols_align( + data = gt::gt( + DT_, + auto_align = FALSE, + caption = 'Available sentiment indicators by exchange'), + align = "left", + columns = "Endpoint" + + ) + + ) ) ```
@@ -352,7 +422,7 @@ kableExtra::kable_styling( Get the *long-short ratio* on Bitcoin (BTC) using the `get_lsratio()`-function, -```{r cryptocurrency sentiment indicators in R, eval=TRUE} +```{r cryptocurrency sentiment indicators in R, eval=TRUE, echo=TRUE} ## BTC OHLC prices ## from Binance spot market ## in 30 minute intervals @@ -360,7 +430,7 @@ BTC_LS <- cryptoQuotes::get_lsratio( ticker = 'BTCUSDT', source = 'binance', interval = '30m', - from = Sys.Date() - 1 + from = Sys.Date() - 2 ) ``` @@ -409,7 +479,7 @@ cryptoQuotes::chart( ) ``` -Charting in the `cryptoQuotes`-package is built on [`plotly`](https://github.com/plotly/plotly.R) for interactivity. It supports *light* and *dark* themes, and accounts for *color-deficiency* via the `options`-argument in the `chart()`-function. +Charting in [{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) is built on [{plotly}](https://github.com/plotly/plotly.R) for interactivity. It supports *light* and *dark* themes, and accounts for *color-deficiency* via the `options`-argument in the `chart()`-function. #### Charting with indicators @@ -432,20 +502,21 @@ cryptoQuotes::chart( cryptoQuotes::sma(n = 14), cryptoQuotes::sma(n = 21), cryptoQuotes::bollinger_bands() + ), + options = list( + static = TRUE ) ) ``` -
-Colorblind friendly version -#### Charting with indicators (colorblind friendly) +Source -```{r chartquote(deficiency), fig.align='center', fig.dpi=180, fig.alt="cryptocurrency charts in R"} +```{r chartquote (Source),echo=TRUE, fig.align='center',fig.dpi=180, fig.alt="cryptocurrency charts in R", eval=FALSE} ## Chart BTC ## using klines, SMA -## Bollinger Bands and -## ling-short ratio with color-deficiency +## Bollinger Bands and +## long-short ratio cryptoQuotes::chart( ticker = BTC, main = cryptoQuotes::kline(), @@ -460,18 +531,17 @@ cryptoQuotes::chart( cryptoQuotes::bollinger_bands() ), options = list( - deficiency = TRUE + static = TRUE ) ) ``` -__________
## :information_source: Installation ### :shield: Stable version -```{r stable version guide, eval = FALSE} +```{r stable version guide, eval = FALSE, echo=TRUE} ## install from CRAN install.packages( pkgs = 'cryptoQuotes', @@ -480,7 +550,7 @@ install.packages( ``` ### :hammer_and_wrench: Development version -```{r development version guide, eval = FALSE} +```{r development version guide, eval = FALSE,echo=TRUE} ## install from github devtools::install_github( repo = 'https://github.com/serkor1/cryptoQuotes/', @@ -490,4 +560,4 @@ devtools::install_github( ## :information_source: Code of Conduct -Please note that the `cryptoQuotes` project is released with a [Contributor Code of Conduct](https://serkor1.github.io/cryptoQuotes/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. +Please note that the [{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) project is released with a [Contributor Code of Conduct](https://serkor1.github.io/cryptoQuotes/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. diff --git a/README.md b/README.md index 9ab287fd..c7534365 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# cryptoQuotes: Open access to cryptocurrency market data cryptocurrency in R +# {cryptoQuotes}: Open access to cryptocurrency market data cryptocurrency in R @@ -19,38 +19,49 @@ stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https:// ## :information_source: About -The `cryptoQuotes`-package is a high-level API client for accessing -public market data endpoints on major cryptocurrency exchanges. It -supports open, high, low, close and volume (OHLC-V) data and a variety -of sentiment indicators; the market data is high quality and can be -retrieved in intervals ranging from *seconds* to *months*. All the -market data is accessed and processed without relying on crawlers, or -API keys, ensuring an open, and reliable, access for researchers, -traders and students alike. There are currently 5 supported -cryptocurrency exchanges, +[{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) is a +high-level API client for accessing public market data endpoints on +major cryptocurrency exchanges. It supports open, high, low, close and +volume (OHLC-V) data and a variety of sentiment indicators; the market +data is high quality and can be retrieved in intervals ranging from +*seconds* to *months*. All the market data is accessed and processed +without relying on crawlers, or API keys, ensuring an open, and +reliable, access for researchers, traders and students alike. There are +currently 8 supported cryptocurrency exchanges,
- +
+ + + + + @@ -59,27 +70,28 @@ kucoin All data is returned as -[`xts`](https://github.com/joshuaulrich/xts)-objects which enables +[{xts}](https://github.com/joshuaulrich/xts)-objects which enables seamless interaction with with -[`quantmod`](https://github.com/joshuaulrich/quantmod) and -[`TTR`](https://github.com/joshuaulrich/TTR), for developing and +[{quantmod}](https://github.com/joshuaulrich/quantmod) and +[{TTR}](https://github.com/joshuaulrich/TTR), for developing and evaluating trading strategies or general purpose cryptocurrency market analysis with a historical or temporal perspective. ## :information_source: Overview -The `cryptoQuotes`-package has *two* main features; retrieving -cryptocurrency market data, and charting. The market data consists of -*OHLC-V* data and sentiment indicators; including, but not limited to, -cryptocurrency *fear and greed index*, *long-short ratio* and *open -interest*. All market data is retrieved using the family of -`get_*`-functions. To get a full overview of the package and -functionality please see the documentation on -[pkgdown](https://serkor1.github.io/cryptoQuotes/). +[{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) has *two* main +features; retrieving cryptocurrency market data, and charting. The +market data consists of *OHLC-V* data and sentiment indicators; +including, but not limited to, cryptocurrency *fear and greed index*, +*long-short ratio* and *open interest*. All market data is retrieved +using the family of `get_*`-functions. To get a full overview of the +package and functionality please see the documentation via +[{pkgdown}](https://serkor1.github.io/cryptoQuotes/). -> **Note:** Given the nature of crypotcurrency data and general -> legislative restrictions, some `exchanges` may not work in your -> geolocation. +> \[!WARNING\] +> +> Given the nature of crypotcurrency data and general legislative +> restrictions, some `exchanges` may not work in your geolocation. Below is a quick overview of the package and basic usage examples on retrieving and charting Bitcoin (BTC) *OHLC-V* and *long-short ratio* in @@ -95,135 +107,72 @@ exchanges,
-
-Supported exchanges +All supported exchanges.
-binance +Binance -bitmart +BitMart -bybit +Bybit -kraken +Crypto.com
-kucoin +Huobi (HTX) + +Kraken + +KuCoin + +MEXC
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
+
-Supported exchanges, markets and intervals. -
-Exchange - -Spot - -Futures - -Available Intervals - -Smallest Interval - -Biggest Interval -
-Binance - -:white_check_mark: - -:white_check_mark: - -16 - -1 second(s) - -1 month(s) -
-Bitmart - -:white_check_mark: - -:white_check_mark: - -13 - -1 minute(s) - -1 week(s) -
-Bybit - -:white_check_mark: - -:white_check_mark: - -13 - -1 minute(s) - -1 month(s) -
-Kraken - -:white_check_mark: - -:white_check_mark: - -10 - -1 minute(s) - -2 week(s) -
-Kucoin - -:white_check_mark: - -:white_check_mark: - -13 - -1 minute(s) - -1 week(s) -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Supported exchanges by spot and futures markets with available intervals.
ExchangeSpotFuturesAvailable IntervalsSmallest IntervalBiggest Interval
Binance:white_check_mark::white_check_mark:161 second(s)1 month(s)
BitMart:white_check_mark::white_check_mark:131 minute(s)1 week(s)
Bybit:white_check_mark::white_check_mark:131 minute(s)1 month(s)
Crypto.com:white_check_mark::white_check_mark:121 minute(s)1 month(s)
Huobi (HTX):white_check_mark::white_check_mark:91 minute(s)1 month(s)
Kraken:white_check_mark::white_check_mark:101 minute(s)2 week(s)
KuCoin:white_check_mark::white_check_mark:131 minute(s)1 week(s)
MEXC:white_check_mark::white_check_mark:101 minute(s)1 month(s)
+
@@ -244,13 +193,13 @@ BTC <- cryptoQuotes::get_quote( source = 'binance', futures = FALSE, interval = '30m', - from = Sys.Date() - 1 + from = Sys.Date() - 2 ) ```
- +
@@ -279,122 +228,122 @@ volume @@ -408,112 +357,72 @@ volume #### Sentiment indicators -The sentiment indicators available in the `cryptoQuotes`-package can be -divided in two; *derived indicators* and *market indicators*. The former -is calculated based on, for example, the price actions such as the -*Moving Average Convergence Divergence* (MACD) indicator. The latter are -public indicators such as the *long-short ratio* or *fear and greed -index*; these are retrieved using the family of `get_*`-functions, while -the derived indicators can be created using, for example, -[`TTR`](https://github.com/joshuaulrich/TTR). +The sentiment indicators available in +[{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) can be divided +in two; *derived indicators* and *market indicators*. The former is +calculated based on, for example, the price actions such as the *Moving +Average Convergence Divergence* (MACD) indicator. The latter are public +indicators such as the *long-short ratio* or *fear and greed index*; +these are retrieved using the family of `get_*`-functions, while the +derived indicators can be created using, for example, +[{TTR}](https://github.com/joshuaulrich/TTR). In this overview we are focusing on *market indicators* made public by the cryptocurrency exchanges. For a full overview of sentiment -indicators please refer to the documentation on -[pkgdown](https://serkor1.github.io/cryptoQuotes/). All supported +indicators please refer to the documentation via +[{pkgdown}](https://serkor1.github.io/cryptoQuotes/). All supported *market indicators* by exchange are listed in the table below,
-
Bitcoin (BTC) OHLC-V data
-2024-05-31 18:00:00 +2024-11-02 13:00:00 -67215.58 +69608 -67352.41 +69680 -66670 +69520 -67000.01 +69529.32 -2093.77494 +111.56801
-2024-05-31 18:30:00 +2024-11-02 13:30:00 -67000.01 +69529.32 -67221.53 +69626 -66876.8 +69390.09 -67200.01 +69459.05 -788.25693 +373.18153
-2024-05-31 19:00:00 +2024-11-02 14:00:00 -67200.01 +69459.05 -67459.66 +69711.59 -67160.3 +69393.22 -67417.98 +69679.99 -598.68095 +524.68007
-2024-05-31 19:30:00 +2024-11-02 14:30:00 -67417.98 +69679.99 -67455.93 +69680 -67287.97 +69358.87 -67342.77 +69365.99 -287.26257 +391.34893
-2024-05-31 20:00:00 +2024-11-02 15:00:00 -67342.77 +69366 -67444.47 +69437.85 -67288.2 +69099.96 -67305.5 +69151.19 -383.04002 +731.13778
-2024-05-31 20:30:00 +2024-11-02 15:30:00 -67305.5 +69151.2 -67427.68 +69253.16 -67170 +69112 -67400 +69112.01 -468.98276 +260.8502
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
+
-Available sentiment indicators by exchange -
-Endpoint - -Binance - -Bitmart - -Bybit - -Kraken - -Kucoin -
-Long-Short Ratio - -:white_check_mark: - -:x: - -:white_check_mark: - -:white_check_mark: - -:x: -
-Open Interest - -:white_check_mark: - -:x: - -:white_check_mark: - -:white_check_mark: - -:x: -
-Funding Rate - -:white_check_mark: - -:x: - -:white_check_mark: - -:x: - -:white_check_mark: -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Available sentiment indicators by exchange
EndpointBinanceBitMartBybitCrypto.comHuobi (HTX)KrakenKuCoinMEXC
Long-Short Ratio:white_check_mark::x::white_check_mark::x::x::white_check_mark::x::x:
Open Interest:white_check_mark::x::white_check_mark::x::x::white_check_mark::x::x:
Fundingrate:white_check_mark::x::white_check_mark::white_check_mark::x::x::white_check_mark::white_check_mark:
+
@@ -533,13 +442,13 @@ BTC_LS <- cryptoQuotes::get_lsratio( ticker = 'BTCUSDT', source = 'binance', interval = '30m', - from = Sys.Date() - 1 + from = Sys.Date() - 2 ) ```
- +
@@ -562,86 +471,86 @@ ls_ratio @@ -655,51 +564,28 @@ ls_ratio ### :information_source: Charting -Charting in the `cryptoQuotes`-package is built on -[`plotly`](https://github.com/plotly/plotly.R) for interactivity. It -supports *light* and *dark* themes, and accounts for *color-deficiency* -via the `options`-argument in the `chart()`-function. +Charting in [{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) is +built on [{plotly}](https://github.com/plotly/plotly.R) for +interactivity. It supports *light* and *dark* themes, and accounts for +*color-deficiency* via the `options`-argument in the `chart()`-function. #### Charting with indicators The OHLC-V data and the sentiment indicator can be charted using the `chart()`-function, -``` r -## Chart BTC -## using klines, SMA -## Bollinger Bands and -## long-short ratio -cryptoQuotes::chart( - ticker = BTC, - main = cryptoQuotes::kline(), - sub = list( - cryptoQuotes::lsr(ratio = BTC_LS), - cryptoQuotes::volume() - ), - indicator = list( - cryptoQuotes::sma(n = 7), - cryptoQuotes::sma(n = 14), - cryptoQuotes::sma(n = 21), - cryptoQuotes::bollinger_bands() - ) -) -``` - cryptocurrency charts in R
-Colorblind friendly version +Source -#### Charting with indicators (colorblind friendly) - ``` r ## Chart BTC ## using klines, SMA -## Bollinger Bands and -## ling-short ratio with color-deficiency +## Bollinger Bands and +## long-short ratio cryptoQuotes::chart( ticker = BTC, main = cryptoQuotes::kline(), @@ -714,15 +600,11 @@ cryptoQuotes::chart( cryptoQuotes::bollinger_bands() ), options = list( - deficiency = TRUE + static = TRUE ) ) ``` -cryptocurrency charts in R - ------------------------------------------------------------------------- -
## :information_source: Installation @@ -749,7 +631,8 @@ devtools::install_github( ## :information_source: Code of Conduct -Please note that the `cryptoQuotes` project is released with a -[Contributor Code of +Please note that the +[{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) project is +released with a [Contributor Code of Conduct](https://serkor1.github.io/cryptoQuotes/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. diff --git a/_pkgdown.yml b/_pkgdown.yml index 6fc6aeaf..a8b6fcdf 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -5,14 +5,15 @@ home: # description for google description: > - An open and unified access to cryptocurrency market data in R. + {cryptoQuotes}: Open access to cryptocurrency market data and + charts in R. navbar: - type: inverse + inverse: true structure: left: [intro, usecase, custom-indicators, reference, articles, news] - right: [github] + right: [search, lightswitch, github] components: usecase: @@ -32,14 +33,19 @@ navbar: href: articles/03-article.html - text: Converting xts-objects href: articles/04-article.html - - text: cryptoQuotes x quantmod and TTR + - text: '{cryptoQuotes} x {quantmod} and {TTR}' href: articles/05-article.html url: https://serkor1.github.io/cryptoQuotes/ template: bootstrap: 5 - bootswatch: flatly + light-switch: true + bslib: + primary: "#0054AD" + border-radius: 0.5rem + btn-border-radius: 0.25rem + danger: "#A6081A" reference: - title: Cryptocurrency Market Data diff --git a/codemeta.json b/codemeta.json index 2e5c5836..d5417ad7 100644 --- a/codemeta.json +++ b/codemeta.json @@ -2,19 +2,19 @@ "@context": "https://doi.org/10.5063/schema/codemeta-2.0", "@type": "SoftwareSourceCode", "identifier": "cryptoQuotes", - "description": " This high-level API client offers a streamlined access to public cryptocurrency market data and sentiment indicators. It features OHLC-V (Open, High, Low, Close, Volume) that comes with granularity ranging from seconds to months and essential sentiment indicators to develop and backtest trading strategies, or conduct detailed market analysis. By interacting directly with the major cryptocurrency exchanges this package ensures a reliable, and stable, flow of market information, eliminating the need for complex, low-level API interactions or webcrawlers.", - "name": "cryptoQuotes: A Streamlined Access to Cryptocurrency OHLC-V Market Data and Sentiment Indicators", + "description": " This high-level API client provides open access to cryptocurrency market data, sentiment indicators, and interactive charting tools. The data is sourced from major cryptocurrency exchanges via 'curl' and returned in 'xts'-format. The data comes in open, high, low, and close (OHLC) format with flexible granularity, ranging from seconds to months. This flexibility makes it ideal for developing and backtesting trading strategies or conducting detailed market analysis.", + "name": "cryptoQuotes: Open Access to Cryptocurrency Market Data, Sentiment Indicators and Interactive Charts", "relatedLink": ["https://serkor1.github.io/cryptoQuotes/", "https://CRAN.R-project.org/package=cryptoQuotes"], "codeRepository": "https://github.com/serkor1/cryptoQuotes", "issueTracker": "https://github.com/serkor1/cryptoQuotes/issues", "license": "https://spdx.org/licenses/GPL-2.0", - "version": "1.3.1", + "version": "1.3.2", "programmingLanguage": { "@type": "ComputerLanguage", "name": "R", "url": "https://r-project.org" }, - "runtimePlatform": "R version 4.4.0 (2024-04-24)", + "runtimePlatform": "R version 4.4.2 (2024-10-31)", "provider": { "@id": "https://cran.r-project.org", "@type": "Organization", @@ -144,7 +144,7 @@ "@type": "SoftwareApplication", "identifier": "cli", "name": "cli", - "version": ">= 3.6.2", + "version": ">= 3.6.3", "provider": { "@id": "https://cran.r-project.org", "@type": "Organization", @@ -227,7 +227,7 @@ "@type": "SoftwareApplication", "identifier": "xts", "name": "xts", - "version": ">= 0.13.2", + "version": ">= 0.14.0", "provider": { "@id": "https://cran.r-project.org", "@type": "Organization", @@ -257,10 +257,10 @@ }, "SystemRequirements": null }, - "fileSize": "808.095KB", + "fileSize": "1455.164KB", "releaseNotes": "https://github.com/serkor1/cryptoQuotes/blob/master/NEWS.md", "readme": "https://github.com/serkor1/cryptoQuotes/blob/main/README.md", - "contIntegration": ["https://github.com/serkor1/cryptoQuotes/actions/workflows/R-CMD-check.yaml", "https://codecov.io/gh/serkor1/cryptoQuotes"], - "developmentStatus": "https://lifecycle.r-lib.org/articles/stages.html#experimental", - "keywords": ["cryptocurrencies", "cryptocurrency", "cryptocurrency-exchanges", "r", "binance", "binance-api", "kucoin", "kucoin-api", "kraken-api", "kraken-exchange-api", "bitmart", "bybit", "bybit-api", "rstats", "rstats-package"] + "contIntegration": ["https://github.com/serkor1/cryptoQuotes/actions/workflows/R-CMD-check.yaml", "https://app.codecov.io/gh/serkor1/cryptoQuotes"], + "developmentStatus": "https://lifecycle.r-lib.org/articles/stages.html#stable", + "keywords": ["cryptocurrencies", "cryptocurrency", "cryptocurrency-exchanges", "r", "binance", "binance-api", "kucoin", "kucoin-api", "kraken-api", "kraken-exchange-api", "bitmart", "bybit", "bybit-api", "rstats", "rstats-package", "huobi", "huobi-api"] } diff --git a/cran-comments.md b/cran-comments.md index 85b962e4..1d8a8914 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,11 +1,15 @@ ## R CMD check results -0 errors ✔ | 0 warnings ✔ | 1 note ✖ +0 errors ✔ | 0 warnings ✔ | 1 notes ✖ ❯ checking installed package size ... NOTE installed size is 13.1Mb sub-directories of 1Mb or more: - doc 11.9Mb - -This is beyond my technical knowledge, but here is a related SO-post: -https://stackoverflow.com/questions/38639266/r-cmd-check-unusual-checking-installed-package-size-note + doc 11.7Mb + help 1.2Mb + + +There is not provided a link to the API in the description as there is (currently) 8 different APIs embedded in the +package. All API are documented in the wiki, pkgdown and vignettes. + + diff --git a/cryptoQuotes.Rproj b/cryptoQuotes.Rproj deleted file mode 100644 index 69fafd4b..00000000 --- a/cryptoQuotes.Rproj +++ /dev/null @@ -1,22 +0,0 @@ -Version: 1.0 - -RestoreWorkspace: No -SaveWorkspace: No -AlwaysSaveHistory: Default - -EnableCodeIndexing: Yes -UseSpacesForTab: Yes -NumSpacesForTab: 2 -Encoding: UTF-8 - -RnwWeave: Sweave -LaTeX: pdfLaTeX - -AutoAppendNewline: Yes -StripTrailingWhitespace: Yes -LineEndingConversion: Posix - -BuildType: Package -PackageUseDevtools: Yes -PackageInstallArgs: --no-multiarch --with-keep.source -PackageRoxygenize: rd,collate,namespace diff --git a/man/alma.Rd b/man/alma.Rd index 9e786902..4f27ccd3 100644 --- a/man/alma.Rd +++ b/man/alma.Rd @@ -14,7 +14,7 @@ alma( } \arguments{ \item{price}{A \link{character}-vector of \link{length} 1. "close" by default -The name of the vector to passed into \link[TTR:MovingAverages]{TTR::ALMA}.} +The name of the vector to passed into \code{\link[TTR:ALMA]{TTR::ALMA()}}.} \item{n}{Number of periods to average over. Must be between 1 and \code{nrow(x)}, inclusive.} @@ -31,8 +31,8 @@ A \code{\link[plotly:plot_ly]{plotly::plot_ly()}}-object \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} -A high-level \code{\link[plotly:add_trace]{plotly::add_lines()}}-wrapper function that -interacts with \link{TTR}'s moving average family of functions. +A high-level \code{\link[plotly:add_lines]{plotly::add_lines()}}-wrapper function that +interacts with \{TTR\}'s moving average family of functions. The function adds moving average indicators to the main \code{\link[=chart]{chart()}}. } \examples{ diff --git a/man/assert.Rd b/man/assert.Rd index 6405a6c1..bb8f500a 100644 --- a/man/assert.Rd +++ b/man/assert.Rd @@ -10,7 +10,7 @@ assert(..., error_message = NULL) \item{...}{expressions >= 1. If named the names are used as error messages, otherwise R's internal error-messages are thrown} -\item{error_message}{character. An error message, supports \link{cli}-formatting.} +\item{error_message}{character. An error message, supports \link[cli:cli]{cli::cli}-formatting.} } \value{ \link{NULL} if all statements in ... are \link{TRUE} diff --git a/man/available_tickers.Rd b/man/available_tickers.Rd index 03197e3e..4c643465 100644 --- a/man/available_tickers.Rd +++ b/man/available_tickers.Rd @@ -19,8 +19,8 @@ and the specified market. \strong{Sample output} -\if{html}{\out{
}}\preformatted{#> [1] "10000000AIDOGEUSDT" "1000000MOGUSDT" "10000COQUSDT" -#> [4] "10000LADYSUSDT" "10000NFTUSDT" "10000SATSUSDT" +\if{html}{\out{
}}\preformatted{#> [1] "10000000AIDOGEUSDT" "1000000BABYDOGEUSDT" "1000000MOGUSDT" +#> [4] "1000000PEIPEIUSDT" "10000COQUSDT" "10000LADYSUSDT" }\if{html}{\out{
}} } \description{ diff --git a/man/bollinger_bands.Rd b/man/bollinger_bands.Rd index 29d5dbb8..0cf307a8 100644 --- a/man/bollinger_bands.Rd +++ b/man/bollinger_bands.Rd @@ -30,8 +30,8 @@ An \link{invisible} \code{\link[plotly:plot_ly]{plotly::plot_ly()}}-object. \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} -A high-level \code{\link[plotly:add_trace]{plotly::add_lines()}}-wrapper function that interacts -with the \code{\link[TTR:bollingerBands]{TTR::BBands()}}-function. The function adds bollinger bands +A high-level \code{\link[plotly:add_lines]{plotly::add_lines()}}-wrapper function that interacts +with the \code{\link[TTR:BBands]{TTR::BBands()}}-function. The function adds bollinger bands to the main \code{\link[=chart]{chart()}}. } \examples{ diff --git a/man/calibrate_window.Rd b/man/calibrate_window.Rd index 74392426..e6992d60 100644 --- a/man/calibrate_window.Rd +++ b/man/calibrate_window.Rd @@ -81,6 +81,7 @@ stopifnot( \seealso{ Other utility: \code{\link{remove_bound}()}, -\code{\link{split_window}()} +\code{\link{split_window}()}, +\code{\link{write_xts}()} } \concept{utility} diff --git a/man/chart.Rd b/man/chart.Rd index 0625b19f..29e35ab1 100644 --- a/man/chart.Rd +++ b/man/chart.Rd @@ -6,7 +6,7 @@ \usage{ chart( ticker, - main = list(kline()), + main = kline(), sub = list(), indicator = list(), event_data = NULL, @@ -21,7 +21,7 @@ can be coerced to a \code{\link[xts:xts]{xts::xts()}}-object.} \item{sub}{An optional \link{list} of \code{\link[plotly:plot_ly]{plotly::plot_ly()}}-function(s).} -\item{indicator}{An optional \link{list} of \code{\link[plotly:add_trace]{plotly::add_lines()}}-function(s).} +\item{indicator}{An optional \link{list} of \code{\link[plotly:add_lines]{plotly::add_lines()}}-function(s).} \item{event_data}{An optional \link{data.frame} with event line(s) to be added to the \code{\link[=chart]{chart()}}. See \code{\link[=add_event]{add_event()}} for more details.} @@ -33,7 +33,8 @@ A \code{\link[plotly:plot_ly]{plotly::plot_ly()}} object. \strong{Sample Output} \if{html}{ - \out{}\figure{README-chartquote-1.png}{options: style="width:750px;max-width:75\%;"}\out{} + \out{} + \figure{README-chartquote-1.png}{options: style="width:750px;max-width:75\%;"}\out{} } \if{latex}{ \out{\begin{center}}\figure{README-chartquote-1.png}\out{\end{center}} @@ -54,11 +55,19 @@ indicators like \link{sma} and \link{bollinger_bands}. \item \code{dark} A <\link{logical}>-value of \link{length} 1. \link{TRUE} by default. Sets the overall theme of the \code{\link[=chart]{chart()}} \item \code{slider} A <\link{logical}>-value of \link{length} 1. \link{FALSE} by default. -If \link{TRUE}, a \code{\link[plotly:rangeslider]{plotly::rangeslider()}} is added +If \link{TRUE}, a \code{\link[plotly:rangeslider]{plotly::rangeslider()}} is added. \item \code{deficiency} A <\link{logical}>-value of \link{length} 1. \link{FALSE} by default. If \link{TRUE}, all \code{\link[=chart]{chart()}}-elements are colorblind friendly \item \code{size} A <\link{numeric}>-value of \link{length} 1. The relative size of the -main chart. 0.6 by default. Must be between 0 and 1, non-inclusive +main chart. 0.6 by default. Must be between 0 and 1, non-inclusive. +\item \code{scale} A <\link{numeric}>-value of \link{length} 1. 1 by default. Scales +all fonts on the chart. +\item \code{width} A <\link{numeric}>-value of \link{length} 1. 0.9 by default. Sets +the width of all line elements on the chart. +\item \code{static} A <\link{logical}>-value of \link{length} 1. \link{FALSE} by default. If \link{FALSE} +the chart can be edited, annotated and explored interactively. +\item \code{palette} A <\link{character}>-vector of \link{length} 1. "hawaii" by default. See \code{\link[=hcl.pals]{hcl.pals()}} for +all possible color palettes. } } @@ -99,7 +108,7 @@ cryptoQuotes::chart( # script end; } \seealso{ -Other chart indicators: +Other chart indicators: \code{\link{add_event}()}, \code{\link{alma}()}, \code{\link{bollinger_bands}()}, @@ -119,7 +128,7 @@ Other chart indicators: \code{\link{wma}()}, \code{\link{zlema}()} -Other price charts: +Other price charts: \code{\link{kline}()}, \code{\link{ohlc}()}, \code{\link{pline}()} diff --git a/man/cryptoQuotes-package.Rd b/man/cryptoQuotes-package.Rd index 70b8390e..eab101c1 100644 --- a/man/cryptoQuotes-package.Rd +++ b/man/cryptoQuotes-package.Rd @@ -4,11 +4,11 @@ \name{cryptoQuotes-package} \alias{cryptoQuotes} \alias{cryptoQuotes-package} -\title{cryptoQuotes: A Streamlined Access to Cryptocurrency OHLC-V Market Data and Sentiment Indicators} +\title{cryptoQuotes: Open Access to Cryptocurrency Market Data, Sentiment Indicators and Interactive Charts} \description{ \if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} -This high-level API client offers a streamlined access to public cryptocurrency market data and sentiment indicators. It features OHLC-V (Open, High, Low, Close, Volume) that comes with granularity ranging from seconds to months and essential sentiment indicators to develop and backtest trading strategies, or conduct detailed market analysis. By interacting directly with the major cryptocurrency exchanges this package ensures a reliable, and stable, flow of market information, eliminating the need for complex, low-level API interactions or webcrawlers. +This high-level API client provides open access to cryptocurrency market data, sentiment indicators, and interactive charting tools. The data is sourced from major cryptocurrency exchanges via 'curl' and returned in 'xts'-format. The data comes in open, high, low, and close (OHLC) format with flexible granularity, ranging from seconds to months. This flexibility makes it ideal for developing and backtesting trading strategies or conducting detailed market analysis. } \seealso{ Useful links: diff --git a/man/dema.Rd b/man/dema.Rd index f15aef88..99773e13 100644 --- a/man/dema.Rd +++ b/man/dema.Rd @@ -15,7 +15,7 @@ dema( } \arguments{ \item{price}{A \link{character}-vector of \link{length} 1. "close" by default. -The name of the vector to passed into \link[TTR:MovingAverages]{TTR::DEMA}.} +The name of the vector to passed into \code{\link[TTR:DEMA]{TTR::DEMA()}}.} \item{n}{Number of periods to average over. Must be between 1 and \code{nrow(x)}, inclusive.} @@ -36,8 +36,8 @@ A \code{\link[plotly:plot_ly]{plotly::plot_ly()}}-object \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} -A high-level \code{\link[plotly:add_trace]{plotly::add_lines()}}-wrapper function that -interacts with \link{TTR}'s moving average family of functions. +A high-level \code{\link[plotly:add_lines]{plotly::add_lines()}}-wrapper function that +interacts with \{TTR\}'s moving average family of functions. The function adds moving average indicators to the main \code{\link[=chart]{chart()}}. } \examples{ diff --git a/man/donchian_channel.Rd b/man/donchian_channel.Rd index fcb1929f..106325d1 100644 --- a/man/donchian_channel.Rd +++ b/man/donchian_channel.Rd @@ -28,7 +28,7 @@ An \link{invisible} \code{\link[plotly:plot_ly]{plotly::plot_ly()}}-object. \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} -A high-level \code{\link[plotly:add_trace]{plotly::add_lines()}}-wrapper function that interacts +A high-level \code{\link[plotly:add_lines]{plotly::add_lines()}}-wrapper function that interacts with the \code{\link[TTR:DonchianChannel]{TTR::DonchianChannel()}}-function. The function adds Donchian Channels to the main \code{\link[=chart]{chart()}}. diff --git a/man/ema.Rd b/man/ema.Rd index b72b2a88..2cee2ad8 100644 --- a/man/ema.Rd +++ b/man/ema.Rd @@ -14,7 +14,7 @@ ema( } \arguments{ \item{price}{A \link{character}-vector of \link{length} 1. "close" by default. -The name of the vector to passed into \link[TTR:MovingAverages]{TTR::EMA}.} +The name of the vector to passed into \code{\link[TTR:EMA]{TTR::EMA()}}.} \item{n}{Number of periods to average over. Must be between 1 and \code{nrow(x)}, inclusive.} @@ -33,8 +33,8 @@ A \code{\link[plotly:plot_ly]{plotly::plot_ly()}}-object \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} -A high-level \code{\link[plotly:add_trace]{plotly::add_lines()}}-wrapper function that -interacts with \link{TTR}'s moving average family of functions. +A high-level \code{\link[plotly:add_lines]{plotly::add_lines()}}-wrapper function that +interacts with \{TTR\}'s moving average family of functions. The function adds moving average indicators to the main \code{\link[=chart]{chart()}}. } \examples{ diff --git a/man/evwma.Rd b/man/evwma.Rd index cdfbcd98..59d5590f 100644 --- a/man/evwma.Rd +++ b/man/evwma.Rd @@ -12,7 +12,7 @@ evwma( } \arguments{ \item{price}{A \link{character}-vector of \link{length} 1. "close" by default. -The name of the vector to passed into \link[TTR:MovingAverages]{TTR::EVWMA}} +The name of the vector to passed into \code{\link[TTR:EVWMA]{TTR::EVWMA()}}} \item{n}{Number of periods to average over. Must be between 1 and \code{nrow(x)}, inclusive.} @@ -25,8 +25,8 @@ A \code{\link[plotly:plot_ly]{plotly::plot_ly()}}-object \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} -A high-level \code{\link[plotly:add_trace]{plotly::add_lines()}}-wrapper function that -interacts with \link{TTR}'s moving average family of functions. +A high-level \code{\link[plotly:add_lines]{plotly::add_lines()}}-wrapper function that +interacts with \{TTR\}'s moving average family of functions. The function adds moving average indicators to the main \code{\link[=chart]{chart()}}. } \examples{ diff --git a/man/fetch.Rd b/man/fetch.Rd index ca415c91..f9e0e8e8 100644 --- a/man/fetch.Rd +++ b/man/fetch.Rd @@ -40,7 +40,7 @@ contracts on both sides. See the \code{\link[=get_openinterest]{get_openinterest \item{...}{additional parameters passed down the endpoint} } \value{ -It returns an \link{xts}-object from the desired endpoint. +It returns an \link[xts:xts]{xts::xts}-object from the desired endpoint. } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} diff --git a/man/figures/NEWS-unnamed-chunk-2-1.png b/man/figures/NEWS-unnamed-chunk-2-1.png index 40eb6491..e5f292a5 100644 Binary files a/man/figures/NEWS-unnamed-chunk-2-1.png and b/man/figures/NEWS-unnamed-chunk-2-1.png differ diff --git a/man/figures/NEWS-unnamed-chunk-3-1.png b/man/figures/NEWS-unnamed-chunk-3-1.png new file mode 100644 index 00000000..0336aa98 Binary files /dev/null and b/man/figures/NEWS-unnamed-chunk-3-1.png differ diff --git a/man/figures/NEWS-unnamed-chunk-4-1.png b/man/figures/NEWS-unnamed-chunk-4-1.png index 29409b54..96fc855e 100644 Binary files a/man/figures/NEWS-unnamed-chunk-4-1.png and b/man/figures/NEWS-unnamed-chunk-4-1.png differ diff --git a/man/figures/NEWS-unnamed-chunk-6-1.png b/man/figures/NEWS-unnamed-chunk-6-1.png new file mode 100644 index 00000000..28f6eaec Binary files /dev/null and b/man/figures/NEWS-unnamed-chunk-6-1.png differ diff --git a/man/figures/NEWS-unnamed-chunk-7-1.png b/man/figures/NEWS-unnamed-chunk-7-1.png new file mode 100644 index 00000000..814d3978 Binary files /dev/null and b/man/figures/NEWS-unnamed-chunk-7-1.png differ diff --git a/man/figures/README-chartquote(deficiency)-1.png b/man/figures/README-chartquote(deficiency)-1.png index 215b000c..352b0cd2 100644 Binary files a/man/figures/README-chartquote(deficiency)-1.png and b/man/figures/README-chartquote(deficiency)-1.png differ diff --git a/man/figures/README-chartquote-1.png b/man/figures/README-chartquote-1.png index 0c72bff2..5d1544bf 100644 Binary files a/man/figures/README-chartquote-1.png and b/man/figures/README-chartquote-1.png differ diff --git a/man/figures/README-unnamed-chunk-1-1.png b/man/figures/README-unnamed-chunk-1-1.png new file mode 100644 index 00000000..5d595c26 Binary files /dev/null and b/man/figures/README-unnamed-chunk-1-1.png differ diff --git a/man/figures/README-unnamed-chunk-3-1.png b/man/figures/README-unnamed-chunk-3-1.png index 161a62c9..88893408 100644 Binary files a/man/figures/README-unnamed-chunk-3-1.png and b/man/figures/README-unnamed-chunk-3-1.png differ diff --git a/man/get_fgindex.Rd b/man/get_fgindex.Rd index 6a0f12f1..25cdf653 100644 --- a/man/get_fgindex.Rd +++ b/man/get_fgindex.Rd @@ -18,7 +18,7 @@ get_fgindex( \link{POSIXct}-vector of \link{length} 1. \link{NULL} by default.} } \value{ -An \link{xts}-object containing, +An <[\link[xts]{xts}]>-object containing, \item{index}{<\link{POSIXct}> the time-index} \item{fgi}{<\link{numeric}> the daily fear and greed index value} diff --git a/man/get_fundingrate.Rd b/man/get_fundingrate.Rd index 80f5212f..d901b2f6 100644 --- a/man/get_fundingrate.Rd +++ b/man/get_fundingrate.Rd @@ -25,7 +25,7 @@ See \code{\link[=available_exchanges]{available_exchanges()}} for available exch \link{POSIXct}-vector of \link{length} 1. \link{NULL} by default.} } \value{ -An \link{xts}-object containing, +An <[\link[xts]{xts}]>-object containing, \item{index}{<\link{POSIXct}> the time-index} \item{funding_rate}{<\link{numeric}> the current funding rate} diff --git a/man/get_lsratio.Rd b/man/get_lsratio.Rd index da1a1596..0af4fef4 100644 --- a/man/get_lsratio.Rd +++ b/man/get_lsratio.Rd @@ -33,7 +33,7 @@ See \code{\link[=available_exchanges]{available_exchanges()}} for available exch If \link{TRUE} it returns the top traders Long-Short ratios.} } \value{ -An \link{xts}-object containing, +An \link[xts:xts]{xts::xts}-object containing, \item{index}{<\link{POSIXct}> the time-index} \item{long}{<\link{numeric}> the share of longs} diff --git a/man/get_openinterest.Rd b/man/get_openinterest.Rd index dc080ed1..ba5b07a5 100644 --- a/man/get_openinterest.Rd +++ b/man/get_openinterest.Rd @@ -29,7 +29,7 @@ See \code{\link[=available_exchanges]{available_exchanges()}} for available exch \link{POSIXct}-vector of \link{length} 1. \link{NULL} by default.} } \value{ -An \link{xts}-object containing, +An <[\link[xts]{xts}]>-object containing, \item{index}{<\link{POSIXct}> the time-index} \item{open_interest}{<\link{numeric}> open perpetual contracts on both both sides} diff --git a/man/get_quote.Rd b/man/get_quote.Rd index b1d15d93..69eaf766 100644 --- a/man/get_quote.Rd +++ b/man/get_quote.Rd @@ -33,7 +33,7 @@ See \code{\link[=available_intervals]{available_intervals()}} for available inte \link{POSIXct}-vector of \link{length} 1. \link{NULL} by default.} } \value{ -An \link{xts}-object containing, +An <[\link[xts]{xts}]>-object containing, \item{index}{<\link{POSIXct}> The time-index} \item{open}{<\link{numeric}> Opening price} diff --git a/man/hma.Rd b/man/hma.Rd index 1a293732..7cd36038 100644 --- a/man/hma.Rd +++ b/man/hma.Rd @@ -12,7 +12,7 @@ hma( } \arguments{ \item{price}{A \link{character}-vector of \link{length} 1. "close" by default. -The name of the vector to passed into \link[TTR:MovingAverages]{TTR::HMA}.} +The name of the vector to passed into \code{\link[TTR:HMA]{TTR::HMA()}}.} \item{n}{Number of periods to average over. Must be between 1 and \code{nrow(x)}, inclusive.} @@ -25,8 +25,8 @@ A \code{\link[plotly:plot_ly]{plotly::plot_ly()}}-object \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} -A high-level \code{\link[plotly:add_trace]{plotly::add_lines()}}-wrapper function that -interacts with \link{TTR}'s moving average family of functions. +A high-level \code{\link[plotly:add_lines]{plotly::add_lines()}}-wrapper function that +interacts with \{TTR\}'s moving average family of functions. The function adds moving average indicators to the main \code{\link[=chart]{chart()}}. } \examples{ diff --git a/man/macd.Rd b/man/macd.Rd index dc81d570..374c5958 100644 --- a/man/macd.Rd +++ b/man/macd.Rd @@ -40,7 +40,7 @@ An \link{invisible} \code{\link[plotly:plot_ly]{plotly::plot_ly()}}-object. \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} -A high-level \code{\link[plotly:plot_ly]{plotly::plot_ly()}}- and \code{\link[plotly:add_trace]{plotly::add_lines()}}-function that +A high-level \code{\link[plotly:plot_ly]{plotly::plot_ly()}}- and \code{\link[plotly:add_lines]{plotly::add_lines()}}-function that interacts with the \code{\link[TTR:MACD]{TTR::MACD()}}-function. The function adds subchart with a \code{\link[TTR:MACD]{TTR::MACD()}}-indicator. } diff --git a/man/remove_bound.Rd b/man/remove_bound.Rd index 644ac991..fa6864ef 100644 --- a/man/remove_bound.Rd +++ b/man/remove_bound.Rd @@ -81,6 +81,7 @@ stopifnot( \seealso{ Other utility: \code{\link{calibrate_window}()}, -\code{\link{split_window}()} +\code{\link{split_window}()}, +\code{\link{write_xts}()} } \concept{utility} diff --git a/man/rsi.Rd b/man/rsi.Rd index 2dcbd751..8cfaf6dd 100644 --- a/man/rsi.Rd +++ b/man/rsi.Rd @@ -43,7 +43,7 @@ An \link{invisible} \code{\link[plotly:plot_ly]{plotly::plot_ly()}}-object. \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} -A high-level \code{\link[plotly:plot_ly]{plotly::plot_ly()}}- and \code{\link[plotly:add_trace]{plotly::add_lines()}}-function that +A high-level \code{\link[plotly:plot_ly]{plotly::plot_ly()}}- and \code{\link[plotly:add_lines]{plotly::add_lines()}}-function that interacts with the \code{\link[TTR:RSI]{TTR::RSI()}}-function. The function adds a subchart with a \code{\link[TTR:RSI]{TTR::RSI()}}-indicator. } diff --git a/man/sma.Rd b/man/sma.Rd index 0000d911..925c07fb 100644 --- a/man/sma.Rd +++ b/man/sma.Rd @@ -12,7 +12,7 @@ sma( } \arguments{ \item{price}{A \link{character}-vector of \link{length} 1. "close" by default. -The name of the vector to passed into \link[TTR:MovingAverages]{TTR::SMA}.} +The name of the vector to passed into \code{\link[TTR:SMA]{TTR::SMA()}}.} \item{n}{Number of periods to average over. Must be between 1 and \code{nrow(x)}, inclusive.} @@ -25,8 +25,8 @@ A \code{\link[plotly:plot_ly]{plotly::plot_ly()}}-object \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} -A high-level \code{\link[plotly:add_trace]{plotly::add_lines()}}-wrapper function that -interacts with \link{TTR}'s moving average family of functions. +A high-level \code{\link[plotly:add_lines]{plotly::add_lines()}}-wrapper function that +interacts with \{TTR\}'s moving average family of functions. The function adds moving average indicators to the main \code{\link[=chart]{chart()}}. } \examples{ diff --git a/man/smi.Rd b/man/smi.Rd index 76cabe74..e063c0bc 100644 --- a/man/smi.Rd +++ b/man/smi.Rd @@ -42,10 +42,10 @@ calculation?} calculating FastK. See Details.} \item{upper_limit}{A \link{numeric}-vector of \link{length} 1. 40 by default. -Sets the upper limit of the \link[TTR:stochastics]{TTR::SMI}.} +Sets the upper limit of the \link[TTR:SMI]{TTR::SMI}.} \item{lower_limit}{A \link{numeric}-vector of \link{length} 1. -40 by default. -Sets the lower limit of the \link[TTR:stochastics]{TTR::SMI}.} +Sets the lower limit of the \link[TTR:SMI]{TTR::SMI}.} \item{color}{A \link{character}-vector of \link{length} 1. "#4682b4" by default.} @@ -57,9 +57,9 @@ An \link{invisible} \code{\link[plotly:plot_ly]{plotly::plot_ly()}}-object. \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} -A high-level \code{\link[plotly:plot_ly]{plotly::plot_ly()}}- and \code{\link[plotly:add_trace]{plotly::add_lines()}}-function that -interacts with the \code{\link[TTR:stochastics]{TTR::SMI()}}-function. -The function adds a subchart with a \code{\link[TTR:stochastics]{TTR::SMI()}}-indicator. +A high-level \code{\link[plotly:plot_ly]{plotly::plot_ly()}}- and \code{\link[plotly:add_lines]{plotly::add_lines()}}-function that +interacts with the \code{\link[TTR:SMI]{TTR::SMI()}}-function. +The function adds a subchart with a \code{\link[TTR:SMI]{TTR::SMI()}}-indicator. } \examples{ # script start; diff --git a/man/split_window.Rd b/man/split_window.Rd index 5f150f03..19655032 100644 --- a/man/split_window.Rd +++ b/man/split_window.Rd @@ -82,6 +82,7 @@ stopifnot( \seealso{ Other utility: \code{\link{calibrate_window}()}, -\code{\link{remove_bound}()} +\code{\link{remove_bound}()}, +\code{\link{write_xts}()} } \concept{utility} diff --git a/man/vwap.Rd b/man/vwap.Rd index 30a66f3f..d8d0a3ce 100644 --- a/man/vwap.Rd +++ b/man/vwap.Rd @@ -13,7 +13,7 @@ vwap( } \arguments{ \item{price}{A \link{character}-vector of \link{length} 1. "close" by default. -The name of the vector to passed into \link[TTR:MovingAverages]{TTR::VWAP}} +The name of the vector to passed into \code{\link[TTR:VWAP]{TTR::VWAP()}}} \item{n}{Number of periods to average over. Must be between 1 and \code{nrow(x)}, inclusive.} @@ -29,8 +29,8 @@ A \code{\link[plotly:plot_ly]{plotly::plot_ly()}}-object \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} -A high-level \code{\link[plotly:add_trace]{plotly::add_lines()}}-wrapper function that -interacts with \link{TTR}'s moving average family of functions. +A high-level \code{\link[plotly:add_lines]{plotly::add_lines()}}-wrapper function that +interacts with \{TTR\}'s moving average family of functions. The function adds moving average indicators to the main \code{\link[=chart]{chart()}}. } \examples{ diff --git a/man/wma.Rd b/man/wma.Rd index 70ee0ac8..f07525e6 100644 --- a/man/wma.Rd +++ b/man/wma.Rd @@ -13,7 +13,7 @@ wma( } \arguments{ \item{price}{A \link{character}-vector of \link{length} 1. "close" by default. -The name of the vector to passed into \link[TTR:MovingAverages]{TTR::WMA}.} +The name of the vector to passed into \code{\link[TTR:WMA]{TTR::WMA()}}.} \item{n}{Number of periods to average over. Must be between 1 and \code{nrow(x)}, inclusive.} @@ -29,8 +29,8 @@ A \code{\link[plotly:plot_ly]{plotly::plot_ly()}}-object \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} -A high-level \code{\link[plotly:add_trace]{plotly::add_lines()}}-wrapper function that -interacts with \link{TTR}'s moving average family of functions. +A high-level \code{\link[plotly:add_lines]{plotly::add_lines()}}-wrapper function that +interacts with \{TTR\}'s moving average family of functions. The function adds moving average indicators to the main \code{\link[=chart]{chart()}}. } \examples{ diff --git a/man/write_xts.Rd b/man/write_xts.Rd new file mode 100644 index 00000000..1542aa68 --- /dev/null +++ b/man/write_xts.Rd @@ -0,0 +1,59 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/store_xts.R +\name{write_xts} +\alias{write_xts} +\alias{read_xts} +\title{Read and Write \code{xts}-objects} +\usage{ +# write XTS-object +write_xts( + x, + file, + ... +) + +# read XTS-object +read_xts( +file +) +} +\arguments{ +\item{x}{An <[\link[xts]{xts}]>-object.} + +\item{file}{character string or strings giving the name of the file(s) + which the data + are to be read from/written to. See \code{\link{read.table}} and + \code{\link{write.table}} for more information. Alternatively, + in \code{read.zoo}, \code{file} can be a \code{connection} or a + \code{data.frame} (e.g., + resulting from a previous \code{read.table} call) that + is subsequently processed to a \code{"zoo"} series.} + +\item{...}{further arguments passed to other functions. In the \code{read.*.zoo} + the arguments are passed to the function specified in \code{read} + (unless \code{file} is a \code{data.frame} already). In \code{write.zoo} the + arguments are passed to \code{\link{write.table}}.} +} +\description{ +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} + +The \code{\link[=write_xts]{write_xts()}}- and \code{\link[=read_xts]{read_xts()}}-functions are \code{\link[zoo:write.zoo]{zoo::write.zoo()}}- and \code{\link[zoo:read.zoo]{zoo::read.zoo()}}-wrapper functions. +} +\details{ +When reading and writing <[\link[xts]{xts}]>-objects the \link{attributes} does not follow the object. +} +\seealso{ +Other utility: +\code{\link{calibrate_window}()}, +\code{\link{remove_bound}()}, +\code{\link{split_window}()} + +Other utility: +\code{\link{calibrate_window}()}, +\code{\link{remove_bound}()}, +\code{\link{split_window}()} +} +\author{ +Serkan Korkmaz +} +\concept{utility} diff --git a/man/zlema.Rd b/man/zlema.Rd index 2145efc8..55f7c60b 100644 --- a/man/zlema.Rd +++ b/man/zlema.Rd @@ -13,7 +13,7 @@ zlema( } \arguments{ \item{price}{A \link{character}-vector of \link{length} 1. "close" by default. -The name of the vector to passed into \link[TTR:MovingAverages]{TTR::ZLEMA}.} +The name of the vector to passed into \code{\link[TTR:ZLEMA]{TTR::ZLEMA()}}.} \item{n}{Number of periods to average over. Must be between 1 and \code{nrow(x)}, inclusive.} @@ -29,8 +29,8 @@ A \code{\link[plotly:plot_ly]{plotly::plot_ly()}}-object \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} -A high-level \code{\link[plotly:add_trace]{plotly::add_lines()}}-wrapper function that -interacts with \link{TTR}'s moving average family of functions. +A high-level \code{\link[plotly:add_lines]{plotly::add_lines()}}-wrapper function that +interacts with \{TTR\}'s moving average family of functions. The function adds moving average indicators to the main \code{\link[=chart]{chart()}}. } \examples{ diff --git a/pkgdown/extra.css b/pkgdown/extra.css index e69de29b..8b137891 100644 --- a/pkgdown/extra.css +++ b/pkgdown/extra.css @@ -0,0 +1 @@ + diff --git a/pkgdown/index.Rmd b/pkgdown/index.Rmd index 733e1010..03075175 100644 --- a/pkgdown/index.Rmd +++ b/pkgdown/index.Rmd @@ -16,83 +16,26 @@ knitr::opts_chunk$set( ) ``` -# Open access to cryptocurrency market data in R cryptocurrency in R +# {cryptoQuotes}: Open access to cryptocurrency market data cryptocurrency in R [![CRAN status](https://www.r-pkg.org/badges/version/cryptoQuotes)](https://CRAN.R-project.org/package=cryptoQuotes) [![CRAN RStudio mirror downloads](https://cranlogs.r-pkg.org/badges/last-month/cryptoQuotes?color=blue)](https://r-pkg.org/pkg/cryptoQuotes) [![R-CMD-check](https://github.com/serkor1/cryptoQuotes/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/serkor1/cryptoQuotes/actions/workflows/R-CMD-check.yaml) -[![codecov](https://codecov.io/gh/serkor1/cryptoQuotes/graph/badge.svg?token=D7NF1BPVL5)](https://codecov.io/gh/serkor1/cryptoQuotes) +[![codecov](https://codecov.io/gh/serkor1/cryptoQuotes/graph/badge.svg?token=D7NF1BPVL5)](https://app.codecov.io/gh/serkor1/cryptoQuotes) [![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) ![GitHub last commit (branch)](https://img.shields.io/github/last-commit/serkor1/cryptoQuotes/development) -The `cryptoQuotes`-package is a high-level API client for accessing public market data endpoints on major cryptocurrency exchanges. It supports open, high, low, close and volume (OHLC-V) data and a variety of sentiment indicators; the market data is high quality and can be retrieved in intervals ranging from *seconds* to *months*. All the market data is accessed and processed without relying on crawlers, or API keys, ensuring an open, and reliable, access for researchers, traders and students alike. +[{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) is a high-level API client for accessing public market data endpoints on major cryptocurrency exchanges. It supports open, high, low, close and volume (OHLC-V) data and a variety of sentiment indicators; the market data is high quality and can be retrieved in intervals ranging from *seconds* to *months*. -## Example: Bitcoin OHLC-V with Long-Short Ratios - -
-```{r print table, echo=FALSE, fig.alt="cryptocurrency prices in R"} -## get OHLC-V in 30 minute intervals -## for Bitcoin from Binance -## futures market since yesterday -BTC <- cryptoQuotes::get_quote( - ticker = 'BTCUSDT', - source = 'binance', - futures = TRUE, - interval = '30m', - from = Sys.Date() - 1 -) - -## get the Long-Short Ratios in 30 minute -## intervals for Bitcoin from -## Binance since yesterday -BTC_LSR <- cryptoQuotes::get_lsratio( - ticker = 'BTCUSDT', - source = 'binance', - interval = '30m', - from = Sys.Date() - 1 -) - -## merge the OHLC-B -## and Long-Short Ratios -BTC <- round( - merge( - BTC, - BTC_LSR - ), - digits = 3 -) +All the market data is accessed and processed without relying on crawlers, or API keys, ensuring an open, and reliable, access for researchers, traders and students alike. +## Basic usage +Below is an example on retrieving OHLC-V data for Bitcoin in 30 minute intervals, -kable_output <- kableExtra::kable_styling( - kable_input = knitr::kable( - caption = 'Bitcoin (BTC) in 30 minute intervals with Long-Short Ratios.', - align = 'lcccc', - table.attr = "style='width: fit-content;'", - x = data.frame( - cbind( - index = paste(tail(zoo::index(BTC))), - tail(zoo::coredata(BTC)) - ), - row.names = NULL - ), - format = 'html' - ), - full_width = TRUE, - position = 'center', - bootstrap_options = c("responsive", "bordered"), - font_size = 14 -) - -kable_output -``` -
- -
-Source -```{r cryptocurrency market data in R, eval=FALSE} +```{r OHLC, echo=TRUE, fig.alt="cryptocurrency prices in R"} ## get OHLC-V in 30 minute intervals ## for Bitcoin from Binance ## futures market since yesterday @@ -104,24 +47,10 @@ BTC <- cryptoQuotes::get_quote( from = Sys.Date() - 1 ) -## get the Long-Short Ratios in 30 minute -## intervals for Bitcoin from -## Binance since yesterday -BTC_LSR <- cryptoQuotes::get_lsratio( - ticker = 'BTCUSDT', - source = 'binance', - interval = '30m', - from = Sys.Date() - 1 -) - -## merge the OHLC-B -## and Long-Short Ratios -BTC <- merge( - BTC, - BTC_LSR -) +## display latest +## values +tail(BTC) ``` -
## :information_source: Installation @@ -145,4 +74,4 @@ devtools::install_github( ## :information_source: Code of Conduct -Please note that the `cryptoQuotes` project is released with a [Contributor Code of Conduct](https://serkor1.github.io/cryptoQuotes/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. +Please note that the [{cryptoQuotes}](https://github.com/serkor1/cryptoQuotes) project is released with a [Contributor Code of Conduct](https://serkor1.github.io/cryptoQuotes/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. diff --git a/pkgdown/index.md b/pkgdown/index.md index 97b6a6c9..f8287389 100644 --- a/pkgdown/index.md +++ b/pkgdown/index.md @@ -1,7 +1,7 @@ -# Open access to cryptocurrency market data in R cryptocurrency in R +# {cryptoQuotes}: Open access to cryptocurrency market data cryptocurrency in R @@ -10,245 +10,28 @@ status](https://www.r-pkg.org/badges/version/cryptoQuotes)](https://CRAN.R-proje [![CRAN RStudio mirror downloads](https://cranlogs.r-pkg.org/badges/last-month/cryptoQuotes?color=blue)](https://r-pkg.org/pkg/cryptoQuotes) [![R-CMD-check](https://github.com/serkor1/cryptoQuotes/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/serkor1/cryptoQuotes/actions/workflows/R-CMD-check.yaml) -[![codecov](https://codecov.io/gh/serkor1/cryptoQuotes/graph/badge.svg?token=D7NF1BPVL5)](https://codecov.io/gh/serkor1/cryptoQuotes) +[![codecov](https://codecov.io/gh/serkor1/cryptoQuotes/graph/badge.svg?token=D7NF1BPVL5)](https://app.codecov.io/gh/serkor1/cryptoQuotes) [![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) ![GitHub last commit (branch)](https://img.shields.io/github/last-commit/serkor1/cryptoQuotes/development) -The `cryptoQuotes`-package is a high-level API client for accessing -public market data endpoints on major cryptocurrency exchanges. It -supports open, high, low, close and volume (OHLC-V) data and a variety -of sentiment indicators; the market data is high quality and can be -retrieved in intervals ranging from *seconds* to *months*. All the -market data is accessed and processed without relying on crawlers, or -API keys, ensuring an open, and reliable, access for researchers, -traders and students alike. +[{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) is a +high-level API client for accessing public market data endpoints on +major cryptocurrency exchanges. It supports open, high, low, close and +volume (OHLC-V) data and a variety of sentiment indicators; the market +data is high quality and can be retrieved in intervals ranging from +*seconds* to *months*. -## Example: Bitcoin OHLC-V with Long-Short Ratios +All the market data is accessed and processed without relying on +crawlers, or API keys, ensuring an open, and reliable, access for +researchers, traders and students alike. -
+## Basic usage -
Long-Short Ratio on Bitcoin (BTC)
-2024-05-31 18:00:00 +2024-11-02 13:00:00 -0.679 +0.523 -0.321 +0.477 -2.114 +1.098
-2024-05-31 18:30:00 +2024-11-02 13:30:00 -0.687 +0.52 -0.313 +0.48 -2.199 +1.085
-2024-05-31 19:00:00 +2024-11-02 14:00:00 -0.696 +0.517 -0.304 +0.483 -2.289 +1.07
-2024-05-31 19:30:00 +2024-11-02 14:30:00 -0.699 +0.519 -0.301 +0.481 -2.323 +1.077
-2024-05-31 20:00:00 +2024-11-02 15:00:00 -0.696 +0.519 -0.304 +0.481 -2.288 +1.08
-2024-05-31 20:30:00 +2024-11-02 15:30:00 -0.696 +0.52 -0.304 +0.48 -2.293 +1.085
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-Bitcoin (BTC) in 30 minute intervals with Long-Short Ratios. -
-index - -open - -high - -low - -close - -volume - -long - -short - -ls_ratio -
-2024-05-25 12:00:00 - -69118 - -69133.8 - -69040.8 - -69061.1 - -1229.377 - -0.587 - -0.413 - -1.42 -
-2024-05-25 12:30:00 - -69061 - -69492.1 - -69058.8 - -69397.6 - -5130.885 - -0.585 - -0.415 - -1.411 -
-2024-05-25 13:00:00 - -69397.7 - -69622.8 - -69345.8 - -69560.1 - -5232.397 - -0.589 - -0.411 - -1.434 -
-2024-05-25 13:30:00 - -69560 - -69563.3 - -69112.4 - -69112.5 - -5320.138 - -0.589 - -0.411 - -1.434 -
-2024-05-25 14:00:00 - -69112.4 - -69323.9 - -69031.4 - -69234.1 - -4699.305 - -0.581 - -0.419 - -1.386 -
-2024-05-25 14:30:00 - -69234 - -69260.4 - -69103.6 - -69131.9 - -1183.558 - -0.585 - -0.416 - -1.407 -
- -
- -
- -Source - +Below is an example on retrieving OHLC-V data for Bitcoin in 30 minute +intervals, ``` r ## get OHLC-V in 30 minute intervals @@ -262,25 +45,18 @@ BTC <- cryptoQuotes::get_quote( from = Sys.Date() - 1 ) -## get the Long-Short Ratios in 30 minute -## intervals for Bitcoin from -## Binance since yesterday -BTC_LSR <- cryptoQuotes::get_lsratio( - ticker = 'BTCUSDT', - source = 'binance', - interval = '30m', - from = Sys.Date() - 1 -) - -## merge the OHLC-B -## and Long-Short Ratios -BTC <- merge( - BTC, - BTC_LSR -) +## display latest +## values +tail(BTC) ``` -
+ #> open high low close volume + #> 2024-07-09 18:30:00 57667.8 57718.6 57318.3 57663.1 5587.568 + #> 2024-07-09 19:00:00 57663.0 57780.0 57422.4 57580.2 3122.371 + #> 2024-07-09 19:30:00 57582.0 57631.6 57344.7 57497.1 2389.315 + #> 2024-07-09 20:00:00 57497.0 57950.0 57418.9 57699.9 4807.539 + #> 2024-07-09 20:30:00 57700.0 58290.6 57679.0 57888.0 12973.359 + #> 2024-07-09 21:00:00 57888.0 57912.2 57716.0 57812.5 1562.662 ## :information_source: Installation @@ -306,7 +82,8 @@ devtools::install_github( ## :information_source: Code of Conduct -Please note that the `cryptoQuotes` project is released with a -[Contributor Code of +Please note that the +[{cryptoQuotes}](https://github.com/serkor1/cryptoQuotes) project is +released with a [Contributor Code of Conduct](https://serkor1.github.io/cryptoQuotes/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. diff --git a/playground/playground.R b/playground/playground.R deleted file mode 100644 index be2c1301..00000000 --- a/playground/playground.R +++ /dev/null @@ -1,53 +0,0 @@ -# script: playground -# date: 2024-02-26 -# author: Serkan Korkmaz, serkor1@duck.com -# objective: A playground for -# testing various elements of the -# library -# script start; - -# setup; -rm(list = ls()); gc(); devtools::load_all() - -BTC <- cryptoQuotes::get_quote( - ticker = 'BTCUSD', - interval = '1d', - source = 'kraken', - futures = FALSE, - from = Sys.Date() - 1000, - to = Sys.Date() -) - -nrow(BTC) - - -head(BTC) -head(BTC) - - - -length( - seq( - from = coerce_date(Sys.Date() - 10), - to = coerce_date(Sys.Date() - 1), - by = "+15 mins" - ) -) - - -default_dates( - interval = "15m", - from = coerce_date(Sys.Date() - 10), - to = coerce_date(Sys.Date() - 1) -) - -# script end; - - -origin_date <- '1970-01-01' - -as.POSIXct( - trunc(as.double(coerce_date(Sys.Date() - 10))/(15*60))*(15*60), - tz = 'UTC', - origin = origin_date -) diff --git a/tests/testthat/test-CICD.R b/tests/testthat/test-CICD.R new file mode 100644 index 00000000..d9d0f43b --- /dev/null +++ b/tests/testthat/test-CICD.R @@ -0,0 +1,322 @@ +# script: Kraken Unit Test +# author: Serkan Korkmaz, serkor1@duck.com +# date: 2024-05-18 +# objective: This unit test is a sample of of the functions +# available in the package for CI/CD. Most tests fails on Github +# because of georestrictions - and this makes the library prone to +# bugs and errors for future contributions. This unit test is a sample test +# to filter errorneous pushses from contributors from the get go. +# +# All tests has to be done locally - but this is an initial security measure +# script start; + +# 1) SPOT +testthat::test_that( + desc = "Test get_quote() for SPOT (On Github)", + code = { + + set.seed(1903) + # 0) skip if offline + # and on github + testthat::skip_if_offline() + + lapply( + X = c("crypto.com", "kraken", "mexc", "huobi", "kucoin"), + FUN = function(x) { + + + # 1) get available tickers + testthat::expect_no_condition( + ticker <- available_tickers( + source = x, + futures = FALSE + ) + ) + + output <- try( + get_quote( + ticker = sample(ticker,size = 1), + source = x, + interval = "1h", + futures = FALSE + ) + ) + + testthat::expect_false( + object = inherits( + x = output, + what = "try-error" + ), + label = paste( + "Error in", x, "(get_quote)" + ) + ) + + # 2) test wether the + # ohlc is logical + testthat::expect_true( + all( + output$high >= output$low, + output$open >= output$low, + output$open <= output$high, + output$close >= output$low, + output$close <= output$high + ) + ) + + + # 3) test if dates are reasonable + # within range + date_range <- as.numeric( + format( + range( + zoo::index(output) + ), + format = "%Y" + ) + ) + + testthat::expect_true( + object = all( + min(date_range) >= 2000, + max(date_range) <= as.numeric(format(Sys.Date(), "%Y")) + ) + ) + + } + ) + + + } +) + +# 2) Futures +testthat::test_that( + desc = "Test get_quote() for FUTURES (On Github)", + code = { + + + set.seed(1453) + # 0) skip if offline + # and on github + testthat::skip_if_offline() + + lapply( + X = c("crypto.com", "kraken", "mexc", "huobi", "kucoin"), + FUN = function(x) { + + + # 1) get available tickers + testthat::expect_no_condition( + ticker <- available_tickers( + source = x, + futures = TRUE + ) + ) + + ticker <- sample(ticker,size = 1) + + # 2) get quote from kraken + testthat::expect_no_condition( + output <- get_quote( + ticker = ticker, + source = x, + interval = "1h", + futures = TRUE + ) + ) + + + # 2) test wether the + # ohlc is logical + testthat::expect_true( + all( + output$high >= output$low, + output$open >= output$low, + output$open <= output$high, + output$close >= output$low, + output$close <= output$high + ), + label = paste(x, ticker) + ) + + + # 3) test if dates are reasonable + # within range + date_range <- as.numeric( + format( + range( + zoo::index(output) + ), + format = "%Y" + ) + ) + + testthat::expect_true( + object = all( + min(date_range) >= 2000, + max(date_range) <= as.numeric(format(Sys.Date(), "%Y")) + ) + ) + + } + ) + + } +) + +# 2) Long-Short Ration +testthat::test_that( + desc = "Test get_lsr() for Kraken (FUTURES)", + code = { + + set.seed(1903) + # 0) skip if offline + # and on github + testthat::skip_if_offline() + + # 1) get available tickers + testthat::expect_no_condition( + ticker <- available_tickers( + source = "kraken", + futures = TRUE + ) + ) + + # 2) get quote from kraken + testthat::expect_no_condition( + output <- get_lsratio( + ticker = sample(ticker,size = 1), + source = "kraken", + interval = "2d" + ) + ) + + + # 3) test if dates are reasonable + # within range + date_range <- as.numeric( + format( + range( + zoo::index(output) + ), + format = "%Y" + ) + ) + + testthat::expect_true( + object = all( + min(date_range) >= 2000, + max(date_range) <= as.numeric(format(Sys.Date(), "%Y")) + ) + ) + + } +) + +# 3) Funding Rate +testthat::test_that( + desc = "Test get_fundingrate() on Github", + code = { + + set.seed(1903) + # 0) skip if offline + # and on github + testthat::skip_if_offline() + + lapply( + X = c("crypto.com", "mexc", "kucoin"), + FUN = function(x) { + + + # 1) get available tickers + testthat::expect_no_condition( + ticker <- available_tickers( + source = x, + futures = TRUE + ) + ) + + # 2) get quote from kraken + testthat::expect_no_condition( + output <- get_fundingrate( + ticker = sample(ticker,size = 1), + source = x + ) + ) + + + # 3) test if dates are reasonable + # within range + date_range <- as.numeric( + format( + range( + zoo::index(output) + ), + format = "%Y" + ) + ) + + testthat::expect_true( + object = all( + min(date_range) >= 2000, + max(date_range) <= as.numeric(format(Sys.Date(), "%Y")) + ) + ) + + } + ) + + } +) + +# 4) open interest +testthat::test_that( + desc = "Test open_interest() for Kraken (FUTURES)", + code = { + + # 0) skip if offline + # and on github + testthat::skip_if_offline() + + # 1) get available tickers + testthat::expect_no_condition( + ticker <- cryptoQuotes::available_tickers( + source = "kraken", + futures = TRUE + ) + ) + + # 2) get quote from kraken + testthat::expect_no_condition( + output <- get_openinterest( + ticker = sample(ticker,size = 1), + source = "kraken", + interval = "2d" + ) + ) + + + # 3) test if dates are reasonable + # within range + date_range <- as.numeric( + format( + range( + zoo::index(output) + ), + format = "%Y" + ) + ) + + testthat::expect_true( + object = all( + min(date_range) >= 2000, + max(date_range) <= as.numeric(format(Sys.Date(), "%Y")) + ) + ) + + } +) + + +# script end; diff --git a/tests/testthat/test-charting.R b/tests/testthat/test-charting.R index 9f316e6b..5017348c 100644 --- a/tests/testthat/test-charting.R +++ b/tests/testthat/test-charting.R @@ -91,7 +91,7 @@ testthat::test_that( ) # 2) check that there is no erros - testthat::expect_no_error( + testthat::expect_no_condition( test_chart ) @@ -143,7 +143,7 @@ testthat::test_that( ) # 2) check that there is no erros - testthat::expect_no_error( + testthat::expect_no_condition( test_chart ) diff --git a/tests/testthat/test-getFundingrate.R b/tests/testthat/test-getFundingrate.R index bd2139e5..eebe95cd 100644 --- a/tests/testthat/test-getFundingrate.R +++ b/tests/testthat/test-getFundingrate.R @@ -26,14 +26,16 @@ testthat::test_that( error_label <- exchange ticker <- switch (exchange, - 'binance' = "BTCUSDT", - "bybit" = "BTCUSDT", - "kucoin" = "XBTUSDTM" + 'binance' = "BTCUSDT", + "bybit" = "BTCUSDT", + "kucoin" = "XBTUSDTM", + "crypto.com" = "BTCUSD-PERP", + "mexc" = "BTC_USDT" ) # 1) run without any errors - testthat::expect_no_condition( - output <- get_fundingrate( + output <- testthat::expect_no_condition( + get_fundingrate( ticker = ticker, source = exchange, # Use yesterdays date diff --git a/tests/testthat/test-getQuote.R b/tests/testthat/test-getQuote.R index 28077913..3bb79a98 100644 --- a/tests/testthat/test-getQuote.R +++ b/tests/testthat/test-getQuote.R @@ -11,7 +11,8 @@ testthat::test_that( # 0) skip if offline # and on github - testthat::skip_if_offline(); testthat::skip_on_ci() + testthat::skip_if_offline() + testthat::skip_on_ci() # 1) create a vector # of available exchanges @@ -20,7 +21,10 @@ testthat::test_that( 'bitmart', 'bybit', 'kraken', - 'kucoin' + 'kucoin', + "crypto.com", + "mexc", + "huobi" ) # 2) start loop @@ -41,32 +45,44 @@ testthat::test_that( ticker <- switch( exchange, - "binance" = "BTCUSDT", - "bybit" = "BTCUSDT", - "bitmart" = "BTCUSDT", - "kraken" = "PF_XBTUSD", - "kucoin" = "XBTUSDTM" + "binance" = "BTCUSDT", + "bybit" = "BTCUSDT", + "bitmart" = "ETHUSDT", + "kraken" = "PF_XBTUSD", + "kucoin" = "XBTUSDTM", + "crypto.com" = "BTCUSD-PERP", + "mexc" = "BTC_USDT", + "huobi" = "BTC-USDT" ) } else { ticker <- switch( exchange, - "binance" = "BTCUSDT", - "bybit" = "BTCUSDT", - "bitmart" = "BTC_USDT", - "kraken" = "XBTUSDT", - "kucoin" = "BTC-USDT" + "binance" = "BTCUSDT", + "bybit" = "BTCUSDT", + "bitmart" = "ETH_USDT", + "kraken" = "XBTUSDT", + "kucoin" = "BTC-USDT", + "crypto.com" = "BTC_USDT", + "mexc" = "BTCUSDT", + "huobi" = "btcusdt" ) } # 2) for each market we # test two intervals - intervals <- c("1d", "1h") + suppressMessages( + intervals <- available_intervals( + source = exchange, + futures = futures + ) + ) for (interval in intervals) { + error_label <- paste( "Error in get_quote for", exchange, @@ -76,38 +92,53 @@ testthat::test_that( interval ) - # 1) Return quote on - # from exchanges - testthat::expect_no_condition( - output <- get_quote( + + output <- try( + get_quote( ticker = ticker, source = exchange, interval = interval, futures = futures + ) + ) + + # 1) Return quote on + # from exchanges + testthat::expect_false( + object = inherits( + x = output, + what = "try-error" ), - message = error_label + label = paste(error_label, "(Test 0)") ) # 2) test wether the # ohlc is logical testthat::expect_true( all( - output$high >= output$low, - output$open >= output$low, - output$open <= output$high, + output$high >= output$low, + output$open >= output$low, + output$open <= output$high, output$close >= output$low, output$close <= output$high ), - label = error_label + label = paste(error_label, "(Test 1)") ) + testthat::expect_true( + setequal( + x = infer_interval(output), + y = interval + ), + label = paste(error_label, "(Expected Interval)") + ) # 2) check if the returned # quote is 100 +/- testthat::expect_equal( object = nrow(output), tolerance = 1, expected = 200, - label = error_label + label = paste(error_label, "(Test 2)") ) # 3) test if dates are reasonable @@ -126,7 +157,18 @@ testthat::test_that( min(date_range) >= 2000, max(date_range) <= as.numeric(format(Sys.Date(), "%Y")) ), - label = error_label + label = paste(error_label, "(Test 3)") + ) + + # 4) test that the inferred interval + # corresponds to the passed interval + testthat::expect_true( + setequal( + interval, + cryptoQuotes:::infer_interval( + output + ) + ) ) @@ -138,3 +180,4 @@ testthat::test_that( } ) + diff --git a/tests/testthat/test-infer_interval.R b/tests/testthat/test-infer_interval.R index d6827c90..60b4e5a8 100644 --- a/tests/testthat/test-infer_interval.R +++ b/tests/testthat/test-infer_interval.R @@ -50,11 +50,38 @@ testthat::test_that( X = intervals, FUN = function(x) { + # 2.0) setup values + + # extract granularity + # from the interval + granularity <- gsub( + pattern = "([0-9]*)", + x = x, + replacement = "" + ) + + granularity <- switch( + EXPR = granularity, + s = "secs", + m = "mins", + h = "hours", + w = "weeks", + d = "days", + M = "months" + ) + + # extract the value + # so it fits the granularity + # 1m, 2m etc. + value <- as.integer( + gsub("([a-zA-Z]+)", "", x) + ) + # 2.1) Generate # date intervals using default_dates date_interval <- cryptoQuotes:::default_dates( interval = x, - length = 2 + length = 200 ) # 2.2) extrapolate @@ -67,8 +94,9 @@ testthat::test_that( # the default_date adds 1 day if chosen # to avoid errors due to conversion # on API level - length.out = 2 + as.numeric(x == "1d" | x == "3d") - )[1:2] + # on API level + by = paste0("+", value, " ", granularity) + ) # 2.3) assert that # the passed interval x is @@ -77,7 +105,7 @@ testthat::test_that( x = x, y = cryptoQuotes:::infer_interval( x = xts::xts( - x = seq_len(2), + x = seq_len(length(dates)), order.by = dates ) diff --git a/tests/testthat/test-kraken.R b/tests/testthat/test-kraken.R deleted file mode 100644 index 305d4a41..00000000 --- a/tests/testthat/test-kraken.R +++ /dev/null @@ -1,237 +0,0 @@ -# script: Kraken Unit Test -# author: Serkan Korkmaz, serkor1@duck.com -# date: 2024-05-18 -# objective: This unit test is a sample of of the functions -# available in the package for CI/CD. Most tests fails on Github -# because of georestrictions - and this makes the library prone to -# bugs and errors for future contributions. This unit test is a sample test -# to filter errorneous pushses from contributors from the get go. -# -# All tests has to be done locally - but this is an initial security measure -# script start; - -# 1) SPOT -testthat::test_that( - desc = "Test get_quote() for Kraken (SPOT)", - code = { - - # 0) skip if offline - # and on github - testthat::skip_if_offline() - - # 1) get available tickers - testthat::expect_no_condition( - ticker <- cryptoQuotes::available_tickers( - source = "kraken", - futures = FALSE - ) - ) - - # 2) get quote from kraken - testthat::expect_no_condition( - output <- get_quote( - ticker = sample(ticker,size = 1), - source = "kraken", - interval = "1d", - futures = FALSE - ) - ) - - - # 2) test wether the - # ohlc is logical - testthat::expect_true( - all( - output$high >= output$low, - output$open >= output$low, - output$open <= output$high, - output$close >= output$low, - output$close <= output$high - ) - ) - - - # 3) test if dates are reasonable - # within range - date_range <- as.numeric( - format( - range( - zoo::index(output) - ), - format = "%Y" - ) - ) - - testthat::expect_true( - object = all( - min(date_range) >= 2000, - max(date_range) <= as.numeric(format(Sys.Date(), "%Y")) - ) - ) - - } -) - - - - - -# 2) Futures -testthat::test_that( - desc = "Test get_quote() for Kraken (FUTURES)", - code = { - - # 0) skip if offline - # and on github - testthat::skip_if_offline() - - # 1) get available tickers - testthat::expect_no_condition( - ticker <- cryptoQuotes::available_tickers( - source = "kraken", - futures = TRUE - ) - ) - - # 2) get quote from kraken - testthat::expect_no_condition( - output <- get_quote( - ticker = sample(ticker,size = 1), - source = "kraken", - interval = "1d", - futures = TRUE - ) - ) - - - # 2) test wether the - # ohlc is logical - testthat::expect_true( - all( - output$high >= output$low, - output$open >= output$low, - output$open <= output$high, - output$close >= output$low, - output$close <= output$high - ) - ) - - - # 3) test if dates are reasonable - # within range - date_range <- as.numeric( - format( - range( - zoo::index(output) - ), - format = "%Y" - ) - ) - - testthat::expect_true( - object = all( - min(date_range) >= 2000, - max(date_range) <= as.numeric(format(Sys.Date(), "%Y")) - ) - ) - - } -) - -# 2) Long-Short Ration -testthat::test_that( - desc = "Test get_lsr() for Kraken (FUTURES)", - code = { - - # 0) skip if offline - # and on github - testthat::skip_if_offline() - - # 1) get available tickers - testthat::expect_no_condition( - ticker <- cryptoQuotes::available_tickers( - source = "kraken", - futures = TRUE - ) - ) - - # 2) get quote from kraken - testthat::expect_no_condition( - output <- get_lsratio( - ticker = sample(ticker,size = 1), - source = "kraken", - interval = "2d" - ) - ) - - - # 3) test if dates are reasonable - # within range - date_range <- as.numeric( - format( - range( - zoo::index(output) - ), - format = "%Y" - ) - ) - - testthat::expect_true( - object = all( - min(date_range) >= 2000, - max(date_range) <= as.numeric(format(Sys.Date(), "%Y")) - ) - ) - - } -) - -# 3) Open Interest -testthat::test_that( - desc = "Test open_interest() for Kraken (FUTURES)", - code = { - - # 0) skip if offline - # and on github - testthat::skip_if_offline() - - # 1) get available tickers - testthat::expect_no_condition( - ticker <- cryptoQuotes::available_tickers( - source = "kraken", - futures = TRUE - ) - ) - - # 2) get quote from kraken - testthat::expect_no_condition( - output <- get_openinterest( - ticker = sample(ticker,size = 1), - source = "kraken", - interval = "2d" - ) - ) - - - # 3) test if dates are reasonable - # within range - date_range <- as.numeric( - format( - range( - zoo::index(output) - ), - format = "%Y" - ) - ) - - testthat::expect_true( - object = all( - min(date_range) >= 2000, - max(date_range) <= as.numeric(format(Sys.Date(), "%Y")) - ) - ) - - } -) - -# script end; diff --git a/tests/testthat/test-store_xts.R b/tests/testthat/test-store_xts.R new file mode 100644 index 00000000..14497e0b --- /dev/null +++ b/tests/testthat/test-store_xts.R @@ -0,0 +1,46 @@ +# script: Test Read and Write +# author: Serkan Korkmaz, serkor1@duck.com +# date: 2024-07-04 +# objective: Unittests for reading and writing +# objects +# script start; + +testthat::test_that( + desc = "Read and Write -objects", + code = { + + # 0) create temporary + # file location and name + temp_file <- paste0( + tempdir(), "BTC.csv" + ) + + # 1) store in temporary file + write_xts( + x = BTC, + file = temp_file + ) + + # 2) check if its equal + # to the original BTC + # object. + # + # NOTE: expect_equal will not + # work as attributes are missing + testthat::expect_true( + setequal( + x = BTC, + y = read_xts( + file = temp_file + ) + ) + ) + + # 3) delete file + # after the test is run + unlink(temp_file) + + } +) +# script end; + diff --git a/vignettes/articles/01-article.Rmd b/vignettes/articles/01-article.Rmd index 7df1fdd6..a2711bbf 100644 --- a/vignettes/articles/01-article.Rmd +++ b/vignettes/articles/01-article.Rmd @@ -19,7 +19,7 @@ knitr::opts_chunk$set( library(cryptoQuotes) ``` -The main goal of the `cryptoQuotes`-package is to bridge the gap between `R` and the cryptocurrency market data. Its a high-level `API`-client that connects to major cryptocurrency exchanges and their respective public market data endpoints. +The main goal of the [{cryptoQuotes}](https://github.com/serkor1/cryptoQuotes) is to bridge the gap between `R` and the cryptocurrency market data. Its a high-level `API`-client that connects to major cryptocurrency exchanges and their respective public market data endpoints. In this article we will focus on `price` and `sentiment` data made available by the [Kraken](https://www.kraken.com/) exchange. @@ -27,9 +27,9 @@ In this article we will focus on `price` and `sentiment` data made available by In this section we will focus on market data from the last 24 hours, on the hourly chart. -### OHLC data +### Open, Highl Low, Close and Volume (OHLC-V) data -To get `OHLC` data the `get_quote()`-function is the go-to function, +To get `OHLC-V` data the `get_quote()`-function is the go-to function, ```{r} ## Get the @@ -182,7 +182,7 @@ nrow( ) ``` -> **Note:** For an indepth analysis of the various limitations and workarounds please see the `cryptoQuotes` [wiki](https://github.com/serkor1/cryptoQuotes/wiki) on +> **Note:** For an indepth analysis of the various limitations and workarounds please see the [{cryptoQuotes}](https://github.com/serkor1/cryptoQuotes) [wiki](https://github.com/serkor1/cryptoQuotes/wiki/Limits-and-Restrictions) on > [Github](https://github.com/serkor1/cryptoQuotes) diff --git a/vignettes/articles/02-article.Rmd b/vignettes/articles/02-article.Rmd index 33594943..45130910 100644 --- a/vignettes/articles/02-article.Rmd +++ b/vignettes/articles/02-article.Rmd @@ -18,9 +18,9 @@ knitr::opts_chunk$set( library(cryptoQuotes) ``` -As an `experimental` feature, the `cryptoQuotes`-package has a variety of `chart`-functions built on top of `plotly` and `TTR` to visualize cryptocurrency market data and trading indicators interactively. +As an `experimental` feature [{cryptoQuotes}](https://github.com/serkor1/cryptoQuotes) has a variety of `chart`-functions built on top of [{plotly}](https://github.com/plotly/plotly.R) and [{TTR}](https://github.com/joshuaulrich/TTR) to visualize cryptocurrency market data and trading indicators interactively. -Throughout this article we will analyze Bitcoin on the hourly chart called by the `get_quotes`-function, +Throughout this article we will analyze Bitcoin on the hourly chart called by the `get_quotes()`-function, ```{r} ## Get the @@ -39,8 +39,6 @@ BTC <- get_quote( There are two main price charts. The Japanese candlestick chart, ```kline()```, and the basic OHLC chart, ```ohlc()```, charts. A chart has to be wrapped in the ```chart()```-function. -> All charts comes with `volume` and `bollinger bands` by `default`. - ### Candlestick charts ```{r, fig.alt="cryptocurrency charts in R"} @@ -70,7 +68,7 @@ chart( ## Charting indicators -All the charts supports various indicators such as `RSI`, `MACD` and `MA`. These can be passed into their respective arguments as follows, +All the charts supports various indicators such as the *relative strenght index* (`rsi()`)-, *Moving Average Convergence Divergence* (`macd()`)- and various *moving average* indicators. These can be passed into their respective arguments as follows, ```{r, fig.alt="cryptocurrency charts in R"} ## chart BTC @@ -155,7 +153,7 @@ event_data$color <- 'darkgray' ``` -Finally, the crosses can be plotted using the `chart()` and `addEvents()` functions, like below, +Finally, the crosses can be plotted using the `chart()` as follows, ```{r} ## add the events @@ -178,4 +176,4 @@ chart( ## Limitations -The charting functions are still at an `experimental`-phase as per version `1.3.0`, and might therefore include various bugs of all sizes. +The charting functions are still at an `experimental`-phase as per version `1.3.0`, and might therefore include various bugs of all sizes and species. diff --git a/vignettes/articles/03-article.Rmd b/vignettes/articles/03-article.Rmd index ba5ff2b2..5bbe7578 100644 --- a/vignettes/articles/03-article.Rmd +++ b/vignettes/articles/03-article.Rmd @@ -1,5 +1,5 @@ --- -title: "Time Zones" +title: "Dealing with Time Zones" --- ```{r setup, include=FALSE} @@ -19,102 +19,81 @@ knitr::opts_chunk$set( library(cryptoQuotes) ``` -By `default` all data is returned with `Sys.timezone()` and, if not specified otherwise, all `dates` passed into the `get`-functions are `Sys.timezone()` too. +By `default` all data from the `get_*`-family of functions is returned with `Sys.timezone()` and, if not specified otherwise, all `dates` passed into the `from` and `to` parameters are assumed to be `Sys.timezone()` too. -## Different time zones +> **NOTE:** +> As the [{pkgdown}](https://github.com/r-lib/pkgdown)-documentation gets built on Github-servers we manually +> specify the timezone of the `from` and `to` parameters. -### OHLC (Local) +In this article we will demonstrate the *time zone* aspect of [{cryptoQuotes}](https://github.com/serkor1/cryptoQuotes). -If `from` and `to` are passed as valid `date`-type `characters`, `sys.time()` or `as.POSIXct()` without specifying the `TZ` the returned `xts::index()` is 'as is', +## Open, High, Low, Close and Volume (OHLC-V) with CET + +Assume that you are interested in the hourly `Bitcoin` price action from yesterday between 16.00 and 18.00 *central European time* (CET). We start the example by defining the `from` and `to` parameters, ```{r} -## Get hourly -## BTC between -## 20.00 and 22.00 from -## yesterday -BTC_local <- get_quote( - ticker = "BTCUSD", - source = "kraken", - interval = "1h", - futures = FALSE, - from = paste(Sys.Date()-1, "20:00:00"), - to = paste(Sys.Date()-1, "22:00:00") +# define from +# and to +from <- as.POSIXct( + x = paste( + Sys.Date() - 1, "16:00:00" + ), + tz = "CET" +) + +to <- as.POSIXct( + x = paste( + Sys.Date() - 1, "18:00:00" + ), + tz = "CET" ) ``` -### OHLC (UTC) +### OHLC-V -If `from` and `to` are passed as `as.POSIXct()` while specifying the `TZ` the returned `xts::index()` is internally converted, +As the *time zone* on Github servers are `CET`, the returned OHLC-V data is `UTC` as demonstrated below, ```{r} ## Get hourly ## BTC between -## 20.00 and 22.00 from +## 16:00 and 18:00 from ## yesterday -BTC_utc <- get_quote( - ticker = "BTCUSD", - source = "kraken", - interval = "1h", - futures = FALSE, - from = as.POSIXct(paste(Sys.Date()-1, "20:00:00"), tz = "UTC"), - to = as.POSIXct(paste(Sys.Date()-1, "22:00:00"), tz = "UTC") -) -``` - -### Difference - -In each case the returned `index` is, alongside the OHLC-V data, different, - -```{r, echo=FALSE} -# 1) create a kable -# and print - knitr::kable( - caption = 'Time zone comparsion', - align = 'lr', - table.attr = "style='width:100%;'", - col.names = c('BTC_local', 'BTC_utc'), - x = cbind( - paste(zoo::index(BTC_local)), - paste(zoo::index(BTC_utc)) - ), - format = 'html' +xts::tzone( + BTC <- get_quote( + ticker = "BTCUSD", + source = "kraken", + interval = "1h", + futures = FALSE, + from = from, + to = to ) +) ``` - -## Changing the time zones - -All time zones can be converted using the `xts::tzone()`-function. Below is an example of converting the `BTC` to `UTC`, +All time zones can be converted using the `xts::tzone()`-function. Below is an example of converting the `BTC` to `CET`, ```{r} ## 1) Change time -## zone to UTC -## -## Store BTC_utc in -## a new variable to avoid -## replacing it. Not necessary in the -## real world - its just for -## demonstrations -BTC_tzone <- BTC_utc - -xts::tzone(BTC_tzone) <- "UTC" +## zone to CET +BTC_CET <- BTC +xts::tzone(BTC_CET) <- "CET" ``` +Below is table with the original *index* in `UTC` and the converted *index* in `CET`, + ```{r, echo=FALSE} # 1) create a kable # and print - knitr::kable( - caption = 'Time zone comparsion', - align = 'lr', - table.attr = "style='width:100%;'", - col.names = c('Original Index', 'Converted Index'), - x = cbind( - paste(zoo::index(BTC_utc)), - paste(zoo::index(BTC_tzone)) - ), - format = 'html' - ) +knitr::kable( + caption = 'Time zone comparsion', + align = 'lr', + table.attr = "style='width:100%;'", + col.names = c('Original Index', 'Converted Index'), + x = cbind( + paste(zoo::index(BTC)), + paste(zoo::index(BTC_CET)) + ), + format = 'html' +) ``` -The converted time zones now match the original `argument`-input in `BTC_utc`. - diff --git a/vignettes/articles/04-article.Rmd b/vignettes/articles/04-article.Rmd index 978311a0..3d20924f 100644 --- a/vignettes/articles/04-article.Rmd +++ b/vignettes/articles/04-article.Rmd @@ -19,13 +19,13 @@ knitr::opts_chunk$set( library(cryptoQuotes) ``` -If you want to use the simplicity of ```tidverse``` or the power of ```data.table```, the ```xts```-object can be easily converted. +If you want to use the simplicity of [{tidyverse}](https://github.com/tidyverse/tidyverse) or the power of [{data.table}](https://github.com/Rdatatable/data.table), the [{xts}](https://github.com/joshuaulrich/xts)-object can be easily converted. -However, its important to maintain data integrity, especially, if the date and timezone is important for you. +However, its important to maintain data integrity, especially, if the date and time zone is important for you. ## Converting xts and zoo to tibble -Converting to ```tibble``` requires a few steps to achieve the same data structure as the ```xts```, +Converting to `tibble` requires a few steps to achieve the same data structure as the `xts`, ```{r tibble} # 1) load pipe @@ -40,17 +40,18 @@ tbl <- tibble::as_tibble( ) ) %>% dplyr::mutate( index = lubridate::as_datetime( - index + x = index, + tz = "Europe/Copenhagen" ) ) -# 3) head data +# 3) tail data head(tbl, 3) ``` ## Converting xts and zoo to data.table -Converting to ```data.table``` is straightforward as ```as.data.table()``` handles everything under the hood, +Converting to a `data.table` is straightforward as `as.data.table()` handles everything under the hood, ```{r data.table} # 1) convert to data.table @@ -73,8 +74,8 @@ It is important that the date.time has not been converted to a different timezon ```{r} # 1) store date.time objects time_objects <- list( - tbl = tbl$Index, - DT = DT$Index + tbl = tbl$index, + DT = DT$index ) # 2) check if they are all equal @@ -96,14 +97,14 @@ all( ### Checking OHLCV values -It goes without saying that ```R```-functions wouldn't tamper with the order of the data during conversion without a warning in the documentation, but nonetheless for the sake of argument, we will check the OHLCV values, +It goes without saying that `R`-functions wouldn't tamper with the order of the data during conversion without a warning in the documentation, but nonetheless for the sake of argument, we will check the OHLCV values, ```{r} # 1) store price objects # Open price here open_price <- list( - tbl = tbl$Open, - DT = DT$Open + tbl = tbl$open, + DT = DT$open ) # 2) check if they are all equal @@ -114,7 +115,7 @@ all( setequal( x = x, - y = ATOM$Open + y = ATOM$open ) }, @@ -126,7 +127,7 @@ all( ## Why even convert? -Even though numerical operations on ```xts```-objects are lightning fast (12% faster than ```data.table```), it comes with a cost; it doesn't support ```factors``` or ```characters```. +Even though numerical operations on [{xts}](https://github.com/joshuaulrich/xts)-objects are lightning fast, it comes with a cost; it doesn't support `factors` or `characters`. -Converting the ```xts```-object is a simple and trivial process, and simplifies grouped operations in a verbose manner. +Converting the [{xts}](https://github.com/joshuaulrich/xts)-object is a simple and trivial process, and simplifies grouped operations in a verbose manner. diff --git a/vignettes/articles/05-article.Rmd b/vignettes/articles/05-article.Rmd index 09a94a5c..d4848de2 100644 --- a/vignettes/articles/05-article.Rmd +++ b/vignettes/articles/05-article.Rmd @@ -1,5 +1,5 @@ --- -title: "Cryptocurrency Market Data with quantmod and TTR" +title: "Cryptocurrency Market Data with {quantmod} and {TTR}" --- ```{r, include = FALSE} @@ -19,7 +19,7 @@ knitr::opts_chunk$set( library(cryptoQuotes) ``` -The `cryptoQuotes` were built with `quantmod` and `TTR` in mind. To demonstrate how `cryptoQuotes` works with these packages, we will use the following data, +[{cryptoQuotes}](https://github.com/serkor1/cryptoQuotes) were built with [{quantmod}](https://github.com/joshuaulrich/quantmod) and [{TTR}](https://github.com/joshuaulrich/TTR) in mind. To demonstrate how [{cryptoQuotes}](https://github.com/serkor1/cryptoQuotes) works with these packages, we will use the following data, ```{r} ## Get daily @@ -40,8 +40,7 @@ The `BTC` can be passed into the charting functions, or be used in the `quantmod ### Building Cryptocurrency Trade Models -Below is an example on how to use the `quantmod::tradeModel` with `BTC`, - +Below is an example on how to use the `quantmod::tradeModel()`-function with the `BTC`-object, ```{r} ## 1) specify @@ -65,9 +64,9 @@ built_model <- quantmod::buildModel( quantmod::tradeModel(built_model, leverage = 2) ``` -### Charting Cryptocurrency with quantmod +### Charting Cryptocurrency with {quantmod} -```{r} +```{r, fig.alt="Cryptocurrency Market Data in Quantmod"} ## chart the ## BTC with candlesticks ## and Bollinger BAnds @@ -80,9 +79,9 @@ quantmod::chartSeries( ) ``` -## Cryptocurrency and TTR +## Cryptocurrency and {TTR} -Below is an example on how to use the `BBands()`-function from the `TTR`-package, +Below is an example on how to use the `BBands()`-function from [{TTR}](https://github.com/joshuaulrich/TTR), ```{r} # 1) calculate @@ -108,7 +107,7 @@ knitr::kable( table.attr = "style='width:100%;'", x = data.frame( cbind( - Index = paste(tail(zoo::index(BTC))), + index = paste(tail(zoo::index(BTC))), round(tail(zoo::coredata(BTC)),3) ),row.names = NULL ), diff --git a/vignettes/cryptoQuotes.Rmd b/vignettes/cryptoQuotes.Rmd index e79d7b49..30a014df 100644 --- a/vignettes/cryptoQuotes.Rmd +++ b/vignettes/cryptoQuotes.Rmd @@ -21,7 +21,7 @@ knitr::opts_chunk$set( library(cryptoQuotes) ``` -This `vignette` is a short introduction to the `cryptoQuotes`-package, for a more extensive introduction on its usecase and limitations please refer to the [wiki](https://github.com/serkor1/cryptoQuotes/wiki). +This `vignette` is a short introduction to [{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/), for a more extensive introduction on its usecase and limitations please refer to the [wiki](https://github.com/serkor1/cryptoQuotes/wiki). > **NOTE:** This `vignette` is limited by geolocation due to various country specific > cryptocurrency laws. The introduction, therefore, is limited to what is available in the US. @@ -96,7 +96,7 @@ LS_BTC <- try( ) ``` -This gives an `error`. The source of the error is the ticker-naming convention; as the `long` to `short` ratio is specific to the perpetual futures market, and the current ticker is specific to the spot-market, the endpoint throws an error. +This gives an `error`. The source of the error is the ticker-naming convention; as the *long-short ratio* is specific to the perpetual futures market, and the current ticker is specific to the spot-market, the endpoint throws an error. To circumvent this, we can either use perpetual futures throughout the `script`, or modify the `ticker`-argument as follows, @@ -133,7 +133,7 @@ sample( ## Charting cryptocurrency market data -The Bitcoin market data can be charted using the `chart()`-function, which uses `plotly` as backend, +The Bitcoin market data can be charted using the `chart()`-function, which uses [{plotly}](https://github.com/plotly/plotly.R) as backend, ```{r, fig.alt="cryptocurrency market data with R"} # candlestick chart with @@ -153,7 +153,7 @@ chart( ### Adding indicators -The `cryptoQuotes`-package also acts as an API-client to the `TTR`-package, and supports most of its functions. We can add Moving Average indicators, and bollinger bands to the chart using the `indicator`-argument, +[{cryptoQuotes}](https://serkor1.github.io/cryptoQuotes/) also acts as an API-client to [{TTR}](https://github.com/joshuaulrich/TTR), and supports most of its functions. We can add Moving Average indicators, and Bollinger Bands to the chart using the `indicator`-argument, ```{r, fig.alt="cryptocurrency market data with R"} # candlestick chart with diff --git a/vignettes/custom_indicators.Rmd b/vignettes/custom_indicators.Rmd index 304f56b4..e321a893 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,392 +22,175 @@ 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 the `cryptoQuotes`-package. +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 the `TTR`-package. +## 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() +# 1) create a simple chart +# object +# +# NOTE: The chart is wrapped in +# plotly::layout() to avoid +# duplicating xaxis when the +# custom indicators are added +chart_object <- plotly::layout( + chart( + ticker = BTC, + main = kline(), + sub = list( + volume() ), - indicator = list( - bollinger_bands() - ) -) -``` - -### 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 -``` -
- -
-Subchart indicator (MACD) -```{r, echo=FALSE} -macd -``` -
- -Common for both indicator `classes` is that they are wrapped in `structure`, with `class = c("plotly", "htmlwidget")`, - -```R -structure( - .Data = { - - # Indicator Logic - - }, - class = c( - yourclass, - "plotly", - "htmlwidget" + options = list( + dark = FALSE + ) + ), + xaxis = list( + showticklabels = FALSE ) ) ``` -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 the `cryptoQuotes`-package uses `plotly` as backend for charting, your `class` of indicator has to be consistent with the use of `plotly`-functions. More specifically; `subchart`-indicators uses `plotly::plot_ly()`-functions, while main chart `indicator` uses `add_*`-functions. +### Sine-oscillator -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()`, +Assume a trading strategy that follows a `sin()`-curve throughout the period of interest. The starting point is generating the indicator, ```{r} -tail( - TTR::DonchianChannel( - HL = BTC[,c("high", "low")] - ) +# 1) generate sin-indicator +sin_indicator <- data.frame( + index = zoo::index(BTC), + sin_indicator = sin(seq(0,8*pi,length.out=nrow(BTC))) + ) ``` -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 the `cryptoQuotes`-package. All layers get built with the `cryptoQuotes:::build()`-function. +The `sin_indicator` in it's basic form can be charted as follows, ```{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 - ) - ) - - } +# 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 ``` -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" + ), + yaxis = list( + title = NA ), - indicator = list( - bollinger_bands(), - donchian_channel() + xaxis = list( + title = NA ) ) ``` ## Summary -Creating custom indicators for the `chart()`-functions can be daunting. Two examples of how these are developed in th e `cryptoQuotes`-packages 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 - - diff --git a/vignettes/usecase.Rmd b/vignettes/usecase.Rmd index 1dca1834..ce109a42 100644 --- a/vignettes/usecase.Rmd +++ b/vignettes/usecase.Rmd @@ -27,9 +27,9 @@ library(cryptoQuotes) ## Introduction -This high-level `API`-client provides open access to cryptocurrency market data without relying on low-level coding and `API`-keys. Currently all actively traded cryptocurrencies on either `binance`, `bybit`, `bitmart`, `kucoin` and `kraken` are available. +This high-level `API`-client provides open access to cryptocurrency market data without relying on low-level coding and `API`-keys. Currently all actively traded cryptocurrencies on `r paste(length(invisible(available_exchanges)))` major exchanges are available, see the [wiki](https://github.com/serkor1/cryptoQuotes/wiki/Available-Exchanges) for more details. -In this vignette we will explore a case study to showcase the capabilities of the `cryptoQuotes`-package; how did the `Dogecoin`-market react to Elon Musks following tweet, +In this vignette we will explore a case study to showcase the capabilities of [{cryptoQuotes}](https://github.com/serkor1/cryptoQuotes); how did the `Dogecoin`-market react to Elon Musks following tweet,
```{r, echo=FALSE, out.width="80%", fig.cap="Tweet by Elon Musk - the timezone is CET.",fig.align='center'} @@ -43,7 +43,7 @@ knitr::include_graphics( ## Cryptocurrency Market Analysis in R -Elon Musk tweeted (Well, now he X'ed) about `Dogecoin` January 14, 06.18 AM (UTC) - and `Dogecoin` rallied. To determine how fast the markets reacted to his tweets, we could get the market data for Dogecoin in 1 minute intervals the day he tweeeted using the ```getQuotes()```, +Elon Musk tweeted (Well, now he X'ed) about `Dogecoin` January 14, 06.18 AM (UTC) - and `Dogecoin` rallied. To determine how fast the markets reacted to his tweets, we could get the market data for Dogecoin in 1 minute intervals the day he tweeeted using the `get_quotes()`-function, @@ -61,7 +61,7 @@ DOGE <- cryptoQuotes::get_quote( ) ``` -This returns an object of class `r paste(class(DOGE),collapse = ' and ')` with `r nrow(DOGE)` rows. To calculate the rally within the first minute of the tweet, we can use `xts`-syntax to determine the how much it rallied, +This returns an object of class `r paste(class(DOGE),collapse = ' and ')` with `r nrow(DOGE)` rows. To calculate the rally within the first minute of the tweet, we can use [{xts}](https://github.com/joshuaulrich/xts)-syntax to determine its magnitude, ```{r} @@ -81,7 +81,7 @@ cat( ### Charting price action with candlesticks -We can illustrate this with candlestick charts using the ```chart()```- and ```kline()```-function, +We can visualize the rally this with candlestick charts using the `chart()`- and `kline()`-function, ```{r, fig.align='center', fig.alt= "Elon Musk DOGE"} ## chart the @@ -104,7 +104,7 @@ cryptoQuotes::chart( ### Charting price action with event lines -To create a, presumably, better visual overview we can add event lines using the ```event_data```-argument, which takes a ```data.frame``` of any kind as argument, +To create a, presumably, better visual overview we can add event lines using the `event_data`-argument, which takes a `data.frame` of any kind as argument, ```{r} ## 1) create event data.frame