diff --git a/README.md b/README.md index ec3e4114..1be939d5 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,6 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader | Huobi.Pro | Yes | Yes | NA | | ItBit | Yes | NA | No | | Kraken | Yes | Yes | NA | -| LakeBTC | Yes | Yes | NA | | Lbank | Yes | No | NA | | LocalBitcoins | Yes | NA | NA | | OKCoin International | Yes | Yes | No | diff --git a/cmd/apichecker/apicheck.go b/cmd/apichecker/apicheck.go index b5d50dcc..4bce0ba9 100644 --- a/cmd/apichecker/apicheck.go +++ b/cmd/apichecker/apicheck.go @@ -46,7 +46,6 @@ const ( pathBitstamp = "https://www.bitstamp.net/api/" pathHitBTC = "https://api.hitbtc.com/" pathBitflyer = "https://lightning.bitflyer.com/docs?lang=en" - pathLakeBTC = "https://www.lakebtc.com/s/api_v2" pathKraken = "https://www.kraken.com/features/api" pathAlphaPoint = "https://alphapoint.github.io/slate/#introduction" pathYobit = "https://www.yobit.net/en/api/" @@ -478,8 +477,6 @@ func checkChangeLog(htmlData *HTMLScrapingData) (string, error) { dataStrings, err = htmlScrapeHitBTC(htmlData) case pathBitflyer: dataStrings, err = htmlScrapeBitflyer(htmlData) - case pathLakeBTC: - dataStrings, err = htmlScrapeLakeBTC(htmlData) case pathKraken: dataStrings, err = htmlScrapeKraken(htmlData) case pathAlphaPoint: @@ -990,28 +987,6 @@ loop: return resp, nil } -// htmlScrapeLakeBTC gets the check string for LakeBTC Exchange -func htmlScrapeLakeBTC(htmlData *HTMLScrapingData) ([]string, error) { - temp, err := http.Get(htmlData.Path) - if err != nil { - return nil, err - } - defer temp.Body.Close() - a, err := ioutil.ReadAll(temp.Body) - if err != nil { - return nil, err - } - r, err := regexp.Compile(htmlData.RegExp) - if err != nil { - return nil, err - } - str := r.FindString(string(a)) - sha := crypto.GetSHA256([]byte(str)) - var resp []string - resp = append(resp, crypto.HexEncodeToString(sha)) - return resp, nil -} - // htmlScrapeBitstamp gets the check string for Bitstamp Exchange func htmlScrapeBitstamp(htmlData *HTMLScrapingData) ([]string, error) { temp, err := http.Get(htmlData.Path) diff --git a/cmd/apichecker/apicheck_test.go b/cmd/apichecker/apicheck_test.go index 714786a4..f0302a00 100644 --- a/cmd/apichecker/apicheck_test.go +++ b/cmd/apichecker/apicheck_test.go @@ -344,22 +344,6 @@ func TestHTMLItBit(t *testing.T) { } } -func TestHTMLLakeBTC(t *testing.T) { - t.Parallel() - data := HTMLScrapingData{TokenData: "div", - Key: "class", - Val: "flash-message", - TokenDataEnd: "h2", - TextTokenData: "h1", - DateFormat: "", - RegExp: `APIv\d{1}`, - Path: "https://www.lakebtc.com/s/api_v2"} - _, err := htmlScrapeLakeBTC(&data) - if err != nil { - t.Error(err) - } -} - func TestHTMLScrapeExmo(t *testing.T) { t.Parallel() data := HTMLScrapingData{RegExp: `Last updated on [\s\S]*, 20\d{2}`, diff --git a/cmd/apichecker/backup.json b/cmd/apichecker/backup.json index ae8644af..5a918c10 100644 --- a/cmd/apichecker/backup.json +++ b/cmd/apichecker/backup.json @@ -270,23 +270,6 @@ }, "Disabled": false }, - { - "Name": "LakeBTC", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "div", - "Key": "class", - "Val": "flash-message", - "TokenDataEnd": "h2", - "TextTokenData": "h1", - "RegExp": "APIv\\d{1}", - "CheckString": "de2491b95ef1f6ea334247b13f0f14f6816fb5961cc63acc0542b07fc0336dd8", - "Path": "https://www.lakebtc.com/s/api_v2" - } - }, - "Disabled": false - }, { "Name": "Exmo", "CheckType": "HTML String Check", diff --git a/cmd/apichecker/testupdates.json b/cmd/apichecker/testupdates.json index 5a34be4f..9847acc6 100644 --- a/cmd/apichecker/testupdates.json +++ b/cmd/apichecker/testupdates.json @@ -275,23 +275,6 @@ }, "Disabled": false }, - { - "Name": "LakeBTC", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "div", - "Key": "class", - "Val": "flash-message", - "TokenDataEnd": "h2", - "TextTokenData": "h1", - "RegExp": "APIv\\d{1}", - "CheckString": "de2491b95ef1f6ea334247b13f0f14f6816fb5961cc63acc0542b07fc0336dd8", - "Path": "https://www.lakebtc.com/s/api_v2" - } - }, - "Disabled": false - }, { "Name": "Exmo", "CheckType": "HTML String Check", diff --git a/cmd/apichecker/updates.json b/cmd/apichecker/updates.json index 0140ec98..a14c5249 100644 --- a/cmd/apichecker/updates.json +++ b/cmd/apichecker/updates.json @@ -275,23 +275,6 @@ }, "Disabled": false }, - { - "Name": "LakeBTC", - "CheckType": "HTML String Check", - "Data": { - "HTMLData": { - "TokenData": "div", - "Key": "class", - "Val": "flash-message", - "TokenDataEnd": "h2", - "TextTokenData": "h1", - "RegExp": "APIv\\d{1}", - "CheckString": "de2491b95ef1f6ea334247b13f0f14f6816fb5961cc63acc0542b07fc0336dd8", - "Path": "https://www.lakebtc.com/s/api_v2" - } - }, - "Disabled": false - }, { "Name": "Exmo", "CheckType": "HTML String Check", diff --git a/cmd/documentation/exchanges_templates/exchanges_trade_readme.tmpl b/cmd/documentation/exchanges_templates/exchanges_trade_readme.tmpl index 185c7159..3444e391 100644 --- a/cmd/documentation/exchanges_templates/exchanges_trade_readme.tmpl +++ b/cmd/documentation/exchanges_templates/exchanges_trade_readme.tmpl @@ -62,7 +62,6 @@ _b in this context is an `IBotExchange` implemented struct_ | Huobi.Pro | Yes | Yes | No | | ItBit | Yes | NA | No | | Kraken | Yes | Yes | No | -| LakeBTC | Yes | No | No | | Lbank | Yes | No | Yes | | LocalBitcoins | Yes | NA | No | | OKCoin International | Yes | Yes | No | diff --git a/cmd/documentation/exchanges_templates/lakebtc.tmpl b/cmd/documentation/exchanges_templates/lakebtc.tmpl deleted file mode 100644 index 9073754f..00000000 --- a/cmd/documentation/exchanges_templates/lakebtc.tmpl +++ /dev/null @@ -1,99 +0,0 @@ -{{define "exchanges lakebtc" -}} -{{template "header" .}} -## LakeBTC Exchange - -### Current Features - -+ REST Support -+ Websocket Support - -### How to enable - -+ [Enable via configuration](https://github.com/thrasher-corp/gocryptotrader/tree/master/config#enable-exchange-via-config-example) - -+ Individual package example below: - -```go - // Exchanges will be abstracted out in further updates and examples will be - // supplied then -``` - -### How to do REST public/private calls - -+ If enabled via "configuration".json file the exchange will be added to the -IBotExchange array in the ```go var bot Bot``` and you will only be able to use -the wrapper interface functions for accessing exchange data. View routines.go -for an example of integration usage with GoCryptoTrader. Rudimentary example -below: - -main.go -```go -var l exchange.IBotExchange - -for i := range bot.Exchanges { - if bot.Exchanges[i].GetName() == "LakeBTC" { - l = bot.Exchanges[i] - } -} - -// Public calls - wrapper functions - -// Fetches current ticker information -tick, err := l.FetchTicker() -if err != nil { - // Handle error -} - -// Fetches current orderbook information -ob, err := l.FetchOrderbook() -if err != nil { - // Handle error -} - -// Private calls - wrapper functions - make sure your APIKEY and APISECRET are -// set and AuthenticatedAPISupport is set to true - -// Fetches current account information -accountInfo, err := l.GetAccountInfo() -if err != nil { - // Handle error -} -``` - -+ If enabled via individually importing package, rudimentary example below: - -```go -// Public calls - -// Fetches current ticker information -ticker, err := l.GetTicker() -if err != nil { - // Handle error -} - -// Fetches current orderbook information -ob, err := l.GetOrderBook() -if err != nil { - // Handle error -} - -// Private calls - make sure your APIKEY and APISECRET are set and -// AuthenticatedAPISupport is set to true - -// GetUserInfo returns account info -accountInfo, err := l.GetUserInfo(...) -if err != nil { - // Handle error -} - -// Submits an order and the exchange and returns its tradeID -tradeID, err := l.Trade(...) -if err != nil { - // Handle error -} -``` - -### Please click GoDocs chevron above to view current GoDoc information for this package -{{template "contributions"}} -{{template "donations" .}} -{{end}} diff --git a/cmd/documentation/root_templates/root_readme.tmpl b/cmd/documentation/root_templates/root_readme.tmpl index 2d1625d1..2217f0a8 100644 --- a/cmd/documentation/root_templates/root_readme.tmpl +++ b/cmd/documentation/root_templates/root_readme.tmpl @@ -40,7 +40,6 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader | Huobi.Pro | Yes | Yes | NA | | ItBit | Yes | NA | No | | Kraken | Yes | Yes | NA | -| LakeBTC | Yes | Yes | NA | | Lbank | Yes | No | NA | | LocalBitcoins | Yes | NA | NA | | OKCoin International | Yes | Yes | No | diff --git a/cmd/exchange_wrapper_issues/wrapperconfig.json b/cmd/exchange_wrapper_issues/wrapperconfig.json index d73e905e..4b0a9ac7 100644 --- a/cmd/exchange_wrapper_issues/wrapperconfig.json +++ b/cmd/exchange_wrapper_issues/wrapperconfig.json @@ -136,11 +136,6 @@ "secret": "Secret", "otpSecret": "-" }, - "lakebtc": { - "key": "Key", - "secret": "Secret", - "otpSecret": "-" - }, "lbank": { "key": "Key", "secret": "Secret", diff --git a/config_example.json b/config_example.json index a43e7974..85cb29f8 100644 --- a/config_example.json +++ b/config_example.json @@ -1847,82 +1847,6 @@ } ] }, - { - "name": "LakeBTC", - "enabled": true, - "verbose": false, - "httpTimeout": 15000000000, - "websocketResponseCheckTimeout": 30000000, - "websocketResponseMaxLimit": 7000000000, - "websocketTrafficTimeout": 30000000000, - "websocketOrderbookBufferLimit": 5, - "baseCurrencies": "USD,EUR,HKD,AUD,GBP,NZD,JPY,SGD,NGN,CHF,CAD", - "currencyPairs": { - "requestFormat": { - "uppercase": true - }, - "configFormat": { - "uppercase": true - }, - "useGlobalFormat": true, - "assetTypes": [ - "spot" - ], - "pairs": { - "spot": { - "enabled": "BTCUSD,BTCAUD", - "available": "USDSGD,ETHBTC,LTCBTC,BTCNZD,BTCSGD,AUDUSD,BTCJPY,BTCEUR,BTCCAD,BTCNGN,USDCAD,USDCHF,BTCAUD,BTCUSD,USDHKD,USDNGN,EURUSD,BACETH,BTCHKD,GBPUSD,BTCCHF,USDJPY,BTCGBP,XRPBTC,NZDUSD,BCHBTC" - } - } - }, - "api": { - "authenticatedSupport": false, - "authenticatedWebsocketApiSupport": false, - "endpoints": { - "url": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API", - "urlSecondary": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API", - "websocketURL": "NON_DEFAULT_HTTP_LINK_TO_WEBSOCKET_EXCHANGE_API" - }, - "credentials": { - "key": "Key", - "secret": "Secret" - }, - "credentialsValidator": { - "requiresKey": true, - "requiresSecret": true - } - }, - "features": { - "supports": { - "restAPI": true, - "restCapabilities": { - "tickerBatching": true, - "autoPairUpdates": true - }, - "websocketAPI": true, - "websocketCapabilities": {} - }, - "enabled": { - "autoPairUpdates": true, - "websocketAPI": false - } - }, - "bankAccounts": [ - { - "enabled": false, - "bankName": "", - "bankAddress": "", - "bankPostalCode": "", - "bankPostalCity": "", - "bankCountry": "", - "accountName": "", - "accountNumber": "", - "swiftCode": "", - "iban": "", - "supportedCurrencies": "" - } - ] - }, { "name": "LBank", "enabled": true, diff --git a/docs/ADD_NEW_EXCHANGE.md b/docs/ADD_NEW_EXCHANGE.md index 4998bb9c..71a1b6aa 100644 --- a/docs/ADD_NEW_EXCHANGE.md +++ b/docs/ADD_NEW_EXCHANGE.md @@ -217,7 +217,6 @@ Yes means supported, No means not yet implemented and NA means protocol unsuppor | ItBit | Yes | NA | No | | Kraken | Yes | Yes | NA | | Lbank | Yes | No | NA | -| LakeBTC | Yes | No | NA | | LocalBitcoins | Yes | NA | NA | | OKCoin International | Yes | Yes | No | | OKEX | Yes | Yes | No | @@ -249,7 +248,6 @@ var Exchanges = []string{ "huobi", "itbit", "kraken", - "lakebtc", "lbank", "localbitcoins", "okcoin international", diff --git a/docs/OHLCV.md b/docs/OHLCV.md index 1183bb65..2f951e8f 100644 --- a/docs/OHLCV.md +++ b/docs/OHLCV.md @@ -84,8 +84,7 @@ A helper tool [cmd/dbseed](../cmd/dbseed/README.md) has been created for assisti | Huobi | Y | | FTX | Y | | itBIT | | -| Kraken | Y | -| LakeBTC | | +| Kraken | Y | | lBank | Y | | Localbitcoins | | | Okcoin | Y | diff --git a/engine/exchange_manager.go b/engine/exchange_manager.go index 6c843584..2a9faab9 100644 --- a/engine/exchange_manager.go +++ b/engine/exchange_manager.go @@ -27,7 +27,6 @@ import ( "github.com/thrasher-corp/gocryptotrader/exchanges/huobi" "github.com/thrasher-corp/gocryptotrader/exchanges/itbit" "github.com/thrasher-corp/gocryptotrader/exchanges/kraken" - "github.com/thrasher-corp/gocryptotrader/exchanges/lakebtc" "github.com/thrasher-corp/gocryptotrader/exchanges/lbank" "github.com/thrasher-corp/gocryptotrader/exchanges/localbitcoins" "github.com/thrasher-corp/gocryptotrader/exchanges/okcoin" @@ -169,8 +168,6 @@ func (m *ExchangeManager) NewExchangeByName(name string) (exchange.IBotExchange, exch = new(itbit.ItBit) case "kraken": exch = new(kraken.Kraken) - case "lakebtc": - exch = new(lakebtc.LakeBTC) case "lbank": exch = new(lbank.Lbank) case "localbitcoins": diff --git a/engine/exchange_manager_test.go b/engine/exchange_manager_test.go index 6257813c..c775f3a3 100644 --- a/engine/exchange_manager_test.go +++ b/engine/exchange_manager_test.go @@ -65,7 +65,7 @@ func TestExchangeManagerRemoveExchange(t *testing.T) { func TestNewExchangeByName(t *testing.T) { m := SetupExchangeManager() - exchanges := []string{"binance", "bitfinex", "bitflyer", "bithumb", "bitmex", "bitstamp", "bittrex", "btc markets", "btse", "coinbene", "coinut", "exmo", "coinbasepro", "ftx", "gateio", "gemini", "hitbtc", "huobi", "itbit", "kraken", "lakebtc", "lbank", "localbitcoins", "okcoin international", "okex", "poloniex", "yobit", "zb", "fake"} + exchanges := []string{"binance", "bitfinex", "bitflyer", "bithumb", "bitmex", "bitstamp", "bittrex", "btc markets", "btse", "coinbene", "coinut", "exmo", "coinbasepro", "ftx", "gateio", "gemini", "hitbtc", "huobi", "itbit", "kraken", "lbank", "localbitcoins", "okcoin international", "okex", "poloniex", "yobit", "zb", "fake"} for i := range exchanges { exch, err := m.NewExchangeByName(exchanges[i]) if err != nil && exchanges[i] != "fake" { diff --git a/exchanges/lakebtc/README.md b/exchanges/lakebtc/README.md deleted file mode 100644 index 6b762b94..00000000 --- a/exchanges/lakebtc/README.md +++ /dev/null @@ -1,133 +0,0 @@ -# GoCryptoTrader package Lakebtc - - - - -[![Build Status](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml) -[![Software License](https://img.shields.io/badge/License-MIT-orange.svg?style=flat-square)](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE) -[![GoDoc](https://godoc.org/github.com/thrasher-corp/gocryptotrader?status.svg)](https://godoc.org/github.com/thrasher-corp/gocryptotrader/exchanges/lakebtc) -[![Coverage Status](http://codecov.io/github/thrasher-corp/gocryptotrader/coverage.svg?branch=master)](http://codecov.io/github/thrasher-corp/gocryptotrader?branch=master) -[![Go Report Card](https://goreportcard.com/badge/github.com/thrasher-corp/gocryptotrader)](https://goreportcard.com/report/github.com/thrasher-corp/gocryptotrader) - - -This lakebtc package is part of the GoCryptoTrader codebase. - -## This is still in active development - -You can track ideas, planned features and what's in progress on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader). - -Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://join.slack.com/t/gocryptotrader/shared_invite/enQtNTQ5NDAxMjA2Mjc5LTc5ZDE1ZTNiOGM3ZGMyMmY1NTAxYWZhODE0MWM5N2JlZDk1NDU0YTViYzk4NTk3OTRiMDQzNGQ1YTc4YmRlMTk) - -## LakeBTC Exchange - -### Current Features - -+ REST Support -+ Websocket Support - -### How to enable - -+ [Enable via configuration](https://github.com/thrasher-corp/gocryptotrader/tree/master/config#enable-exchange-via-config-example) - -+ Individual package example below: - -```go - // Exchanges will be abstracted out in further updates and examples will be - // supplied then -``` - -### How to do REST public/private calls - -+ If enabled via "configuration".json file the exchange will be added to the -IBotExchange array in the ```go var bot Bot``` and you will only be able to use -the wrapper interface functions for accessing exchange data. View routines.go -for an example of integration usage with GoCryptoTrader. Rudimentary example -below: - -main.go -```go -var l exchange.IBotExchange - -for i := range bot.Exchanges { - if bot.Exchanges[i].GetName() == "LakeBTC" { - l = bot.Exchanges[i] - } -} - -// Public calls - wrapper functions - -// Fetches current ticker information -tick, err := l.FetchTicker() -if err != nil { - // Handle error -} - -// Fetches current orderbook information -ob, err := l.FetchOrderbook() -if err != nil { - // Handle error -} - -// Private calls - wrapper functions - make sure your APIKEY and APISECRET are -// set and AuthenticatedAPISupport is set to true - -// Fetches current account information -accountInfo, err := l.GetAccountInfo() -if err != nil { - // Handle error -} -``` - -+ If enabled via individually importing package, rudimentary example below: - -```go -// Public calls - -// Fetches current ticker information -ticker, err := l.GetTicker() -if err != nil { - // Handle error -} - -// Fetches current orderbook information -ob, err := l.GetOrderBook() -if err != nil { - // Handle error -} - -// Private calls - make sure your APIKEY and APISECRET are set and -// AuthenticatedAPISupport is set to true - -// GetUserInfo returns account info -accountInfo, err := l.GetUserInfo(...) -if err != nil { - // Handle error -} - -// Submits an order and the exchange and returns its tradeID -tradeID, err := l.Trade(...) -if err != nil { - // Handle error -} -``` - -### Please click GoDocs chevron above to view current GoDoc information for this package - -## Contribution - -Please feel free to submit any pull requests or suggest any desired features to be added. - -When submitting a PR, please abide by our coding guidelines: - -+ Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)). -+ Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines. -+ Code must adhere to our [coding style](https://github.com/thrasher-corp/gocryptotrader/blob/master/doc/coding_style.md). -+ Pull requests need to be based on and opened against the `master` branch. - -## Donations - - - -If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to: - -***bc1qk0jareu4jytc0cfrhr5wgshsq8282awpavfahc*** diff --git a/exchanges/lakebtc/lakebtc.go b/exchanges/lakebtc/lakebtc.go deleted file mode 100644 index d091c97f..00000000 --- a/exchanges/lakebtc/lakebtc.go +++ /dev/null @@ -1,382 +0,0 @@ -package lakebtc - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "net/http" - "net/url" - "strconv" - "strings" - - "github.com/thrasher-corp/gocryptotrader/common/crypto" - "github.com/thrasher-corp/gocryptotrader/currency" - exchange "github.com/thrasher-corp/gocryptotrader/exchanges" - "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "github.com/thrasher-corp/gocryptotrader/log" -) - -const ( - lakeBTCAPIURL = "https://api.lakebtc.com/api_v2" - lakeBTCAPIVersion = "2" - lakeBTCTicker = "ticker" - lakeBTCOrderbook = "bcorderbook" - lakeBTCTrades = "bctrades" - lakeBTCGetAccountInfo = "getAccountInfo" - lakeBTCBuyOrder = "buyOrder" - lakeBTCSellOrder = "sellOrder" - lakeBTCOpenOrders = "openOrders" - lakeBTCGetOrders = "getOrders" - lakeBTCCancelOrder = "cancelOrders" - lakeBTCGetTrades = "getTrades" - lakeBTCGetExternalAccounts = "getExternalAccounts" - lakeBTCCreateWithdraw = "createWithdraw" -) - -// LakeBTC is the overarching type across the LakeBTC package -type LakeBTC struct { - exchange.Base - WebsocketConn -} - -// GetTicker returns the current ticker from lakeBTC -func (l *LakeBTC) GetTicker() (map[string]Ticker, error) { - response := make(map[string]TickerResponse) - path := fmt.Sprintf("/%s", lakeBTCTicker) - - err := l.SendHTTPRequest(exchange.RestSpot, path, &response) - if err != nil { - return nil, err - } - - result := make(map[string]Ticker) - - for k, v := range response { - var tick Ticker - key := strings.ToUpper(k) - if v.Ask != nil { - tick.Ask, err = strconv.ParseFloat(v.Ask.(string), 64) - if err != nil { - return nil, err - } - } - if v.Bid != nil { - tick.Bid, err = strconv.ParseFloat(v.Bid.(string), 64) - if err != nil { - return nil, err - } - } - if v.High != nil { - tick.High, err = strconv.ParseFloat(v.High.(string), 64) - if err != nil { - return nil, err - } - } - if v.Last != nil { - tick.Last, err = strconv.ParseFloat(v.Last.(string), 64) - if err != nil { - return nil, err - } - } - if v.Low != nil { - tick.Low, err = strconv.ParseFloat(v.Low.(string), 64) - if err != nil { - return nil, err - } - } - if v.Volume != nil { - tick.Volume, err = strconv.ParseFloat(v.Volume.(string), 64) - if err != nil { - return nil, err - } - } - result[key] = tick - } - return result, nil -} - -// GetOrderBook returns the order book from LakeBTC -func (l *LakeBTC) GetOrderBook(currency string) (Orderbook, error) { - type Response struct { - Bids [][]string `json:"bids"` - Asks [][]string `json:"asks"` - } - path := fmt.Sprintf("/%s?symbol=%s", lakeBTCOrderbook, strings.ToLower(currency)) - resp := Response{} - err := l.SendHTTPRequest(exchange.RestSpot, path, &resp) - if err != nil { - return Orderbook{}, err - } - orderbook := Orderbook{} - - for _, x := range resp.Bids { - price, err := strconv.ParseFloat(x[0], 64) - if err != nil { - log.Error(log.ExchangeSys, err) - continue - } - amount, err := strconv.ParseFloat(x[1], 64) - if err != nil { - log.Error(log.ExchangeSys, err) - continue - } - orderbook.Bids = append(orderbook.Bids, OrderbookStructure{price, amount}) - } - - for _, x := range resp.Asks { - price, err := strconv.ParseFloat(x[0], 64) - if err != nil { - log.Error(log.ExchangeSys, err) - continue - } - amount, err := strconv.ParseFloat(x[1], 64) - if err != nil { - log.Error(log.ExchangeSys, err) - continue - } - orderbook.Asks = append(orderbook.Asks, OrderbookStructure{price, amount}) - } - return orderbook, nil -} - -// GetTradeHistory returns the trade history for a given currency pair -func (l *LakeBTC) GetTradeHistory(currency string) ([]TradeHistory, error) { - v := url.Values{} - v.Set("symbol", strings.ToLower(currency)) - path := fmt.Sprintf("/%s?%s", lakeBTCTrades, v.Encode()) - var resp []TradeHistory - return resp, l.SendHTTPRequest(exchange.RestSpot, path, &resp) -} - -// GetAccountInformation returns your current account information -func (l *LakeBTC) GetAccountInformation() (AccountInfo, error) { - resp := AccountInfo{} - return resp, l.SendAuthenticatedHTTPRequest(exchange.RestSpot, lakeBTCGetAccountInfo, "", &resp) -} - -// Trade executes an order on the exchange and returns trade inforamtion or an -// error -func (l *LakeBTC) Trade(isBuyOrder bool, amount, price float64, currency string) (Trade, error) { - resp := Trade{} - params := strconv.FormatFloat(price, 'f', -1, 64) + "," + strconv.FormatFloat(amount, 'f', -1, 64) + "," + currency - - if isBuyOrder { - if err := l.SendAuthenticatedHTTPRequest(exchange.RestSpot, lakeBTCBuyOrder, params, &resp); err != nil { - return resp, err - } - } else { - if err := l.SendAuthenticatedHTTPRequest(exchange.RestSpot, lakeBTCSellOrder, params, &resp); err != nil { - return resp, err - } - } - - if resp.Result != "order received" { - return resp, fmt.Errorf("unexpected result: %s", resp.Result) - } - - return resp, nil -} - -// GetOpenOrders returns all open orders associated with your account -func (l *LakeBTC) GetOpenOrders() ([]OpenOrders, error) { - var orders []OpenOrders - - return orders, l.SendAuthenticatedHTTPRequest(exchange.RestSpot, lakeBTCOpenOrders, "", &orders) -} - -// GetOrders returns your orders -func (l *LakeBTC) GetOrders(orders []int64) ([]Orders, error) { - var ordersStr []string - for _, x := range orders { - ordersStr = append(ordersStr, strconv.FormatInt(x, 10)) - } - - var resp []Orders - return resp, - l.SendAuthenticatedHTTPRequest(exchange.RestSpot, lakeBTCGetOrders, strings.Join(ordersStr, ","), &resp) -} - -// CancelExistingOrder cancels an order by ID number and returns an error -func (l *LakeBTC) CancelExistingOrder(orderID int64) error { - type Response struct { - Result bool `json:"Result"` - } - - resp := Response{} - params := strconv.FormatInt(orderID, 10) - err := l.SendAuthenticatedHTTPRequest(exchange.RestSpot, lakeBTCCancelOrder, params, &resp) - if err != nil { - return err - } - - if !resp.Result { - return errors.New("unable to cancel order") - } - return nil -} - -// CancelExistingOrders cancels an order by ID number and returns an error -func (l *LakeBTC) CancelExistingOrders(orderIDs []string) error { - type Response struct { - Result bool `json:"Result"` - } - - resp := Response{} - params := strings.Join(orderIDs, ",") - err := l.SendAuthenticatedHTTPRequest(exchange.RestSpot, lakeBTCCancelOrder, params, &resp) - if err != nil { - return err - } - - if !resp.Result { - return fmt.Errorf("unable to cancel order(s): %v", orderIDs) - } - return nil -} - -// GetTrades returns trades associated with your account by timestamp -func (l *LakeBTC) GetTrades(timestamp int64) ([]AuthenticatedTradeHistory, error) { - params := "" - if timestamp != 0 { - params = strconv.FormatInt(timestamp, 10) - } - - var trades []AuthenticatedTradeHistory - return trades, l.SendAuthenticatedHTTPRequest(exchange.RestSpot, lakeBTCGetTrades, params, &trades) -} - -// GetExternalAccounts returns your external accounts WARNING: Only for BTC! -func (l *LakeBTC) GetExternalAccounts() ([]ExternalAccounts, error) { - var resp []ExternalAccounts - - return resp, l.SendAuthenticatedHTTPRequest(exchange.RestSpot, lakeBTCGetExternalAccounts, "", &resp) -} - -// CreateWithdraw allows your to withdraw to external account WARNING: Only for -// BTC! -func (l *LakeBTC) CreateWithdraw(amount float64, accountID string) (Withdraw, error) { - resp := Withdraw{} - params := strconv.FormatFloat(amount, 'f', -1, 64) + ",btc," + accountID - - err := l.SendAuthenticatedHTTPRequest(exchange.RestSpot, lakeBTCCreateWithdraw, params, &resp) - if err != nil { - return Withdraw{}, err - } - if len(resp.Error) > 0 { - return resp, errors.New(resp.Error) - } - - return resp, nil -} - -// SendHTTPRequest sends an unauthenticated http request -func (l *LakeBTC) SendHTTPRequest(endpoint exchange.URL, path string, result interface{}) error { - pathURL, err := l.API.Endpoints.GetURL(endpoint) - if err != nil { - return err - } - return l.SendPayload(context.Background(), &request.Item{ - Method: http.MethodGet, - Path: pathURL + path, - Result: result, - Verbose: l.Verbose, - HTTPDebugging: l.HTTPDebugging, - HTTPRecording: l.HTTPRecording, - }) -} - -// SendAuthenticatedHTTPRequest sends an autheticated HTTP request to a LakeBTC -func (l *LakeBTC) SendAuthenticatedHTTPRequest(ep exchange.URL, method, params string, result interface{}) (err error) { - if !l.AllowAuthenticatedRequest() { - return fmt.Errorf("%s %w", l.Name, exchange.ErrAuthenticatedRequestWithoutCredentialsSet) - } - endpoint, err := l.API.Endpoints.GetURL(ep) - if err != nil { - return err - } - n := l.Requester.GetNonce(true).String() - - req := fmt.Sprintf("tonce=%s&accesskey=%s&requestmethod=post&id=1&method=%s¶ms=%s", n, l.API.Credentials.Key, method, params) - hmac := crypto.GetHMAC(crypto.HashSHA1, []byte(req), []byte(l.API.Credentials.Secret)) - - if l.Verbose { - log.Debugf(log.ExchangeSys, "Sending POST request to %s calling method %s with params %s\n", endpoint, method, req) - } - - postData := make(map[string]interface{}) - postData["method"] = method - postData["id"] = 1 - postData["params"] = strings.Split(params, ",") - - data, err := json.Marshal(postData) - if err != nil { - return err - } - - headers := make(map[string]string) - headers["Json-Rpc-Tonce"] = l.Nonce.String() - headers["Authorization"] = "Basic " + crypto.Base64Encode([]byte(l.API.Credentials.Key+":"+crypto.HexEncodeToString(hmac))) - headers["Content-Type"] = "application/json-rpc" - - return l.SendPayload(context.Background(), &request.Item{ - Method: http.MethodPost, - Path: endpoint, - Headers: headers, - Body: strings.NewReader(string(data)), - Result: result, - AuthRequest: true, - NonceEnabled: true, - Verbose: l.Verbose, - HTTPDebugging: l.HTTPDebugging, - HTTPRecording: l.HTTPRecording, - }) -} - -// GetFee returns an estimate of fee based on type of transaction -func (l *LakeBTC) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) { - var fee float64 - switch feeBuilder.FeeType { - case exchange.CryptocurrencyTradeFee: - fee = calculateTradingFee(feeBuilder.PurchasePrice, - feeBuilder.Amount, - feeBuilder.IsMaker) - case exchange.CryptocurrencyDepositFee: - fee = getCryptocurrencyWithdrawalFee(feeBuilder.Pair.Base) - case exchange.InternationalBankWithdrawalFee: - // fees for withdrawals are dynamic. They cannot be calculated in - // advance as they are manually performed via the website, it can only - // be determined when submitting the request - case exchange.OfflineTradeFee: - fee = getOfflineTradeFee(feeBuilder.PurchasePrice, feeBuilder.Amount) - } - - if fee < 0 { - fee = 0 - } - - return fee, nil -} - -// getOfflineTradeFee calculates the worst case-scenario trading fee -func getOfflineTradeFee(price, amount float64) float64 { - return 0.002 * price * amount -} - -func calculateTradingFee(purchasePrice, amount float64, isMaker bool) (fee float64) { - if isMaker { - // TODO: Volume based fee calculation - fee = 0.0015 - } else { - fee = 0.002 - } - - return fee * amount * purchasePrice -} - -func getCryptocurrencyWithdrawalFee(c currency.Code) (fee float64) { - if c == currency.BTC { - fee = 0.001 - } - return fee -} diff --git a/exchanges/lakebtc/lakebtc_test.go b/exchanges/lakebtc/lakebtc_test.go deleted file mode 100644 index 5d4da1db..00000000 --- a/exchanges/lakebtc/lakebtc_test.go +++ /dev/null @@ -1,502 +0,0 @@ -package lakebtc - -import ( - "log" - "os" - "testing" - "time" - - "github.com/thrasher-corp/gocryptotrader/common" - "github.com/thrasher-corp/gocryptotrader/config" - "github.com/thrasher-corp/gocryptotrader/core" - "github.com/thrasher-corp/gocryptotrader/currency" - exchange "github.com/thrasher-corp/gocryptotrader/exchanges" - "github.com/thrasher-corp/gocryptotrader/exchanges/asset" - "github.com/thrasher-corp/gocryptotrader/exchanges/order" - "github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues" - "github.com/thrasher-corp/gocryptotrader/exchanges/stream" - "github.com/thrasher-corp/gocryptotrader/portfolio/withdraw" -) - -var l LakeBTC - -// Please add your own APIkeys to do correct due diligence testing. -const ( - apiKey = "" - apiSecret = "" - canManipulateRealOrders = false -) - -func TestMain(m *testing.M) { - l.SetDefaults() - cfg := config.GetConfig() - err := cfg.LoadConfig("../../testdata/configtest.json", true) - if err != nil { - log.Fatal("LakeBTC load config error", err) - } - lakebtcConfig, err := cfg.GetExchangeConfig("LakeBTC") - if err != nil { - log.Fatal("LakeBTC Setup() init error", err) - } - lakebtcConfig.API.AuthenticatedSupport = true - lakebtcConfig.API.Credentials.Key = apiKey - lakebtcConfig.API.Credentials.Secret = apiSecret - lakebtcConfig.Features.Enabled.Websocket = true - l.Websocket = sharedtestvalues.NewTestWebsocket() - err = l.Setup(lakebtcConfig) - if err != nil { - log.Fatal("LakeBTC setup error", err) - } - os.Exit(m.Run()) -} - -func TestFetchTradablePairs(t *testing.T) { - t.Parallel() - _, err := l.FetchTradablePairs(asset.Spot) - if err != nil { - t.Fatalf("GetTradablePairs err: %s", err) - } -} - -func TestGetTicker(t *testing.T) { - t.Parallel() - _, err := l.GetTicker() - if err != nil { - t.Error("GetTicker() error", err) - } -} - -func TestGetOrderBook(t *testing.T) { - t.Parallel() - _, err := l.GetOrderBook("BTCUSD") - if err != nil { - t.Error("GetOrderBook() error", err) - } -} - -func TestGetTradeHistory(t *testing.T) { - t.Parallel() - _, err := l.GetTradeHistory("BTCUSD") - if err != nil { - t.Error("GetTradeHistory() error", err) - } -} - -func TestTrade(t *testing.T) { - t.Parallel() - if !l.ValidateAPICredentials() { - t.Skip() - } - _, err := l.Trade(false, 0, 0, "USD") - if err == nil { - t.Error("Trade() Expected error") - } -} - -func TestGetOpenOrders(t *testing.T) { - t.Parallel() - if !l.ValidateAPICredentials() { - t.Skip() - } - _, err := l.GetOpenOrders() - if err == nil { - t.Error("GetOpenOrders() Expected error") - } -} - -func TestGetOrders(t *testing.T) { - t.Parallel() - if !l.ValidateAPICredentials() { - t.Skip() - } - _, err := l.GetOrders([]int64{1, 2}) - if err == nil { - t.Error("GetOrders() Expected error") - } -} - -func TestCancelOrder(t *testing.T) { - t.Parallel() - if !l.ValidateAPICredentials() { - t.Skip() - } - err := l.CancelExistingOrder(1337) - if err == nil { - t.Error("CancelExistingOrder() Expected error") - } -} - -func TestGetTrades(t *testing.T) { - t.Parallel() - if !l.ValidateAPICredentials() { - t.Skip() - } - _, err := l.GetTrades(1337) - if err == nil { - t.Error("GetTrades() Expected error") - } -} - -func TestGetExternalAccounts(t *testing.T) { - t.Parallel() - if !l.ValidateAPICredentials() { - t.Skip() - } - _, err := l.GetExternalAccounts() - if err == nil { - t.Error("GetExternalAccounts() Expected error") - } -} - -func setFeeBuilder() *exchange.FeeBuilder { - return &exchange.FeeBuilder{ - Amount: 1, - FeeType: exchange.CryptocurrencyTradeFee, - Pair: currency.NewPairWithDelimiter(currency.BTC.String(), - currency.LTC.String(), - "_"), - IsMaker: false, - PurchasePrice: 1, - FiatCurrency: currency.USD, - BankTransactionType: exchange.WireTransfer, - } -} - -// TestGetFeeByTypeOfflineTradeFee logic test -func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { - var feeBuilder = setFeeBuilder() - l.GetFeeByType(feeBuilder) - if !areTestAPIKeysSet() { - if feeBuilder.FeeType != exchange.OfflineTradeFee { - t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType) - } - } else { - if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee { - t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType) - } - } -} - -func TestGetFee(t *testing.T) { - t.Parallel() - var feeBuilder = setFeeBuilder() - // CryptocurrencyTradeFee Basic - if _, err := l.GetFee(feeBuilder); err != nil { - t.Error(err) - } - - // CryptocurrencyTradeFee High quantity - feeBuilder = setFeeBuilder() - feeBuilder.Amount = 1000 - feeBuilder.PurchasePrice = 1000 - if _, err := l.GetFee(feeBuilder); err != nil { - t.Error(err) - } - - // CryptocurrencyTradeFee IsMaker - feeBuilder = setFeeBuilder() - feeBuilder.IsMaker = true - if _, err := l.GetFee(feeBuilder); err != nil { - t.Error(err) - } - - // CryptocurrencyTradeFee Negative purchase price - feeBuilder = setFeeBuilder() - feeBuilder.PurchasePrice = -1000 - if _, err := l.GetFee(feeBuilder); err != nil { - t.Error(err) - } - // CryptocurrencyWithdrawalFee Basic - feeBuilder = setFeeBuilder() - feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee - if _, err := l.GetFee(feeBuilder); err != nil { - t.Error(err) - } - - // CryptocurrencyWithdrawalFee Invalid currency - feeBuilder = setFeeBuilder() - feeBuilder.Pair.Base = currency.NewCode("hello") - feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee - if _, err := l.GetFee(feeBuilder); err != nil { - t.Error(err) - } - - // CryptocurrencyDepositFee Basic - feeBuilder = setFeeBuilder() - feeBuilder.FeeType = exchange.CryptocurrencyDepositFee - if _, err := l.GetFee(feeBuilder); err != nil { - t.Error(err) - } - // InternationalBankDepositFee Basic - feeBuilder = setFeeBuilder() - feeBuilder.FeeType = exchange.InternationalBankDepositFee - if _, err := l.GetFee(feeBuilder); err != nil { - t.Error(err) - } - // InternationalBankWithdrawalFee Basic - feeBuilder = setFeeBuilder() - feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee - feeBuilder.FiatCurrency = currency.USD - if _, err := l.GetFee(feeBuilder); err != nil { - t.Error(err) - } -} - -func TestFormatWithdrawPermissions(t *testing.T) { - expectedResult := exchange.AutoWithdrawCryptoText + " & " + exchange.WithdrawFiatViaWebsiteOnlyText - withdrawPermissions := l.FormatWithdrawPermissions() - if withdrawPermissions != expectedResult { - t.Errorf("Expected: %s, Received: %s", expectedResult, withdrawPermissions) - } -} - -func TestGetActiveOrders(t *testing.T) { - var getOrdersRequest = order.GetOrdersRequest{ - Type: order.AnyType, - AssetType: asset.Spot, - } - - _, err := l.GetActiveOrders(&getOrdersRequest) - if areTestAPIKeysSet() && err != nil { - t.Errorf("Could not get open orders: %s", err) - } else if !areTestAPIKeysSet() && err == nil { - t.Error("Expecting an error when no keys are set") - } -} - -func TestGetOrderHistory(t *testing.T) { - var getOrdersRequest = order.GetOrdersRequest{ - Type: order.AnyType, - AssetType: asset.Spot, - } - - _, err := l.GetOrderHistory(&getOrdersRequest) - if areTestAPIKeysSet() && err != nil { - t.Errorf("Could not get order history: %s", err) - } else if !areTestAPIKeysSet() && err == nil { - t.Error("Expecting an error when no keys are set") - } -} - -// Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them -// ---------------------------------------------------------------------------------------------------------------------------- -func areTestAPIKeysSet() bool { - return l.ValidateAPICredentials() -} - -func TestSubmitOrder(t *testing.T) { - if areTestAPIKeysSet() && !canManipulateRealOrders { - t.Skip("API keys set, canManipulateRealOrders false, skipping test") - } - - var orderSubmission = &order.Submit{ - Pair: currency.Pair{ - Base: currency.BTC, - Quote: currency.EUR, - }, - Side: order.Buy, - Type: order.Limit, - Price: 1, - Amount: 1, - ClientID: "meowOrder", - AssetType: asset.Spot, - } - response, err := l.SubmitOrder(orderSubmission) - if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) { - t.Errorf("Order failed to be placed: %v", err) - } else if !areTestAPIKeysSet() && err == nil { - t.Error("Expecting an error when no keys are set") - } -} - -func TestCancelExchangeOrder(t *testing.T) { - if areTestAPIKeysSet() && !canManipulateRealOrders { - t.Skip("API keys set, canManipulateRealOrders false, skipping test") - } - - currencyPair := currency.NewPair(currency.LTC, currency.BTC) - var orderCancellation = &order.Cancel{ - ID: "1", - WalletAddress: core.BitcoinDonationAddress, - AccountID: "1", - Pair: currencyPair, - AssetType: asset.Spot, - } - - err := l.CancelOrder(orderCancellation) - if !areTestAPIKeysSet() && err == nil { - t.Error("Expecting an error when no keys are set") - } - if areTestAPIKeysSet() && err != nil { - t.Errorf("Could not cancel orders: %v", err) - } -} - -func TestCancelAllExchangeOrders(t *testing.T) { - if areTestAPIKeysSet() && !canManipulateRealOrders { - t.Skip("API keys set, canManipulateRealOrders false, skipping test") - } - - currencyPair := currency.NewPair(currency.LTC, currency.BTC) - var orderCancellation = &order.Cancel{ - ID: "1", - WalletAddress: core.BitcoinDonationAddress, - AccountID: "1", - Pair: currencyPair, - AssetType: asset.Spot, - } - - resp, err := l.CancelAllOrders(orderCancellation) - - if !areTestAPIKeysSet() && err == nil { - t.Error("Expecting an error when no keys are set") - } - if areTestAPIKeysSet() && err != nil { - t.Errorf("Could not cancel orders: %v", err) - } - - if len(resp.Status) > 0 { - t.Errorf("%v orders failed to cancel", len(resp.Status)) - } -} - -func TestModifyOrder(t *testing.T) { - if areTestAPIKeysSet() && !canManipulateRealOrders { - t.Skip("API keys set, canManipulateRealOrders false, skipping test") - } - _, err := l.ModifyOrder(&order.Modify{AssetType: asset.Spot}) - if err == nil { - t.Error("ModifyOrder() Expected error") - } -} - -func TestWithdraw(t *testing.T) { - withdrawCryptoRequest := withdraw.Request{ - Amount: -1, - Currency: currency.BTC, - Description: "WITHDRAW IT ALL", - Crypto: withdraw.CryptoRequest{ - Address: core.BitcoinDonationAddress, - }, - } - - if areTestAPIKeysSet() && !canManipulateRealOrders { - t.Skip("API keys set, canManipulateRealOrders false, skipping test") - } - - _, err := l.WithdrawCryptocurrencyFunds(&withdrawCryptoRequest) - if !areTestAPIKeysSet() && err == nil { - t.Error("Expecting an error when no keys are set") - } - if areTestAPIKeysSet() && err != nil { - t.Errorf("Withdraw failed to be placed: %v", err) - } -} - -func TestWithdrawFiat(t *testing.T) { - if areTestAPIKeysSet() && !canManipulateRealOrders { - t.Skip("API keys set, canManipulateRealOrders false, skipping test") - } - - var withdrawFiatRequest = withdraw.Request{} - _, err := l.WithdrawFiatFunds(&withdrawFiatRequest) - if err != common.ErrFunctionNotSupported { - t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err) - } -} - -func TestWithdrawInternationalBank(t *testing.T) { - if areTestAPIKeysSet() && !canManipulateRealOrders { - t.Skip("API keys set, canManipulateRealOrders false, skipping test") - } - - var withdrawFiatRequest = withdraw.Request{} - _, err := l.WithdrawFiatFundsToInternationalBank(&withdrawFiatRequest) - if err != common.ErrFunctionNotSupported { - t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err) - } -} - -func TestGetDepositAddress(t *testing.T) { - if areTestAPIKeysSet() { - _, err := l.GetDepositAddress(currency.BTC, "") - if err != nil { - t.Error("GetDepositAddress() error", err) - } - } else { - _, err := l.GetDepositAddress(currency.DASH, "") - if err == nil { - t.Error("GetDepositAddress() error cannot be nil") - } - } -} - -// TestWsConn websocket connection test -func TestWsConn(t *testing.T) { - if !l.Websocket.IsEnabled() { - t.Skip(stream.WebsocketNotEnabled) - } - err := l.WsConnect() - if err != nil { - t.Fatal(err) - } -} - -// TestWsTickerProcessing logic test -func TestWsTickerProcessing(t *testing.T) { - json := `{"btcusd":{"low":"10990.05","high":"11966.24","last":"11903.29","volume":"1803.967079","sell":"11912.39","buy":"11902.2"},"btceur":{"low":"9886.87","high":"10732.72","last":"10691.44","volume":"87.994478","sell":"10711.62","buy":"10691.44"},"btchkd":{"low":null,"high":null,"last":"51776.98","volume":null,"sell":"93307.37","buy":"93177.56"},"btcjpy":{"low":"1176039.0","high":"1272246.0","last":"1265680.0","volume":"129.021421","sell":"1266764.0","buy":"1265680.0"},"btcgbp":{"low":"9157.12","high":"9953.43","last":"9941.28","volume":"10.4997","sell":"10007.89","buy":"9941.28"},"btcaud":{"low":"16102.57","high":"17594.22","last":"17548.16","volume":"7.338316","sell":"17616.67","buy":"17549.69"},"btccad":{"low":"14541.69","high":"15834.87","last":"15763.54","volume":"30.480309","sell":"15793.45","buy":"15756.13"},"btcsgd":{"low":"15133.82","high":"16501.62","last":"16455.53","volume":"4.044026","sell":"16484.37","buy":"16462.18"},"btcchf":{"low":"10800.58","high":"11526.24","last":"11526.24","volume":"0.1765","sell":"11675.34","buy":"11632.02"},"btcnzd":{"low":null,"high":null,"last":"8340.98","volume":null,"sell":"18315.49","buy":"18221.37"},"btcngn":{"low":null,"high":null,"last":"600000.0","volume":null,"sell":null,"buy":null},"eurusd":{"low":"1.1088","high":"1.1138","last":"1.1125","volume":"2680.105249","sell":"1.1142","buy":"1.1121"},"gbpusd":{"low":"1.1934","high":"1.1958","last":"1.1934","volume":"1493.923823","sell":"1.1979","buy":"1.1903"},"usdjpy":{"low":"105.26","high":"107.25","last":"106.33","volume":"114490.2179","sell":"106.34","buy":"106.27"},"usdhkd":{"low":null,"high":null,"last":"7.851","volume":null,"sell":"7.8328","buy":"7.8286"},"usdcad":{"low":"1.3225","high":"1.3272","last":"1.3255","volume":"11033.9877","sell":"1.3258","buy":"1.3238"},"usdsgd":{"low":"1.3776","high":"1.3839","last":"1.3838","volume":"2523.75","sell":"1.3838","buy":"1.3819"},"audusd":{"low":"0.6764","high":"0.6853","last":"0.6771","volume":"5442.608321","sell":"0.6782","buy":"0.6762"},"nzdusd":{"low":null,"high":null,"last":"0.6758","volume":null,"sell":"0.6532","buy":"0.6504"},"usdchf":{"low":"0.9838","high":"0.9838","last":"0.9838","volume":"108.3352","sell":"0.9801","buy":"0.9773"},"usdngn":{"low":null,"high":null,"last":"200.0","volume":null,"sell":null,"buy":null},"ethbtc":{"low":"0.0205","high":"0.025","last":"0.0205","volume":null,"sell":"0.03","buy":"0.0194"},"ltcbtc":{"low":null,"high":null,"last":"0.0114","volume":null,"sell":"0.009","buy":"0.0073"},"bchbtc":{"low":null,"high":null,"last":"0.0544","volume":null,"sell":"0.0322","buy":"0.0274"},"xrpbtc":{"low":"0.000042","high":"0.000042","last":"0.000042","volume":null,"sell":"0.000037","buy":"0.000022"},"baceth":{"low":"0.000035","high":"0.000035","last":"0.000035","volume":null,"sell":"0.0015","buy":null}}` - err := l.processTicker(json) - if err != nil { - t.Error(err) - } -} - -func TestGetCurrencyFromChannel(t *testing.T) { - curr := currency.NewPair(currency.LTC, currency.BTC) - result, err := l.getCurrencyFromChannel(marketSubstring + - curr.String() + - globalSubstring) - if err != nil { - t.Fatal(err) - } - - if !curr.Equal(result) { - t.Errorf("currency result is not equal. Expected %v", curr) - } -} - -// TestWsOrderbookProcessing logic test -func TestWsOrderbookProcessing(t *testing.T) { - json := `{"asks":[["11905.66","0.0019"],["11905.73","0.0015"],["11906.43","0.0013"],["11906.62","0.0019"],["11907.25","11.087"],["11907.66","0.0006"],["11907.73","0.3113"],["11907.84","0.0006"],["11908.37","0.0016"],["11908.86","10.3786"],["11909.54","4.2955"],["11910.15","0.0012"],["11910.56","13.5505"],["11911.06","0.0011"],["11911.37","0.0023"]],"bids":[["11905.55","0.0171"],["11904.43","0.0225"],["11903.31","0.0223"],["11902.2","0.0027"],["11901.92","1.002"],["11901.6","0.0015"],["11901.49","0.0012"],["11901.08","0.0227"],["11900.93","0.0009"],["11900.53","1.662"],["11900.08","0.001"],["11900.01","3.6745"],["11899.96","0.003"],["11899.91","0.0006"],["11899.44","0.0013"]]}` - err := l.processOrderbook(json, "market-btcusd-global") - if err != nil { - t.Error(err) - } -} - -func TestGetRecentTrades(t *testing.T) { - t.Parallel() - currencyPair, err := currency.NewPairFromString("BTCUSD") - if err != nil { - t.Fatal(err) - } - _, err = l.GetRecentTrades(currencyPair, asset.Spot) - if err != nil { - t.Error(err) - } -} - -func TestGetHistoricTrades(t *testing.T) { - t.Parallel() - currencyPair, err := currency.NewPairFromString("BTCUSD") - if err != nil { - t.Fatal(err) - } - _, err = l.GetHistoricTrades(currencyPair, asset.Spot, time.Now().Add(-time.Minute*15), time.Now()) - if err != nil && err != common.ErrFunctionNotSupported { - t.Error(err) - } - if err == nil { - t.Error("expected error") - } -} diff --git a/exchanges/lakebtc/lakebtc_types.go b/exchanges/lakebtc/lakebtc_types.go deleted file mode 100644 index e706156d..00000000 --- a/exchanges/lakebtc/lakebtc_types.go +++ /dev/null @@ -1,152 +0,0 @@ -package lakebtc - -import pusher "github.com/toorop/go-pusher" - -// Ticker holds ticker information -type Ticker struct { - Last float64 - Bid float64 - Ask float64 - High float64 - Low float64 - Volume float64 -} - -// OrderbookStructure stores price and amount for order books -type OrderbookStructure struct { - Price float64 - Amount float64 -} - -// Orderbook contains arrays of orderbook information -type Orderbook struct { - Bids []OrderbookStructure `json:"bids"` - Asks []OrderbookStructure `json:"asks"` -} - -// TickerResponse stores temp response -// Silly hack due to API returning null instead of strings -type TickerResponse struct { - Last interface{} - Bid interface{} - Ask interface{} - High interface{} - Low interface{} - Volume interface{} -} - -// TradeHistory holds trade history data -type TradeHistory struct { - Date int64 `json:"date"` - Price float64 `json:"price,string"` - Amount float64 `json:"amount,string"` - TID int64 `json:"tid"` -} - -// AccountInfo contains account information -type AccountInfo struct { - Balance map[string]string `json:"balance"` - Locked map[string]string `json:"locked"` - Profile struct { - Email string `json:"email"` - UID string `json:"uid"` - BTCDepositAddress string `json:"btc_deposit_addres"` // nolint // API misspelling - } `json:"profile"` -} - -// Trade holds trade information -type Trade struct { - ID int64 `json:"id"` - Result string `json:"result"` -} - -// OpenOrders stores full information on your open orders -type OpenOrders struct { - ID int64 `json:"id"` - Amount float64 `json:"amount,string"` - Price float64 `json:"price,string"` - Symbol string `json:"symbol"` - Type string `json:"type"` - At int64 `json:"at"` -} - -// Orders holds current order information -type Orders struct { - ID int64 `json:"id"` - OriginalAmount float64 `json:"original_amount,string"` - Amount float64 `json:"amount,string"` - Price float64 `json:"price,string"` - Symbol string `json:"symbol"` - Type string `json:"type"` - State string `json:"state"` - At int64 `json:"at"` -} - -// AuthenticatedTradeHistory is a store of personalised auth trade history -type AuthenticatedTradeHistory struct { - Type string `json:"type"` - Symbol string `json:"symbol"` - Amount float64 `json:"amount,string"` - Total float64 `json:"total,string"` - At int64 `json:"at"` -} - -// ExternalAccounts holds external account information -type ExternalAccounts struct { - ID int64 `json:"id,string"` - Type string `json:"type"` - Address string `json:"address"` - Alias interface{} `json:"alias"` - Currencies string `json:"currencies"` - State string `json:"state"` - UpdatedAt int64 `json:"updated_at,string"` -} - -// Withdraw holds withdrawal information -type Withdraw struct { - ID int64 `json:"id,string"` - Amount float64 `json:"amount,string"` - Currency string `json:"currency"` - Fee float64 `json:"fee,string"` - State string `json:"state"` - Source string `json:"source"` - ExternalAccountID int64 `json:"external_account_id,string"` - At int64 `json:"at"` - Error string `json:"error"` -} - -// WebsocketConn defines a pusher websocket connection -type WebsocketConn struct { - Client *pusher.Client - Ticker chan *pusher.Event - Orderbook chan *pusher.Event - Trade chan *pusher.Event -} - -// WsOrderbookUpdate contains orderbook data from websocket -type WsOrderbookUpdate struct { - Asks [][2]string `json:"asks"` - Bids [][2]string `json:"bids"` -} - -// WsTrades contains trade data from websocket -type WsTrades struct { - Trades []WsTrade `json:"trades"` -} - -// WsTrade contains individual trade details from websocket -type WsTrade struct { - Type string `json:"type"` - Date int64 `json:"date"` - Price float64 `json:"price,string"` - Amount float64 `json:"amount,string"` -} - -type wsTicker struct { - Low float64 `json:"low,string"` - High float64 `json:"high,string"` - Last float64 `json:"last,string"` - Volume float64 `json:"volume,string"` - Sell float64 `json:"sell,string"` - Buy float64 `json:"buy,string"` -} diff --git a/exchanges/lakebtc/lakebtc_websocket.go b/exchanges/lakebtc/lakebtc_websocket.go deleted file mode 100644 index b4624eab..00000000 --- a/exchanges/lakebtc/lakebtc_websocket.go +++ /dev/null @@ -1,261 +0,0 @@ -package lakebtc - -import ( - "encoding/json" - "errors" - "fmt" - "strconv" - "strings" - "time" - - "github.com/thrasher-corp/gocryptotrader/common" - "github.com/thrasher-corp/gocryptotrader/currency" - "github.com/thrasher-corp/gocryptotrader/exchanges/asset" - "github.com/thrasher-corp/gocryptotrader/exchanges/orderbook" - "github.com/thrasher-corp/gocryptotrader/exchanges/stream" - "github.com/thrasher-corp/gocryptotrader/exchanges/ticker" - "github.com/thrasher-corp/gocryptotrader/log" - "github.com/toorop/go-pusher" -) - -const ( - lakeBTCWSURL = "wss://ws.lakebtc.com:8085" - marketGlobalEndpoint = "market-global" - marketSubstring = "market-" - globalSubstring = "-global" - wssSchem = "wss" -) - -// WsConnect initiates a new websocket connection -func (l *LakeBTC) WsConnect() error { - if !l.Websocket.IsEnabled() || !l.IsEnabled() { - return errors.New(stream.WebsocketNotEnabled) - } - - url := strings.Split(lakeBTCWSURL, "://") - var err error - l.WebsocketConn.Client, err = pusher.NewCustomClient(strings.ToLower(l.Name), - url[1], - wssSchem) - if err != nil { - return err - } - err = l.WebsocketConn.Client.Subscribe(marketGlobalEndpoint) - if err != nil { - return err - } - - err = l.listenToEndpoints() - if err != nil { - return err - } - go l.wsHandleIncomingData() - return nil -} - -func (l *LakeBTC) listenToEndpoints() error { - var err error - l.WebsocketConn.Ticker, err = l.WebsocketConn.Client.Bind("tickers") - if err != nil { - return fmt.Errorf("%s Websocket Bind error: %s", l.Name, err) - } - l.WebsocketConn.Orderbook, err = l.WebsocketConn.Client.Bind("update") - if err != nil { - return fmt.Errorf("%s Websocket Bind error: %s", l.Name, err) - } - // LakeBTC does not provide enough trade data to sync to the trade database table - // please use REST until the API is updated - // l.WebsocketConn.Trade, err = l.WebsocketConn.Client.Bind("trades") - return nil -} - -// GenerateDefaultSubscriptions Adds default subscriptions to websocket to be handled by ManageSubscriptions() -func (l *LakeBTC) GenerateDefaultSubscriptions() ([]stream.ChannelSubscription, error) { - var subscriptions []stream.ChannelSubscription - enabledCurrencies, err := l.GetEnabledPairs(asset.Spot) - if err != nil { - return nil, err - } - - for j := range enabledCurrencies { - enabledCurrencies[j].Delimiter = "" - channel := marketSubstring + - enabledCurrencies[j].Lower().String() + - globalSubstring - - subscriptions = append(subscriptions, stream.ChannelSubscription{ - Channel: channel, - Currency: enabledCurrencies[j], - Asset: asset.Spot, - }) - } - return subscriptions, nil -} - -// Subscribe sends a websocket message to receive data from the channel -func (l *LakeBTC) Subscribe(channelsToSubscribe []stream.ChannelSubscription) error { - var errs common.Errors - for i := range channelsToSubscribe { - err := l.WebsocketConn.Client.Subscribe(channelsToSubscribe[i].Channel) - if err != nil { - errs = append(errs, err) - continue - } - l.Websocket.AddSuccessfulSubscriptions(channelsToSubscribe[i]) - } - if errs != nil { - return errs - } - return nil -} - -// Unsubscribe sends a websocket message to unsubscribe from the channel -func (l *LakeBTC) Unsubscribe(channelsToUnsubscribe []stream.ChannelSubscription) error { - var errs common.Errors - for i := range channelsToUnsubscribe { - err := l.WebsocketConn.Client.Unsubscribe(channelsToUnsubscribe[i].Channel) - if err != nil { - errs = append(errs, err) - continue - } - l.Websocket.RemoveSuccessfulUnsubscriptions(channelsToUnsubscribe[i]) - } - if errs != nil { - return errs - } - return nil -} - -// wsHandleIncomingData services incoming data from the websocket connection -func (l *LakeBTC) wsHandleIncomingData() { - l.Websocket.Wg.Add(1) - defer l.Websocket.Wg.Done() - - for { - select { - case <-l.Websocket.ShutdownC: - return - case data := <-l.WebsocketConn.Ticker: - if l.Verbose { - log.Debugf(log.ExchangeSys, - "%v Websocket message received: %v", l.Name, data) - } - err := l.processTicker(data.Data) - if err != nil { - l.Websocket.DataHandler <- err - } - case data := <-l.WebsocketConn.Orderbook: - if l.Verbose { - log.Debugf(log.ExchangeSys, - "%v Websocket message received: %v", l.Name, data) - } - err := l.processOrderbook(data.Data, data.Channel) - if err != nil { - l.Websocket.DataHandler <- err - } - } - select { - case l.Websocket.TrafficAlert <- struct{}{}: - default: - } - } -} - -func (l *LakeBTC) processOrderbook(obUpdate, channel string) error { - var update WsOrderbookUpdate - err := json.Unmarshal([]byte(obUpdate), &update) - if err != nil { - return err - } - - p, err := l.getCurrencyFromChannel(channel) - if err != nil { - return err - } - - book := orderbook.Base{ - Pair: p, - LastUpdated: time.Now(), - Asset: asset.Spot, - Exchange: l.Name, - VerifyOrderbook: l.CanVerifyOrderbook, - } - - for i := range update.Asks { - var amount, price float64 - amount, err = strconv.ParseFloat(update.Asks[i][1], 64) - if err != nil { - return err - } - price, err = strconv.ParseFloat(update.Asks[i][0], 64) - if err != nil { - return err - } - book.Asks = append(book.Asks, orderbook.Item{ - Amount: amount, - Price: price, - }) - } - - for i := range update.Bids { - var amount, price float64 - amount, err = strconv.ParseFloat(update.Bids[i][1], 64) - if err != nil { - return err - } - price, err = strconv.ParseFloat(update.Bids[i][0], 64) - if err != nil { - return err - } - book.Bids = append(book.Bids, orderbook.Item{ - Amount: amount, - Price: price, - }) - } - - return l.Websocket.Orderbook.LoadSnapshot(&book) -} - -func (l *LakeBTC) getCurrencyFromChannel(channel string) (currency.Pair, error) { - curr := strings.Replace(channel, marketSubstring, "", 1) - curr = strings.Replace(curr, globalSubstring, "", 1) - return currency.NewPairFromString(curr) -} - -func (l *LakeBTC) processTicker(data string) error { - var tUpdate map[string]wsTicker - err := json.Unmarshal([]byte(data), &tUpdate) - if err != nil { - l.Websocket.DataHandler <- err - return err - } - - enabled, err := l.GetEnabledPairs(asset.Spot) - if err != nil { - return err - } - - for k, v := range tUpdate { - returnCurrency, err := currency.NewPairFromString(k) - if err != nil { - return err - } - - if !enabled.Contains(returnCurrency, true) { - continue - } - - l.Websocket.DataHandler <- &ticker.Price{ - ExchangeName: l.Name, - Bid: v.Buy, - High: v.High, - Last: v.Last, - Low: v.Low, - Ask: v.Sell, - Volume: v.Volume, - AssetType: asset.Spot, - Pair: returnCurrency, - } - } - return nil -} diff --git a/exchanges/lakebtc/lakebtc_wrapper.go b/exchanges/lakebtc/lakebtc_wrapper.go deleted file mode 100644 index 93b69159..00000000 --- a/exchanges/lakebtc/lakebtc_wrapper.go +++ /dev/null @@ -1,654 +0,0 @@ -package lakebtc - -import ( - "errors" - "fmt" - "sort" - "strconv" - "strings" - "sync" - "time" - - "github.com/thrasher-corp/gocryptotrader/common" - "github.com/thrasher-corp/gocryptotrader/config" - "github.com/thrasher-corp/gocryptotrader/currency" - exchange "github.com/thrasher-corp/gocryptotrader/exchanges" - "github.com/thrasher-corp/gocryptotrader/exchanges/account" - "github.com/thrasher-corp/gocryptotrader/exchanges/asset" - "github.com/thrasher-corp/gocryptotrader/exchanges/kline" - "github.com/thrasher-corp/gocryptotrader/exchanges/order" - "github.com/thrasher-corp/gocryptotrader/exchanges/orderbook" - "github.com/thrasher-corp/gocryptotrader/exchanges/protocol" - "github.com/thrasher-corp/gocryptotrader/exchanges/request" - "github.com/thrasher-corp/gocryptotrader/exchanges/stream" - "github.com/thrasher-corp/gocryptotrader/exchanges/ticker" - "github.com/thrasher-corp/gocryptotrader/exchanges/trade" - "github.com/thrasher-corp/gocryptotrader/log" - "github.com/thrasher-corp/gocryptotrader/portfolio/withdraw" -) - -// GetDefaultConfig returns a default exchange config -func (l *LakeBTC) GetDefaultConfig() (*config.ExchangeConfig, error) { - l.SetDefaults() - exchCfg := new(config.ExchangeConfig) - exchCfg.Name = l.Name - exchCfg.HTTPTimeout = exchange.DefaultHTTPTimeout - exchCfg.BaseCurrencies = l.BaseCurrencies - - err := l.SetupDefaults(exchCfg) - if err != nil { - return nil, err - } - - if l.Features.Supports.RESTCapabilities.AutoPairUpdates { - err = l.UpdateTradablePairs(true) - if err != nil { - return nil, err - } - } - - return exchCfg, nil -} - -// SetDefaults sets LakeBTC defaults -func (l *LakeBTC) SetDefaults() { - l.Name = "LakeBTC" - l.Enabled = true - l.Verbose = true - l.API.CredentialsValidator.RequiresKey = true - l.API.CredentialsValidator.RequiresSecret = true - - requestFmt := ¤cy.PairFormat{Uppercase: true} - configFmt := ¤cy.PairFormat{Uppercase: true} - err := l.SetGlobalPairsManager(requestFmt, configFmt, asset.Spot) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - - l.Features = exchange.Features{ - Supports: exchange.FeaturesSupported{ - REST: true, - Websocket: true, - RESTCapabilities: protocol.Features{ - TickerBatching: true, - TickerFetching: true, - TradeFetching: true, - OrderbookFetching: true, - AutoPairUpdates: true, - AccountInfo: true, - GetOrder: true, - GetOrders: true, - CancelOrders: true, - CancelOrder: true, - SubmitOrder: true, - UserTradeHistory: true, - CryptoWithdrawal: true, - TradeFee: true, - CryptoDepositFee: true, - }, - WebsocketCapabilities: protocol.Features{ - TradeFetching: true, - OrderbookFetching: true, - Subscribe: true, - Unsubscribe: true, - }, - WithdrawPermissions: exchange.AutoWithdrawCrypto | - exchange.WithdrawFiatViaWebsiteOnly, - }, - Enabled: exchange.FeaturesEnabled{ - AutoPairUpdates: true, - }, - } - - l.Requester = request.New(l.Name, - common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout)) - l.API.Endpoints = l.NewEndpoints() - err = l.API.Endpoints.SetDefaultEndpoints(map[exchange.URL]string{ - exchange.RestSpot: lakeBTCAPIURL, - exchange.WebsocketSpot: lakeBTCWSURL, - }) - if err != nil { - log.Errorln(log.ExchangeSys, err) - } - l.Websocket = stream.New() - l.WebsocketResponseMaxLimit = exchange.DefaultWebsocketResponseMaxLimit - l.WebsocketResponseCheckTimeout = exchange.DefaultWebsocketResponseCheckTimeout - l.WebsocketOrderbookBufferLimit = exchange.DefaultWebsocketOrderbookBufferLimit -} - -// Setup sets exchange configuration profile -func (l *LakeBTC) Setup(exch *config.ExchangeConfig) error { - if !exch.Enabled { - l.SetEnabled(false) - return nil - } - - err := l.SetupDefaults(exch) - if err != nil { - return err - } - - wsRunningURL, err := l.API.Endpoints.GetURL(exchange.WebsocketSpot) - if err != nil { - return err - } - - return l.Websocket.Setup(&stream.WebsocketSetup{ - Enabled: exch.Features.Enabled.Websocket, - Verbose: exch.Verbose, - AuthenticatedWebsocketAPISupport: exch.API.AuthenticatedWebsocketSupport, - WebsocketTimeout: exch.WebsocketTrafficTimeout, - DefaultURL: lakeBTCWSURL, - ExchangeName: exch.Name, - RunningURL: wsRunningURL, - Connector: l.WsConnect, - Subscriber: l.Subscribe, - UnSubscriber: l.Unsubscribe, - GenerateSubscriptions: l.GenerateDefaultSubscriptions, - Features: &l.Features.Supports.WebsocketCapabilities, - OrderbookBufferLimit: exch.OrderbookConfig.WebsocketBufferLimit, - BufferEnabled: exch.OrderbookConfig.WebsocketBufferEnabled, - }) -} - -// Start starts the LakeBTC go routine -func (l *LakeBTC) Start(wg *sync.WaitGroup) { - wg.Add(1) - go func() { - l.Run() - wg.Done() - }() -} - -// Run implements the LakeBTC wrapper -func (l *LakeBTC) Run() { - if l.Verbose { - l.PrintEnabledPairs() - } - - if !l.GetEnabledFeatures().AutoPairUpdates { - return - } - - err := l.UpdateTradablePairs(false) - if err != nil { - log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", l.Name, err) - } -} - -// FetchTradablePairs returns a list of the exchanges tradable pairs -func (l *LakeBTC) FetchTradablePairs(asset asset.Item) ([]string, error) { - result, err := l.GetTicker() - if err != nil { - return nil, err - } - - var currencies []string - for x := range result { - currencies = append(currencies, strings.ToUpper(x)) - } - - return currencies, nil -} - -// UpdateTradablePairs updates the exchanges available pairs and stores -// them in the exchanges config -func (l *LakeBTC) UpdateTradablePairs(forceUpdate bool) error { - pairs, err := l.FetchTradablePairs(asset.Spot) - if err != nil { - return err - } - - p, err := currency.NewPairsFromStrings(pairs) - if err != nil { - return err - } - return l.UpdatePairs(p, asset.Spot, false, forceUpdate) -} - -// UpdateTicker updates and returns the ticker for a currency pair -func (l *LakeBTC) UpdateTicker(p currency.Pair, assetType asset.Item) (*ticker.Price, error) { - ticks, err := l.GetTicker() - if err != nil { - return nil, err - } - - pairs, err := l.GetEnabledPairs(assetType) - if err != nil { - return nil, err - } - - for i := range pairs { - fpair, err := l.FormatExchangeCurrency(pairs[i], assetType) - if err != nil { - return nil, err - } - - c, ok := ticks[fpair.String()] - if !ok { - continue - } - - tickerPrice := new(ticker.Price) - tickerPrice.Pair = pairs[i] - tickerPrice.Ask = c.Ask - tickerPrice.Bid = c.Bid - tickerPrice.Volume = c.Volume - tickerPrice.High = c.High - tickerPrice.Low = c.Low - tickerPrice.Last = c.Last - tickerPrice.ExchangeName = l.Name - tickerPrice.AssetType = assetType - - err = ticker.ProcessTicker(tickerPrice) - if err != nil { - return nil, err - } - } - return ticker.GetTicker(l.Name, p, assetType) -} - -// FetchTicker returns the ticker for a currency pair -func (l *LakeBTC) FetchTicker(p currency.Pair, assetType asset.Item) (*ticker.Price, error) { - fPair, err := l.FormatExchangeCurrency(p, assetType) - if err != nil { - return nil, err - } - - tickerNew, err := ticker.GetTicker(l.Name, fPair, assetType) - if err != nil { - return l.UpdateTicker(fPair, assetType) - } - return tickerNew, nil -} - -// FetchOrderbook returns orderbook base on the currency pair -func (l *LakeBTC) FetchOrderbook(p currency.Pair, assetType asset.Item) (*orderbook.Base, error) { - fPair, err := l.FormatExchangeCurrency(p, assetType) - if err != nil { - return nil, err - } - - ob, err := orderbook.Get(l.Name, fPair, assetType) - if err != nil { - return l.UpdateOrderbook(fPair, assetType) - } - return ob, nil -} - -// UpdateOrderbook updates and returns the orderbook for a currency pair -func (l *LakeBTC) UpdateOrderbook(p currency.Pair, assetType asset.Item) (*orderbook.Base, error) { - book := &orderbook.Base{ - Exchange: l.Name, - Pair: p, - Asset: assetType, - VerifyOrderbook: l.CanVerifyOrderbook, - } - fPair, err := l.FormatExchangeCurrency(p, assetType) - if err != nil { - return book, err - } - - orderbookNew, err := l.GetOrderBook(fPair.String()) - if err != nil { - return book, err - } - - for x := range orderbookNew.Bids { - book.Bids = append(book.Bids, orderbook.Item{ - Amount: orderbookNew.Bids[x].Amount, - Price: orderbookNew.Bids[x].Price}) - } - - for x := range orderbookNew.Asks { - book.Asks = append(book.Asks, orderbook.Item{ - Amount: orderbookNew.Asks[x].Amount, - Price: orderbookNew.Asks[x].Price}) - } - err = book.Process() - if err != nil { - return book, err - } - return orderbook.Get(l.Name, fPair, assetType) -} - -// UpdateAccountInfo retrieves balances for all enabled currencies for the -// LakeBTC exchange -func (l *LakeBTC) UpdateAccountInfo(assetType asset.Item) (account.Holdings, error) { - var response account.Holdings - response.Exchange = l.Name - accountInfo, err := l.GetAccountInformation() - if err != nil { - return response, err - } - - var currencies []account.Balance - for x, y := range accountInfo.Balance { - for z, w := range accountInfo.Locked { - if z != x { - continue - } - var exchangeCurrency account.Balance - exchangeCurrency.CurrencyName = currency.NewCode(x) - exchangeCurrency.TotalValue, _ = strconv.ParseFloat(y, 64) - exchangeCurrency.Hold, _ = strconv.ParseFloat(w, 64) - currencies = append(currencies, exchangeCurrency) - } - } - - response.Accounts = append(response.Accounts, account.SubAccount{ - Currencies: currencies, - }) - - err = account.Process(&response) - if err != nil { - return account.Holdings{}, err - } - - return response, nil -} - -// FetchAccountInfo retrieves balances for all enabled currencies -func (l *LakeBTC) FetchAccountInfo(assetType asset.Item) (account.Holdings, error) { - acc, err := account.GetHoldings(l.Name, assetType) - if err != nil { - return l.UpdateAccountInfo(assetType) - } - - return acc, nil -} - -// GetFundingHistory returns funding history, deposits and -// withdrawals -func (l *LakeBTC) GetFundingHistory() ([]exchange.FundHistory, error) { - return nil, common.ErrFunctionNotSupported -} - -// GetWithdrawalsHistory returns previous withdrawals data -func (l *LakeBTC) GetWithdrawalsHistory(c currency.Code) (resp []exchange.WithdrawalHistory, err error) { - return nil, common.ErrNotYetImplemented -} - -// GetRecentTrades returns the most recent trades for a currency and asset -func (l *LakeBTC) GetRecentTrades(p currency.Pair, assetType asset.Item) ([]trade.Data, error) { - var err error - p, err = l.FormatExchangeCurrency(p, assetType) - if err != nil { - return nil, err - } - var resp []trade.Data - var tradeData []TradeHistory - tradeData, err = l.GetTradeHistory(p.String()) - if err != nil { - return nil, err - } - for i := range tradeData { - tradeTS := time.Unix(tradeData[i].Date, 0) - resp = append(resp, trade.Data{ - TID: strconv.FormatInt(tradeData[i].TID, 10), - Exchange: l.Name, - CurrencyPair: p, - AssetType: assetType, - Price: tradeData[i].Price, - Amount: tradeData[i].Amount, - Timestamp: tradeTS, - }) - } - - err = l.AddTradesToBuffer(resp...) - if err != nil { - return nil, err - } - - sort.Sort(trade.ByDate(resp)) - return resp, nil -} - -// GetHistoricTrades returns historic trade data within the timeframe provided -func (l *LakeBTC) GetHistoricTrades(_ currency.Pair, _ asset.Item, _, _ time.Time) ([]trade.Data, error) { - return nil, common.ErrFunctionNotSupported -} - -// SubmitOrder submits a new order -func (l *LakeBTC) SubmitOrder(s *order.Submit) (order.SubmitResponse, error) { - var submitOrderResponse order.SubmitResponse - if err := s.Validate(); err != nil { - return submitOrderResponse, err - } - - fPair, err := l.FormatExchangeCurrency(s.Pair, s.AssetType) - if err != nil { - return submitOrderResponse, err - } - - isBuyOrder := s.Side == order.Buy - response, err := l.Trade(isBuyOrder, - s.Amount, - s.Price, - fPair.Lower().String()) - if err != nil { - return submitOrderResponse, err - } - if response.ID > 0 { - submitOrderResponse.OrderID = strconv.FormatInt(response.ID, 10) - } - - submitOrderResponse.IsOrderPlaced = true - if s.Type == order.Market { - submitOrderResponse.FullyMatched = true - } - return submitOrderResponse, nil -} - -// ModifyOrder will allow of changing orderbook placement and limit to -// market conversion -func (l *LakeBTC) ModifyOrder(action *order.Modify) (string, error) { - return "", common.ErrFunctionNotSupported -} - -// CancelOrder cancels an order by its corresponding ID number -func (l *LakeBTC) CancelOrder(o *order.Cancel) error { - if err := o.Validate(o.StandardCancel()); err != nil { - return err - } - - orderIDInt, err := strconv.ParseInt(o.ID, 10, 64) - if err != nil { - return err - } - - return l.CancelExistingOrder(orderIDInt) -} - -// CancelBatchOrders cancels an orders by their corresponding ID numbers -func (l *LakeBTC) CancelBatchOrders(o []order.Cancel) (order.CancelBatchResponse, error) { - return order.CancelBatchResponse{}, common.ErrNotYetImplemented -} - -// CancelAllOrders cancels all orders associated with a currency pair -func (l *LakeBTC) CancelAllOrders(_ *order.Cancel) (order.CancelAllResponse, error) { - var cancelAllOrdersResponse order.CancelAllResponse - openOrders, err := l.GetOpenOrders() - if err != nil { - return cancelAllOrdersResponse, err - } - - var ordersToCancel []string - for i := range openOrders { - ordersToCancel = append(ordersToCancel, strconv.FormatInt(openOrders[i].ID, 10)) - } - - return cancelAllOrdersResponse, l.CancelExistingOrders(ordersToCancel) -} - -// GetOrderInfo returns order information based on order ID -func (l *LakeBTC) GetOrderInfo(orderID string, pair currency.Pair, assetType asset.Item) (order.Detail, error) { - var orderDetail order.Detail - return orderDetail, common.ErrNotYetImplemented -} - -// GetDepositAddress returns a deposit address for a specified currency -func (l *LakeBTC) GetDepositAddress(cryptocurrency currency.Code, _ string) (string, error) { - if !strings.EqualFold(cryptocurrency.String(), currency.BTC.String()) { - return "", fmt.Errorf("unsupported currency %s deposit address can only be BTC, manual deposit is required for other currencies", - cryptocurrency.String()) - } - - info, err := l.GetAccountInformation() - if err != nil { - return "", err - } - - return info.Profile.BTCDepositAddress, nil -} - -// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is -// submitted -func (l *LakeBTC) WithdrawCryptocurrencyFunds(withdrawRequest *withdraw.Request) (*withdraw.ExchangeResponse, error) { - if err := withdrawRequest.Validate(); err != nil { - return nil, err - } - if withdrawRequest.Currency != currency.BTC { - return nil, errors.New("only BTC supported for withdrawals") - } - - resp, err := l.CreateWithdraw(withdrawRequest.Amount, withdrawRequest.Description) - if err != nil { - return nil, err - } - - return &withdraw.ExchangeResponse{ - ID: strconv.FormatInt(resp.ID, 10), - }, nil -} - -// WithdrawFiatFunds returns a withdrawal ID when a -// withdrawal is submitted -func (l *LakeBTC) WithdrawFiatFunds(_ *withdraw.Request) (*withdraw.ExchangeResponse, error) { - return nil, common.ErrFunctionNotSupported -} - -// WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a -// withdrawal is submitted -func (l *LakeBTC) WithdrawFiatFundsToInternationalBank(_ *withdraw.Request) (*withdraw.ExchangeResponse, error) { - return nil, common.ErrFunctionNotSupported -} - -// GetFeeByType returns an estimate of fee based on type of transaction -func (l *LakeBTC) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) { - if !l.AllowAuthenticatedRequest() && // Todo check connection status - feeBuilder.FeeType == exchange.CryptocurrencyTradeFee { - feeBuilder.FeeType = exchange.OfflineTradeFee - } - return l.GetFee(feeBuilder) -} - -// GetActiveOrders retrieves any orders that are active/open -func (l *LakeBTC) GetActiveOrders(req *order.GetOrdersRequest) ([]order.Detail, error) { - if err := req.Validate(); err != nil { - return nil, err - } - - resp, err := l.GetOpenOrders() - if err != nil { - return nil, err - } - - format, err := l.GetPairFormat(asset.Spot, false) - if err != nil { - return nil, err - } - - var orders []order.Detail - for i := range resp { - var symbol currency.Pair - symbol, err = currency.NewPairDelimiter(resp[i].Symbol, - format.Delimiter) - if err != nil { - return nil, err - } - orderDate := time.Unix(resp[i].At, 0) - side := order.Side(strings.ToUpper(resp[i].Type)) - - orders = append(orders, order.Detail{ - Amount: resp[i].Amount, - ID: strconv.FormatInt(resp[i].ID, 10), - Price: resp[i].Price, - Side: side, - Date: orderDate, - Pair: symbol, - Exchange: l.Name, - }) - } - - order.FilterOrdersByTimeRange(&orders, req.StartTime, req.EndTime) - order.FilterOrdersBySide(&orders, req.Side) - order.FilterOrdersByCurrencies(&orders, req.Pairs) - - return orders, nil -} - -// GetOrderHistory retrieves account order information -// Can Limit response to specific order status -func (l *LakeBTC) GetOrderHistory(req *order.GetOrdersRequest) ([]order.Detail, error) { - if err := req.Validate(); err != nil { - return nil, err - } - - resp, err := l.GetOrders([]int64{}) - if err != nil { - return nil, err - } - - format, err := l.GetPairFormat(asset.Spot, false) - if err != nil { - return nil, err - } - - var orders []order.Detail - for i := range resp { - if resp[i].State == "active" { - continue - } - var symbol currency.Pair - symbol, err = currency.NewPairDelimiter(resp[i].Symbol, format.Delimiter) - if err != nil { - return nil, err - } - orderDate := time.Unix(resp[i].At, 0) - side := order.Side(strings.ToUpper(resp[i].Type)) - - orders = append(orders, order.Detail{ - Amount: resp[i].Amount, - ID: strconv.FormatInt(resp[i].ID, 10), - Price: resp[i].Price, - Side: side, - Date: orderDate, - Pair: symbol, - Exchange: l.Name, - }) - } - - order.FilterOrdersByTimeRange(&orders, req.StartTime, req.EndTime) - order.FilterOrdersBySide(&orders, req.Side) - order.FilterOrdersByCurrencies(&orders, req.Pairs) - - return orders, nil -} - -// ValidateCredentials validates current credentials used for wrapper -// functionality -func (l *LakeBTC) ValidateCredentials(assetType asset.Item) error { - _, err := l.UpdateAccountInfo(assetType) - return l.CheckTransientError(err) -} - -// GetHistoricCandles returns candles between a time period for a set time interval -func (l *LakeBTC) GetHistoricCandles(pair currency.Pair, a asset.Item, start, end time.Time, interval kline.Interval) (kline.Item, error) { - return kline.Item{}, common.ErrFunctionNotSupported -} - -// GetHistoricCandlesExtended returns candles between a time period for a set time interval -func (l *LakeBTC) GetHistoricCandlesExtended(pair currency.Pair, a asset.Item, start, end time.Time, interval kline.Interval) (kline.Item, error) { - return kline.Item{}, common.ErrFunctionNotSupported -} diff --git a/exchanges/lbank/lbank_wrapper.go b/exchanges/lbank/lbank_wrapper.go index a7da426f..ae72a6b2 100644 --- a/exchanges/lbank/lbank_wrapper.go +++ b/exchanges/lbank/lbank_wrapper.go @@ -139,7 +139,7 @@ func (l *Lbank) Setup(exch *config.ExchangeConfig) error { return nil } -// Start starts the LakeBTC go routine +// Start starts the Lbank go routine func (l *Lbank) Start(wg *sync.WaitGroup) { wg.Add(1) go func() { diff --git a/exchanges/orderbook/orderbook.go b/exchanges/orderbook/orderbook.go index 78663995..d15768c0 100644 --- a/exchanges/orderbook/orderbook.go +++ b/exchanges/orderbook/orderbook.go @@ -225,7 +225,7 @@ func (b *Base) Verify() error { } // Checking for both ask and bid lengths being zero has been removed and - // a warning has been put in place some exchanges e.g. LakeBTC return zero + // a warning has been put in place for some exchanges that return zero // level books. In the event that there is a massive liquidity change where // a book dries up, this will still update so we do not traverse potential // incorrect old data. diff --git a/exchanges/support.go b/exchanges/support.go index 4cd8a546..ef165c5c 100644 --- a/exchanges/support.go +++ b/exchanges/support.go @@ -34,7 +34,6 @@ var Exchanges = []string{ "huobi", "itbit", "kraken", - "lakebtc", "lbank", "localbitcoins", "okcoin international", diff --git a/exchanges/trade/README.md b/exchanges/trade/README.md index 41616058..2a9deb9e 100644 --- a/exchanges/trade/README.md +++ b/exchanges/trade/README.md @@ -80,7 +80,6 @@ _b in this context is an `IBotExchange` implemented struct_ | Huobi.Pro | Yes | Yes | No | | ItBit | Yes | NA | No | | Kraken | Yes | Yes | No | -| LakeBTC | Yes | No | No | | Lbank | Yes | No | Yes | | LocalBitcoins | Yes | NA | No | | OKCoin International | Yes | Yes | No | diff --git a/go.mod b/go.mod index 0294cf01..d939202a 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,6 @@ require ( github.com/thrasher-corp/gct-ta v0.0.0-20200623072738-f2b55b7f9f41 github.com/thrasher-corp/goose v2.7.0-rc4.0.20191002032028-0f2c2a27abdb+incompatible github.com/thrasher-corp/sqlboiler v1.0.1-0.20191001234224-71e17f37a85e - github.com/toorop/go-pusher v0.0.0-20180521062818-4521e2eb39fb github.com/urfave/cli/v2 v2.3.0 github.com/volatiletech/inflect v0.0.1 // indirect github.com/volatiletech/null v8.0.0+incompatible diff --git a/go.sum b/go.sum index ca416158..b2a62892 100644 --- a/go.sum +++ b/go.sum @@ -369,8 +369,6 @@ github.com/thrasher-corp/goose v2.7.0-rc4.0.20191002032028-0f2c2a27abdb+incompat github.com/thrasher-corp/sqlboiler v1.0.1-0.20191001234224-71e17f37a85e h1:4kYBo2YhqqFY7aZPPEhrtPTMoAq4iCsoDITd3jseRbY= github.com/thrasher-corp/sqlboiler v1.0.1-0.20191001234224-71e17f37a85e/go.mod h1:JfJE+3gijF30ZJbUCzxGkU0+ymQxBfBOVp4XDObmJBE= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/toorop/go-pusher v0.0.0-20180521062818-4521e2eb39fb h1:9kcmLvQdiIecpgVEL3/+J5QIP/ElRBJDljOay0SvqnA= -github.com/toorop/go-pusher v0.0.0-20180521062818-4521e2eb39fb/go.mod h1:VTLqNCX1tXrur6pdIRCl8Q90FR7nw/mEBdyMkWMcsb0= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= diff --git a/testdata/configtest.json b/testdata/configtest.json index 0f8f5324..5096e20f 100644 --- a/testdata/configtest.json +++ b/testdata/configtest.json @@ -1647,82 +1647,6 @@ } ] }, - { - "name": "LakeBTC", - "enabled": true, - "verbose": false, - "httpTimeout": 15000000000, - "websocketResponseCheckTimeout": 30000000, - "websocketResponseMaxLimit": 7000000000, - "websocketTrafficTimeout": 30000000000, - "websocketOrderbookBufferLimit": 5, - "baseCurrencies": "USD,EUR,HKD,AUD,GBP,NZD,JPY,SGD,NGN,CHF,CAD", - "currencyPairs": { - "requestFormat": { - "uppercase": true - }, - "configFormat": { - "uppercase": true - }, - "useGlobalFormat": true, - "assetTypes": [ - "spot" - ], - "pairs": { - "spot": { - "enabled": "BTCUSD,BTCEUR,LTCBTC", - "available": "USDCAD,USDSGD,BTCUSD,GBPUSD,LTCBTC,BCHBTC,USDJPY,USDCHF,EURUSD,ETHBTC,XRPBTC,USDHKD,BTCGBP,BTCNZD,NZDUSD,BTCNGN,BTCHKD,BTCAUD,BTCEUR,BTCCHF,AUDUSD,USDNGN,BACETH,BTCJPY,BTCCAD,BTCSGD" - } - } - }, - "api": { - "authenticatedSupport": false, - "authenticatedWebsocketApiSupport": false, - "endpoints": { - "url": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API", - "urlSecondary": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API", - "websocketURL": "NON_DEFAULT_HTTP_LINK_TO_WEBSOCKET_EXCHANGE_API" - }, - "credentials": { - "key": "Key", - "secret": "Secret" - }, - "credentialsValidator": { - "requiresKey": true, - "requiresSecret": true - } - }, - "features": { - "supports": { - "restAPI": true, - "restCapabilities": { - "tickerBatching": true, - "autoPairUpdates": true - }, - "websocketAPI": true, - "websocketCapabilities": {} - }, - "enabled": { - "autoPairUpdates": true, - "websocketAPI": true - } - }, - "bankAccounts": [ - { - "enabled": false, - "bankName": "", - "bankAddress": "", - "bankPostalCode": "", - "bankPostalCity": "", - "bankCountry": "", - "accountName": "", - "accountNumber": "", - "swiftCode": "", - "iban": "", - "supportedCurrencies": "" - } - ] - }, { "name": "LocalBitcoins", "enabled": true, diff --git a/testdata/exchangelist.csv b/testdata/exchangelist.csv index b9abd82e..29da937f 100644 --- a/testdata/exchangelist.csv +++ b/testdata/exchangelist.csv @@ -18,7 +18,6 @@ hitbtc, huobi, itbit, kraken, -lakebtc, lbank, localbitcoins, okcoin international,