Exchanges: Remove LakeBTC exchange implementation (#713)

* Remove LakeBTC exchange

* Remove more LakeBTC remnants

* Update LBank comment

* go mod tiderinos

* Remove LakeBTC from backup.json file
This commit is contained in:
Adrian Gallagher
2021-07-14 13:24:32 +10:00
committed by GitHub
parent 9527614431
commit 214ae37b7c
29 changed files with 4 additions and 2451 deletions

View File

@@ -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 |

View File

@@ -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)

View File

@@ -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}`,

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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 |

View File

@@ -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}}

View File

@@ -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 |

View File

@@ -136,11 +136,6 @@
"secret": "Secret",
"otpSecret": "-"
},
"lakebtc": {
"key": "Key",
"secret": "Secret",
"otpSecret": "-"
},
"lbank": {
"key": "Key",
"secret": "Secret",

View File

@@ -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,

View File

@@ -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",

View File

@@ -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 |

View File

@@ -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":

View File

@@ -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" {

View File

@@ -1,133 +0,0 @@
# GoCryptoTrader package Lakebtc
<img src="/common/gctlogo.png?raw=true" width="350px" height="350px" hspace="70">
[![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
<img src="https://github.com/thrasher-corp/gocryptotrader/blob/master/web/src/assets/donate.png?raw=true" hspace="70">
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
***bc1qk0jareu4jytc0cfrhr5wgshsq8282awpavfahc***

View File

@@ -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&params=%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
}

View File

@@ -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")
}
}

View File

@@ -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"`
}

View File

@@ -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
}

View File

@@ -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 := &currency.PairFormat{Uppercase: true}
configFmt := &currency.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
}

View File

@@ -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() {

View File

@@ -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.

View File

@@ -34,7 +34,6 @@ var Exchanges = []string{
"huobi",
"itbit",
"kraken",
"lakebtc",
"lbank",
"localbitcoins",
"okcoin international",

View File

@@ -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 |

1
go.mod
View File

@@ -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

2
go.sum
View File

@@ -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=

View File

@@ -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,

View File

@@ -18,7 +18,6 @@ hitbtc,
huobi,
itbit,
kraken,
lakebtc,
lbank,
localbitcoins,
okcoin international,
1 binance
18 huobi
19 itbit
20 kraken
lakebtc
21 lbank
22 localbitcoins
23 okcoin international