library(httr) library(digest) API_URL <- "https://bittrex.com/api/v1.1/" API_KEY <- "XO51EkeqEgKJt4lrSNZTu5W1JsMXxK2D" API_SECRET <- "xt4BJFAejv9rvrAZEZjxYI9Dl3w5TZAE" SYMBOL <- "USDT-BTC" FEE <- 0.0025 NONCE_LAST <- 0 GetNonce <- function(){ nonce <- as.integer(Sys.time()) while(nonce <= NONCE_LAST){ nonce <- as.integer(Sys.time()) } NONCE_LAST <<- nonce return(nonce) } API_GetBalance <- function(){ nonce <- GetNonce() tryCatch({ uri <- paste0(API_URL,"account/getbalances?apikey=", API_KEY,"&nonce=",nonce) sign <- hmac(key = API_SECRET, object = uri, algo = "sha512") response <- GET(url = uri, add_headers("apisign" = sign, "Content-Type" = "application/x-www-form-urlencoded")) return(content(response, type="application/json")) },error=function(e){ cat(format(Sys.time()), "Error in API_GetBalance()\n") }) return(NULL) } API_GetOpenOrders <- function(){ nonce <- GetNonce() tryCatch({ uri <- paste0(API_URL,"market/getopenorders?market=", SYMBOL,"&apikey=", API_KEY,"&nonce=",nonce) sign <- hmac(key = API_SECRET, object = uri, algo = "sha512") response <- GET(url = uri, add_headers("apisign" = sign, "Content-Type" = "application/x-www-form-urlencoded")) return(content(response, type="application/json")) },error=function(e){ cat(format(Sys.time()), "Error in API_GetOpenOrders()\n") }) return(NULL) } API_CancelOrder <- function(uuid){ nonce <- GetNonce() tryCatch({ uri <- paste0(API_URL,"market/cancel?apikey=", API_KEY, "&uuid=", uuid, "&nonce=",nonce) sign <- hmac(key = API_SECRET, object = uri, algo = "sha512") response <- GET(url = uri, add_headers("apisign" = sign, "Content-Type" = "application/x-www-form-urlencoded")) return(content(response, type="application/json")) },error=function(e){ cat(format(Sys.time()), "Error in API_CancelOrder()\n") }) return(NULL) } API_BuyLimit <- function(amount, price){ cat(format(Sys.time()), "LimitBuy ", amount, SYMBOL_LONG, "for", price, "\n") nonce <- GetNonce() tryCatch({ uri <- paste0(API_URL,"market/buylimit?apikey=", API_KEY, "&market=", SYMBOL, "&quantity=", amount, "&rate=", price, "&nonce=",nonce) sign <- hmac(key = API_SECRET, object = uri, algo = "sha512") response <- GET(url = uri, add_headers("apisign" = sign, "Content-Type" = "application/x-www-form-urlencoded")) return(content(response, type="application/json")) },error=function(e){ cat(format(Sys.time()), "Error in API_BuyLimit()\n") }) return(NULL) } API_SellLimit <- function(amount, price){ cat(format(Sys.time()), "LimitSell", amount, SYMBOL_LONG, "for", price, "\n") nonce <- GetNonce() tryCatch({ uri <- paste0(API_URL,"market/selllimit?apikey=", API_KEY, "&market=", SYMBOL, "&quantity=", amount, "&rate=", price, "&nonce=",nonce) sign <- hmac(key = API_SECRET, object = uri, algo = "sha512") response <- GET(url = uri, add_headers("apisign" = sign, "Content-Type" = "application/x-www-form-urlencoded")) return(content(response, type="application/json")) },error=function(e){ cat(format(Sys.time()), "Error in API_SellLimit()\n") }) return(NULL) } API_GetMarkets <- function(){ nonce <- GetNonce() tryCatch({ uri <- paste0(API_URL,"public/getmarkets") response <- GET(url = uri, add_headers("Content-Type" = "application/x-www-form-urlencoded")) return(content(response, type="application/json")) },error=function(e){ cat(format(Sys.time()), "Error in API_GetMarkets()\n") }) return(NULL) } API_GetOrderbook <- function(buy = TRUE, sell = TRUE){ nonce <- GetNonce() tryCatch({ if(buy & sell){ type <- "both" }else if(buy){ type <- "buy" }else if(sell){ type <- "sell" } uri <- paste0(API_URL,"public/getorderbook?market=", SYMBOL, "&type=", type) response <- GET(url = uri, add_headers("Content-Type" = "application/x-www-form-urlencoded")) return(content(response, type="application/json")) },error=function(e){ cat(format(Sys.time()), "Error in API_GetOrderbook()\n") }) return(NULL) } CloseLimitOrders <- function(limitBuy = TRUE, limitSell = TRUE){ orders <- API_GetOpenOrders() if(!is.null(orders) && orders$success && length(orders$result) > 0){ for(i in 1:length(orders$result)){ if((limitBuy & orders$result[[i]]$OrderType == "LIMIT_BUY") || (limitSell & orders$result[[i]]$OrderType == "LIMIT_SELL")){ API_CancelOrder(orders$result[[i]]$OrderUuid) } } } } CountDigits <- function(x){ di <- 0 while(TRUE){ if(x == round(x, di)){ return(di) } di <- di + 1 } } FloorToDigits <- function(x, digits){ return(as.integer(x * 10^digits)/10^digits) } MarketBuy <- function(){ while(TRUE){ CloseLimitOrders() bal <- API_GetBalance() maxAmount <- 0 if(!is.null(bal) && bal$success && length(bal$result)>0){ for(i in 1:length(bal$result)){ if(bal$result[[i]]$Currency == SYMBOL_SHORT){ maxAmount <- bal$result[[i]]$Available break } } } if(maxAmount <= 0){ return() } ob <- API_GetOrderbook(buy = FALSE, sell = TRUE) if(!is.null(ob) && ob$success && length(ob$result)>0){ obAmountCumsum <- 0 obIt <- 1 while(TRUE){ obAmountCumsum <- obAmountCumsum + ob$result[[obIt]]$Quantity orderPrice <- ob$result[[obIt]]$Rate orderAmount <- FloorToDigits(maxAmount / orderPrice / (1+FEE),SYMBOL_DIGITS) orderAmountChar <- format(orderAmount, scientific = FALSE, digits = SYMBOL_DIGITS) if(orderAmount < obAmountCumsum){ break } obIt <- obIt + 1 } if(orderAmount < SYMBOL_MINTRADESIZE){ break } buyResult <- API_BuyLimit(orderAmountChar, orderPrice) if(is.null(buyResult) || !buyResult$success){ cat(format(Sys.time()), "LimitBuy failed\n") if(!is.null(buyResult)){ cat(format(Sys.time()), "-", buyResult$message, "\n") break } } }else{ break } Sys.sleep(1) } } MarketSell <- function(){ while(TRUE){ CloseLimitOrders() bal <- API_GetBalance() maxAmount <- 0 if(!is.null(bal) && bal$success && length(bal$result)>0){ for(i in 1:length(bal$result)){ if(bal$result[[i]]$Currency == SYMBOL_LONG){ maxAmount <- bal$result[[i]]$Available break } } } if(maxAmount <= 0){ return() } ob <- API_GetOrderbook(buy = TRUE, sell = FALSE) if(!is.null(ob) && ob$success && length(ob$result)>0){ obAmountCumsum <- 0 obIt <- 1 while(TRUE){ obAmountCumsum <- obAmountCumsum + ob$result[[obIt]]$Quantity orderPrice <- ob$result[[obIt]]$Rate orderAmount <- FloorToDigits(maxAmount, SYMBOL_DIGITS) orderAmountChar <- format(orderAmount, scientific = FALSE, digits = SYMBOL_DIGITS) if(orderAmount < obAmountCumsum){ break } obIt <- obIt + 1 } if(orderAmount < SYMBOL_MINTRADESIZE){ break } sellResult <- API_SellLimit(orderAmountChar, orderPrice) if(is.null(sellResult) || !sellResult$success){ cat(format(Sys.time()), "LimitBuy failed\n") if(!is.null(sellResult)){ cat(format(Sys.time()), "-", sellResult$message, "\n") break } } }else{ break } Sys.sleep(1) } } symbolFound <- FALSE markets <- API_GetMarkets() if(!is.null(markets) && markets$success && length(markets$result)>0){ for(i in 1:length(markets$result)){ if(markets$result[[i]]$MarketName == SYMBOL && markets$result[[i]]$IsActive){ SYMBOL_LONG <- markets$result[[i]]$MarketCurrency SYMBOL_SHORT <- markets$result[[i]]$BaseCurrency SYMBOL_MINTRADESIZE <- markets$result[[i]]$MinTradeSize SYMBOL_DIGITS <- CountDigits(markets$result[[i]]$MinTradeSize) symbolFound <- TRUE break } } } if(!symbolFound){ cat("Cannot trade selected symbol\n") stop() } #Trade functions #API_BuyLimit(0.1, 8000) #CloseLimitOrders(limitBuy = TRUE, limitSell = FALSE) #API_SellLimit(0.1, 8300) #CloseLimitOrders(limitBuy = FALSE, limitSell = TRUE) #CloseLimitOrders(limitBuy = TRUE, limitSell = TRUE) #MarketBuy() #MarketSell()