Coinbene: Fix ticker pair parsing (#663)

* Fix coinbene ticker pair parsing

* Update swap path plus add get instruments method

* Fix tests

* Add additional swap ticker fields

* Add endpoint to auth payload request
This commit is contained in:
Adrian Gallagher
2021-04-23 11:28:41 +10:00
committed by GitHub
parent 08f1b5d5d3
commit 9973523f1e
6 changed files with 80 additions and 32 deletions

View File

@@ -27,9 +27,9 @@ type Coinbene struct {
const (
coinbeneAPIURL = "https://openapi-exchange.coinbene.com/api/exchange/"
coinbeneSwapAPIURL = "https://openapi-contract.coinbene.com/api/swap/"
coinbeneSwapAPIURL = "https://openapi-contract.coinbene.com/api/usdt/"
coinbeneAuthPath = "/api/exchange/v2"
coinbeneSwapAuthPath = "/api/swap/v2"
coinbeneSwapAuthPath = "/api/usdt/v2"
coinbeneAPIVersion = "v2"
// Public endpoints
@@ -38,6 +38,7 @@ const (
coinbeneGetTickers = "/market/tickers"
coinbeneGetOrderBook = "/market/orderBook"
coinbeneGetKlines = "/market/klines"
coinbeneGetInstruments = "/market/instruments"
// TODO: Implement function ---
coinbeneSpotKlines = "/market/instruments/candles"
coinbeneSpotExchangeRate = "/market/rate/list"
@@ -555,6 +556,15 @@ func (c *Coinbene) GetSwapTicker(symbol string) (SwapTicker, error) {
return t, nil
}
// GetSwapInstruments returns a list of tradable instruments
func (c *Coinbene) GetSwapInstruments() ([]Instrument, error) {
resp := struct {
Data []Instrument `json:"data"`
}{}
return resp.Data, c.SendHTTPRequest(exchange.RestSwap,
coinbeneAPIVersion+coinbeneGetInstruments, contractInstruments, &resp)
}
// GetSwapOrderbook returns an orderbook for the specified currency
func (c *Coinbene) GetSwapOrderbook(symbol string, size int64) (Orderbook, error) {
var s Orderbook
@@ -1180,6 +1190,7 @@ func (c *Coinbene) SendAuthHTTPRequest(ep exchange.URL, method, path, epPath str
Verbose: c.Verbose,
HTTPDebugging: c.HTTPDebugging,
HTTPRecording: c.HTTPRecording,
Endpoint: f,
}); err != nil {
return err
}

View File

@@ -21,7 +21,7 @@ const (
testAPISecret = ""
canManipulateRealOrders = false
spotTestPair = "BTC/USDT"
swapTestPair = "BTCUSDT"
swapTestPair = "BTC-SWAP"
)
var c Coinbene
@@ -226,11 +226,18 @@ func TestCancelSpotOrders(t *testing.T) {
func TestUpdateTicker(t *testing.T) {
t.Parallel()
cp := currency.NewPairWithDelimiter("BTC", "USDT", "/")
_, err := c.UpdateTicker(cp, asset.Spot)
cp, err := currency.NewPairFromString(spotTestPair)
if err != nil {
t.Fatal(err)
}
_, err = c.UpdateTicker(cp, asset.Spot)
if err != nil {
t.Error(err)
}
cp, err = currency.NewPairFromString(swapTestPair)
if err != nil {
t.Fatal(err)
}
_, err = c.UpdateTicker(cp, asset.PerpetualSwap)
if err != nil {
t.Error(err)
@@ -250,11 +257,18 @@ func TestGetAccountInfo(t *testing.T) {
func TestUpdateOrderbook(t *testing.T) {
t.Parallel()
cp := currency.NewPairWithDelimiter("BTC", "USDT", "/")
_, err := c.UpdateOrderbook(cp, asset.Spot)
cp, err := currency.NewPairFromString(spotTestPair)
if err != nil {
t.Fatal(err)
}
_, err = c.UpdateOrderbook(cp, asset.Spot)
if err != nil {
t.Error(err)
}
cp, err = currency.NewPairFromString(swapTestPair)
if err != nil {
t.Fatal(err)
}
_, err = c.UpdateOrderbook(cp, asset.PerpetualSwap)
if err != nil {
t.Error(err)
@@ -319,6 +333,14 @@ func TestGetSwapTrades(t *testing.T) {
}
}
func TestGetSwapInstruments(t *testing.T) {
t.Parallel()
_, err := c.GetSwapInstruments()
if err != nil {
t.Error(err)
}
}
func TestGetSwapAccountInfo(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
@@ -616,7 +638,7 @@ func TestGetHistoricCandles(t *testing.T) {
t.Fatal(err)
}
currencyPairSwap, err := currency.NewPairFromString(spotTestPair)
currencyPairSwap, err := currency.NewPairFromString(swapTestPair)
if err != nil {
t.Fatal(err)
}

View File

@@ -3,6 +3,7 @@ package coinbene
import (
"time"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
)
@@ -255,17 +256,19 @@ type WsUserOrders struct {
// 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"`
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
@@ -287,6 +290,16 @@ type SwapKlineItem struct {
// 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

View File

@@ -75,6 +75,7 @@ func (c *Coinbene) SetDefaults() {
err = c.StoreAssetPairFormat(asset.PerpetualSwap, currency.PairStore{
RequestFormat: &currency.PairFormat{
Uppercase: true,
Delimiter: currency.DashDelimiter,
},
ConfigFormat: &currency.PairFormat{
Uppercase: true,
@@ -257,23 +258,17 @@ func (c *Coinbene) FetchTradablePairs(a asset.Item) ([]string, error) {
currencies = append(currencies, pairs[x].Symbol)
}
case asset.PerpetualSwap:
format, err := c.GetPairFormat(a, false)
instruments, err := c.GetSwapInstruments()
if err != nil {
return nil, err
}
tickers, err := c.GetSwapTickers()
pFmt, err := c.GetPairFormat(asset.PerpetualSwap, false)
if err != nil {
return nil, err
}
for t := range tickers {
idx := strings.Index(t, currency.USDT.String())
if idx == 0 {
return nil,
fmt.Errorf("%s SWAP currency does not contain USDT", c.Name)
}
for x := range instruments {
currencies = append(currencies,
t[0:idx]+format.Delimiter+t[idx:])
instruments[x].InstrumentID.Format(pFmt.Delimiter, pFmt.Uppercase).String())
}
}
return currencies, nil

View File

@@ -15,6 +15,7 @@ const (
tickersContractReqRate = 20
klineContractReqRate = 20
tradesContractReqRate = 20
contractInstrumentsReqRate = 20
contractAccountInfoContractReqRate = 10
positionInfoContractReqRate = 10
placeOrderContractReqRate = 20
@@ -54,6 +55,7 @@ const (
contractTickers
contractKline
contractTrades
contractInstruments
contractAccountInfo
contractPositionInfo
contractPlaceOrder
@@ -93,6 +95,7 @@ type RateLimit struct {
ContractTickers *rate.Limiter
ContractKline *rate.Limiter
ContractTrades *rate.Limiter
ContractInstruments *rate.Limiter
ContractAccountInfo *rate.Limiter
ContractPositionInfo *rate.Limiter
ContractPlaceOrder *rate.Limiter
@@ -136,6 +139,8 @@ func (r *RateLimit) Limit(f request.EndpointLimit) error {
time.Sleep(r.ContractKline.Reserve().Delay())
case contractTrades:
time.Sleep(r.ContractTrades.Reserve().Delay())
case contractInstruments:
time.Sleep(r.ContractInstruments.Reserve().Delay())
case contractAccountInfo:
time.Sleep(r.ContractAccountInfo.Reserve().Delay())
case contractPositionInfo:
@@ -209,6 +214,7 @@ func SetRateLimit() *RateLimit {
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),

View File

@@ -2360,10 +2360,11 @@
],
"pairs": {
"perpetualswap": {
"enabled": "BTC/USDT",
"available": "EOS/USDT,LTC/USDT,ETH/USDT,BTC/USDT",
"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
"uppercase": true,
"delimiter": "-"
},
"configFormat": {
"uppercase": true,