mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-18 07:26:50 +00:00
Bugfix: BTSE websocket panic + REST orderbook fix (#626)
* Fixes issue with BTSE processing of new events. Also prevents panics in the event some other unexpected data comes along * Removes old auth code * Parallelogram * BTSE Filters out zero values for REST orderbooks as they do not provide enough decimal places via API to have accurate orderbooks.
This commit is contained in:
@@ -525,8 +525,6 @@ func TestParseOrderTime(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them
|
||||
// ----------------------------------------------------------------------------------------------------------------------------
|
||||
func TestSubmitOrder(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
@@ -624,7 +622,8 @@ func TestCancelAllExchangeOrders(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWsOrderbook(t *testing.T) {
|
||||
pressXToJSON := []byte(`{"topic":"orderBookApi:BTC-USD_0","data":{"buyQuote":[{"price":"9272.0","size":"0.077"},{"price":"9271.0","size":"1.122"},{"price":"9270.0","size":"2.548"},{"price":"9267.5","size":"1.015"},{"price":"9265.5","size":"0.930"},{"price":"9265.0","size":"0.475"},{"price":"9264.5","size":"2.216"},{"price":"9264.0","size":"9.709"},{"price":"9263.5","size":"3.667"},{"price":"9263.0","size":"8.481"},{"price":"9262.5","size":"7.660"},{"price":"9262.0","size":"9.689"},{"price":"9261.5","size":"4.213"},{"price":"9261.0","size":"1.491"},{"price":"9260.5","size":"6.264"},{"price":"9260.0","size":"1.690"},{"price":"9259.5","size":"5.718"},{"price":"9259.0","size":"2.706"},{"price":"9258.5","size":"0.192"},{"price":"9258.0","size":"1.592"},{"price":"9257.5","size":"1.749"},{"price":"9257.0","size":"8.104"},{"price":"9256.0","size":"0.161"},{"price":"9252.0","size":"1.544"},{"price":"9249.5","size":"1.462"},{"price":"9247.5","size":"1.833"},{"price":"9247.0","size":"0.168"},{"price":"9245.5","size":"1.941"},{"price":"9244.0","size":"1.423"},{"price":"9243.5","size":"0.175"}],"currency":"USD","sellQuote":[{"price":"9303.5","size":"1.839"},{"price":"9303.0","size":"2.067"},{"price":"9302.0","size":"0.117"},{"price":"9298.5","size":"1.569"},{"price":"9297.0","size":"1.527"},{"price":"9295.0","size":"0.184"},{"price":"9294.0","size":"1.785"},{"price":"9289.0","size":"1.673"},{"price":"9287.5","size":"4.194"},{"price":"9287.0","size":"6.622"},{"price":"9286.5","size":"2.147"},{"price":"9286.0","size":"3.348"},{"price":"9285.5","size":"5.655"},{"price":"9285.0","size":"10.423"},{"price":"9284.5","size":"6.233"},{"price":"9284.0","size":"8.860"},{"price":"9283.5","size":"9.441"},{"price":"9283.0","size":"3.455"},{"price":"9282.5","size":"11.033"},{"price":"9282.0","size":"11.471"},{"price":"9281.5","size":"4.742"},{"price":"9281.0","size":"14.789"},{"price":"9280.5","size":"11.117"},{"price":"9280.0","size":"0.807"},{"price":"9279.5","size":"1.651"},{"price":"9279.0","size":"0.244"},{"price":"9278.5","size":"0.533"},{"price":"9277.0","size":"1.447"},{"price":"9273.0","size":"1.976"},{"price":"9272.5","size":"0.093"}]}}`)
|
||||
t.Parallel()
|
||||
pressXToJSON := []byte(`{"topic":"orderBookL2Api:BTC-USD_0","data":{"buyQuote":[{"price":"9272.0","size":"0.077"},{"price":"9271.0","size":"1.122"},{"price":"9270.0","size":"2.548"},{"price":"9267.5","size":"1.015"},{"price":"9265.5","size":"0.930"},{"price":"9265.0","size":"0.475"},{"price":"9264.5","size":"2.216"},{"price":"9264.0","size":"9.709"},{"price":"9263.5","size":"3.667"},{"price":"9263.0","size":"8.481"},{"price":"9262.5","size":"7.660"},{"price":"9262.0","size":"9.689"},{"price":"9261.5","size":"4.213"},{"price":"9261.0","size":"1.491"},{"price":"9260.5","size":"6.264"},{"price":"9260.0","size":"1.690"},{"price":"9259.5","size":"5.718"},{"price":"9259.0","size":"2.706"},{"price":"9258.5","size":"0.192"},{"price":"9258.0","size":"1.592"},{"price":"9257.5","size":"1.749"},{"price":"9257.0","size":"8.104"},{"price":"9256.0","size":"0.161"},{"price":"9252.0","size":"1.544"},{"price":"9249.5","size":"1.462"},{"price":"9247.5","size":"1.833"},{"price":"9247.0","size":"0.168"},{"price":"9245.5","size":"1.941"},{"price":"9244.0","size":"1.423"},{"price":"9243.5","size":"0.175"}],"currency":"USD","sellQuote":[{"price":"9303.5","size":"1.839"},{"price":"9303.0","size":"2.067"},{"price":"9302.0","size":"0.117"},{"price":"9298.5","size":"1.569"},{"price":"9297.0","size":"1.527"},{"price":"9295.0","size":"0.184"},{"price":"9294.0","size":"1.785"},{"price":"9289.0","size":"1.673"},{"price":"9287.5","size":"4.194"},{"price":"9287.0","size":"6.622"},{"price":"9286.5","size":"2.147"},{"price":"9286.0","size":"3.348"},{"price":"9285.5","size":"5.655"},{"price":"9285.0","size":"10.423"},{"price":"9284.5","size":"6.233"},{"price":"9284.0","size":"8.860"},{"price":"9283.5","size":"9.441"},{"price":"9283.0","size":"3.455"},{"price":"9282.5","size":"11.033"},{"price":"9282.0","size":"11.471"},{"price":"9281.5","size":"4.742"},{"price":"9281.0","size":"14.789"},{"price":"9280.5","size":"11.117"},{"price":"9280.0","size":"0.807"},{"price":"9279.5","size":"1.651"},{"price":"9279.0","size":"0.244"},{"price":"9278.5","size":"0.533"},{"price":"9277.0","size":"1.447"},{"price":"9273.0","size":"1.976"},{"price":"9272.5","size":"0.093"}]}}`)
|
||||
err := b.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -632,6 +631,7 @@ func TestWsOrderbook(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWsTrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
pressXToJSON := []byte(`{"topic":"tradeHistory:BTC-USD","data":[{"amount":0.09,"gain":1,"newest":0,"price":9273.6,"serialId":0,"transactionUnixtime":1580349090693}]}`)
|
||||
err := b.wsHandleData(pressXToJSON)
|
||||
if err != nil {
|
||||
@@ -640,6 +640,7 @@ func TestWsTrades(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWsOrderNotification(t *testing.T) {
|
||||
t.Parallel()
|
||||
status := []string{"ORDER_INSERTED", "ORDER_CANCELLED", "TRIGGER_INSERTED", "ORDER_FULL_TRANSACTED", "ORDER_PARTIALLY_TRANSACTED", "INSUFFICIENT_BALANCE", "TRIGGER_ACTIVATED", "MARKET_UNAVAILABLE"}
|
||||
for i := range status {
|
||||
pressXToJSON := []byte(`{"topic": "notificationApi","data": [{"symbol": "BTC-USD","orderID": "1234","orderMode": "MODE_BUY","orderType": "TYPE_LIMIT","price": "1","size": "1","status": "` + status[i] + `","timestamp": "1580349090693","type": "STOP","triggerPrice": "1"}]}`)
|
||||
@@ -865,3 +866,45 @@ func TestOrderbookFilter(t *testing.T) {
|
||||
t.Fatal("incorrect filtering")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWsLogin(t *testing.T) {
|
||||
t.Parallel()
|
||||
data := []byte(`{"event":"login","success":true}`)
|
||||
err := b.wsHandleData(data)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !b.Websocket.CanUseAuthenticatedEndpoints() {
|
||||
t.Error("expected true")
|
||||
}
|
||||
|
||||
data = []byte(`{"event":"login","success":false}`)
|
||||
err = b.wsHandleData(data)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if b.Websocket.CanUseAuthenticatedEndpoints() {
|
||||
t.Error("expected false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWsSubscription(t *testing.T) {
|
||||
t.Parallel()
|
||||
data := []byte(`{"event":"subscribe","channel":["orderBookL2Api:SFI-ETH_0","tradeHistory:SFI-ETH"]}`)
|
||||
err := b.wsHandleData(data)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWsUnexpectedData(t *testing.T) {
|
||||
t.Parallel()
|
||||
data := []byte(`{}`)
|
||||
err := b.wsHandleData(data)
|
||||
if err != nil && err.Error() != "BTSE - Unhandled websocket message: {}" {
|
||||
t.Error(err)
|
||||
}
|
||||
if err == nil {
|
||||
t.Error("expected error response from bad data")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,3 +351,15 @@ type OrderSizeLimit struct {
|
||||
|
||||
// orderSizeLimitMap map of OrderSizeLimit per currency
|
||||
var orderSizeLimitMap sync.Map
|
||||
|
||||
// WsSubscriptionAcknowledgement contains successful subscription messages
|
||||
type WsSubscriptionAcknowledgement struct {
|
||||
Channel []string `json:"channel"`
|
||||
Event string `json:"event"`
|
||||
}
|
||||
|
||||
// WsLoginAcknowledgement contains whether authentication was successful
|
||||
type WsLoginAcknowledgement struct {
|
||||
Event string `json:"event"`
|
||||
Success bool `json:"success"`
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/stream"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/trade"
|
||||
"github.com/thrasher-corp/gocryptotrader/log"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -111,17 +112,48 @@ func (b *BTSE) wsHandleData(respRaw []byte) error {
|
||||
var result Result
|
||||
err := json.Unmarshal(respRaw, &result)
|
||||
if err != nil {
|
||||
if strings.Contains(string(respRaw), "connect success") ||
|
||||
strings.Contains(string(respRaw), "authenticated successfully") {
|
||||
if strings.Contains(string(respRaw), "connect success") {
|
||||
return nil
|
||||
} else if strings.Contains(string(respRaw), "AUTHENTICATE ERROR") {
|
||||
b.Websocket.SetCanUseAuthenticatedEndpoints(false)
|
||||
return errors.New("authentication failure")
|
||||
}
|
||||
return err
|
||||
}
|
||||
if result == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if result["event"] != nil {
|
||||
event, ok := result["event"].(string)
|
||||
if !ok {
|
||||
return errors.New(b.Name + stream.UnhandledMessage + string(respRaw))
|
||||
}
|
||||
switch event {
|
||||
case "subscribe":
|
||||
var subscribe WsSubscriptionAcknowledgement
|
||||
err = json.Unmarshal(respRaw, &subscribe)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof(log.WebsocketMgr, "%v subscribed to %v", b.Name, strings.Join(subscribe.Channel, ", "))
|
||||
case "login":
|
||||
var login WsLoginAcknowledgement
|
||||
err = json.Unmarshal(respRaw, &login)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.Websocket.SetCanUseAuthenticatedEndpoints(login.Success)
|
||||
log.Infof(log.WebsocketMgr, "%v websocket authenticated: %v", b.Name, login.Success)
|
||||
default:
|
||||
return errors.New(b.Name + stream.UnhandledMessage + string(respRaw))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
topic, ok := result["topic"].(string)
|
||||
if !ok {
|
||||
return errors.New(b.Name + stream.UnhandledMessage + string(respRaw))
|
||||
}
|
||||
switch {
|
||||
case result["topic"] == "notificationApi":
|
||||
case topic == "notificationApi":
|
||||
var notification wsNotification
|
||||
err = json.Unmarshal(respRaw, ¬ification)
|
||||
if err != nil {
|
||||
@@ -182,7 +214,7 @@ func (b *BTSE) wsHandleData(respRaw []byte) error {
|
||||
Pair: p,
|
||||
}
|
||||
}
|
||||
case strings.Contains(result["topic"].(string), "tradeHistory"):
|
||||
case strings.Contains(topic, "tradeHistory"):
|
||||
if !b.IsSaveTradeDataEnabled() {
|
||||
return nil
|
||||
}
|
||||
@@ -223,7 +255,7 @@ func (b *BTSE) wsHandleData(respRaw []byte) error {
|
||||
})
|
||||
}
|
||||
return trade.AddTradesToBuffer(b.Name, trades...)
|
||||
case strings.Contains(result["topic"].(string), "orderBookL2Api"):
|
||||
case strings.Contains(topic, "orderBookL2Api"):
|
||||
var t wsOrderBook
|
||||
err = json.Unmarshal(respRaw, &t)
|
||||
if err != nil {
|
||||
@@ -288,9 +320,9 @@ func (b *BTSE) wsHandleData(respRaw []byte) error {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
b.Websocket.DataHandler <- stream.UnhandledMessageWarning{Message: b.Name + stream.UnhandledMessage + string(respRaw)}
|
||||
return nil
|
||||
return errors.New(b.Name + stream.UnhandledMessage + string(respRaw))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -335,11 +335,17 @@ func (b *BTSE) UpdateOrderbook(p currency.Pair, assetType asset.Item) (*orderboo
|
||||
}
|
||||
|
||||
for x := range a.BuyQuote {
|
||||
if b.orderbookFilter(a.BuyQuote[x].Price, a.BuyQuote[x].Size) {
|
||||
continue
|
||||
}
|
||||
book.Bids = append(book.Bids, orderbook.Item{
|
||||
Price: a.BuyQuote[x].Price,
|
||||
Amount: a.BuyQuote[x].Size})
|
||||
}
|
||||
for x := range a.SellQuote {
|
||||
if b.orderbookFilter(a.SellQuote[x].Price, a.SellQuote[x].Size) {
|
||||
continue
|
||||
}
|
||||
book.Asks = append(book.Asks, orderbook.Item{
|
||||
Price: a.SellQuote[x].Price,
|
||||
Amount: a.SellQuote[x].Size})
|
||||
|
||||
1
go.sum
1
go.sum
@@ -668,6 +668,7 @@ google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
|
||||
google.golang.org/grpc v1.34.0 h1:raiipEjMOIC/TO2AvyTxP25XFdLxNIBwzDh3FM3XztI=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.34.1/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0 h1:TwIQcH3es+MojMVojxxfQ3l3OF2KzlRxML2xZq0kRo8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.0 h1:lQ+dE99pFsb8osbJB3oRfE5eW4Hx6a/lZQr8Jh+eoT4=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
|
||||
Reference in New Issue
Block a user