Merge branch 'master' into engine

This commit is contained in:
Adrian Gallagher
2019-06-21 18:10:55 +10:00
87 changed files with 5669 additions and 992 deletions

View File

@@ -1,15 +1,18 @@
package bitfinex
import (
"net/http"
"net/url"
"reflect"
"testing"
"time"
"github.com/gorilla/websocket"
"github.com/thrasher-/gocryptotrader/common"
"github.com/thrasher-/gocryptotrader/config"
"github.com/thrasher-/gocryptotrader/currency"
exchange "github.com/thrasher-/gocryptotrader/exchanges"
"github.com/thrasher-/gocryptotrader/exchanges/sharedtestvalues"
)
// Please supply your own keys here to do better tests
@@ -38,6 +41,7 @@ func TestSetup(t *testing.T) {
}
b.API.AuthenticatedSupport = true
b.API.AuthenticatedWebsocketSupport = true
// custom rate limit for testing
b.Requester.SetRateLimit(true, time.Millisecond*300, 1)
b.Requester.SetRateLimit(false, time.Millisecond*300, 1)
@@ -962,3 +966,37 @@ func TestGetDepositAddress(t *testing.T) {
}
}
}
// TestWsAuth dials websocket, sends login request.
func TestWsAuth(t *testing.T) {
b.SetDefaults()
TestSetup(t)
if !b.Websocket.IsEnabled() && !b.API.AuthenticatedWebsocketSupport || !areTestAPIKeysSet() {
t.Skip(exchange.WebsocketNotEnabled)
}
var err error
var dialer websocket.Dialer
b.WebsocketConn, _, err = dialer.Dial(b.Websocket.GetWebsocketURL(),
http.Header{})
if err != nil {
t.Fatal(err)
}
b.Websocket.DataHandler = sharedtestvalues.GetWebsocketInterfaceChannelOverride()
b.Websocket.TrafficAlert = sharedtestvalues.GetWebsocketStructChannelOverride()
go b.WsDataHandler()
defer b.WebsocketConn.Close()
err = b.WsSendAuth()
if err != nil {
t.Error(err)
}
timer := time.NewTimer(sharedtestvalues.WebsocketResponseDefaultTimeout)
select {
case resp := <-b.Websocket.DataHandler:
if resp.(map[string]interface{})["event"] != "auth" && resp.(map[string]interface{})["status"] != "OK" {
t.Error("expected successful login")
}
case <-timer.C:
t.Error("Have not received a response")
}
timer.Stop()
}

View File

@@ -448,6 +448,18 @@ type WebsocketTradeExecuted struct {
PriceExecuted float64
}
// WebsocketTradeData holds executed trade data
type WebsocketTradeData struct {
TradeID int64
Pair string
Timestamp int64
OrderID int64
AmountExecuted float64
PriceExecuted float64
Fee float64
FeeCurrency string
}
// ErrorCapture is a simple type for returned errors from Bitfinex
type ErrorCapture struct {
Message string `json:"message"`

View File

@@ -20,28 +20,30 @@ import (
)
const (
bitfinexWebsocket = "wss://api.bitfinex.com/ws"
bitfinexWebsocketVersion = "1.1"
bitfinexWebsocketPositionSnapshot = "ps"
bitfinexWebsocketPositionNew = "pn"
bitfinexWebsocketPositionUpdate = "pu"
bitfinexWebsocketPositionClose = "pc"
bitfinexWebsocketWalletSnapshot = "ws"
bitfinexWebsocketWalletUpdate = "wu"
bitfinexWebsocketOrderSnapshot = "os"
bitfinexWebsocketOrderNew = "on"
bitfinexWebsocketOrderUpdate = "ou"
bitfinexWebsocketOrderCancel = "oc"
bitfinexWebsocketTradeExecuted = "te"
bitfinexWebsocketHeartbeat = "hb"
bitfinexWebsocketAlertRestarting = "20051"
bitfinexWebsocketAlertRefreshing = "20060"
bitfinexWebsocketAlertResume = "20061"
bitfinexWebsocketUnknownEvent = "10000"
bitfinexWebsocketUnknownPair = "10001"
bitfinexWebsocketSubscriptionFailed = "10300"
bitfinexWebsocketAlreadySubscribed = "10301"
bitfinexWebsocketUnknownChannel = "10302"
bitfinexWebsocket = "wss://api.bitfinex.com/ws"
bitfinexWebsocketVersion = "1.1"
bitfinexWebsocketPositionSnapshot = "ps"
bitfinexWebsocketPositionNew = "pn"
bitfinexWebsocketPositionUpdate = "pu"
bitfinexWebsocketPositionClose = "pc"
bitfinexWebsocketWalletSnapshot = "ws"
bitfinexWebsocketWalletUpdate = "wu"
bitfinexWebsocketOrderSnapshot = "os"
bitfinexWebsocketOrderNew = "on"
bitfinexWebsocketOrderUpdate = "ou"
bitfinexWebsocketOrderCancel = "oc"
bitfinexWebsocketTradeExecuted = "te"
bitfinexWebsocketTradeExecutionUpdate = "tu"
bitfinexWebsocketTradeSnapshots = "ts"
bitfinexWebsocketHeartbeat = "hb"
bitfinexWebsocketAlertRestarting = "20051"
bitfinexWebsocketAlertRefreshing = "20060"
bitfinexWebsocketAlertResume = "20061"
bitfinexWebsocketUnknownEvent = "10000"
bitfinexWebsocketUnknownPair = "10001"
bitfinexWebsocketSubscriptionFailed = "10300"
bitfinexWebsocketAlreadySubscribed = "10301"
bitfinexWebsocketUnknownChannel = "10302"
)
// WebsocketHandshake defines the communication between the websocket API for
@@ -78,6 +80,9 @@ func (b *Bitfinex) wsSend(data interface{}) error {
// WsSendAuth sends a autheticated event payload
func (b *Bitfinex) WsSendAuth() error {
if !b.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
return fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", b.Name)
}
req := make(map[string]interface{})
payload := "AUTH" + strconv.FormatInt(time.Now().UnixNano(), 10)[:13]
req["event"] = "auth"
@@ -91,7 +96,12 @@ func (b *Bitfinex) WsSendAuth() error {
req["authPayload"] = payload
return b.wsSend(req)
err := b.wsSend(req)
if err != nil {
b.Websocket.SetCanUseAuthenticatedEndpoints(false)
return err
}
return nil
}
// WsSendUnauth sends an unauthenticated payload
@@ -151,6 +161,11 @@ func (b *Bitfinex) WsConnect() error {
return err
}
err = b.WsSendAuth()
if err != nil {
log.Errorf("%v - authentication failed: %v", b.Name, err)
}
b.GenerateDefaultSubscriptions()
if hs.Event == "info" {
if b.Verbose {
@@ -158,13 +173,6 @@ func (b *Bitfinex) WsConnect() error {
}
}
if b.AllowAuthenticatedRequest() {
err = b.WsSendAuth()
if err != nil {
return err
}
}
pongReceive = make(chan struct{}, 1)
go b.WsDataHandler()
@@ -226,15 +234,13 @@ func (b *Bitfinex) WsDataHandler() {
case "auth":
status := eventData["status"].(string)
if status == "OK" {
b.Websocket.DataHandler <- eventData
b.WsAddSubscriptionChannel(0, "account", "N/A")
} else if status == "fail" {
b.Websocket.DataHandler <- fmt.Errorf("bitfinex.go error - Websocket unable to AUTH. Error code: %s",
eventData["code"].(string))
b.API.AuthenticatedSupport = false
}
}
@@ -418,6 +424,19 @@ func (b *Bitfinex) WsDataHandler() {
AmountExecuted: data[4].(float64),
PriceExecuted: data[5].(float64)}
b.Websocket.DataHandler <- trade
case bitfinexWebsocketTradeSnapshots, bitfinexWebsocketTradeExecutionUpdate:
data := chanData[2].([]interface{})
trade := WebsocketTradeData{
TradeID: int64(data[0].(float64)),
Pair: data[1].(string),
Timestamp: int64(data[2].(float64)),
OrderID: int64(data[3].(float64)),
AmountExecuted: data[4].(float64),
PriceExecuted: data[5].(float64),
Fee: data[6].(float64),
FeeCurrency: data[7].(string)}
b.Websocket.DataHandler <- trade
}
@@ -603,7 +622,7 @@ func (b *Bitfinex) WsUpdateOrderbook(p currency.Pair, assetType asset.Item, book
// GenerateDefaultSubscriptions Adds default subscriptions to websocket to be handled by ManageSubscriptions()
func (b *Bitfinex) GenerateDefaultSubscriptions() {
var channels = []string{"book", "trades", "ticker"}
subscriptions := []exchange.WebsocketChannelSubscription{}
var subscriptions []exchange.WebsocketChannelSubscription
for i := range channels {
enabledPairs := b.GetEnabledPairs(asset.Spot)
for j := range enabledPairs {
@@ -626,7 +645,9 @@ func (b *Bitfinex) Subscribe(channelToSubscribe exchange.WebsocketChannelSubscri
req := make(map[string]interface{})
req["event"] = "subscribe"
req["channel"] = channelToSubscribe.Channel
req["pair"] = channelToSubscribe.Currency.String()
if channelToSubscribe.Currency.String() != "" {
req["pair"] = channelToSubscribe.Currency.String()
}
if len(channelToSubscribe.Params) > 0 {
for k, v := range channelToSubscribe.Params {
req[k] = v

View File

@@ -579,3 +579,13 @@ func (b *Bitfinex) UnsubscribeToWebsocketChannels(channels []exchange.WebsocketC
b.Websocket.UnsubscribeToChannels(channels)
return nil
}
// GetSubscriptions returns a copied list of subscriptions
func (b *Bitfinex) GetSubscriptions() ([]exchange.WebsocketChannelSubscription, error) {
return b.Websocket.GetSubscriptions(), nil
}
// AuthenticateWebsocket sends an authentication message to the websocket
func (b *Bitfinex) AuthenticateWebsocket() error {
return b.WsSendAuth()
}