mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
exchanges: remove Coinbene exchange support (#849)
* exchanges: remove Coinbene exchange support * RM Coinbene from apichecker backup
This commit is contained in:
@@ -29,7 +29,6 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
|
||||
| BTCMarkets | Yes | Yes | NA |
|
||||
| BTSE | Yes | Yes | NA |
|
||||
| CoinbasePro | Yes | Yes | No|
|
||||
| Coinbene | Yes | Yes | No |
|
||||
| COINUT | Yes | Yes | NA |
|
||||
| Exmo | Yes | NA | NA |
|
||||
| FTX | Yes | Yes | No |
|
||||
|
||||
@@ -78,28 +78,6 @@
|
||||
},
|
||||
"Disabled": false
|
||||
},
|
||||
{
|
||||
"Name": "CoinbeneSpot",
|
||||
"CheckType": "GitHub Sha Check",
|
||||
"Data": {
|
||||
"GitHubData": {
|
||||
"Repo": "Coinbene/API-SPOT-v2-Documents",
|
||||
"Sha": "e9135a782ba6016bcf008778be368882ad7c784d"
|
||||
}
|
||||
},
|
||||
"Disabled": false
|
||||
},
|
||||
{
|
||||
"Name": "CoinbeneSwap",
|
||||
"CheckType": "GitHub Sha Check",
|
||||
"Data": {
|
||||
"GitHubData": {
|
||||
"Repo": "Coinbene/API-SWAP-Documents",
|
||||
"Sha": "6b7871dae4d2af028a33dde956fbce101e2f9acd"
|
||||
}
|
||||
},
|
||||
"Disabled": false
|
||||
},
|
||||
{
|
||||
"Name": "Coinut",
|
||||
"CheckType": "GitHub Sha Check",
|
||||
|
||||
@@ -83,28 +83,6 @@
|
||||
},
|
||||
"Disabled": false
|
||||
},
|
||||
{
|
||||
"Name": "CoinbeneSpot",
|
||||
"CheckType": "GitHub Sha Check",
|
||||
"Data": {
|
||||
"GitHubData": {
|
||||
"Repo": "Coinbene/API-SPOT-v2-Documents",
|
||||
"Sha": "e9135a782ba6016bcf008778be368882ad7c784d"
|
||||
}
|
||||
},
|
||||
"Disabled": false
|
||||
},
|
||||
{
|
||||
"Name": "CoinbeneSwap",
|
||||
"CheckType": "GitHub Sha Check",
|
||||
"Data": {
|
||||
"GitHubData": {
|
||||
"Repo": "Coinbene/API-SWAP-Documents",
|
||||
"Sha": "6b7871dae4d2af028a33dde956fbce101e2f9acd"
|
||||
}
|
||||
},
|
||||
"Disabled": false
|
||||
},
|
||||
{
|
||||
"Name": "Coinut",
|
||||
"CheckType": "GitHub Sha Check",
|
||||
|
||||
@@ -83,28 +83,6 @@
|
||||
},
|
||||
"Disabled": false
|
||||
},
|
||||
{
|
||||
"Name": "CoinbeneSpot",
|
||||
"CheckType": "GitHub Sha Check",
|
||||
"Data": {
|
||||
"GitHubData": {
|
||||
"Repo": "Coinbene/API-SPOT-v2-Documents",
|
||||
"Sha": "e9135a782ba6016bcf008778be368882ad7c784d"
|
||||
}
|
||||
},
|
||||
"Disabled": false
|
||||
},
|
||||
{
|
||||
"Name": "CoinbeneSwap",
|
||||
"CheckType": "GitHub Sha Check",
|
||||
"Data": {
|
||||
"GitHubData": {
|
||||
"Repo": "Coinbene/API-SWAP-Documents",
|
||||
"Sha": "6b7871dae4d2af028a33dde956fbce101e2f9acd"
|
||||
}
|
||||
},
|
||||
"Disabled": false
|
||||
},
|
||||
{
|
||||
"Name": "Coinut",
|
||||
"CheckType": "GitHub Sha Check",
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
{{define "exchanges coinbene" -}}
|
||||
{{template "header" .}}
|
||||
## Coinbene 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 c exchange.IBotExchange
|
||||
|
||||
for i := range Bot.Exchanges {
|
||||
if Bot.Exchanges[i].GetName() == "Coinbene" {
|
||||
c = Bot.Exchanges[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Public calls - wrapper functions
|
||||
|
||||
// Fetches current ticker information
|
||||
tick, err := c.FetchTicker()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches current orderbook information
|
||||
ob, err := c.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 := c.GetAccountInfo()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
+ If enabled via individually importing package, rudimentary example below:
|
||||
|
||||
```go
|
||||
// Public calls
|
||||
|
||||
// Fetches current ticker information
|
||||
ticker, err := c.GetTicker()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches current orderbook information
|
||||
ob, err := c.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 := c.GetUserInfo(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Submits an order and the exchange and returns its tradeID
|
||||
resp, err := c.SubmitOrder(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
### How to do Websocket public/private calls
|
||||
|
||||
```go
|
||||
// Exchanges will be abstracted out in further updates and examples will be
|
||||
// supplied then
|
||||
```
|
||||
|
||||
### Please click GoDocs chevron above to view current GoDoc information for this package
|
||||
{{template "contributions"}}
|
||||
{{template "donations" .}}
|
||||
{{end}}
|
||||
@@ -51,7 +51,6 @@ _b in this context is an `IBotExchange` implemented struct_
|
||||
| Bittrex | Yes | Yes | No |
|
||||
| BTCMarkets | Yes | Yes | No |
|
||||
| BTSE | Yes | Yes | No |
|
||||
| Coinbene | Yes | Yes | No |
|
||||
| CoinbasePro | Yes | Yes | No|
|
||||
| COINUT | Yes | Yes | No |
|
||||
| Exmo | Yes | NA | No |
|
||||
|
||||
@@ -30,7 +30,6 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
|
||||
| BTCMarkets | Yes | Yes | NA |
|
||||
| BTSE | Yes | Yes | NA |
|
||||
| CoinbasePro | Yes | Yes | No|
|
||||
| Coinbene | Yes | Yes | No |
|
||||
| COINUT | Yes | Yes | NA |
|
||||
| Exmo | Yes | NA | NA |
|
||||
| FTX | Yes | Yes | No |
|
||||
|
||||
@@ -86,11 +86,6 @@
|
||||
"clientID": "ClientID",
|
||||
"otpSecret": "-"
|
||||
},
|
||||
"coinbene": {
|
||||
"key": "Key",
|
||||
"secret": "Secret",
|
||||
"otpSecret": "-"
|
||||
},
|
||||
"coinut": {
|
||||
"key": "Key",
|
||||
"clientID": "ClientID",
|
||||
|
||||
@@ -1208,95 +1208,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Coinbene",
|
||||
"enabled": true,
|
||||
"verbose": false,
|
||||
"httpTimeout": 15000000000,
|
||||
"websocketResponseCheckTimeout": 30000000,
|
||||
"websocketResponseMaxLimit": 7000000000,
|
||||
"websocketTrafficTimeout": 30000000000,
|
||||
"websocketOrderbookBufferLimit": 5,
|
||||
"baseCurrencies": "USD",
|
||||
"currencyPairs": {
|
||||
"assetTypes": [
|
||||
"spot",
|
||||
"perpetualswap"
|
||||
],
|
||||
"pairs": {
|
||||
"perpetualswap": {
|
||||
"enabled": "BTC/USDT",
|
||||
"available": "LTC/USDT,EOS/USDT,ETH/USDT,BTC/USDT",
|
||||
"requestFormat": {
|
||||
"uppercase": true
|
||||
},
|
||||
"configFormat": {
|
||||
"uppercase": true,
|
||||
"delimiter": "/"
|
||||
}
|
||||
},
|
||||
"spot": {
|
||||
"enabled": "BTC/USDT",
|
||||
"available": "ABBC/BTC,ABBC/USDT,ABT/ETH,ABT/USDT,ABYSS/ETH,ACDC/USDT,ADA/USDT,ADK/BTC,ADN/BTC,AE/BTC,AE/USDT,AIDOC/BTC,AIDUS/BTC,AION/BTC,AIPE/USDT,ALI/ETH,ALX/ETH,AMDC/USDT,APL/ETH,ATX/BTC,BAAS/BTC,BAT/BTC,BCH/USDT,BCT/USDT,BETHER/ETH,BEZ/BTC,BGC/USDT,BKG/BTC,BNB/USDT,BNT/BTC,BOA/USDT,BR/USDT,BSTN/ETH,BSV/BTC,BSV/USDT,BTC/USDT,BTCV/BTC,BTNT/BTC,BVT/ETH,CCC/ETH,CCE/USDT,CEDEX/ETH,CFT/USDT,CMT/ETH,CMT/USDT,CNN/BTC,CNN/ETH,CNN/USDT,CONI/USDT,COSM/BTC,COSM/ETH,CPM1/USDT,CPS/BTC,CREDO/ETH,CRN/BTC,CSCC/USDT,CTCN/USDT,CTXC/ETH,CUST/USDT,CVC/BTC,DASH/USDT,DDAM/ETH,DDAM/USDT,DENT/BTC,DGD/BTC,DTA/ETH,DVC/ETH,EBC/BTC,EBC/ETH,EBC/USDT,ECA/BTC,ECP/BTC,EDC/BTC,EDR/ETH,EHT/USDT,ELF/BTC,EOS/BTC,EOS/USDT,EQUAD/BTC,ESH/BTC,ETC/BTC,ETC/USDT,ETH/BTC,ETH/USDT,ETK/BTC,ETN/BTC,EXO/USDT,FAB/ETH,FCR/USDT,FND/ETH,FNKOS/ETH,FTN/BTC,FTN/USDT,FTT/BTC,FXT/ETH,GDC/BTC,GDC/ETH,GDC/USDT,GETX/ETH,GOM2/USDT,GRAM/USDT,GRN/BTC,GUSD/USDT,GVT/BTC,HAPPY/BTC,HDAC/BTC,HMB/USDT,HNB/USDT,HTDF/USDT,HT/USDT,HUP/USDT,INCX/ETH,IOST/BTC,IOTE/USDT,ISR/ETH,IVY/ETH,JOB/BTC,KBC/BTC,KBC/USDT,KMD/BTC,KNT/ETH,KST/BTC,KUKY/BTC,LAMB/USDT,LATX/BTC,LBK/BTC,LINK/BTC,LOOM/BTC,LP/USDT,LTC/BTC,LTC/USDT,LUC/ETH,LUCKY/USDT,LUX/BTC,LVTC/ETH,MC/USDT,MIB/BTC,MINX/BTC,MOAC/USDT,MTC/BTC,MTN/ETH,MT/USDT,MVL/ETH,MXM/ETH,MXM/USDT,MZG/USDT,NANO/BTC,NBAI/ETH,NEO/BTC,NEO/USDT,NOBS/BTC,NPXS/USDT,NTY/ETH,ODC/USDT,OKB/USDT,OMG/BTC,OMX/ETH,OVC/ETH,OZX/ETH,PAT/ETH,PAX/USDT,PLF/USDT,PMA/ETH,POLL/BTC,POLY/BTC,PPT/BTC,PSM/BTC,PWT/USDT,QKC/BTC,QTUM/BTC,QTUM/USDT,RBTC/BTC,RCOIN/BTC,RCOIN/USDT,REP/BTC,REV/BTC,RIF/BTC,SBT/USDT,SCC/BTC,SEN/BTC,SHE/BTC,SHVR/BTC,SIM/BTC,SKB/BTC,SKM/ETH,SKYM/USDT,SLT/ETH,SMARTUP/USDT,SMART/USDT,SORO/USDT,SRCOIN/BTC,SRCOIN/ETH,STORJ/BTC,SWET/BTC,SWTC/USDT,SWYFTT/BTC,TCT/BTC,TEN/BTC,TEN/ETH,THC/USDT,TIB/BTC,TMTG/BTC,TOC/USDT,TOSC/BTC,TRUE/ETH,TRX/BTC,TRX/USDT,TWEE/USDT,UTNP/BTC,VEEN/BTC,VME/BTC,VME/ETH,VSC/ETH,W12/BTC,W12/ETH,WBL/BTC,WBX/USDT,WFX/BTC,XEM/BTC,XLM/BTC,XMR/BTC,XNK/ETH,XRP/BTC,XRP/USDT,XSR/USDT,YAP/BTC,YAP/USDT,YTA/USDT,ZAT/ETH,ZEC/BTC,ZEC/USDT,ZRX/BTC",
|
||||
"requestFormat": {
|
||||
"uppercase": true,
|
||||
"delimiter": "/"
|
||||
},
|
||||
"configFormat": {
|
||||
"uppercase": true,
|
||||
"delimiter": "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"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",
|
||||
"clientID": "ClientID"
|
||||
},
|
||||
"credentialsValidator": {
|
||||
"requiresKey": true,
|
||||
"requiresSecret": true
|
||||
}
|
||||
},
|
||||
"features": {
|
||||
"supports": {
|
||||
"restAPI": true,
|
||||
"restCapabilities": {
|
||||
"autoPairUpdates": true
|
||||
},
|
||||
"websocketAPI": true,
|
||||
"websocketCapabilities": {}
|
||||
},
|
||||
"enabled": {
|
||||
"autoPairUpdates": true,
|
||||
"websocketAPI": false
|
||||
}
|
||||
},
|
||||
"bankAccounts": [
|
||||
{
|
||||
"enabled": false,
|
||||
"bankName": "",
|
||||
"bankAddress": "",
|
||||
"bankPostalCode": "",
|
||||
"bankPostalCity": "",
|
||||
"bankCountry": "",
|
||||
"accountName": "",
|
||||
"accountNumber": "",
|
||||
"swiftCode": "",
|
||||
"iban": "",
|
||||
"supportedCurrencies": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "FTX",
|
||||
"enabled": true,
|
||||
|
||||
@@ -209,7 +209,6 @@ Yes means supported, No means not yet implemented and NA means protocol unsuppor
|
||||
| Exmo | Yes | NA | NA |
|
||||
| FTX | Yes | Yes | No | // <-------- new exchange
|
||||
| CoinbasePro | Yes | Yes | No|
|
||||
| Coinbene | Yes | No | No |
|
||||
| GateIO | Yes | Yes | NA |
|
||||
| Gemini | Yes | Yes | No |
|
||||
| HitBTC | Yes | Yes | No |
|
||||
@@ -238,7 +237,6 @@ var Exchanges = []string{
|
||||
"btc markets",
|
||||
"btse",
|
||||
"coinbasepro",
|
||||
"coinbene",
|
||||
"coinut",
|
||||
"exmo",
|
||||
"ftx", // <-------- new exchange
|
||||
|
||||
@@ -53,7 +53,6 @@ $ ./gctcli withdrawcryptofunds --exchange=ftx --currency=USDT --address=TJU9piX2
|
||||
| BTCMarkets | No | No| NA |
|
||||
| BTSE | No | No | Only through website |
|
||||
| CoinbasePro | No | No | No|
|
||||
| Coinbene | Yes | Yes | Addresses must be created via their website first |
|
||||
| COINUT | No | No | NA |
|
||||
| Exmo | Yes | Yes | Addresses must be created via their website first |
|
||||
| FTX | Yes | Yes | |
|
||||
|
||||
@@ -75,7 +75,6 @@ A helper tool [cmd/dbseed](../cmd/dbseed/README.md) has been created for assisti
|
||||
| Bittrex | |
|
||||
| BTSE | Y |
|
||||
| Coinbase Pro | Y |
|
||||
| Coinbene | Y |
|
||||
| Coinut | |
|
||||
| Exmo | |
|
||||
| GateIO | Y |
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/btcmarkets"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/btse"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/coinbasepro"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/coinbene"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/coinut"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/exmo"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/ftx"
|
||||
@@ -160,8 +159,6 @@ func (m *ExchangeManager) NewExchangeByName(name string) (exchange.IBotExchange,
|
||||
exch = new(btcmarkets.BTCMarkets)
|
||||
case "btse":
|
||||
exch = new(btse.BTSE)
|
||||
case "coinbene":
|
||||
exch = new(coinbene.Coinbene)
|
||||
case "coinut":
|
||||
exch = new(coinut.COINUT)
|
||||
case "exmo":
|
||||
|
||||
@@ -82,7 +82,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", "lbank", "localbitcoins", "okcoin international", "okex", "poloniex", "yobit", "zb", "fake"}
|
||||
exchanges := []string{"binance", "bitfinex", "bitflyer", "bithumb", "bitmex", "bitstamp", "bittrex", "btc markets", "btse", "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" {
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
# GoCryptoTrader package Coinbene
|
||||
|
||||
<img src="/common/gctlogo.png?raw=true" width="350px" height="350px" hspace="70">
|
||||
|
||||
|
||||
[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
|
||||
[](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE)
|
||||
[](https://godoc.org/github.com/thrasher-corp/gocryptotrader/exchanges/coinbene)
|
||||
[](http://codecov.io/github/thrasher-corp/gocryptotrader?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/thrasher-corp/gocryptotrader)
|
||||
|
||||
|
||||
This coinbene 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)
|
||||
|
||||
## Coinbene 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 c exchange.IBotExchange
|
||||
|
||||
for i := range Bot.Exchanges {
|
||||
if Bot.Exchanges[i].GetName() == "Coinbene" {
|
||||
c = Bot.Exchanges[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Public calls - wrapper functions
|
||||
|
||||
// Fetches current ticker information
|
||||
tick, err := c.FetchTicker()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches current orderbook information
|
||||
ob, err := c.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 := c.GetAccountInfo()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
+ If enabled via individually importing package, rudimentary example below:
|
||||
|
||||
```go
|
||||
// Public calls
|
||||
|
||||
// Fetches current ticker information
|
||||
ticker, err := c.GetTicker()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Fetches current orderbook information
|
||||
ob, err := c.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 := c.GetUserInfo(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// Submits an order and the exchange and returns its tradeID
|
||||
resp, err := c.SubmitOrder(...)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
### How to do Websocket public/private calls
|
||||
|
||||
```go
|
||||
// Exchanges will be abstracted out in further updates and examples will be
|
||||
// supplied then
|
||||
```
|
||||
|
||||
### 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***
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,892 +0,0 @@
|
||||
package coinbene
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
"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"
|
||||
"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/sharedtestvalues"
|
||||
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
|
||||
)
|
||||
|
||||
// Please supply your own keys here for due diligence testing
|
||||
const (
|
||||
testAPIKey = ""
|
||||
testAPISecret = ""
|
||||
canManipulateRealOrders = false
|
||||
spotTestPair = "BTC/USDT"
|
||||
swapTestPair = "BTC-SWAP"
|
||||
)
|
||||
|
||||
var c Coinbene
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
c.SetDefaults()
|
||||
cfg := config.GetConfig()
|
||||
err := cfg.LoadConfig("../../testdata/configtest.json", true)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
coinbeneConfig, err := cfg.GetExchangeConfig("Coinbene")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
coinbeneConfig.API.AuthenticatedWebsocketSupport = true
|
||||
coinbeneConfig.API.AuthenticatedSupport = true
|
||||
coinbeneConfig.API.Credentials.Secret = testAPISecret
|
||||
coinbeneConfig.API.Credentials.Key = testAPIKey
|
||||
c.Websocket = sharedtestvalues.NewTestWebsocket()
|
||||
err = c.Setup(coinbeneConfig)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func areTestAPIKeysSet() bool {
|
||||
return c.AllowAuthenticatedRequest()
|
||||
}
|
||||
|
||||
func TestStart(t *testing.T) {
|
||||
t.Parallel()
|
||||
err := c.Start(nil)
|
||||
if !errors.Is(err, common.ErrNilPointer) {
|
||||
t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer)
|
||||
}
|
||||
var testWg sync.WaitGroup
|
||||
err = c.Start(&testWg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testWg.Wait()
|
||||
}
|
||||
|
||||
func TestGetAllPairs(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := c.GetAllPairs(context.Background())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPairInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := c.GetPairInfo(context.Background(), spotTestPair)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderbook(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := c.GetOrderbook(context.Background(), spotTestPair, 100)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := c.GetTicker(context.Background(), spotTestPair)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := c.GetTrades(context.Background(), spotTestPair, 100)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAcounntBalances(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
_, err := c.GetAccountBalances(context.Background())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccountAssetBalance(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
_, err := c.GetAccountAssetBalance(context.Background(), currency.BTC.String())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlaceOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
|
||||
}
|
||||
_, err := c.PlaceSpotOrder(context.Background(),
|
||||
1,
|
||||
1,
|
||||
spotTestPair,
|
||||
order.Buy.Lower(),
|
||||
order.Limit.Lower(),
|
||||
"Sup3rAw3s0m3Cl13ntiDH",
|
||||
0,
|
||||
)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlaceOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
|
||||
}
|
||||
|
||||
_, err := c.PlaceSpotOrders(context.Background(),
|
||||
[]PlaceOrderRequest{
|
||||
{
|
||||
1,
|
||||
1,
|
||||
spotTestPair,
|
||||
order.Buy.Lower(),
|
||||
order.Limit.Lower(),
|
||||
"Sup3rAw3s0m3Cl13ntiDH",
|
||||
0,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchOpenOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
_, err := c.FetchOpenSpotOrders(context.Background(), spotTestPair)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchClosedOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
_, err := c.FetchClosedOrders(context.Background(), spotTestPair, "")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchOrderInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
_, err := c.FetchSpotOrderInfo(context.Background(), "adfjashjgsag")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDepositAddress(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
_, err := c.GetDepositAddress(context.Background(), currency.USDT, "", "ETH")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdraw(t *testing.T) {
|
||||
t.Parallel()
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
|
||||
withdrawCryptoRequest := withdraw.Request{
|
||||
Exchange: c.Name,
|
||||
Amount: -1,
|
||||
Currency: currency.BTC,
|
||||
Description: "WITHDRAW IT ALL",
|
||||
Crypto: withdraw.CryptoRequest{
|
||||
Address: core.BitcoinDonationAddress,
|
||||
},
|
||||
}
|
||||
|
||||
_, err := c.WithdrawCryptocurrencyFunds(context.Background(), &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 TestGetSpotOrderFills(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
_, err := c.GetSpotOrderFills(context.Background(), "1912131427156307968")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelSpotOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
|
||||
}
|
||||
_, err := c.CancelSpotOrder(context.Background(), "adfjashjgsag")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelSpotOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
|
||||
}
|
||||
|
||||
_, err := c.CancelSpotOrders(context.Background(),
|
||||
[]string{"578639816552972288", "578639902896914432"})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
cp, err := currency.NewPairFromString(spotTestPair)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = c.UpdateTicker(context.Background(), cp, asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
cp, err = currency.NewPairFromString(swapTestPair)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = c.UpdateTicker(context.Background(), cp, asset.PerpetualSwap)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateTickers(t *testing.T) {
|
||||
// TODO: fix Coinbene rate limiting that will allow to uncomment the next line
|
||||
// and enable parallel testing
|
||||
// t.Parallel()
|
||||
err := c.UpdateTickers(context.Background(), asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
err = c.UpdateTickers(context.Background(), asset.PerpetualSwap)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccountInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
_, err := c.UpdateAccountInfo(context.Background(), asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateOrderbook(t *testing.T) {
|
||||
t.Parallel()
|
||||
cp, err := currency.NewPairFromString(spotTestPair)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = c.UpdateOrderbook(context.Background(), cp, asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
cp, err = currency.NewPairFromString(swapTestPair)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = c.UpdateOrderbook(context.Background(), cp, asset.PerpetualSwap)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSwapTickers(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := c.GetSwapTickers(context.Background())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSwapTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := c.GetSwapTicker(context.Background(), swapTestPair)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSwapOrderbook(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := c.GetSwapOrderbook(context.Background(), swapTestPair, 100)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetKlines(t *testing.T) {
|
||||
t.Parallel()
|
||||
p, err := currency.NewPairFromString(spotTestPair)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = c.GetKlines(context.Background(),
|
||||
p.String(),
|
||||
time.Now().Add(-time.Hour*1),
|
||||
time.Now(),
|
||||
"1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSwapKlines(t *testing.T) {
|
||||
t.Parallel()
|
||||
p, err := currency.NewPairFromString(swapTestPair)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = c.GetSwapKlines(context.Background(),
|
||||
p.String(),
|
||||
time.Now().Add(-time.Hour*1),
|
||||
time.Now(),
|
||||
"1")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSwapTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := c.GetSwapTrades(context.Background(), swapTestPair, 10)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSwapInstruments(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := c.GetSwapInstruments(context.Background())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSwapAccountInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
_, err := c.GetSwapAccountInfo(context.Background())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSwapPositions(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("API keys required but not set, skipping test")
|
||||
}
|
||||
_, err := c.GetSwapPositions(context.Background(), swapTestPair)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlaceSwapOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
|
||||
}
|
||||
|
||||
_, err := c.PlaceSwapOrder(context.Background(),
|
||||
swapTestPair,
|
||||
order.Buy.Lower(),
|
||||
"limit",
|
||||
"fixed",
|
||||
"12345",
|
||||
1,
|
||||
1,
|
||||
2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelSwapOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
|
||||
}
|
||||
|
||||
_, err := c.CancelSwapOrder(context.Background(), "1337")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOpenSwapOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
|
||||
}
|
||||
|
||||
_, err := c.GetSwapOpenOrders(context.Background(), swapTestPair, 0, 0)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSwapOpenOrdersByPage(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
|
||||
}
|
||||
|
||||
_, err := c.GetSwapOpenOrdersByPage(context.Background(), swapTestPair, 0)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSwapOrderInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
|
||||
}
|
||||
|
||||
_, err := c.GetSwapOrderInfo(context.Background(), "1337")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSwapOrderHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
|
||||
}
|
||||
|
||||
_, err := c.GetSwapOrderHistory(context.Background(),
|
||||
"", "", swapTestPair, 1, 10, "", "")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSwapOrderHistoryByOrderID(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
|
||||
}
|
||||
|
||||
_, err := c.GetSwapOrderHistoryByOrderID(context.Background(),
|
||||
"", "", swapTestPair, "", 0)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelSwapOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
|
||||
}
|
||||
|
||||
_, err := c.CancelSwapOrders(context.Background(),
|
||||
[]string{"578639816552972288", "578639902896914432"})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSwapOrderFills(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
|
||||
}
|
||||
|
||||
_, err := c.GetSwapOrderFills(context.Background(),
|
||||
swapTestPair, "5807143157122003", 580714315825905664)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSwapFundingRates(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip("skipping test, either api keys or manipulaterealorders isnt set correctly")
|
||||
}
|
||||
|
||||
_, err := c.GetSwapFundingRates(context.Background(), 1, 2)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWsSubscribe(t *testing.T) {
|
||||
pressXToJSON := []byte(`{"event":"subscribe","topic":"orderBook.BTCUSDT.10"}`)
|
||||
err := c.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWsUnsubscribe(t *testing.T) {
|
||||
pressXToJSON := []byte(`{"event":"unsubscribe","topic":"tradeList.BTCUSDT"}`)
|
||||
err := c.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWsLogin(t *testing.T) {
|
||||
pressXToJSON := []byte(`{"event":"login","success":true}`)
|
||||
err := c.wsHandleData(pressXToJSON)
|
||||
if err == nil {
|
||||
t.Error("error cannot be nil as this will initiate an auth subscription")
|
||||
}
|
||||
|
||||
pressXToJSON = []byte(`{"event":"login","success":false}`)
|
||||
err = c.wsHandleData(pressXToJSON)
|
||||
if err == nil {
|
||||
t.Error("Expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWsOrderbook(t *testing.T) {
|
||||
pressXToJSON := []byte(`{"topic":"spot/orderBook.BTCUSDT","action":"insert","data":[{"bids":[["0.00000015","174215.91"],["0.00000012","600000.00"],["0.00000010","10000.00"],["0.00000006","33333.00"],["0.00000004","50000.00"],["0.00000003","2000000.00"],["0.00000002","100000.00"],["0.00000001","1100000.00"]],"asks":[["0.00000262","5152.79"],["0.00000263","44626.00"],["0.00000340","2649.85"],["0.00000398","20056.93"],["0.00000400","1420385.54"],["0.00000790","8594.85"],["0.00000988","42380.97"],["0.00000997","43850.97"],["0.00001398","10541.59"],["0.00001400","3409.29"],["0.00002636","52.11"],["0.00002810","2543.66"],["0.00003200","1018.36"],["0.00004999","19.81"],["0.00005000","400.00"],["0.00005898","4060.56"],["0.00006498","3302.60"],["0.00006668","4060.56"],["0.00008000","400.00"]],"version":4915,"timestamp":1598529668288}]}`)
|
||||
err := c.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
pressXToJSON = []byte(`{"topic":"spot/orderBook.BTCUSDT","action":"update","data":[{"bids":[["2.983","8696"]],"asks":[["3.113","0"]],"version":34600866,"timestamp":1598587478738}]}`)
|
||||
err = c.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWsTrade(t *testing.T) {
|
||||
pressXToJSON := []byte(`{"data":[["0.00000050","s","37.00",1598500505000],["0.00000060","s","10.00",1598499782000],["0.00000066","s","1.00",1598499782000],["0.00000067","s","1.00",1598499782000],["0.00000068","s","1.00",1598499745000],["0.00000080","b","1.00",1598262728000],["0.00000089","b","5592.81",1597738441000],["0.00000072","b","1.00",1597693134000],["0.00000069","s","21739.13",1597378140000],["0.00000069","s","1.00",1597378140000],["0.00000074","b","1.00",1597354497000],["0.00000079","b","1.00",1597325675000],["0.00000082","b","1.00",1597162162000],["0.00000089","b","1.00",1597084892000],["0.00000073","b","109404.43",1597015827000],["0.00000070","b","1067.00",1597015827000],["0.00000070","b","1.00",1594732841000],["0.00000070","b","10.00",1592178569000],["0.00000065","b","194.76",1592178545000],["0.00000064","b","2.37",1592105641000],["0.00000064","b","3.00",1592087828000],["0.00000045","b","5.00",1592087828000],["0.00000045","b","5.00",1592004274000],["0.00000030","s","100.00",1591931268000],["0.00000020","b","138.12",1591928623000],["0.00000020","b","55027.66",1591928623000],["0.00000020","b","59880.11",1591572812000],["0.00000021","s","138.12",1590413750000],["0.00000021","s","5.37",1590413750000],["0.00000056","s","1.00",1589567228000],["0.00000065","b","1.00",1589567217000],["0.00000060","b","84890.64",1589407481000],["0.00000060","b","17.13",1589407433000],["0.00000060","b","9148.70",1589389270000],["0.00000059","b","9010.00",1589389159000],["0.00000055","b","3876.00",1589389098000],["0.00000055","b","30000.00",1588899981000],["0.00000055","b","5724.00",1588891192000],["0.00000050","b","400.00",1588891192000],["0.00000048","b","26874.64",1588891129000],["0.00000048","b","2.00",1588891129000],["0.00000049","b","7547.75",1585279296000],["0.00000049","b","12180.30",1584932828000],["0.00000049","b","8256.95",1584932828000],["0.00000053","b","500.42",1583351500000],["0.00000053","b","500.00",1583351484000],["0.00000053","b","400.00",1583351470000],["0.00000053","b","394.62",1583351455000],["0.00000053","b","1.99",1583343633000],["0.00000018","s","250.00",1583338813000]],"topic":"spot/tradeList.BTCUSDT","action":"insert"}`)
|
||||
err := c.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWsTicker(t *testing.T) {
|
||||
pressXToJSON := []byte(`{"topic": "spot/ticker.BTCUSDT","action":"insert","data": [{"symbol":"BTCUSDT","lastPrice":"23.3746","bestAskPrice":"23.3885","bestBidPrice":"23.3603","high24h":"23.5773","open24h":"22.1961","openPrice":"22.5546","low24h":"21.8077","volume24h":"3784807.9709","timestamp":1598587472634}]}`)
|
||||
err := c.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWsKLine(t *testing.T) {
|
||||
pressXToJSON := []byte(`{"topic": "spot/kline.BTCUSDT.1h","action":"insert","data": [{"t":1594990800,"o":1.1e-07,"h":1.1e-07,"l":1.1e-07,"c":1.1e-07,"v":0}]}`)
|
||||
err := c.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWsUserAccount(t *testing.T) {
|
||||
pressXToJSON := []byte(`{
|
||||
"topic": "btc/user.account",
|
||||
"data": [{
|
||||
"asset": "BTC",
|
||||
"availableBalance": "20.3859",
|
||||
"frozenBalance": "0.7413",
|
||||
"balance": "21.1272",
|
||||
"timestamp": "2019-05-22T03:11:22.0Z"
|
||||
}]
|
||||
}`)
|
||||
err := c.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWsUserPosition(t *testing.T) {
|
||||
pressXToJSON := []byte(`{
|
||||
"topic": "user.position",
|
||||
"data": [{
|
||||
"availableQuantity": "100",
|
||||
"avgPrice": "7778.1",
|
||||
"leverage": "20",
|
||||
"liquidationPrice": "5441.0",
|
||||
"markPrice": "8086.5",
|
||||
"positionMargin": "0.0285",
|
||||
"quantity": "507",
|
||||
"realisedPnl": "0.0069",
|
||||
"side": "long",
|
||||
"symbol": "BTCUSDT",
|
||||
"marginMode": "1",
|
||||
"createTime": "2019-05-22T03:11:22.0Z"
|
||||
}]
|
||||
}`)
|
||||
err := c.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWsUserOrder(t *testing.T) {
|
||||
pressXToJSON := []byte(`{
|
||||
"topic": "user.order",
|
||||
"data": [{
|
||||
"orderId": "580721369818955776",
|
||||
"direction": "openLong",
|
||||
"leverage": "20",
|
||||
"symbol": "BTCUSDT",
|
||||
"orderType": "limit",
|
||||
"quantity": "7",
|
||||
"orderPrice": "146.30",
|
||||
"orderValue": "0.0010",
|
||||
"fee": "0.0000",
|
||||
"filledQuantity": "0",
|
||||
"averagePrice": "0.00",
|
||||
"orderTime": "2019-05-22T03:39:24.0Z",
|
||||
"status": "new",
|
||||
"lastFillQuantity": "0",
|
||||
"lastFillPrice": "0",
|
||||
"lastFillTime": ""
|
||||
}]
|
||||
}`)
|
||||
err := c.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetHistoricCandles(t *testing.T) {
|
||||
currencyPair, err := currency.NewPairFromString(spotTestPair)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
startTime := time.Now().Add(-time.Hour * 24)
|
||||
_, err = c.GetHistoricCandles(context.Background(),
|
||||
currencyPair, asset.Spot, startTime, time.Now(), kline.OneHour)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
currencyPairSwap, err := currency.NewPairFromString(swapTestPair)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = c.GetHistoricCandles(context.Background(),
|
||||
currencyPairSwap, asset.PerpetualSwap, startTime, time.Now(), kline.OneHour)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetHistoricCandlesExtended(t *testing.T) {
|
||||
currencyPair, err := currency.NewPairFromString(spotTestPair)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
startTime := time.Now().Add(-time.Hour * 2)
|
||||
_, err = c.GetHistoricCandlesExtended(context.Background(),
|
||||
currencyPair, asset.Spot, startTime, time.Now(), kline.OneHour)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_FormatExchangeKlineInterval(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
interval kline.Interval
|
||||
output string
|
||||
}{
|
||||
{
|
||||
"OneMin",
|
||||
kline.OneMin,
|
||||
"1",
|
||||
},
|
||||
{
|
||||
"OneHour",
|
||||
kline.OneHour,
|
||||
"60",
|
||||
},
|
||||
{
|
||||
"OneDay",
|
||||
kline.OneDay,
|
||||
"D",
|
||||
},
|
||||
{
|
||||
"OneWeek",
|
||||
kline.OneWeek,
|
||||
"W",
|
||||
},
|
||||
{
|
||||
"OneMonth",
|
||||
kline.OneMonth,
|
||||
"M",
|
||||
},
|
||||
{
|
||||
"AllOther",
|
||||
kline.TwoWeek,
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
for x := range testCases {
|
||||
test := testCases[x]
|
||||
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
ret := c.FormatExchangeKlineInterval(test.interval)
|
||||
|
||||
if ret != test.output {
|
||||
t.Fatalf("unexpected result return expected: %v received: %v", test.output, ret)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInferAssetFromTopic(t *testing.T) {
|
||||
a := inferAssetFromTopic("spot/orderBook.BSVBTC")
|
||||
if a != asset.Spot {
|
||||
t.Error("expected spot")
|
||||
}
|
||||
a = inferAssetFromTopic("btc/orderBook.BSVBTC")
|
||||
if a != asset.PerpetualSwap {
|
||||
t.Error("expected PerpetualSwap")
|
||||
}
|
||||
a = inferAssetFromTopic("usdt/orderBook.BSVBTC")
|
||||
if a != asset.PerpetualSwap {
|
||||
t.Error("expected PerpetualSwap")
|
||||
}
|
||||
a = inferAssetFromTopic("orderBook.BSVBTC")
|
||||
if a != asset.PerpetualSwap {
|
||||
t.Error("expected PerpetualSwap")
|
||||
}
|
||||
a = inferAssetFromTopic("")
|
||||
if a != asset.PerpetualSwap {
|
||||
t.Error("expected PerpetualSwap")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCurrencyFromWsTopic(t *testing.T) {
|
||||
p, err := c.getCurrencyFromWsTopic(asset.Spot, "spot/orderbook.BTCUSDT")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if p.Base.String() != "BTC" && p.Quote.String() != "USDT" {
|
||||
t.Errorf("unexpected currency, wanted BTCUSD, received %v", p.String())
|
||||
}
|
||||
|
||||
_, err = c.getCurrencyFromWsTopic(asset.Spot, "fake")
|
||||
if err != nil && err.Error() != "no currency found in topic fake" {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = c.getCurrencyFromWsTopic(asset.Spot, "hello.moto")
|
||||
if err != nil && err.Error() != "currency moto not found in supplied pairs" {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = c.getCurrencyFromWsTopic(asset.Spot, "spot/kline.GOM2USDT.1h")
|
||||
if err != nil && err.Error() != "currency moto not found in enabled pairs" {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRecentTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
currencyPair, err := currency.NewPairFromString(spotTestPair)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = c.GetRecentTrades(context.Background(), currencyPair, asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetHistoricTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
currencyPair, err := currency.NewPairFromString(spotTestPair)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = c.GetHistoricTrades(context.Background(),
|
||||
currencyPair, asset.Spot, time.Now().Add(-time.Minute*15), time.Now())
|
||||
if err != nil && err != common.ErrFunctionNotSupported {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListDepositAddress(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("api keys not set")
|
||||
}
|
||||
_, err := c.ListDepositAddress(context.Background(), currency.USDT)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAvailableTransferCurrencies(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() {
|
||||
t.Skip("api keys not set")
|
||||
}
|
||||
_, err := c.GetAvailableTransferChains(context.Background(), currency.USDT)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,439 +0,0 @@
|
||||
package coinbene
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
)
|
||||
|
||||
// Coinbene path vals
|
||||
const (
|
||||
APISpotPath uint8 = iota
|
||||
APISwapPath
|
||||
APICapitalPath
|
||||
)
|
||||
|
||||
// TickerData stores ticker data
|
||||
type TickerData struct {
|
||||
Symbol string `json:"symbol"`
|
||||
LatestPrice float64 `json:"latestPrice,string"`
|
||||
BestBid float64 `json:"bestBid,string"`
|
||||
BestAsk float64 `json:"bestAsk,string"`
|
||||
DailyHigh float64 `json:"high24h,string"`
|
||||
DailyLow float64 `json:"low24h,string"`
|
||||
DailyVolume float64 `json:"volume24h,string"`
|
||||
}
|
||||
|
||||
// OrderbookItem stores an individual orderbook item
|
||||
type OrderbookItem struct {
|
||||
Price float64
|
||||
Amount float64
|
||||
Count int64
|
||||
}
|
||||
|
||||
// Orderbook stores the orderbook data
|
||||
type Orderbook struct {
|
||||
Bids []OrderbookItem
|
||||
Asks []OrderbookItem
|
||||
Symbol string
|
||||
Time time.Time
|
||||
}
|
||||
|
||||
// TradeItem stores a single trade
|
||||
type TradeItem struct {
|
||||
CurrencyPair string
|
||||
Price float64
|
||||
Volume float64
|
||||
Direction string
|
||||
TradeTime time.Time
|
||||
}
|
||||
|
||||
// Trades stores trade data
|
||||
type Trades []TradeItem
|
||||
|
||||
// PairData stores pair data
|
||||
type PairData struct {
|
||||
Symbol string `json:"symbol"`
|
||||
BaseAsset string `json:"baseAsset"`
|
||||
QuoteAsset string `json:"quoteAsset"`
|
||||
PricePrecision int64 `json:"pricePrecision,string"`
|
||||
AmountPrecision int64 `json:"amountPrecision,string"`
|
||||
TakerFeeRate float64 `json:"takerFeeRate,string"`
|
||||
MakerFeeRate float64 `json:"makerFeeRate,string"`
|
||||
MinAmount float64 `json:"minAmount,string"`
|
||||
Site string `json:"site"`
|
||||
PriceFluctuation float64 `json:"priceFluctuation,string"`
|
||||
}
|
||||
|
||||
// UserBalanceData stores user balance data
|
||||
type UserBalanceData struct {
|
||||
Asset string `json:"asset"`
|
||||
Available float64 `json:"available,string"`
|
||||
Reserved float64 `json:"reserved,string"`
|
||||
Total float64 `json:"total,string"`
|
||||
}
|
||||
|
||||
// PlaceOrderRequest places an order request
|
||||
type PlaceOrderRequest struct {
|
||||
Price float64
|
||||
Quantity float64
|
||||
Symbol string
|
||||
Direction string
|
||||
OrderType string
|
||||
ClientID string
|
||||
Notional int
|
||||
}
|
||||
|
||||
// CancelOrdersResponse stores data for a cancelled order
|
||||
type CancelOrdersResponse struct {
|
||||
OrderID string `json:"orderId"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// OrderInfo stores order info
|
||||
type OrderInfo struct {
|
||||
OrderID string `json:"orderId"`
|
||||
BaseAsset string `json:"baseAsset"`
|
||||
QuoteAsset string `json:"quoteAsset"`
|
||||
OrderType string `json:"orderDirection"`
|
||||
Quantity float64 `json:"quntity,string"`
|
||||
Amount float64 `json:"amout,string"`
|
||||
FilledAmount float64 `json:"filledAmount"`
|
||||
TakerRate float64 `json:"takerFeeRate,string"`
|
||||
MakerRate float64 `json:"makerFeeRate,string"`
|
||||
AvgPrice float64 `json:"avgPrice,string"`
|
||||
OrderPrice float64 `json:"orderPrice,string"`
|
||||
OrderStatus string `json:"orderStatus"`
|
||||
OrderTime time.Time `json:"orderTime"`
|
||||
TotalFee float64 `json:"totalFee"`
|
||||
}
|
||||
|
||||
// OrderFills stores the fill info
|
||||
type OrderFills struct {
|
||||
Price float64 `json:"price,string"`
|
||||
Quantity float64 `json:"quantity,string"`
|
||||
Amount float64 `json:"amount,string"`
|
||||
Fee float64 `json:"fee,string"`
|
||||
Direction string `json:"direction"`
|
||||
TradeTime time.Time `json:"tradeTime"`
|
||||
FeeByConi float64 `json:"feeByConi,string"`
|
||||
}
|
||||
|
||||
// OrdersInfo stores a collection of orders
|
||||
type OrdersInfo []OrderInfo
|
||||
|
||||
// WsSub stores subscription data
|
||||
type WsSub struct {
|
||||
Operation string `json:"op"`
|
||||
Arguments []string `json:"args"`
|
||||
}
|
||||
|
||||
// WsTickerData stores websocket ticker data
|
||||
type WsTickerData struct {
|
||||
Symbol string `json:"symbol"`
|
||||
LastPrice float64 `json:"lastPrice,string"`
|
||||
MarkPrice float64 `json:"markPrice,string"`
|
||||
BestAskPrice float64 `json:"bestAskPrice,string"`
|
||||
BestBidPrice float64 `json:"bestBidPrice,string"`
|
||||
BestAskVolume float64 `json:"bestAskVolume,string"`
|
||||
BestBidVolume float64 `json:"bestBidVolume,string"`
|
||||
High24h float64 `json:"high24h,string"`
|
||||
Low24h float64 `json:"low24h,string"`
|
||||
Volume24h float64 `json:"volume24h,string"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
// WsTicker stores websocket ticker
|
||||
type WsTicker struct {
|
||||
Topic string `json:"topic"`
|
||||
Data []WsTickerData `json:"data"`
|
||||
}
|
||||
|
||||
// WsTradeList stores websocket tradelist data
|
||||
type WsTradeList struct {
|
||||
Topic string `json:"topic"`
|
||||
Data [][4]interface{} `json:"data"`
|
||||
}
|
||||
|
||||
// WsTradeData stores trade data for websocket
|
||||
type WsTradeData struct {
|
||||
BestAskPrice float64 `json:"bestAskPrice,string"`
|
||||
BestBidPrice float64 `json:"bestBidPrice,string"`
|
||||
High24h float64 `json:"high24h,string"`
|
||||
LastPrice float64 `json:"lastPrice,string"`
|
||||
Low24h float64 `json:"low24h,string"`
|
||||
Open24h float64 `json:"open24h,string"`
|
||||
OpenPrice float64 `json:"openPrice,string"`
|
||||
Symbol string `json:"symbol"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
Volume24h float64 `json:"volume24h,string"`
|
||||
}
|
||||
|
||||
// WsKline stores websocket kline data
|
||||
type WsKline struct {
|
||||
Topic string `json:"topic"`
|
||||
Data []WsKLineData `json:"data"`
|
||||
}
|
||||
|
||||
// WsKLineData holds OHLCV data
|
||||
type WsKLineData struct {
|
||||
Open float64 `json:"o"`
|
||||
High float64 `json:"h"`
|
||||
Low float64 `json:"l"`
|
||||
Close float64 `json:"c"`
|
||||
Volume float64 `json:"v"`
|
||||
Timestamp int64 `json:"t"`
|
||||
}
|
||||
|
||||
// WsUserData stores websocket user data
|
||||
type WsUserData struct {
|
||||
Asset string `json:"string"`
|
||||
Available float64 `json:"availableBalance,string"`
|
||||
Locked float64 `json:"frozenBalance,string"`
|
||||
Total float64 `json:"balance,string"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
}
|
||||
|
||||
// WsUserInfo stores websocket user info
|
||||
type WsUserInfo struct {
|
||||
Topic string `json:"topic"`
|
||||
Data []WsUserData `json:"data"`
|
||||
}
|
||||
|
||||
// WsPositionData stores websocket info on user's position
|
||||
type WsPositionData struct {
|
||||
AvailableQuantity float64 `json:"availableQuantity,string"`
|
||||
AveragePrice float64 `json:"avgPrice,string"`
|
||||
Leverage int64 `json:"leverage,string"`
|
||||
LiquidationPrice float64 `json:"liquidationPrice,string"`
|
||||
MarkPrice float64 `json:"markPrice,string"`
|
||||
PositionMargin float64 `json:"positionMargin,string"`
|
||||
Quantity float64 `json:"quantity,string"`
|
||||
RealisedPNL float64 `json:"realisedPnl,string"`
|
||||
Side string `json:"side"`
|
||||
Symbol string `json:"symbol"`
|
||||
MarginMode int64 `json:"marginMode,string"`
|
||||
CreateTime time.Time `json:"createTime"`
|
||||
}
|
||||
|
||||
// WsPosition stores websocket info on user's positions
|
||||
type WsPosition struct {
|
||||
Topic string `json:"topic"`
|
||||
Data []WsPositionData `json:"data"`
|
||||
}
|
||||
|
||||
// WsOrderbookData stores ws orderbook data
|
||||
type WsOrderbookData struct {
|
||||
Topic string `json:"topic"`
|
||||
Action string `json:"action"`
|
||||
Data []struct {
|
||||
Bids [][2]string `json:"bids"`
|
||||
Asks [][2]string `json:"asks"`
|
||||
Version int64 `json:"version"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// WsOrderData stores websocket user order data
|
||||
type WsOrderData struct {
|
||||
OrderID string `json:"orderId"`
|
||||
Direction string `json:"direction"`
|
||||
Leverage int64 `json:"leverage,string"`
|
||||
Symbol string `json:"symbol"`
|
||||
OrderType string `json:"orderType"`
|
||||
Quantity float64 `json:"quantity,string"`
|
||||
OrderPrice float64 `json:"orderPrice,string"`
|
||||
OrderValue float64 `json:"orderValue,string"`
|
||||
Fee float64 `json:"fee,string"`
|
||||
FilledQuantity float64 `json:"filledQuantity,string"`
|
||||
AveragePrice float64 `json:"averagePrice,string"`
|
||||
OrderTime time.Time `json:"orderTime"`
|
||||
Status string `json:"status"`
|
||||
LastFillQuantity float64 `json:"lastFillQuantity,string"`
|
||||
LastFillPrice float64 `json:"lastFillPrice,string"`
|
||||
LastFillTime string `json:"lastFillTime"`
|
||||
}
|
||||
|
||||
// WsUserOrders stores websocket user orders' data
|
||||
type WsUserOrders struct {
|
||||
Topic string `json:"topic"`
|
||||
Data []WsOrderData `json:"data"`
|
||||
}
|
||||
|
||||
// SwapTicker stores the swap ticker info
|
||||
type SwapTicker struct {
|
||||
LastPrice float64 `json:"lastPrice,string"`
|
||||
MarkPrice float64 `json:"markPrice,string"`
|
||||
BestAskPrice float64 `json:"bestAskPrice,string"`
|
||||
BestBidPrice float64 `json:"bestBidPrice,string"`
|
||||
High24Hour float64 `json:"high24h,string"`
|
||||
Low24Hour float64 `json:"low24h,string"`
|
||||
Volume24Hour float64 `json:"volume24h,string"`
|
||||
BestAskVolume float64 `json:"bestAskVolume,string"`
|
||||
BestBidVolume float64 `json:"bestBidVolume,string"`
|
||||
Turnover float64 `json:"turnover,string"`
|
||||
Timestamp time.Time `json:"timeStamp"`
|
||||
Change24Hour float64 `json:"chg24h,string"`
|
||||
ChangeZeroHour float64 `json:"chg0h,string"`
|
||||
}
|
||||
|
||||
// SwapTickers stores a map of swap tickers
|
||||
type SwapTickers map[string]SwapTicker
|
||||
|
||||
// SwapKlineItem stores an individual kline data item
|
||||
type SwapKlineItem struct {
|
||||
Time time.Time
|
||||
Open float64
|
||||
Close float64
|
||||
High float64
|
||||
Low float64
|
||||
Volume float64
|
||||
Turnover float64
|
||||
BuyVolume float64
|
||||
BuyTurnover float64
|
||||
}
|
||||
|
||||
// SwapKlines stores an array of kline data
|
||||
type SwapKlines []SwapKlineItem
|
||||
|
||||
// Instrument stores an individual tradable instrument
|
||||
type Instrument struct {
|
||||
InstrumentID currency.Pair `json:"instrumentId"`
|
||||
Multiplier float64 `json:"multiplier,string"`
|
||||
MinimumAmount float64 `json:"minAmount,string"`
|
||||
MaximumAmount float64 `json:"maxAmount,string"`
|
||||
MinimumPriceChange float64 `json:"minPriceChange,string"`
|
||||
PricePrecision int64 `json:"pricePrecision,string"`
|
||||
}
|
||||
|
||||
// SwapTrade stores an individual trade
|
||||
type SwapTrade struct {
|
||||
Price float64
|
||||
Side order.Side
|
||||
Volume float64
|
||||
Time time.Time
|
||||
}
|
||||
|
||||
// SwapTrades stores an array of swap trades
|
||||
type SwapTrades []SwapTrade
|
||||
|
||||
// SwapAccountInfo returns the swap account balance info
|
||||
type SwapAccountInfo struct {
|
||||
AvailableBalance float64 `json:"availableBalance,string"`
|
||||
FrozenBalance float64 `json:"frozenBalance,string"`
|
||||
MarginBalance float64 `json:"marginBalance,string"`
|
||||
MarginRate float64 `json:"marginRate,string"`
|
||||
Balance float64 `json:"balance,string"`
|
||||
UnrealisedProfitAndLoss float64 `json:"unrealisedPnl,string"`
|
||||
}
|
||||
|
||||
// SwapPosition stores a single swap position's data
|
||||
type SwapPosition struct {
|
||||
AvailableQuantity float64 `json:"availableQuantity,string"`
|
||||
AveragePrice float64 `json:"averagePrice,string"`
|
||||
CreateTime time.Time `json:"createTime"`
|
||||
DeleveragePercentile int64 `json:"deleveragePercentile,string"`
|
||||
Leverage int64 `json:"leverage,string"`
|
||||
LiquidationPrice float64 `json:"liquidationPrice,string"`
|
||||
MarkPrice float64 `json:"markPrice,string"`
|
||||
PositionMargin float64 `json:"positionMargin,string"`
|
||||
PositionValue float64 `json:"positionValue,string"`
|
||||
Quantity float64 `json:"quantity,string"`
|
||||
RateOfReturn float64 `json:"roe,string"`
|
||||
Side string `json:"side"`
|
||||
Symbol string `json:"symbol"`
|
||||
UnrealisedProfitAndLoss float64 `json:"UnrealisedPnl,string"`
|
||||
}
|
||||
|
||||
// SwapPositions stores a collection of swap positions
|
||||
type SwapPositions []SwapPosition
|
||||
|
||||
// SwapPlaceOrderResponse stores the response data for placing a swap order
|
||||
type SwapPlaceOrderResponse struct {
|
||||
OrderID string `json:"orderId"`
|
||||
ClientID string `json:"clientId"`
|
||||
}
|
||||
|
||||
// SwapOrder stores the swap order data
|
||||
type SwapOrder struct {
|
||||
OrderID string `json:"orderId"`
|
||||
Direction string `json:"direction"`
|
||||
Leverage int64 `json:"leverage,string"`
|
||||
OrderType string `json:"orderType"`
|
||||
Quantity float64 `json:"quantity,string"`
|
||||
OrderPrice float64 `json:"orderPrice,string"`
|
||||
OrderValue float64 `json:"orderValue,string"`
|
||||
Fee float64 `json:"fee"`
|
||||
FilledQuantity float64 `json:"filledQuantity,string"`
|
||||
AveragePrice float64 `json:"averagePrice,string"`
|
||||
OrderTime time.Time `json:"orderTime"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// SwapOrders stores a collection of swap orders
|
||||
type SwapOrders []SwapOrder
|
||||
|
||||
// OrderCancellationResponse returns a list of cancel order status
|
||||
type OrderCancellationResponse struct {
|
||||
OrderID string `json:"orderId"`
|
||||
Code int `json:"code,string"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// OrderPlacementResponse stores the order placement data
|
||||
type OrderPlacementResponse OrderCancellationResponse
|
||||
|
||||
// SwapOrderFill stores a swap orders fill info
|
||||
type SwapOrderFill struct {
|
||||
Symbol string `json:"symbol"`
|
||||
TradeTime time.Time `json:"tradeTime"`
|
||||
TradeID int64 `json:"tradeId,string"`
|
||||
OrderID int64 `json:"orderId,string"`
|
||||
Price float64 `json:"price,string"`
|
||||
Fee float64 `json:"fee,string"`
|
||||
ExecType string `json:"execType"`
|
||||
Side string `json:"side"`
|
||||
Quantity float64 `json:"quantity,string"`
|
||||
}
|
||||
|
||||
// SwapOrderFills stores a collection of swap order fills
|
||||
type SwapOrderFills []SwapOrderFill
|
||||
|
||||
// SwapFundingRate stores a collection of funding rates
|
||||
type SwapFundingRate struct {
|
||||
Symbol string `json:"symbol"`
|
||||
Side string `json:"side"`
|
||||
MarkPrice float64 `json:"markPrice,string"`
|
||||
PositionValue float64 `json:"positionValue,string"`
|
||||
Fee float64 `json:"fee,string"`
|
||||
FeeRate float64 `json:"feeRate,string"`
|
||||
Leverage int64 `json:"leverage"`
|
||||
}
|
||||
|
||||
// CandleResponse stores returned kline data
|
||||
type CandleResponse struct {
|
||||
Code int64 `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data [][]interface{} `json:"data"`
|
||||
}
|
||||
|
||||
// DepositAddress stores the deposit address data
|
||||
type DepositAddress struct {
|
||||
Asset string `json:"asset"`
|
||||
Chain string `json:"chain"`
|
||||
Address string `json:"address"`
|
||||
AddressTag string `json:"addressTag"`
|
||||
DepositLimit float64 `json:"depositLimit,string"`
|
||||
BlockNumber uint8 `json:"blockNumber,string"`
|
||||
}
|
||||
|
||||
// WithdrawResponse stores the withdrawal request response data
|
||||
type WithdrawResponse struct {
|
||||
ID string `json:"id"`
|
||||
Amount float64 `json:"amount"`
|
||||
Asset string `json:"asset"`
|
||||
Address string `json:"address"`
|
||||
Tag string `json:"tag"`
|
||||
Chain string `json:"chain"`
|
||||
}
|
||||
@@ -1,517 +0,0 @@
|
||||
package coinbene
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"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/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/stream"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/stream/buffer"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/trade"
|
||||
)
|
||||
|
||||
const (
|
||||
wsContractURL = "wss://ws.coinbene.com/stream/ws"
|
||||
event = "event"
|
||||
topic = "topic"
|
||||
swapChannelPrefix = "btc/"
|
||||
spotChannelPrefix = "spot/"
|
||||
)
|
||||
|
||||
// WsConnect connects to websocket
|
||||
func (c *Coinbene) WsConnect() error {
|
||||
if !c.Websocket.IsEnabled() || !c.IsEnabled() {
|
||||
return errors.New(stream.WebsocketNotEnabled)
|
||||
}
|
||||
var dialer websocket.Dialer
|
||||
err := c.Websocket.Conn.Dial(&dialer, http.Header{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Websocket.Wg.Add(1)
|
||||
go c.wsReadData()
|
||||
|
||||
if c.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
|
||||
err = c.Login()
|
||||
if err != nil {
|
||||
c.Websocket.DataHandler <- err
|
||||
c.Websocket.SetCanUseAuthenticatedEndpoints(false)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateDefaultSubscriptions generates stuff
|
||||
func (c *Coinbene) GenerateDefaultSubscriptions() ([]stream.ChannelSubscription, error) {
|
||||
var channels = []string{"orderBook.%s.100", "tradeList.%s", "ticker.%s", "kline.%s.1h"}
|
||||
var subscriptions []stream.ChannelSubscription
|
||||
perpetualPairs, err := c.GetEnabledPairs(asset.PerpetualSwap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var spotPairs currency.Pairs
|
||||
spotPairs, err = c.GetEnabledPairs(asset.Spot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for x := range channels {
|
||||
for y := range perpetualPairs {
|
||||
perpetualPairs[y].Delimiter = ""
|
||||
subscriptions = append(subscriptions, stream.ChannelSubscription{
|
||||
Channel: swapChannelPrefix + fmt.Sprintf(channels[x], perpetualPairs[y]),
|
||||
Currency: perpetualPairs[y],
|
||||
Asset: asset.PerpetualSwap,
|
||||
})
|
||||
}
|
||||
for z := range spotPairs {
|
||||
spotPairs[z].Delimiter = ""
|
||||
subscriptions = append(subscriptions, stream.ChannelSubscription{
|
||||
Channel: spotChannelPrefix + fmt.Sprintf(channels[x], spotPairs[z]),
|
||||
Currency: spotPairs[z],
|
||||
Asset: asset.Spot,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return subscriptions, nil
|
||||
}
|
||||
|
||||
// GenerateAuthSubs generates auth subs
|
||||
func (c *Coinbene) GenerateAuthSubs() ([]stream.ChannelSubscription, error) {
|
||||
var subscriptions []stream.ChannelSubscription
|
||||
var sub stream.ChannelSubscription
|
||||
var userChannels = []string{"user.account", "user.position", "user.order"}
|
||||
for z := range userChannels {
|
||||
sub.Channel = userChannels[z]
|
||||
subscriptions = append(subscriptions, sub)
|
||||
}
|
||||
return subscriptions, nil
|
||||
}
|
||||
|
||||
// wsReadData receives and passes on websocket messages for processing
|
||||
func (c *Coinbene) wsReadData() {
|
||||
defer c.Websocket.Wg.Done()
|
||||
for {
|
||||
resp := c.Websocket.Conn.ReadMessage()
|
||||
if resp.Raw == nil {
|
||||
return
|
||||
}
|
||||
err := c.wsHandleData(resp.Raw)
|
||||
if err != nil {
|
||||
c.Websocket.DataHandler <- err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func inferAssetFromTopic(topic string) asset.Item {
|
||||
if strings.Contains(topic, "spot/") {
|
||||
return asset.Spot
|
||||
}
|
||||
return asset.PerpetualSwap
|
||||
}
|
||||
|
||||
func (c *Coinbene) wsHandleData(respRaw []byte) error {
|
||||
if string(respRaw) == stream.Ping {
|
||||
err := c.Websocket.Conn.SendRawMessage(websocket.TextMessage, []byte(stream.Pong))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
var result map[string]interface{}
|
||||
err := json.Unmarshal(respRaw, &result)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, ok := result[event]
|
||||
switch {
|
||||
case ok && (result[event].(string) == "subscribe" || result[event].(string) == "unsubscribe"):
|
||||
return nil
|
||||
case ok && result[event].(string) == "error":
|
||||
return fmt.Errorf("message: %s. code: %v", result["message"], result["code"])
|
||||
}
|
||||
if ok && strings.Contains(result[event].(string), "login") {
|
||||
if result["success"].(bool) {
|
||||
c.Websocket.SetCanUseAuthenticatedEndpoints(true)
|
||||
var authsubs []stream.ChannelSubscription
|
||||
authsubs, err = c.GenerateAuthSubs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Websocket.SubscribeToChannels(authsubs)
|
||||
}
|
||||
c.Websocket.SetCanUseAuthenticatedEndpoints(false)
|
||||
return fmt.Errorf("message: %s. code: %v", result["message"], result["code"])
|
||||
}
|
||||
assetType := inferAssetFromTopic(result[topic].(string))
|
||||
var newPair currency.Pair
|
||||
switch {
|
||||
case strings.Contains(result[topic].(string), "ticker"):
|
||||
var wsTicker WsTicker
|
||||
err = json.Unmarshal(respRaw, &wsTicker)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newPair, err = c.getCurrencyFromWsTopic(assetType, wsTicker.Topic)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for x := range wsTicker.Data {
|
||||
c.Websocket.DataHandler <- &ticker.Price{
|
||||
Volume: wsTicker.Data[x].Volume24h,
|
||||
Last: wsTicker.Data[x].LastPrice,
|
||||
High: wsTicker.Data[x].High24h,
|
||||
Low: wsTicker.Data[x].Low24h,
|
||||
Bid: wsTicker.Data[x].BestBidPrice,
|
||||
Ask: wsTicker.Data[x].BestAskPrice,
|
||||
Pair: newPair,
|
||||
ExchangeName: c.Name,
|
||||
AssetType: assetType,
|
||||
LastUpdated: time.Unix(wsTicker.Data[x].Timestamp, 0),
|
||||
}
|
||||
}
|
||||
case strings.Contains(result[topic].(string), "tradeList"):
|
||||
if !c.IsSaveTradeDataEnabled() {
|
||||
return nil
|
||||
}
|
||||
var tradeList WsTradeList
|
||||
err = json.Unmarshal(respRaw, &tradeList)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var trades []trade.Data
|
||||
for i := range tradeList.Data {
|
||||
var price, amount float64
|
||||
t := time.Unix(int64(tradeList.Data[i][3].(float64))/1000, 0)
|
||||
price, err = strconv.ParseFloat(tradeList.Data[i][0].(string), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
amount, err = strconv.ParseFloat(tradeList.Data[i][2].(string), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var tSide = order.Buy
|
||||
if tradeList.Data[i][1] == "s" {
|
||||
tSide = order.Sell
|
||||
}
|
||||
|
||||
newPair, err = c.getCurrencyFromWsTopic(assetType, tradeList.Topic)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trades = append(trades, trade.Data{
|
||||
Timestamp: t,
|
||||
Exchange: c.Name,
|
||||
CurrencyPair: newPair,
|
||||
AssetType: assetType,
|
||||
Price: price,
|
||||
Amount: amount,
|
||||
Side: tSide,
|
||||
})
|
||||
}
|
||||
return trade.AddTradesToBuffer(c.Name, trades...)
|
||||
case strings.Contains(result[topic].(string), "orderBook"):
|
||||
var orderBook WsOrderbookData
|
||||
err = json.Unmarshal(respRaw, &orderBook)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(orderBook.Data) != 1 {
|
||||
return errors.New("incomplete orderbook data has been received")
|
||||
}
|
||||
|
||||
newPair, err = c.getCurrencyFromWsTopic(assetType, orderBook.Topic)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var amount, price float64
|
||||
var asks, bids []orderbook.Item
|
||||
for i := range orderBook.Data[0].Asks {
|
||||
amount, err = strconv.ParseFloat(orderBook.Data[0].Asks[i][1], 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
price, err = strconv.ParseFloat(orderBook.Data[0].Asks[i][0], 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
asks = append(asks, orderbook.Item{
|
||||
Amount: amount,
|
||||
Price: price,
|
||||
})
|
||||
}
|
||||
for j := range orderBook.Data[0].Bids {
|
||||
price, err = strconv.ParseFloat(orderBook.Data[0].Bids[j][0], 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if price == 0 {
|
||||
// Last level is coming back as a float with not enough decimal
|
||||
// places e.g. ["0.000","1001.95"]],
|
||||
// This needs to be filtered out as this can skew orderbook
|
||||
// calculations
|
||||
continue
|
||||
}
|
||||
|
||||
amount, err = strconv.ParseFloat(orderBook.Data[0].Bids[j][1], 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bids = append(bids, orderbook.Item{
|
||||
Amount: amount,
|
||||
Price: price,
|
||||
})
|
||||
}
|
||||
if orderBook.Action == "insert" {
|
||||
var newOB orderbook.Base
|
||||
newOB.Asks = asks
|
||||
newOB.Bids = bids
|
||||
newOB.Asset = assetType
|
||||
newOB.Pair = newPair
|
||||
newOB.Exchange = c.Name
|
||||
newOB.LastUpdated = time.Unix(orderBook.Data[0].Timestamp, 0)
|
||||
newOB.VerifyOrderbook = c.CanVerifyOrderbook
|
||||
err = c.Websocket.Orderbook.LoadSnapshot(&newOB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if orderBook.Action == "update" {
|
||||
newOB := buffer.Update{
|
||||
Asks: asks,
|
||||
Bids: bids,
|
||||
Asset: assetType,
|
||||
Pair: newPair,
|
||||
UpdateID: orderBook.Data[0].Version,
|
||||
UpdateTime: time.Unix(orderBook.Data[0].Timestamp, 0),
|
||||
}
|
||||
err = c.Websocket.Orderbook.Update(&newOB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case strings.Contains(result[topic].(string), "kline"):
|
||||
var candleData WsKline
|
||||
err = json.Unmarshal(respRaw, &candleData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newPair, err = c.getCurrencyFromWsTopic(assetType, candleData.Topic)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range candleData.Data {
|
||||
c.Websocket.DataHandler <- stream.KlineData{
|
||||
Pair: newPair,
|
||||
AssetType: assetType,
|
||||
Exchange: c.Name,
|
||||
OpenPrice: candleData.Data[i].Open,
|
||||
HighPrice: candleData.Data[i].High,
|
||||
LowPrice: candleData.Data[i].Low,
|
||||
ClosePrice: candleData.Data[i].Close,
|
||||
Volume: candleData.Data[i].Volume,
|
||||
Timestamp: time.Unix(candleData.Data[i].Timestamp, 0),
|
||||
}
|
||||
}
|
||||
case strings.Contains(result[topic].(string), "user.account"):
|
||||
var userInfo WsUserInfo
|
||||
err = json.Unmarshal(respRaw, &userInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Websocket.DataHandler <- userInfo
|
||||
case strings.Contains(result[topic].(string), "user.position"):
|
||||
var position WsPosition
|
||||
err = json.Unmarshal(respRaw, &position)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Websocket.DataHandler <- position
|
||||
case strings.Contains(result[topic].(string), "user.order"):
|
||||
var orders WsUserOrders
|
||||
err = json.Unmarshal(respRaw, &orders)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
format, err := c.GetPairFormat(assetType, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pairs, err := c.GetEnabledPairs(assetType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range orders.Data {
|
||||
oType, err := order.StringToOrderType(orders.Data[i].OrderType)
|
||||
if err != nil {
|
||||
c.Websocket.DataHandler <- order.ClassificationError{
|
||||
Exchange: c.Name,
|
||||
OrderID: orders.Data[i].OrderID,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
oStatus, err := order.StringToOrderStatus(orders.Data[i].Status)
|
||||
if err != nil {
|
||||
c.Websocket.DataHandler <- order.ClassificationError{
|
||||
Exchange: c.Name,
|
||||
OrderID: orders.Data[i].OrderID,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
newPair, err = currency.NewPairFromFormattedPairs(orders.Data[i].Symbol,
|
||||
pairs,
|
||||
format)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Websocket.DataHandler <- &order.Detail{
|
||||
Price: orders.Data[i].OrderPrice,
|
||||
Amount: orders.Data[i].Quantity,
|
||||
ExecutedAmount: orders.Data[i].FilledQuantity,
|
||||
RemainingAmount: orders.Data[i].Quantity - orders.Data[i].FilledQuantity,
|
||||
Fee: orders.Data[i].Fee,
|
||||
Exchange: c.Name,
|
||||
ID: orders.Data[i].OrderID,
|
||||
Type: oType,
|
||||
Status: oStatus,
|
||||
AssetType: assetType,
|
||||
Date: orders.Data[i].OrderTime,
|
||||
Leverage: float64(orders.Data[i].Leverage),
|
||||
Pair: newPair,
|
||||
}
|
||||
}
|
||||
default:
|
||||
c.Websocket.DataHandler <- stream.UnhandledMessageWarning{
|
||||
Message: c.Name + stream.UnhandledMessage + string(respRaw),
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Coinbene) getCurrencyFromWsTopic(assetType asset.Item, channelTopic string) (cp currency.Pair, err error) {
|
||||
var format currency.PairFormat
|
||||
format, err = c.GetPairFormat(assetType, true)
|
||||
if err != nil {
|
||||
return cp, err
|
||||
}
|
||||
|
||||
var pairs currency.Pairs
|
||||
pairs, err = c.GetEnabledPairs(assetType)
|
||||
if err != nil {
|
||||
return cp, err
|
||||
}
|
||||
// channel topics are formatted as "spot/orderbook.BTCUSDT"
|
||||
channelSplit := strings.Split(channelTopic, ".")
|
||||
if len(channelSplit) == 1 {
|
||||
return currency.Pair{}, errors.New("no currency found in topic " + channelTopic)
|
||||
}
|
||||
cp, err = currency.MatchPairsWithNoDelimiter(channelSplit[1], pairs, format)
|
||||
if err != nil {
|
||||
return cp, err
|
||||
}
|
||||
if !pairs.Contains(cp, true) {
|
||||
return cp, fmt.Errorf("currency %s not found in enabled pairs", cp.String())
|
||||
}
|
||||
return cp, nil
|
||||
}
|
||||
|
||||
// Subscribe sends a websocket message to receive data from the channel
|
||||
func (c *Coinbene) Subscribe(channelsToSubscribe []stream.ChannelSubscription) error {
|
||||
if maxSubsPerHour := 240; len(channelsToSubscribe) > maxSubsPerHour {
|
||||
return fmt.Errorf("channel subscriptions length %d exceeds coinbene's limit of %d, try reducing enabled pairs",
|
||||
len(channelsToSubscribe),
|
||||
maxSubsPerHour)
|
||||
}
|
||||
|
||||
var sub WsSub
|
||||
sub.Operation = "subscribe"
|
||||
// enabling all currencies can lead to a message too large being sent
|
||||
// and no subscriptions being made
|
||||
chanLimit := 15
|
||||
for i := range channelsToSubscribe {
|
||||
if len(sub.Arguments) > chanLimit {
|
||||
err := c.Websocket.Conn.SendJSONMessage(sub)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sub.Arguments = []string{}
|
||||
}
|
||||
sub.Arguments = append(sub.Arguments, channelsToSubscribe[i].Channel)
|
||||
}
|
||||
err := c.Websocket.Conn.SendJSONMessage(sub)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Websocket.AddSuccessfulSubscriptions(channelsToSubscribe...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unsubscribe sends a websocket message to receive data from the channel
|
||||
func (c *Coinbene) Unsubscribe(channelToUnsubscribe []stream.ChannelSubscription) error {
|
||||
var unsub WsSub
|
||||
unsub.Operation = "unsubscribe"
|
||||
// enabling all currencies can lead to a message too large being sent
|
||||
// and no unsubscribes being made
|
||||
chanLimit := 15
|
||||
for i := range channelToUnsubscribe {
|
||||
if len(unsub.Arguments) > chanLimit {
|
||||
err := c.Websocket.Conn.SendJSONMessage(unsub)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
unsub.Arguments = []string{}
|
||||
}
|
||||
unsub.Arguments = append(unsub.Arguments, channelToUnsubscribe[i].Channel)
|
||||
}
|
||||
err := c.Websocket.Conn.SendJSONMessage(unsub)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Websocket.RemoveSuccessfulUnsubscriptions(channelToUnsubscribe...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Login logs in
|
||||
func (c *Coinbene) Login() error {
|
||||
var sub WsSub
|
||||
expTime := time.Now().Add(time.Minute * 10).Format("2006-01-02T15:04:05Z")
|
||||
signMsg := expTime + http.MethodGet + "/login"
|
||||
|
||||
tempSign, err := crypto.GetHMAC(crypto.HashSHA256,
|
||||
[]byte(signMsg),
|
||||
[]byte(c.API.Credentials.Secret))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sign := crypto.HexEncodeToString(tempSign)
|
||||
sub.Operation = "login"
|
||||
sub.Arguments = []string{c.API.Credentials.Key, expTime, sign}
|
||||
return c.Websocket.Conn.SendJSONMessage(sub)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,259 +0,0 @@
|
||||
package coinbene
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
const (
|
||||
// Contract rate limit time interval and request rates
|
||||
contractRateInterval = time.Second * 2
|
||||
orderbookContractReqRate = 20
|
||||
tickersContractReqRate = 20
|
||||
klineContractReqRate = 20
|
||||
tradesContractReqRate = 20
|
||||
contractInstrumentsReqRate = 20
|
||||
contractAccountInfoContractReqRate = 10
|
||||
positionInfoContractReqRate = 10
|
||||
placeOrderContractReqRate = 20
|
||||
cancelOrderContractReqRate = 20
|
||||
getOpenOrdersContractReqRate = 5
|
||||
openOrdersByPageContractReqRate = 5
|
||||
getOrderInfoContractReqRate = 10
|
||||
getClosedOrdersContractReqRate = 5
|
||||
getClosedOrdersbyPageContractReqRate = 5
|
||||
cancelMultipleOrdersContractReqRate = 5
|
||||
getOrderFillsContractReqRate = 10
|
||||
getFundingRatesContractReqRate = 10
|
||||
|
||||
// Spot rate limit time interval and request rates
|
||||
spotRateInterval = time.Second
|
||||
getPairsSpotReqRate = 2
|
||||
getPairsInfoSpotReqRate = 3
|
||||
getOrderbookSpotReqRate = 6
|
||||
getTickerListSpotReqRate = 6
|
||||
getSpecificTickerSpotReqRate = 6
|
||||
getMarketTradesSpotReqRate = 3
|
||||
// getKlineSpotReqRate = 1
|
||||
// getExchangeRateSpotReqRate = 1
|
||||
getAccountInfoSpotReqRate = 3
|
||||
queryAccountAssetInfoSpotReqRate = 6
|
||||
placeOrderSpotReqRate = 6
|
||||
batchOrderSpotReqRate = 3
|
||||
queryOpenOrdersSpotReqRate = 3
|
||||
queryClosedOrdersSpotReqRate = 3
|
||||
querySpecficOrderSpotReqRate = 6
|
||||
queryTradeFillsSpotReqRate = 3
|
||||
cancelOrderSpotReqRate = 6
|
||||
cancelOrdersBatchSpotReqRate = 3
|
||||
capitalDepositReqRate = 1
|
||||
capitalWithdrawReqRate = 1
|
||||
|
||||
// Rate limit functionality
|
||||
contractOrderbook request.EndpointLimit = iota
|
||||
contractTickers
|
||||
contractKline
|
||||
contractTrades
|
||||
contractInstruments
|
||||
contractAccountInfo
|
||||
contractPositionInfo
|
||||
contractPlaceOrder
|
||||
contractCancelOrder
|
||||
contractGetOpenOrders
|
||||
contractOpenOrdersByPage
|
||||
contractGetOrderInfo
|
||||
contractGetClosedOrders
|
||||
contractGetClosedOrdersbyPage
|
||||
contractCancelMultipleOrders
|
||||
contractGetOrderFills
|
||||
contractGetFundingRates
|
||||
|
||||
spotPairs
|
||||
spotPairInfo
|
||||
spotOrderbook
|
||||
spotTickerList
|
||||
spotSpecificTicker
|
||||
spotMarketTrades
|
||||
spotKline // Not implemented yet
|
||||
spotExchangeRate // Not implemented yet
|
||||
spotAccountInfo
|
||||
spotAccountAssetInfo
|
||||
spotPlaceOrder
|
||||
spotBatchOrder
|
||||
spotQueryOpenOrders
|
||||
spotQueryClosedOrders
|
||||
spotQuerySpecficOrder
|
||||
spotQueryTradeFills
|
||||
spotCancelOrder
|
||||
spotCancelOrdersBatch
|
||||
capitalDeposit
|
||||
capitalWithdraw
|
||||
)
|
||||
|
||||
// RateLimit implements the request.Limiter interface
|
||||
type RateLimit struct {
|
||||
ContractOrderbook *rate.Limiter
|
||||
ContractTickers *rate.Limiter
|
||||
ContractKline *rate.Limiter
|
||||
ContractTrades *rate.Limiter
|
||||
ContractInstruments *rate.Limiter
|
||||
ContractAccountInfo *rate.Limiter
|
||||
ContractPositionInfo *rate.Limiter
|
||||
ContractPlaceOrder *rate.Limiter
|
||||
ContractCancelOrder *rate.Limiter
|
||||
ContractGetOpenOrders *rate.Limiter
|
||||
ContractOpenOrdersByPage *rate.Limiter
|
||||
ContractGetOrderInfo *rate.Limiter
|
||||
ContractGetClosedOrders *rate.Limiter
|
||||
ContractGetClosedOrdersbyPage *rate.Limiter
|
||||
ContractCancelMultipleOrders *rate.Limiter
|
||||
ContractGetOrderFills *rate.Limiter
|
||||
ContractGetFundingRates *rate.Limiter
|
||||
SpotPairs *rate.Limiter
|
||||
SpotPairInfo *rate.Limiter
|
||||
SpotOrderbook *rate.Limiter
|
||||
SpotTickerList *rate.Limiter
|
||||
SpotSpecificTicker *rate.Limiter
|
||||
SpotMarketTrades *rate.Limiter
|
||||
// spotKline // Not implemented yet
|
||||
// spotExchangeRate // Not implemented yet
|
||||
SpotAccountInfo *rate.Limiter
|
||||
SpotAccountAssetInfo *rate.Limiter
|
||||
SpotPlaceOrder *rate.Limiter
|
||||
SpotBatchOrder *rate.Limiter
|
||||
SpotQueryOpenOrders *rate.Limiter
|
||||
SpotQueryClosedOrders *rate.Limiter
|
||||
SpotQuerySpecficOrder *rate.Limiter
|
||||
SpotQueryTradeFills *rate.Limiter
|
||||
SpotCancelOrder *rate.Limiter
|
||||
SpotCancelOrdersBatch *rate.Limiter
|
||||
CapitalDeposit *rate.Limiter
|
||||
CapitalWithdraw *rate.Limiter
|
||||
}
|
||||
|
||||
// Limit limits outbound requests
|
||||
func (r *RateLimit) Limit(ctx context.Context, f request.EndpointLimit) error {
|
||||
switch f {
|
||||
case contractOrderbook:
|
||||
return r.ContractOrderbook.Wait(ctx)
|
||||
case contractTickers:
|
||||
return r.ContractTickers.Wait(ctx)
|
||||
case contractKline:
|
||||
return r.ContractKline.Wait(ctx)
|
||||
case contractTrades:
|
||||
return r.ContractTrades.Wait(ctx)
|
||||
case contractInstruments:
|
||||
return r.ContractInstruments.Wait(ctx)
|
||||
case contractAccountInfo:
|
||||
return r.ContractAccountInfo.Wait(ctx)
|
||||
case contractPositionInfo:
|
||||
return r.ContractPositionInfo.Wait(ctx)
|
||||
case contractPlaceOrder:
|
||||
return r.ContractPlaceOrder.Wait(ctx)
|
||||
case contractCancelOrder:
|
||||
return r.ContractCancelOrder.Wait(ctx)
|
||||
case contractGetOpenOrders:
|
||||
return r.ContractGetOpenOrders.Wait(ctx)
|
||||
case contractOpenOrdersByPage:
|
||||
return r.ContractOpenOrdersByPage.Wait(ctx)
|
||||
case contractGetOrderInfo:
|
||||
return r.ContractGetOrderInfo.Wait(ctx)
|
||||
case contractGetClosedOrders:
|
||||
return r.ContractGetClosedOrders.Wait(ctx)
|
||||
case contractGetClosedOrdersbyPage:
|
||||
return r.ContractGetClosedOrdersbyPage.Wait(ctx)
|
||||
case contractCancelMultipleOrders:
|
||||
return r.ContractCancelMultipleOrders.Wait(ctx)
|
||||
case contractGetOrderFills:
|
||||
return r.ContractGetOrderFills.Wait(ctx)
|
||||
case contractGetFundingRates:
|
||||
return r.ContractGetFundingRates.Wait(ctx)
|
||||
case spotPairs:
|
||||
return r.SpotPairs.Wait(ctx)
|
||||
case spotPairInfo:
|
||||
return r.SpotPairInfo.Wait(ctx)
|
||||
case spotOrderbook:
|
||||
return r.SpotOrderbook.Wait(ctx)
|
||||
case spotTickerList:
|
||||
return r.SpotTickerList.Wait(ctx)
|
||||
case spotSpecificTicker:
|
||||
return r.SpotSpecificTicker.Wait(ctx)
|
||||
case spotMarketTrades:
|
||||
return r.SpotMarketTrades.Wait(ctx)
|
||||
case capitalDeposit:
|
||||
return r.CapitalDeposit.Wait(ctx)
|
||||
case capitalWithdraw:
|
||||
return r.CapitalWithdraw.Wait(ctx)
|
||||
// case spotKline: // Not implemented yet
|
||||
// return r.SpotKline.Wait(ctx)
|
||||
// case spotExchangeRate:
|
||||
// return r.SpotExchangeRate.Wait(ctx)
|
||||
case spotAccountInfo:
|
||||
return r.SpotAccountInfo.Wait(ctx)
|
||||
case spotAccountAssetInfo:
|
||||
return r.SpotAccountAssetInfo.Wait(ctx)
|
||||
case spotPlaceOrder:
|
||||
return r.SpotPlaceOrder.Wait(ctx)
|
||||
case spotBatchOrder:
|
||||
return r.SpotBatchOrder.Wait(ctx)
|
||||
case spotQueryOpenOrders:
|
||||
return r.SpotQueryOpenOrders.Wait(ctx)
|
||||
case spotQueryClosedOrders:
|
||||
return r.SpotQueryClosedOrders.Wait(ctx)
|
||||
case spotQuerySpecficOrder:
|
||||
return r.SpotQuerySpecficOrder.Wait(ctx)
|
||||
case spotQueryTradeFills:
|
||||
return r.SpotQueryTradeFills.Wait(ctx)
|
||||
case spotCancelOrder:
|
||||
return r.SpotCancelOrder.Wait(ctx)
|
||||
case spotCancelOrdersBatch:
|
||||
return r.SpotCancelOrdersBatch.Wait(ctx)
|
||||
default:
|
||||
return errors.New("rate limit endpoint functionality not set")
|
||||
}
|
||||
}
|
||||
|
||||
// SetRateLimit returns the rate limit for the exchange
|
||||
func SetRateLimit() *RateLimit {
|
||||
return &RateLimit{
|
||||
ContractOrderbook: request.NewRateLimit(contractRateInterval, orderbookContractReqRate),
|
||||
ContractTickers: request.NewRateLimit(contractRateInterval, tickersContractReqRate),
|
||||
ContractKline: request.NewRateLimit(contractRateInterval, klineContractReqRate),
|
||||
ContractTrades: request.NewRateLimit(contractRateInterval, tradesContractReqRate),
|
||||
ContractInstruments: request.NewRateLimit(contractRateInterval, contractInstrumentsReqRate),
|
||||
ContractAccountInfo: request.NewRateLimit(contractRateInterval, contractAccountInfoContractReqRate),
|
||||
ContractPositionInfo: request.NewRateLimit(contractRateInterval, positionInfoContractReqRate),
|
||||
ContractPlaceOrder: request.NewRateLimit(contractRateInterval, placeOrderContractReqRate),
|
||||
ContractCancelOrder: request.NewRateLimit(contractRateInterval, cancelOrderContractReqRate),
|
||||
ContractGetOpenOrders: request.NewRateLimit(contractRateInterval, getOpenOrdersContractReqRate),
|
||||
ContractOpenOrdersByPage: request.NewRateLimit(contractRateInterval, openOrdersByPageContractReqRate),
|
||||
ContractGetOrderInfo: request.NewRateLimit(contractRateInterval, getOrderInfoContractReqRate),
|
||||
ContractGetClosedOrders: request.NewRateLimit(contractRateInterval, getClosedOrdersContractReqRate),
|
||||
ContractGetClosedOrdersbyPage: request.NewRateLimit(contractRateInterval, getClosedOrdersbyPageContractReqRate),
|
||||
ContractCancelMultipleOrders: request.NewRateLimit(contractRateInterval, cancelMultipleOrdersContractReqRate),
|
||||
ContractGetOrderFills: request.NewRateLimit(contractRateInterval, getOrderFillsContractReqRate),
|
||||
ContractGetFundingRates: request.NewRateLimit(contractRateInterval, getFundingRatesContractReqRate),
|
||||
SpotPairs: request.NewRateLimit(spotRateInterval, getPairsSpotReqRate),
|
||||
SpotPairInfo: request.NewRateLimit(spotRateInterval, getPairsInfoSpotReqRate),
|
||||
SpotOrderbook: request.NewRateLimit(spotRateInterval, getOrderbookSpotReqRate),
|
||||
SpotTickerList: request.NewRateLimit(spotRateInterval, getTickerListSpotReqRate),
|
||||
SpotSpecificTicker: request.NewRateLimit(spotRateInterval, getSpecificTickerSpotReqRate),
|
||||
SpotMarketTrades: request.NewRateLimit(spotRateInterval, getMarketTradesSpotReqRate),
|
||||
SpotAccountInfo: request.NewRateLimit(spotRateInterval, getAccountInfoSpotReqRate),
|
||||
SpotAccountAssetInfo: request.NewRateLimit(spotRateInterval, queryAccountAssetInfoSpotReqRate),
|
||||
SpotPlaceOrder: request.NewRateLimit(spotRateInterval, placeOrderSpotReqRate),
|
||||
SpotBatchOrder: request.NewRateLimit(spotRateInterval, batchOrderSpotReqRate),
|
||||
SpotQueryOpenOrders: request.NewRateLimit(spotRateInterval, queryOpenOrdersSpotReqRate),
|
||||
SpotQueryClosedOrders: request.NewRateLimit(spotRateInterval, queryClosedOrdersSpotReqRate),
|
||||
SpotQuerySpecficOrder: request.NewRateLimit(spotRateInterval, querySpecficOrderSpotReqRate),
|
||||
SpotQueryTradeFills: request.NewRateLimit(spotRateInterval, queryTradeFillsSpotReqRate),
|
||||
SpotCancelOrder: request.NewRateLimit(spotRateInterval, cancelOrderSpotReqRate),
|
||||
SpotCancelOrdersBatch: request.NewRateLimit(spotRateInterval, cancelOrdersBatchSpotReqRate),
|
||||
CapitalDeposit: request.NewRateLimit(spotRateInterval, capitalDepositReqRate),
|
||||
CapitalWithdraw: request.NewRateLimit(spotRateInterval, capitalWithdrawReqRate),
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,6 @@ var Exchanges = []string{
|
||||
"btc markets",
|
||||
"btse",
|
||||
"coinbasepro",
|
||||
"coinbene",
|
||||
"coinut",
|
||||
"exmo",
|
||||
"ftx",
|
||||
|
||||
@@ -69,7 +69,6 @@ _b in this context is an `IBotExchange` implemented struct_
|
||||
| Bittrex | Yes | Yes | No |
|
||||
| BTCMarkets | Yes | Yes | No |
|
||||
| BTSE | Yes | Yes | No |
|
||||
| Coinbene | Yes | Yes | No |
|
||||
| CoinbasePro | Yes | Yes | No|
|
||||
| COINUT | Yes | Yes | No |
|
||||
| Exmo | Yes | NA | No |
|
||||
|
||||
89
testdata/configtest.json
vendored
89
testdata/configtest.json
vendored
@@ -2267,95 +2267,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Coinbene",
|
||||
"enabled": true,
|
||||
"verbose": false,
|
||||
"httpTimeout": 15000000000,
|
||||
"websocketResponseCheckTimeout": 30000000,
|
||||
"websocketResponseMaxLimit": 7000000000,
|
||||
"websocketTrafficTimeout": 30000000000,
|
||||
"websocketOrderbookBufferLimit": 5,
|
||||
"baseCurrencies": "USD",
|
||||
"currencyPairs": {
|
||||
"assetTypes": [
|
||||
"spot",
|
||||
"perpetualswap"
|
||||
],
|
||||
"pairs": {
|
||||
"perpetualswap": {
|
||||
"enabled": "BTC/SWAP",
|
||||
"available": "YFI/SWAP,SUSHI/SWAP,TRX/SWAP,ETC/SWAP,XRP/SWAP,LTC/SWAP,EOS/SWAP,FIL/SWAP,UNI/SWAP,DOT/SWAP,LINK/SWAP,BSV/SWAP,BCH/SWAP,ETH/SWAP,BTC/SWAP",
|
||||
"requestFormat": {
|
||||
"uppercase": true,
|
||||
"delimiter": "-"
|
||||
},
|
||||
"configFormat": {
|
||||
"uppercase": true,
|
||||
"delimiter": "/"
|
||||
}
|
||||
},
|
||||
"spot": {
|
||||
"enabled": "BTC/USDT,GOM2/USDT",
|
||||
"available": "ABBC/BTC,ABBC/USDT,ABT/ETH,ABT/USDT,ABYSS/ETH,ACDC/BTC,ACDC/USDT,ADI/ETH,ADK/BTC,ADN/BTC,AE/BTC,AE/USDT,AIDOC/BTC,AION/BTC,AIPE/USDT,AIT/USDT,ALI/ETH,ALX/ETH,APL/ETH,ATX/BTC,BAAS/BTC,BABA/USDT,BAT/BTC,BCH/USDT,BETHER/ETH,BEZ/BTC,BGC/USDT,BKG/BTC,BNB/USDT,BNT/BTC,BOA/USDT,BSTN/ETH,BSV/USDT,BTC/USDT,BTNT/BTC,BTSC/BTC,BTT/USDT,BU/ETH,BVT/ETH,CAN/ETH,CCC/ETH,CCE/USDT,CEDEX/ETH,CENT/BTC,CFT/USDT,CMT/ETH,CMT/USDT,CNN/BTC,CNN/ETH,CNN/USDT,CONI/USDT,COSM/BTC,COSM/ETH,CPC/BTC,CREDO/ETH,CRN/BTC,CSCC/USDT,CS/ETH,CS/USDT,CTXC/ETH,CUST/USDT,CVC/BTC,CXP/BTC,DDAM/ETH,DDAM/USDT,DENT/BTC,DGD/BTC,DSCB/USDT,DTA/ETH,DUC/BTC,DVC/ETH,EBC/BTC,EBC/ETH,EBC/USDT,ECP/BTC,EDC/BTC,EDR/ETH,ELF/BTC,EMT/USDT,EOS/BTC,EOS/USDT,EQUAD/BTC,ETC/BTC,ETC/USDT,ETH/BTC,ETH/USDT,ETK/BTC,FAB/ETH,FCC/BTC,FND/ETH,FNKOS/ETH,FTN/BTC,FTN/USDT,FTT/BTC,FXT/ETH,GDC/BTC,GDC/ETH,GDC/USDT,GETX/ETH,GOM2/USDT,GRAM/USDT,GRN/BTC,GUSD/USDT,GVT/BTC,HAPPY/BTC,HDAC/BTC,HMB/USDT,HNB/USDT,HPT/ETH,HT/USDT,HUP/USDT,INCX/ETH,IOST/BTC,IOTE/USDT,ISR/ETH,IVY/ETH,JOB/BTC,KBC/BTC,KBC/USDT,KMD/BTC,KNT/ETH,KST/BTC,LAMB/USDT,LATX/BTC,LBK/BTC,LINK/BTC,LOOM/BTC,LTC/BTC,LTC/USDT,LUC/ETH,LUX/BTC,LVTC/ETH,MC/USDT,MIB/BTC,MINX/BTC,MINX/ETH,MOAC/USDT,MPL/BTC,MTC/BTC,MT/ETH,MTN/ETH,MT/USDT,MVL/ETH,MXM/ETH,MXM/USDT,MZG/USDT,NANO/BTC,NBAI/ETH,NEO/BTC,NEO/USDT,NFT/USDT,NOBS/BTC,NPXS/ETH,NPXS/USDT,NTY/ETH,ODC/USDT,OMG/BTC,OMX/ETH,OVC/ETH,OZX/ETH,PAT/ETH,PAX/USDT,PLAY/BTC,PMA/ETH,POLL/BTC,POLY/BTC,PPT/BTC,PSM/BTC,QKC/BTC,QTUM/BTC,QTUM/USDT,RBTC/BTC,RCOIN/BTC,RCOIN/USDT,REP/BTC,REV/BTC,RIF/BTC,RRW/USDT,SBT/USDT,SCC/BTC,SCO/BTC,SEN/BTC,SENC/ETH,SHE/BTC,SHVR/BTC,SIM/BTC,SKB/BTC,SKM/ETH,SKYM/USDT,SLT/ETH,SMARTUP/ETH,SMARTUP/USDT,SORO/USDT,SRCOIN/BTC,SRCOIN/ETH,STORJ/BTC,SWET/BTC,SWTC/USDT,TCT/BTC,TEMCO/USDT,TEN/BTC,TEN/ETH,TIB/BTC,TMTG/BTC,TOC/ETH,TOOS/USDT,TOSC/BTC,TRUE/ETH,TRX/BTC,TRX/USDT,TSL/BTC,UNI/USDT,UTNP/BTC,VBT/USDT,VEEN/BTC,VME/BTC,VME/ETH,VSC/ETH,VSF/BTC,W12/BTC,W12/ETH,WBL/BTC,WFX/BTC,XEM/BTC,XLM/BTC,XMCT/ETH,XMCT/USDT,XMR/BTC,XNK/ETH,XRP/BTC,XRP/USDT,XSR/USDT,YAP/BTC,YAP/USDT,YTA/USDT,ZAT/ETH,ZDC/BTC,ZEC/BTC,ZGC/BTC,ZRX/BTC",
|
||||
"requestFormat": {
|
||||
"uppercase": true,
|
||||
"delimiter": "/"
|
||||
},
|
||||
"configFormat": {
|
||||
"uppercase": true,
|
||||
"delimiter": "/"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"autoPairUpdates": true
|
||||
},
|
||||
"websocketAPI": true,
|
||||
"websocketCapabilities": {}
|
||||
},
|
||||
"enabled": {
|
||||
"autoPairUpdates": true,
|
||||
"websocketAPI": false
|
||||
}
|
||||
},
|
||||
"bankAccounts": [
|
||||
{
|
||||
"enabled": false,
|
||||
"bankName": "",
|
||||
"bankAddress": "",
|
||||
"bankPostalCode": "",
|
||||
"bankPostalCity": "",
|
||||
"bankCountry": "",
|
||||
"accountName": "",
|
||||
"accountNumber": "",
|
||||
"swiftCode": "",
|
||||
"iban": "",
|
||||
"supportedCurrencies": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "FTX",
|
||||
"enabled": true,
|
||||
|
||||
1
testdata/exchangelist.csv
vendored
1
testdata/exchangelist.csv
vendored
@@ -8,7 +8,6 @@ bittrex,
|
||||
btc markets,
|
||||
btse,
|
||||
coinbasepro,
|
||||
coinbene,
|
||||
coinut,
|
||||
exmo,
|
||||
ftx,
|
||||
|
||||
|
Reference in New Issue
Block a user