diff --git a/DESCRIPTION b/DESCRIPTION new file mode 100644 index 0000000..5f41263 --- /dev/null +++ b/DESCRIPTION @@ -0,0 +1,16 @@ +Package: okxAPI +Title: An Unofficial Wrapper for 'okx exchange v5' API +Version: 0.1.1 +Authors@R: + person(family = "Fang", given = "Yongchao", email = "yongchao.fang@outlook.com", role = c("aut", "cre", "cph")) +Description: An unofficial wrapper for 'okx exchange v5' API , including 'REST' API and 'WebSocket' API. +License: MIT + file LICENSE +Encoding: UTF-8 +RoxygenNote: 7.2.3 +Imports: R6, data.table, httr, base64enc, jsonlite, websocket, digest +NeedsCompilation: no +Packaged: 2023-04-21 12:04:16 UTC; fangyongchao +Author: Yongchao Fang [aut, cre, cph] +Maintainer: Yongchao Fang +Repository: CRAN +Date/Publication: 2023-04-22 07:10:02 UTC diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..31e220d --- /dev/null +++ b/LICENSE @@ -0,0 +1,2 @@ +YEAR: 2023 +COPYRIGHT HOLDER: Yongchao Fang diff --git a/MD5 b/MD5 new file mode 100644 index 0000000..20581c9 --- /dev/null +++ b/MD5 @@ -0,0 +1,18 @@ +0df37465f88340fdcd308abbca5a1138 *DESCRIPTION +0d3cb8d6ab2e2ec2955fd3e7e0674652 *LICENSE +c43b22885efa36e5be67cb4e5beb4b99 *NAMESPACE +a42ec1c4244360d3eec4031cb5e03648 *R/funcs.R +70f6b0fb294838cf04f5b782e6eb0559 *R/restAPI.R +2ac6566ea0e1e3230d60124baa76eae8 *R/utils.R +580132d53dc4d1455d2dca1e5fb724f5 *R/websockerAPIprivate.R +13873099c8fc3e9b2466cdbd66237ae6 *R/websocketAPIpublic.R +703ddbf7088aff8797ce4d6315b172ca *README.md +eae3f11c522c7f9c34fcdeb24e231041 *man/get_functions.Rd +45700e5426fda3522acedec9ff6636b0 *man/get_history_candles.Rd +5c9e06661a94a771518e944398790373 *man/get_positions_history.Rd +07f49942d8cb0a6400ae4a680b0007e0 *man/restAPI.Rd +96d6b96cc4d461b2cbe4908b0c26fe67 *man/restAPIaccount.Rd +44dfd99788fe451e16578f879fe46d13 *man/restAPImarket.Rd +3b0c114f825b8f93f4dabafd04bc162b *man/restAPItrade.Rd +6883bf6c50b48bf01093925f03111910 *man/websocketAPIprivate.Rd +6c3bdcc93739a40a916d4761aa47471f *man/websocketAPIpublic.Rd diff --git a/NAMESPACE b/NAMESPACE new file mode 100644 index 0000000..49695b5 --- /dev/null +++ b/NAMESPACE @@ -0,0 +1,17 @@ +# Generated by roxygen2: do not edit by hand + +export(get_history_candles) +export(get_positions_history) +export(restAPI) +export(restAPIaccount) +export(restAPImarket) +export(restAPItrade) +export(websocketAPIprivate) +export(websocketAPIpublic) +import(R6) +import(base64enc) +import(data.table) +import(digest) +import(httr) +import(jsonlite) +import(websocket) diff --git a/R/funcs.R b/R/funcs.R new file mode 100644 index 0000000..0840de2 --- /dev/null +++ b/R/funcs.R @@ -0,0 +1,133 @@ +#' @name get_functions +#' +#' @title Wrapper for some frequently used APIs to get data easily +#' +#' @description The main purpose is to handle APIs that have limitations on the number of results returned per single request. +#' @seealso +#' \code{\link{get_positions_history}} +#' \code{\link{get_history_candles}} +NULL + + +#' @title Retrieve the position data +#' +#' @description Wrapper for API [Get positions history](https://www.okx.com/docs-v5/en/#rest-api-account-get-positions-history). +#' +#' @param api_key Okx API key. +#' @param secret_key Okx API secret key. +#' @param passphrase Okx API passphrase. +#' @param count Retrieve position data for a specified number of past days, with a maximum of 90(days) +#' @param period Due to the 'Number of results per request' limitation of the API, +#' the \code{period} parameter must be specified to ensure that the number of position data entries within each period does not exceed 100. +#' @param ... Other request parameters to be passed, See +#' [Get positions history](https://www.okx.com/docs-v5/en/#rest-api-account-get-positions-history) for more information. +#' +#' @return Position data +#' +#' @examples +#' \dontrun{ +#' positions <- get_positions_history( +#' api_key, secret_key, passphrase, count = 90, period = 10, +#' instType = "SWAP", mgnMode = "isolated" +#' ) +#' } +#' +#' @import data.table +#' @export +get_positions_history <- function( + api_key, secret_key, passphrase, count = 90, period = 10, ... +) { + account <- restAPIaccount$new(api_key, secret_key, passphrase) + now <- time2ts(Sys.time()) + start <- now - count*24*60*60 + end <- start + period*24*60*60 - 0.001 + dat <- list() + while (start < now) { + result <- account$positions_history( + before = as.character(1000*start - 1), after = as.character(1000*end + 1), ... + ) + if (result$code == "0") { + dat <- c(dat, result$data) + message("From ", ts2time(start), " to ", ts2time(end), " complete") + start <- end + 0.001 + end <- start + period*24*60*60 - 0.001 + Sys.sleep(15) + } + } + dat <- lapply(dat, data.table::as.data.table) + dat <- data.table::rbindlist(dat) + to_time <- c("cTime", "uTime") + dat[, (to_time) := lapply(.SD, ts2time), .SDcols = to_time] + to_numeric <- c("closeAvgPx", "closeTotalPos", "lever", "openAvgPx", "openMaxPos", "pnl", "pnlRatio") + dat[, (to_numeric) := lapply(.SD, as.numeric), .SDcols = to_numeric] + dat +} + +#' @title Retrieve the candlestick charts +#' +#' @description Wrapper for API [Get candlesticks](https://www.okx.com/docs-v5/en/#rest-api-market-data-get-candlesticks) +#' and [Get candlesticks history](https://www.okx.com/docs-v5/en/#rest-api-market-data-get-candlesticks-history). +#' +#' @param api_key Okx API key. +#' @param secret_key Okx API secret key. +#' @param passphrase Okx API passphrase. +#' @param bar Bar size, the default is 1m, e.g. 1m/3m/5m/15m/30m/1H/2H/4H, Hong Kong time opening price k-line: 6H/12H/1D/2D/3D. +#' @param count Number of Bars. +#' @param instId Instrument ID, e.g. BTC-USDT-SWAP. +#' @param ... Other request parameters to be passed, See [Get candlesticks history](https://www.okx.com/docs-v5/en/#rest-api-market-data-get-candlesticks-history) for more information. +#' +#' @return Candlestick charts data +#' +#' @examples +#' \dontrun{ +#' candles <- get_history_candles( +#' api_key, secret_key, passphrase, bar = "1m", +#' count = 24*60, instId = "CFX-USDT-SWAP" +#' ) +#' } +#' +#' @import data.table +#' @export +get_history_candles <- function( + api_key, secret_key, passphrase, + bar = c("1m", "3m", "5m", "15m", "30m", "1H", "4H", "6H", "12H", "1D", "2D", "3D"), + count, instId, ... +) { + bar <- match.arg(bar) + period <- str2period(bar) + + market <- restAPImarket$new(api_key, secret_key, passphrase) + + now <- time2ts(Sys.time()) + end <- now + start <- end - ifelse(count >= 100, 100, count) * period + 0.001 + dat <- list() + for (i in 1:ceiling(count / 100)) { + if (i == 1) { + result <- market$candles( + instId = instId, before = as.character(1000*start - 1), + after = as.character(1000*end + 1), bar = bar, ... + ) + } else { + result <- market$history_candles( + instId = instId, before = as.character(1000*start - 1), + after = as.character(1000*end + 1), bar = bar, ... + ) + } + if (result$code == "0") { + dat <- c(dat, result$data) + message("From ", ts2time(start), " to ", ts2time(end), " complete") + count <- count - 100 + end <- start - 0.001 + start <- end - ifelse(count >= 100, 100, count) * period + 0.001 + # Sys.sleep(1/20) + } + } + col_names <- c("ts", "open", "high", "low", "close", "vol", "volCcy", "volCcyQuote", "confirm") + dat <- lapply(dat, as.data.frame, col.names = c(col_names)) + dat <- data.table::rbindlist(dat) + dat$ts <- ts2time(dat$ts) + to_numeric <- c("open", "high", "low", "close", "vol", "volCcy", "volCcyQuote") + dat[, (to_numeric) := lapply(.SD, as.numeric), .SDcols = to_numeric] + dat +} diff --git a/R/restAPI.R b/R/restAPI.R new file mode 100644 index 0000000..459bcfd --- /dev/null +++ b/R/restAPI.R @@ -0,0 +1,299 @@ +#' @title restAPI Class +#' +#' @description Base class for [Okx exchange v5 API](https://www.okx.com/docs-v5/en/). +#' +#' @details You can implement all REST API requests in Okx exchange by inheriting the \code{restAPI} class. +#' Please refer to the example provided at the end of the document. +#' +#' For commonly used interfaces, they have been implemented in this package. +#' The naming convention is as follows: for "/api/v5/AAA/BBB", a new class named \code{restAPIAAA}, +#' which inherits from \code{restAPI}, has been defined in this package. +#' The \code{BBB} method in this new class is used to call the API. +#' +#' @examples +#' \dontrun{ +#' # for [Get currencies](https://www.okx.com/docs-v5/en/#rest-api-funding-get-currencies) +#' # you can define the class like this +#' myRestAPI <- R6::R6Class( +#' inherit = restAPI, +#' public = list( +#' get_currencies = function(ccy, process = "identity") { +#' self$get_result( +#' api = "/api/v5/asset/currencies", method = "GET", process = process, +#' ccy = ccy +#' ) +#' } +#' ) +#' ) +#' # And call it like this +#' tmp <- myRestAPI$new(api_key, secret_key, passphrase) +#' tmp$get_currencies("BTC") +#' } +#' +#' @seealso +#' \code{\link{restAPItrade}} +#' \code{\link{restAPIaccount}} +#' \code{\link{restAPImarket}} +#' +#' @import R6 httr jsonlite base64enc base64enc +#' @export +restAPI <- R6::R6Class( + "restAPI", + public = list( + #' @field url Okx REST API url, which is https://www.okx.com. + url = "https://www.okx.com", + #' @field api_key Okx API key. + api_key = NA, + #' @field secret_key Okx API secret key. + secret_key = NA, + #' @field passphrase Okx API passphrase. + passphrase = NA, + #' @field simulate Whether to use demo trading service. + simulate = NA, + #' @description Create a new REST API object. + #' @param api_key Okx API key. + #' @param secret_key Okx API secret key. + #' @param passphrase Okx API passphrase. + #' @param simulate Whether to use demo trading service. + initialize = function(api_key, secret_key, passphrase, simulate = FALSE) { + self$api_key <- api_key + self$secret_key <- secret_key + self$passphrase <- passphrase + self$simulate <- simulate + }, + #' @description Get UTC timestamp. + get_timestamp = function() { + timestamp <- as.numeric(Sys.time()) * 1000 + timestamp <- as.POSIXct(timestamp / 1000, origin = "1970-01-01", tz = "UTC") + timestamp <- format(timestamp, format = "%Y-%m-%dT%H:%M:%OS3Z", usetz = FALSE) + timestamp + }, + #' @description Get request path. + #' @param api Request api e.g. /api/v5/account/positions-history. + #' @param method Request method, \code{GET} or \code{POST}. + #' @param ... Other request parameters. + get_request_path = function(api, method = c("GET", "POST"), ...) { + method <- match.arg(method) + if (method == "GET") { + tmp <- list(...) + if (length(tmp) == 0) { + request_path <- api + } else { + tmp <- tmp[!is.na(tmp)] + request_path <- paste0(api, "?") + for (i in 1:length(tmp)) { + tmp[[i]] <- paste0(names(tmp)[i], "=", paste(tmp[[i]], collapse = ",")) + } + tmp <- paste(unlist(tmp), collapse = "&") + request_path <- paste0(api, "?", tmp) + } + } else { + request_path <- api + } + request_path + }, + #' @description Get request body. + #' @param method Request method, \code{GET} or \code{POST}. + #' @param ... Other request parameters. + get_body = function(method = c("GET", "POST"), ...) { + method <- match.arg(method) + if (method == "GET") { + body <- "" + } else { + tmp <- list(...) + tmp <- tmp[!is.na(tmp)] + body <- jsonlite::toJSON(tmp, auto_unbox = TRUE) + } + body + }, + #' @description Get the signing messages. + #' @param timestamp Retrieve through method \code{get_timestamp}. + #' @param request_path Retrieve through method \code{get_request_path}. + #' @param body Retrieve through method \code{get_body}. + #' @param method Request method, \code{GET} or \code{POST}. + get_message = function(timestamp, request_path, body, method = c("GET", "POST")) { + method <- match.arg(method) + paste0(timestamp, method, request_path, body) + }, + #' @description Get the signature. + #' @param msg Retrieve through method \code{get_message}. + #' @param secret_key Okx API secret key. + get_signature = function(msg, secret_key = self$secret_key) { + base64enc::base64encode(base64enc::hmac(secret_key, msg, algo = "sha256", raw = TRUE)) + }, + #' @description Get request headers. + #' @param timestamp Retrieve through method \code{get_timestamp}. + #' @param msg Retrieve through method \code{get_message}. + get_header = function(timestamp, msg) { + headers <- c( + "OK-ACCESS-KEY" = self$api_key, + "OK-ACCESS-SIGN" = self$get_signature(msg), + "OK-ACCESS-TIMESTAMP" = timestamp, + "OK-ACCESS-PASSPHRASE" = self$passphrase, + "Content-Type" = "application/json" + ) + if (self$simulate) { + headers <- c(headers, "x-simulated-trading" = "1") + } + headers + }, + #' @description Retrieve data from api. + #' @param api Request api e.g. /api/v5/account/positions-history. + #' @param method Request method, \code{GET} or \code{POST}. + #' @param process A function to process the data received from the API. + #' @param ... Other request parameters. + get_result = function(api, method = c("GET", "POST"), process, ...) { + method <- match.arg(method) + timestamp <- self$get_timestamp() + request_path <- self$get_request_path(api = api, method = method, ...) + body <- self$get_body(method = method, ...) + msg <- self$get_message(timestamp, request_path, body, method) + if (method == "GET") { + response <- httr::GET( + paste0(self$url, request_path), + httr::add_headers(.headers = self$get_header(timestamp, msg)) + ) + } else { + response <- httr::POST( + paste0(self$url, request_path), + httr::add_headers(.headers = self$get_header(timestamp, msg)), + body = body + ) + } + result <- httr::content(response) + if (httr::http_error(response)) { + message("Error code ", result$code, ": ", result$msg) + } else if (result$code != "0") { + message("Error code ", result$data[[1]]$sCode, ": ", result$data[[1]]$sMsg) + } else { + return(do.call(process, list(result))) + } + } + ) +) + + +#' @title restAPItrade Class +#' +#' @description Wrapper for [REST API TRADE](https://www.okx.com/docs-v5/en/#rest-api-trade). +#' +#' @import R6 +#' @export +restAPItrade <- R6::R6Class( + "restAPItrade", + inherit = restAPI, + public = list( + #' @description See [Place order](https://www.okx.com/docs-v5/en/#rest-api-trade-place-order) for more information. + #' @param instId Instrument ID, e.g. BTC-USD-190927-5000-C. + #' @param tdMode Trade mode. Margin mode: \code{cross} or \code{isolated.} Non-Margin mode: \code{cash}. + #' @param side Order side, \code{buy} or \code{sell}. + #' @param sz Quantity to buy or sell. + #' @param ordType Order type. \code{market}: Market order, \code{limit}: Limit order, \code{post_only}: Post-only order, + #' \code{fok}: Fill-or-kill order, \code{ioc}: Immediate-or-cancel order, + #' \code{optimal_limit_ioc}: Market order with immediate-or-cancel order (applicable only to Futures and Perpetual swap). + #' @param process A function to process the data received from the API. Default to \code{identity}. + #' @param ... Other request parameters. + order = function( + instId, tdMode = c("isolated", "cross", "cash"), side = c("buy", "sell"), sz, + ordType = c("market", "limit", "post_only", "fok", "ioc", "optimal_limit_ioc"), + process = "identity", ... + ) { + tdMode <- match.arg(tdMode) + side <- match.arg(side) + ordType <- match.arg(ordType) + + self$get_result( + api = "/api/v5/trade/order", method = "POST", process = process, + instId = instId, tdMode = tdMode, side = side, sz = sz, ordType = ordType, ... + ) + }, + #' @description See [Cancel order](https://www.okx.com/docs-v5/en/#rest-api-trade-cancel-order) for more information. + #' @param instId Instrument ID, e.g. BTC-USD-190927. + #' @param ordId Order ID, Either \code{ordId} or \code{clOrdId} is required. If both are passed, \code{ordId} will be used. + #' @param clOrdId Client Order ID as assigned by the client. + #' @param process A function to process the data received from the API. Default to \code{identity}. + #' @param ... Other request parameters. + cancel_order = function(instId, ordId, clOrdId, process = "identity", ...) { + if (missing(ordId)) ordId <- NA + if (missing(clOrdId)) clOrdId <- NA + self$get_result( + api = "/api/v5/trade/cancel-order", method = "POST", process = process, + instId = instId, ordId = ordId, clOrdId = clOrdId, ... + ) + } + ) +) + +#' @title restAPIaccount Class +#' +#' @description Wrapper for [REST API ACCOUNT](https://www.okx.com/docs-v5/en/#rest-api-account). +#' +#' @import R6 +#' @export +restAPIaccount <- R6::R6Class( + "restAPIaccount", + inherit = restAPI, + public = list( + #' @description See [Get balance](https://www.okx.com/docs-v5/en/#rest-api-account-get-balance) for more information. + #' @param ccy Single currency or a vector composed of multiple currencies. (no more than 20). + #' @param process A function to process the data received from the API. Default to \code{identity}. + balance = function(ccy, process = "identity") { + self$get_result( + api = "/api/v5/account/balance", method = "GET", process = process, + ccy = ccy + ) + }, + #' @description See [Get positions](https://www.okx.com/docs-v5/en/#rest-api-account-get-positions) for more information. + #' @param process A function to process the data received from the API. Default to \code{identity}. + #' @param ... Other request parameters. + positions = function(process = "identity", ...) { + self$get_result( + api = "/api/v5/account/positions", method = "GET", process = process, + ... + ) + }, + #' @description See [Get positions history](https://www.okx.com/docs-v5/en/#rest-api-account-get-positions-history) for more information. + #' @param process A function to process the data received from the API. Default to \code{identity}. + #' @param ... Other request parameters. + positions_history = function(process = "identity", ...) { + self$get_result( + api = "/api/v5/account/positions-history", method = "GET", process = process, + ... + ) + } + ) +) + + +#' @title restAPImarket Class +#' +#' @description Wrapper for [REST API MARKET](https://www.okx.com/docs-v5/en/#rest-api-market-data). +#' +#' @import R6 +#' @export +restAPImarket <- R6::R6Class( + "restAPImarket", + inherit = restAPI, + public = list( + #' @description See [Get candlesticks](https://www.okx.com/docs-v5/en/#rest-api-market-data-get-candlesticks) for more information. + #' @param instId Instrument ID, e.g. BTC-USD-190927-5000-C. + #' @param process A function to process the data received from the API. Default to \code{identity}. + #' @param ... Other request parameters. + candles = function(instId, process = "identity", ...) { + self$get_result( + api = "/api/v5/market/candles", method = "GET", process = process, + instId = instId, ... + ) + }, + #' @description See [Get candlesticks history](https://www.okx.com/docs-v5/en/#rest-api-market-data-get-candlesticks-history) for more information. + #' @param instId Instrument ID, e.g. BTC-USD-190927-5000-C. + #' @param process A function to process the data received from the API. Default to \code{identity}. + #' @param ... Other request parameters. + history_candles = function(instId, process = "identity", ...) { + self$get_result( + api = "/api/v5/market/history-candles", method = "GET", process = process, + instId = instId, ... + ) + } + ) +) diff --git a/R/utils.R b/R/utils.R new file mode 100644 index 0000000..286410a --- /dev/null +++ b/R/utils.R @@ -0,0 +1,30 @@ + +ts2time <- function(timestamp) { + timestamp <- substr(as.character(timestamp), 1, 10) + as.POSIXct(as.integer(timestamp), origin = "1970-01-01 00:00:00", tz = "Asia/Shanghai") +} + + +time2ts <- function(time, type = c("s", "ms")) { + if (!inherits(time, "POSIXt")) { + stop("parameter time must be of POSIXt type") + } else { + type <- match.arg(type) + time <- as.integer(time) + if (type == "ms") { + time <- time * 1000 + } + time + } +} + + +str2period <- function(str) { + time_vec <- c( + "1m" = 60, "3m" = 3*60, "5m" = 5*60, "15m" = 15*60, "30m" = 30*60, + "1H" = 1*60*60, "2H" = 2*60*60, "4H" = 4*60*60, + "6H" = 6*60*60, "12H" = 12*60*60, + "1D" = 1*24*60*60, "2D" = 2*24*60*60, "3D" = 3*24*60*60 + ) + time_vec[str] +} diff --git a/R/websockerAPIprivate.R b/R/websockerAPIprivate.R new file mode 100644 index 0000000..da6bd84 --- /dev/null +++ b/R/websockerAPIprivate.R @@ -0,0 +1,161 @@ +#' @title websocketAPIprivate Class +#' +#' @description Private channel of WebSocket API for [Okx exchange v5 API](https://www.okx.com/docs-v5/en/). +#' See [Private Channel](https://www.okx.com/docs-v5/en/#websocket-api-private-channel) for more information. +#' +#' @examples +#' \dontrun{ +#' tmp <- websocketAPIprivate$new(api_key, secret_key, passphrase) +#' tmp$connect() +#' Sys.sleep(1) +#' tmp$login() +#' +#' # subscribe account information +#' msg <- list( +#' op = "subscribe", +#' args = list( +#' list(channel = "account", ccy = "USDT") +#' ) +#' ) +#' msg <- jsonlite::toJSON(msg, auto_unbox = TRUE, pretty = TRUE) +#' tmp$send(msg) +#' +#' # pass your own callback function +#' tmp$on_message(function(event) { +#' if (event$data == "pong") { +#' cat("Bingo!!\n") +#' } +#' }) +#' tmp$send("ping") +#' +#' tmp$close() +#' } +#' +#' @import R6 websocket base64enc digest +#' @export +websocketAPIprivate <- R6::R6Class( + "websockerAPIprivate", + public = list( + #' @field channel Private WebSocket url. + channel = "wss://ws.okx.com:8443/ws/v5/private", + #' @field api_key Okx API key. + api_key = NA, + #' @field secret_key Okx API secret key. + secret_key = NA, + #' @field passphrase Okx API passphrase. + passphrase = NA, + #' @field simulate Whether to use demo trading service. + simulate = NA, + #' @field ws A websocket::WebSocket object to establish a connection to the server. + ws = NA, + #' @description Craeate a new websocketAPIprivate object. + #' @param api_key Okx API key. + #' @param secret_key Okx API secret key. + #' @param passphrase Okx API passphrase. + #' @param simulate Whether to use demo trading service. + initialize = function(api_key, secret_key, passphrase, simulate = FALSE) { + self$api_key <- api_key + self$secret_key <- secret_key + self$passphrase <- passphrase + self$simulate <- simulate + if (simulate) self$channel <- "wss://wspap.okx.com:8443/ws/v5/private?brokerId=9999" + self$ws <- websocket::WebSocket$new(self$channel, autoConnect = FALSE) + }, + #' @description Get UTC timestamp. + get_timestamp = function() { + as.integer(Sys.time()) + }, + #' @description Get the signing messages. + #' @param timestamp Retrieve through method \code{get_timestamp}. + get_message = function(timestamp) { + paste0(timestamp, "GET", "/users/self/verify") + }, + #' @description Get the signature. + #' @param secret_key Okx API secret key. + #' @param msg Retrieve through method \code{get_message}. + get_signature = function(secret_key, msg) { + base64enc::base64encode(digest::hmac( + secret_key, msg, algo = "sha256", raw = TRUE + )) + }, + #' @description Initiate the connection to the server. + connect = function() { + self$ws$onOpen(function(event) { + cat("Connection opened\n") + }) + + self$ws$onMessage(function(event) { + cat("Client got msg: ", event$data, "\n") + }) + + self$ws$onClose(function(event) { + cat("Client disconnected with code ", event$code, ": ", event$reason, "\n") + }) + + self$ws$onError(function(event) { + cat("Client failed to connect: ", event$message, "\n") + }) + + self$ws$connect() + }, + #' @description Log in. + login = function() { + status <- attr(self$ws$readyState(), "description") == "Open" + if (status) { + timestamp <- self$get_timestamp() + msg <- self$get_message(timestamp) + signature <- self$get_signature(self$secret_key, msg) + + login_msg <- list( + "op" = "login", + "args" = list( + list( + "apiKey" = self$api_key, + "passphrase" = self$passphrase, + "timestamp" = timestamp, + "sign" = signature + ) + ) + ) + login_msg <- jsonlite::toJSON(login_msg, auto_unbox = TRUE) + self$ws$send(login_msg) + } else { + stop("Connection is not open") + } + }, + #' @description Called when the connection is established. + #' @param func A Callback function. + on_open = function(func) { + self$ws$onOpen(func) + }, + #' @description Called when a previously-opened connection is closed. + #' The event will have 'code' (integer) and 'reason' (one-element character) + #' elements that describe the remote's reason for closing. + #' @param func A Callback function. + on_close = function(func) { + self$ws$onClose(func) + }, + #' @description Called each time a message is received from the server. + #' The event will have a 'data' element, which is the message content. + #' @param func A Callback function. + on_message = function(func) { + self$ws$onMessage(func) + }, + #' @description Called when the connection fails to be established. + #' The event will have an 'message' element, a character vector of length 1 + #' describing the reason for the error. + #' @param func A Callback function. + on_error = function(func) { + self$ws$onError(func) + }, + #' @description Send a message to the server. + #' @param msg Messages. + send = function(msg) { + self$ws$send(msg) + }, + #' @description Close the connection. + close = function() { + self$ws$close() + } + ) +) diff --git a/R/websocketAPIpublic.R b/R/websocketAPIpublic.R new file mode 100644 index 0000000..a0985e5 --- /dev/null +++ b/R/websocketAPIpublic.R @@ -0,0 +1,106 @@ +#' @title websocketAPIpublic Class +#' +#' @description Public channel of WebSocket API for [Okx exchange v5 API](https://www.okx.com/docs-v5/en/). +#' See [Public Channel](https://www.okx.com/docs-v5/en/#websocket-api-public-channel) for more information. +#' +#' @examples +#' \dontrun{ +#' tmp <- websocketAPIpublic$new() +#' tmp$connect() +#' +#' # subscribe BTC-USDT-SWAP 5m candlesticks data +#' msg <- list( +#' op = "unsubscribe", +#' args = list( +#' list(channel = "candle5m", instId = "BTC-USDT-SWAP") +#' ) +#' ) +#' msg <- jsonlite::toJSON(msg, auto_unbox = TRUE, pretty = TRUE) +#' tmp$send(msg) +#' +#' # pass your own callback function +#' tmp$on_message(function(event) { +#' if (event$data == "pong") { +#' cat("Bingo!!\n") +#' } +#' }) +#' tmp$send("ping") +#' +#' tmp$close() +#' } +#' +#' @import R6 websocket +#' @export +websocketAPIpublic <- R6::R6Class( + "websocketAPIpublic", + public = list( + #' @field channel Public WebSocket url. + channel = "wss://ws.okx.com:8443/ws/v5/public", + #' @field simulate Whether to use demo trading service. + simulate = NA, + #' @field ws A websocket::WebSocket object to establish a connection to the server. + ws = NA, + #' @description Create a new websocketAPIpublic object. + #' @param simulate Whether to use demo trading service. + initialize = function(simulate = FALSE) { + self$simulate <- simulate + if (simulate) self$channel <- "wss://wspap.okx.com:8443/ws/v5/public?brokerId=9999" + self$ws <- websocket::WebSocket$new(self$channel, autoConnect = FALSE) + }, + #' @description Initiate the connection to the server. + connect = function() { + self$ws$onOpen(function(event) { + cat("Connection opened\n") + }) + + self$ws$onMessage(function(event) { + cat("Client got msg: ", event$data, "\n") + }) + + self$ws$onClose(function(event) { + cat("Client disconnected with code ", event$code, ": ", event$reason, "\n") + }) + + self$ws$onError(function(event) { + cat("Client failed to connect: ", event$message, "\n") + }) + + self$ws$connect() + }, + #' @description Called when the connection is established. + #' @param func A Callback function. + on_open = function(func) { + self$ws$onOpen(func) + }, + #' @description Called when a previously-opened connection is closed. + #' The event will have 'code' (integer) and 'reason' (one-element character) + #' elements that describe the remote's reason for closing. + #' @param func A Callback function. + on_close = function(func) { + self$ws$onClose(func) + }, + #' @description Called each time a message is received from the server. + #' The event will have a 'data' element, which is the message content. + #' @param func A Callback function. + on_message = function(func) { + self$ws$onMessage(func) + }, + #' @description Called when the connection fails to be established. + #' The event will have an 'message' element, a character vector of length 1 + #' describing the reason for the error. + #' @param func A Callback function. + on_error = function(func) { + self$ws$onError(func) + }, + #' @description Send a message to the server. + #' @param msg Messages. + send = function(msg) { + self$ws$send(msg) + }, + #' @description Close the connection. + close = function() { + self$ws$close() + } + ) +) + diff --git a/README.md b/README.md new file mode 100644 index 0000000..7d23178 --- /dev/null +++ b/README.md @@ -0,0 +1,130 @@ +# okxAPI + +An unofficial wrapper for [Okx exchange v5 API](https://www.okx.com/docs-v5/en/) + +## Installation + +You can install the released version of okxAPI from [CRAN](https://CRAN.R-project.org) with: + +``` r +install.packages("okxAPI") +``` + +And the development version from [GitHub](https://github.com/) with: + +``` r +# install.packages("devtools") +devtools::install_github("fanggong/okxAPI") +``` + +## Requirements + +Please refer to [okx my api page](https://www.okx.com/account/my-api) regarding V5 API Key creation. + +## Example + +### REST API + +You can implement all REST API requests in Okx exchange by inheriting the `restAPI` class. For example, to implement [Get currencies](https://www.okx.com/docs-v5/en/#rest-api-funding-get-currencies), you can define the class and call the method as follows: + +``` r +myRestAPI <- R6::R6Class( + inherit = restAPI, + public = list( + get_currencies = function(ccy, process = "identity") { + self$get_result( + api = "/api/v5/asset/currencies", method = "GET", process = process, + ccy = ccy + ) + } + ) +) +tmp <- myRestAPI$new(api_key, secret_key, passphrase) +tmp$get_currencies("BTC") +``` + +For commonly used interfaces, they have been implemented in this package. The naming convention is as follows: for "/api/v5/AAA/BBB", a new class named `restAPIAAA`, which inherits from `restAPI`, has been defined in this package. The `BBB` method in this new class is used to call the API. + +### WebSocket API Public Channel + +A `websocketAPIpublic` class based on [websocket package](https://github.com/rstudio/websocket) is used here. + +Create new `websocketAPIpublic` object and initiate the connection to the server. + +``` r +tmp <- websocketAPIpublic$new() +tmp$connect() +``` + +Subscribe BTC-USDT-SWAP 5m candlesticks data. + +``` r +msg <- list( + op = "subscribe", + args = list( + list(channel = "candle5m", instId = "BTC-USDT-SWAP") + ) +) +msg <- jsonlite::toJSON(msg, auto_unbox = TRUE, pretty = TRUE) +tmp$send(msg) +``` + +Pass your own callback function + +``` r +tmp$on_message(function(event) { + if (event$data == "pong") { + cat("Bingo!!") + } +}) +tmp$send("ping") +``` + +Close the connection. + +``` r +tmp$close() +``` + +### WebSocket API Private Channel + +A `websocketAPIprivate` class based on [websocket package](https://github.com/rstudio/websocket) is used here. + +Create new `websocketAPIprivate` object and initiate the connection to the server. + +``` r +tmp <- websocketAPIprivate$new(api_key, secret_key, passphrase) +tmp$connect() +Sys.sleep(1) # Waiting for connection success +tmp$login() +``` + +Subscribe account information. + +``` r +msg <- list( + op = "subscribe", + args = list( + list(channel = "account", ccy = "USDT") + ) +) +msg <- jsonlite::toJSON(msg, auto_unbox = TRUE, pretty = TRUE) +tmp$send(msg) +``` + +Pass your own callback function. + +``` r +tmp$on_message(function(event) { + if (event$data == "pong") { + cat("Bingo!!") + } +}) +tmp$send("ping") +``` + +Close the connection. + +``` r +tmp$close() +``` diff --git a/man/get_functions.Rd b/man/get_functions.Rd new file mode 100644 index 0000000..57c0bf6 --- /dev/null +++ b/man/get_functions.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/funcs.R +\name{get_functions} +\alias{get_functions} +\title{Wrapper for some frequently used APIs to get data easily} +\description{ +The main purpose is to handle APIs that have limitations on the number of results returned per single request. +} +\seealso{ +\code{\link{get_positions_history}} +\code{\link{get_history_candles}} +} diff --git a/man/get_history_candles.Rd b/man/get_history_candles.Rd new file mode 100644 index 0000000..01b4aa7 --- /dev/null +++ b/man/get_history_candles.Rd @@ -0,0 +1,47 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/funcs.R +\name{get_history_candles} +\alias{get_history_candles} +\title{Retrieve the candlestick charts} +\usage{ +get_history_candles( + api_key, + secret_key, + passphrase, + bar = c("1m", "3m", "5m", "15m", "30m", "1H", "4H", "6H", "12H", "1D", "2D", "3D"), + count, + instId, + ... +) +} +\arguments{ +\item{api_key}{Okx API key.} + +\item{secret_key}{Okx API secret key.} + +\item{passphrase}{Okx API passphrase.} + +\item{bar}{Bar size, the default is 1m, e.g. 1m/3m/5m/15m/30m/1H/2H/4H, Hong Kong time opening price k-line: 6H/12H/1D/2D/3D.} + +\item{count}{Number of Bars.} + +\item{instId}{Instrument ID, e.g. BTC-USDT-SWAP.} + +\item{...}{Other request parameters to be passed, See \href{https://www.okx.com/docs-v5/en/#rest-api-market-data-get-candlesticks-history}{Get candlesticks history} for more information.} +} +\value{ +Candlestick charts data +} +\description{ +Wrapper for API \href{https://www.okx.com/docs-v5/en/#rest-api-market-data-get-candlesticks}{Get candlesticks} +and \href{https://www.okx.com/docs-v5/en/#rest-api-market-data-get-candlesticks-history}{Get candlesticks history}. +} +\examples{ +\dontrun{ +candles <- get_history_candles( + api_key, secret_key, passphrase, bar = "1m", + count = 24*60, instId = "CFX-USDT-SWAP" +) +} + +} diff --git a/man/get_positions_history.Rd b/man/get_positions_history.Rd new file mode 100644 index 0000000..394858d --- /dev/null +++ b/man/get_positions_history.Rd @@ -0,0 +1,45 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/funcs.R +\name{get_positions_history} +\alias{get_positions_history} +\title{Retrieve the position data} +\usage{ +get_positions_history( + api_key, + secret_key, + passphrase, + count = 90, + period = 10, + ... +) +} +\arguments{ +\item{api_key}{Okx API key.} + +\item{secret_key}{Okx API secret key.} + +\item{passphrase}{Okx API passphrase.} + +\item{count}{Retrieve position data for a specified number of past days, with a maximum of 90(days)} + +\item{period}{Due to the 'Number of results per request' limitation of the API, +the \code{period} parameter must be specified to ensure that the number of position data entries within each period does not exceed 100.} + +\item{...}{Other request parameters to be passed, See +\href{https://www.okx.com/docs-v5/en/#rest-api-account-get-positions-history}{Get positions history} for more information.} +} +\value{ +Position data +} +\description{ +Wrapper for API \href{https://www.okx.com/docs-v5/en/#rest-api-account-get-positions-history}{Get positions history}. +} +\examples{ +\dontrun{ +positions <- get_positions_history( + api_key, secret_key, passphrase, count = 90, period = 10, + instType = "SWAP", mgnMode = "isolated" +) +} + +} diff --git a/man/restAPI.Rd b/man/restAPI.Rd new file mode 100644 index 0000000..2cd159d --- /dev/null +++ b/man/restAPI.Rd @@ -0,0 +1,247 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/restAPI.R +\name{restAPI} +\alias{restAPI} +\title{restAPI Class} +\description{ +Base class for \href{https://www.okx.com/docs-v5/en/}{Okx exchange v5 API}. +} +\details{ +You can implement all REST API requests in Okx exchange by inheriting the \code{restAPI} class. +Please refer to the example provided at the end of the document. + +For commonly used interfaces, they have been implemented in this package. +The naming convention is as follows: for "/api/v5/AAA/BBB", a new class named \code{restAPIAAA}, +which inherits from \code{restAPI}, has been defined in this package. +The \code{BBB} method in this new class is used to call the API. +} +\examples{ +\dontrun{ +# for [Get currencies](https://www.okx.com/docs-v5/en/#rest-api-funding-get-currencies) +# you can define the class like this +myRestAPI <- R6::R6Class( + inherit = restAPI, + public = list( + get_currencies = function(ccy, process = "identity") { + self$get_result( + api = "/api/v5/asset/currencies", method = "GET", process = process, + ccy = ccy + ) + } + ) +) +# And call it like this +tmp <- myRestAPI$new(api_key, secret_key, passphrase) +tmp$get_currencies("BTC") +} + +} +\seealso{ +\code{\link{restAPItrade}} +\code{\link{restAPIaccount}} +\code{\link{restAPImarket}} +} +\section{Public fields}{ +\if{html}{\out{
}} +\describe{ +\item{\code{url}}{Okx REST API url, which is https://www.okx.com.} + +\item{\code{api_key}}{Okx API key.} + +\item{\code{secret_key}}{Okx API secret key.} + +\item{\code{passphrase}}{Okx API passphrase.} + +\item{\code{simulate}}{Whether to use demo trading service.} +} +\if{html}{\out{
}} +} +\section{Methods}{ +\subsection{Public methods}{ +\itemize{ +\item \href{#method-restAPI-new}{\code{restAPI$new()}} +\item \href{#method-restAPI-get_timestamp}{\code{restAPI$get_timestamp()}} +\item \href{#method-restAPI-get_request_path}{\code{restAPI$get_request_path()}} +\item \href{#method-restAPI-get_body}{\code{restAPI$get_body()}} +\item \href{#method-restAPI-get_message}{\code{restAPI$get_message()}} +\item \href{#method-restAPI-get_signature}{\code{restAPI$get_signature()}} +\item \href{#method-restAPI-get_header}{\code{restAPI$get_header()}} +\item \href{#method-restAPI-get_result}{\code{restAPI$get_result()}} +\item \href{#method-restAPI-clone}{\code{restAPI$clone()}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPI-new}{}}} +\subsection{Method \code{new()}}{ +Create a new REST API object. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPI$new(api_key, secret_key, passphrase, simulate = FALSE)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{api_key}}{Okx API key.} + +\item{\code{secret_key}}{Okx API secret key.} + +\item{\code{passphrase}}{Okx API passphrase.} + +\item{\code{simulate}}{Whether to use demo trading service.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPI-get_timestamp}{}}} +\subsection{Method \code{get_timestamp()}}{ +Get UTC timestamp. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPI$get_timestamp()}\if{html}{\out{
}} +} + +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPI-get_request_path}{}}} +\subsection{Method \code{get_request_path()}}{ +Get request path. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPI$get_request_path(api, method = c("GET", "POST"), ...)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{api}}{Request api e.g. /api/v5/account/positions-history.} + +\item{\code{method}}{Request method, \code{GET} or \code{POST}.} + +\item{\code{...}}{Other request parameters.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPI-get_body}{}}} +\subsection{Method \code{get_body()}}{ +Get request body. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPI$get_body(method = c("GET", "POST"), ...)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{method}}{Request method, \code{GET} or \code{POST}.} + +\item{\code{...}}{Other request parameters.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPI-get_message}{}}} +\subsection{Method \code{get_message()}}{ +Get the signing messages. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPI$get_message(timestamp, request_path, body, method = c("GET", "POST"))}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{timestamp}}{Retrieve through method \code{get_timestamp}.} + +\item{\code{request_path}}{Retrieve through method \code{get_request_path}.} + +\item{\code{body}}{Retrieve through method \code{get_body}.} + +\item{\code{method}}{Request method, \code{GET} or \code{POST}.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPI-get_signature}{}}} +\subsection{Method \code{get_signature()}}{ +Get the signature. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPI$get_signature(msg, secret_key = self$secret_key)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{msg}}{Retrieve through method \code{get_message}.} + +\item{\code{secret_key}}{Okx API secret key.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPI-get_header}{}}} +\subsection{Method \code{get_header()}}{ +Get request headers. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPI$get_header(timestamp, msg)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{timestamp}}{Retrieve through method \code{get_timestamp}.} + +\item{\code{msg}}{Retrieve through method \code{get_message}.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPI-get_result}{}}} +\subsection{Method \code{get_result()}}{ +Retrieve data from api. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPI$get_result(api, method = c("GET", "POST"), process, ...)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{api}}{Request api e.g. /api/v5/account/positions-history.} + +\item{\code{method}}{Request method, \code{GET} or \code{POST}.} + +\item{\code{process}}{A function to process the data received from the API.} + +\item{\code{...}}{Other request parameters.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPI-clone}{}}} +\subsection{Method \code{clone()}}{ +The objects of this class are cloneable with this method. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPI$clone(deep = FALSE)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{deep}}{Whether to make a deep clone.} +} +\if{html}{\out{
}} +} +} +} diff --git a/man/restAPIaccount.Rd b/man/restAPIaccount.Rd new file mode 100644 index 0000000..e8a8094 --- /dev/null +++ b/man/restAPIaccount.Rd @@ -0,0 +1,109 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/restAPI.R +\name{restAPIaccount} +\alias{restAPIaccount} +\title{restAPIaccount Class} +\description{ +Wrapper for \href{https://www.okx.com/docs-v5/en/#rest-api-account}{REST API ACCOUNT}. +} +\section{Super class}{ +\code{\link[okxAPI:restAPI]{okxAPI::restAPI}} -> \code{restAPIaccount} +} +\section{Methods}{ +\subsection{Public methods}{ +\itemize{ +\item \href{#method-restAPIaccount-balance}{\code{restAPIaccount$balance()}} +\item \href{#method-restAPIaccount-positions}{\code{restAPIaccount$positions()}} +\item \href{#method-restAPIaccount-positions_history}{\code{restAPIaccount$positions_history()}} +\item \href{#method-restAPIaccount-clone}{\code{restAPIaccount$clone()}} +} +} +\if{html}{\out{ +
Inherited methods + +
+}} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPIaccount-balance}{}}} +\subsection{Method \code{balance()}}{ +See \href{https://www.okx.com/docs-v5/en/#rest-api-account-get-balance}{Get balance} for more information. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPIaccount$balance(ccy, process = "identity")}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{ccy}}{Single currency or a vector composed of multiple currencies. (no more than 20).} + +\item{\code{process}}{A function to process the data received from the API. Default to \code{identity}.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPIaccount-positions}{}}} +\subsection{Method \code{positions()}}{ +See \href{https://www.okx.com/docs-v5/en/#rest-api-account-get-positions}{Get positions} for more information. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPIaccount$positions(process = "identity", ...)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{process}}{A function to process the data received from the API. Default to \code{identity}.} + +\item{\code{...}}{Other request parameters.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPIaccount-positions_history}{}}} +\subsection{Method \code{positions_history()}}{ +See \href{https://www.okx.com/docs-v5/en/#rest-api-account-get-positions-history}{Get positions history} for more information. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPIaccount$positions_history(process = "identity", ...)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{process}}{A function to process the data received from the API. Default to \code{identity}.} + +\item{\code{...}}{Other request parameters.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPIaccount-clone}{}}} +\subsection{Method \code{clone()}}{ +The objects of this class are cloneable with this method. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPIaccount$clone(deep = FALSE)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{deep}}{Whether to make a deep clone.} +} +\if{html}{\out{
}} +} +} +} diff --git a/man/restAPImarket.Rd b/man/restAPImarket.Rd new file mode 100644 index 0000000..8ecf313 --- /dev/null +++ b/man/restAPImarket.Rd @@ -0,0 +1,93 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/restAPI.R +\name{restAPImarket} +\alias{restAPImarket} +\title{restAPImarket Class} +\description{ +Wrapper for \href{https://www.okx.com/docs-v5/en/#rest-api-market-data}{REST API MARKET}. +} +\section{Super class}{ +\code{\link[okxAPI:restAPI]{okxAPI::restAPI}} -> \code{restAPImarket} +} +\section{Methods}{ +\subsection{Public methods}{ +\itemize{ +\item \href{#method-restAPImarket-candles}{\code{restAPImarket$candles()}} +\item \href{#method-restAPImarket-history_candles}{\code{restAPImarket$history_candles()}} +\item \href{#method-restAPImarket-clone}{\code{restAPImarket$clone()}} +} +} +\if{html}{\out{ +
Inherited methods + +
+}} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPImarket-candles}{}}} +\subsection{Method \code{candles()}}{ +See \href{https://www.okx.com/docs-v5/en/#rest-api-market-data-get-candlesticks}{Get candlesticks} for more information. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPImarket$candles(instId, process = "identity", ...)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{instId}}{Instrument ID, e.g. BTC-USD-190927-5000-C.} + +\item{\code{process}}{A function to process the data received from the API. Default to \code{identity}.} + +\item{\code{...}}{Other request parameters.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPImarket-history_candles}{}}} +\subsection{Method \code{history_candles()}}{ +See \href{https://www.okx.com/docs-v5/en/#rest-api-market-data-get-candlesticks-history}{Get candlesticks history} for more information. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPImarket$history_candles(instId, process = "identity", ...)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{instId}}{Instrument ID, e.g. BTC-USD-190927-5000-C.} + +\item{\code{process}}{A function to process the data received from the API. Default to \code{identity}.} + +\item{\code{...}}{Other request parameters.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPImarket-clone}{}}} +\subsection{Method \code{clone()}}{ +The objects of this class are cloneable with this method. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPImarket$clone(deep = FALSE)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{deep}}{Whether to make a deep clone.} +} +\if{html}{\out{
}} +} +} +} diff --git a/man/restAPItrade.Rd b/man/restAPItrade.Rd new file mode 100644 index 0000000..a94bed1 --- /dev/null +++ b/man/restAPItrade.Rd @@ -0,0 +1,115 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/restAPI.R +\name{restAPItrade} +\alias{restAPItrade} +\title{restAPItrade Class} +\description{ +Wrapper for \href{https://www.okx.com/docs-v5/en/#rest-api-trade}{REST API TRADE}. +} +\section{Super class}{ +\code{\link[okxAPI:restAPI]{okxAPI::restAPI}} -> \code{restAPItrade} +} +\section{Methods}{ +\subsection{Public methods}{ +\itemize{ +\item \href{#method-restAPItrade-order}{\code{restAPItrade$order()}} +\item \href{#method-restAPItrade-cancel_order}{\code{restAPItrade$cancel_order()}} +\item \href{#method-restAPItrade-clone}{\code{restAPItrade$clone()}} +} +} +\if{html}{\out{ +
Inherited methods + +
+}} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPItrade-order}{}}} +\subsection{Method \code{order()}}{ +See \href{https://www.okx.com/docs-v5/en/#rest-api-trade-place-order}{Place order} for more information. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPItrade$order( + instId, + tdMode = c("isolated", "cross", "cash"), + side = c("buy", "sell"), + sz, + ordType = c("market", "limit", "post_only", "fok", "ioc", "optimal_limit_ioc"), + process = "identity", + ... +)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{instId}}{Instrument ID, e.g. BTC-USD-190927-5000-C.} + +\item{\code{tdMode}}{Trade mode. Margin mode: \code{cross} or \code{isolated.} Non-Margin mode: \code{cash}.} + +\item{\code{side}}{Order side, \code{buy} or \code{sell}.} + +\item{\code{sz}}{Quantity to buy or sell.} + +\item{\code{ordType}}{Order type. \code{market}: Market order, \code{limit}: Limit order, \code{post_only}: Post-only order, +\code{fok}: Fill-or-kill order, \code{ioc}: Immediate-or-cancel order, +\code{optimal_limit_ioc}: Market order with immediate-or-cancel order (applicable only to Futures and Perpetual swap).} + +\item{\code{process}}{A function to process the data received from the API. Default to \code{identity}.} + +\item{\code{...}}{Other request parameters.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPItrade-cancel_order}{}}} +\subsection{Method \code{cancel_order()}}{ +See \href{https://www.okx.com/docs-v5/en/#rest-api-trade-cancel-order}{Cancel order} for more information. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPItrade$cancel_order(instId, ordId, clOrdId, process = "identity", ...)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{instId}}{Instrument ID, e.g. BTC-USD-190927.} + +\item{\code{ordId}}{Order ID, Either \code{ordId} or \code{clOrdId} is required. If both are passed, \code{ordId} will be used.} + +\item{\code{clOrdId}}{Client Order ID as assigned by the client.} + +\item{\code{process}}{A function to process the data received from the API. Default to \code{identity}.} + +\item{\code{...}}{Other request parameters.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-restAPItrade-clone}{}}} +\subsection{Method \code{clone()}}{ +The objects of this class are cloneable with this method. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{restAPItrade$clone(deep = FALSE)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{deep}}{Whether to make a deep clone.} +} +\if{html}{\out{
}} +} +} +} diff --git a/man/websocketAPIprivate.Rd b/man/websocketAPIprivate.Rd new file mode 100644 index 0000000..ae9862d --- /dev/null +++ b/man/websocketAPIprivate.Rd @@ -0,0 +1,280 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/websockerAPIprivate.R +\name{websocketAPIprivate} +\alias{websocketAPIprivate} +\title{websocketAPIprivate Class} +\description{ +Private channel of WebSocket API for \href{https://www.okx.com/docs-v5/en/}{Okx exchange v5 API}. +See \href{https://www.okx.com/docs-v5/en/#websocket-api-private-channel}{Private Channel} for more information. +} +\examples{ +\dontrun{ +tmp <- websocketAPIprivate$new(api_key, secret_key, passphrase) +tmp$connect() +Sys.sleep(1) +tmp$login() + +# subscribe account information +msg <- list( + op = "subscribe", + args = list( + list(channel = "account", ccy = "USDT") + ) +) +msg <- jsonlite::toJSON(msg, auto_unbox = TRUE, pretty = TRUE) +tmp$send(msg) + +# pass your own callback function +tmp$on_message(function(event) { + if (event$data == "pong") { + cat("Bingo!!\n") + } +}) +tmp$send("ping") + +tmp$close() +} + +} +\section{Public fields}{ +\if{html}{\out{
}} +\describe{ +\item{\code{channel}}{Private WebSocket url.} + +\item{\code{api_key}}{Okx API key.} + +\item{\code{secret_key}}{Okx API secret key.} + +\item{\code{passphrase}}{Okx API passphrase.} + +\item{\code{simulate}}{Whether to use demo trading service.} + +\item{\code{ws}}{A websocket::WebSocket object to establish a connection to the server.} +} +\if{html}{\out{
}} +} +\section{Methods}{ +\subsection{Public methods}{ +\itemize{ +\item \href{#method-websockerAPIprivate-new}{\code{websocketAPIprivate$new()}} +\item \href{#method-websockerAPIprivate-get_timestamp}{\code{websocketAPIprivate$get_timestamp()}} +\item \href{#method-websockerAPIprivate-get_message}{\code{websocketAPIprivate$get_message()}} +\item \href{#method-websockerAPIprivate-get_signature}{\code{websocketAPIprivate$get_signature()}} +\item \href{#method-websockerAPIprivate-connect}{\code{websocketAPIprivate$connect()}} +\item \href{#method-websockerAPIprivate-login}{\code{websocketAPIprivate$login()}} +\item \href{#method-websockerAPIprivate-on_open}{\code{websocketAPIprivate$on_open()}} +\item \href{#method-websockerAPIprivate-on_close}{\code{websocketAPIprivate$on_close()}} +\item \href{#method-websockerAPIprivate-on_message}{\code{websocketAPIprivate$on_message()}} +\item \href{#method-websockerAPIprivate-on_error}{\code{websocketAPIprivate$on_error()}} +\item \href{#method-websockerAPIprivate-send}{\code{websocketAPIprivate$send()}} +\item \href{#method-websockerAPIprivate-close}{\code{websocketAPIprivate$close()}} +\item \href{#method-websockerAPIprivate-clone}{\code{websocketAPIprivate$clone()}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websockerAPIprivate-new}{}}} +\subsection{Method \code{new()}}{ +Craeate a new websocketAPIprivate object. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIprivate$new(api_key, secret_key, passphrase, simulate = FALSE)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{api_key}}{Okx API key.} + +\item{\code{secret_key}}{Okx API secret key.} + +\item{\code{passphrase}}{Okx API passphrase.} + +\item{\code{simulate}}{Whether to use demo trading service.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websockerAPIprivate-get_timestamp}{}}} +\subsection{Method \code{get_timestamp()}}{ +Get UTC timestamp. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIprivate$get_timestamp()}\if{html}{\out{
}} +} + +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websockerAPIprivate-get_message}{}}} +\subsection{Method \code{get_message()}}{ +Get the signing messages. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIprivate$get_message(timestamp)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{timestamp}}{Retrieve through method \code{get_timestamp}.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websockerAPIprivate-get_signature}{}}} +\subsection{Method \code{get_signature()}}{ +Get the signature. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIprivate$get_signature(secret_key, msg)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{secret_key}}{Okx API secret key.} + +\item{\code{msg}}{Retrieve through method \code{get_message}.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websockerAPIprivate-connect}{}}} +\subsection{Method \code{connect()}}{ +Initiate the connection to the server. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIprivate$connect()}\if{html}{\out{
}} +} + +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websockerAPIprivate-login}{}}} +\subsection{Method \code{login()}}{ +Log in. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIprivate$login()}\if{html}{\out{
}} +} + +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websockerAPIprivate-on_open}{}}} +\subsection{Method \code{on_open()}}{ +Called when the connection is established. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIprivate$on_open(func)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{func}}{A Callback function.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websockerAPIprivate-on_close}{}}} +\subsection{Method \code{on_close()}}{ +Called when a previously-opened connection is closed. +The event will have 'code' (integer) and 'reason' (one-element character) +elements that describe the remote's reason for closing. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIprivate$on_close(func)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{func}}{A Callback function.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websockerAPIprivate-on_message}{}}} +\subsection{Method \code{on_message()}}{ +Called each time a message is received from the server. +The event will have a 'data' element, which is the message content. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIprivate$on_message(func)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{func}}{A Callback function.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websockerAPIprivate-on_error}{}}} +\subsection{Method \code{on_error()}}{ +Called when the connection fails to be established. +The event will have an 'message' element, a character vector of length 1 +describing the reason for the error. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIprivate$on_error(func)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{func}}{A Callback function.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websockerAPIprivate-send}{}}} +\subsection{Method \code{send()}}{ +Send a message to the server. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIprivate$send(msg)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{msg}}{Messages.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websockerAPIprivate-close}{}}} +\subsection{Method \code{close()}}{ +Close the connection. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIprivate$close()}\if{html}{\out{
}} +} + +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websockerAPIprivate-clone}{}}} +\subsection{Method \code{clone()}}{ +The objects of this class are cloneable with this method. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIprivate$clone(deep = FALSE)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{deep}}{Whether to make a deep clone.} +} +\if{html}{\out{
}} +} +} +} diff --git a/man/websocketAPIpublic.Rd b/man/websocketAPIpublic.Rd new file mode 100644 index 0000000..f645259 --- /dev/null +++ b/man/websocketAPIpublic.Rd @@ -0,0 +1,206 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/websocketAPIpublic.R +\name{websocketAPIpublic} +\alias{websocketAPIpublic} +\title{websocketAPIpublic Class} +\description{ +Public channel of WebSocket API for \href{https://www.okx.com/docs-v5/en/}{Okx exchange v5 API}. +See \href{https://www.okx.com/docs-v5/en/#websocket-api-public-channel}{Public Channel} for more information. +} +\examples{ +\dontrun{ +tmp <- websocketAPIpublic$new() +tmp$connect() + +# subscribe BTC-USDT-SWAP 5m candlesticks data +msg <- list( + op = "unsubscribe", + args = list( + list(channel = "candle5m", instId = "BTC-USDT-SWAP") + ) +) +msg <- jsonlite::toJSON(msg, auto_unbox = TRUE, pretty = TRUE) +tmp$send(msg) + +# pass your own callback function +tmp$on_message(function(event) { + if (event$data == "pong") { + cat("Bingo!!\n") + } +}) +tmp$send("ping") + +tmp$close() +} + +} +\section{Public fields}{ +\if{html}{\out{
}} +\describe{ +\item{\code{channel}}{Public WebSocket url.} + +\item{\code{simulate}}{Whether to use demo trading service.} + +\item{\code{ws}}{A websocket::WebSocket object to establish a connection to the server.} +} +\if{html}{\out{
}} +} +\section{Methods}{ +\subsection{Public methods}{ +\itemize{ +\item \href{#method-websocketAPIpublic-new}{\code{websocketAPIpublic$new()}} +\item \href{#method-websocketAPIpublic-connect}{\code{websocketAPIpublic$connect()}} +\item \href{#method-websocketAPIpublic-on_open}{\code{websocketAPIpublic$on_open()}} +\item \href{#method-websocketAPIpublic-on_close}{\code{websocketAPIpublic$on_close()}} +\item \href{#method-websocketAPIpublic-on_message}{\code{websocketAPIpublic$on_message()}} +\item \href{#method-websocketAPIpublic-on_error}{\code{websocketAPIpublic$on_error()}} +\item \href{#method-websocketAPIpublic-send}{\code{websocketAPIpublic$send()}} +\item \href{#method-websocketAPIpublic-close}{\code{websocketAPIpublic$close()}} +\item \href{#method-websocketAPIpublic-clone}{\code{websocketAPIpublic$clone()}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websocketAPIpublic-new}{}}} +\subsection{Method \code{new()}}{ +Create a new websocketAPIpublic object. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIpublic$new(simulate = FALSE)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{simulate}}{Whether to use demo trading service.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websocketAPIpublic-connect}{}}} +\subsection{Method \code{connect()}}{ +Initiate the connection to the server. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIpublic$connect()}\if{html}{\out{
}} +} + +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websocketAPIpublic-on_open}{}}} +\subsection{Method \code{on_open()}}{ +Called when the connection is established. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIpublic$on_open(func)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{func}}{A Callback function.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websocketAPIpublic-on_close}{}}} +\subsection{Method \code{on_close()}}{ +Called when a previously-opened connection is closed. +The event will have 'code' (integer) and 'reason' (one-element character) +elements that describe the remote's reason for closing. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIpublic$on_close(func)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{func}}{A Callback function.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websocketAPIpublic-on_message}{}}} +\subsection{Method \code{on_message()}}{ +Called each time a message is received from the server. +The event will have a 'data' element, which is the message content. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIpublic$on_message(func)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{func}}{A Callback function.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websocketAPIpublic-on_error}{}}} +\subsection{Method \code{on_error()}}{ +Called when the connection fails to be established. +The event will have an 'message' element, a character vector of length 1 +describing the reason for the error. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIpublic$on_error(func)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{func}}{A Callback function.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websocketAPIpublic-send}{}}} +\subsection{Method \code{send()}}{ +Send a message to the server. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIpublic$send(msg)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{msg}}{Messages.} +} +\if{html}{\out{
}} +} +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websocketAPIpublic-close}{}}} +\subsection{Method \code{close()}}{ +Close the connection. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIpublic$close()}\if{html}{\out{
}} +} + +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-websocketAPIpublic-clone}{}}} +\subsection{Method \code{clone()}}{ +The objects of this class are cloneable with this method. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{websocketAPIpublic$clone(deep = FALSE)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{deep}}{Whether to make a deep clone.} +} +\if{html}{\out{
}} +} +} +}