mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-27 15:10:30 +00:00
Websocket request-response correlation (#328)
* Establishes new websocket functionality. Begins the creation of the websocket request * Adding a wrapper over gorilla websocket connect,send,receive to handle ID messages. Doesn't work * Successfully moved exchange_websocket into its own wshandler namespace. oof * Sets up ZB to use a round trip WS request system * Adds Kraken ID support to subscriptions. Renames duplicate func name UnsubscribeToChannels to RemoveSubscribedChannels. Adds some helper methods in the WebsocketConn to reduce duplicate code. Cleans up ZB implementation * Fixes double locking which caused no websocket data to be read. Fixes requestid for kraken subscriptions * Completes Huobi and Hadax implementation. Extends ZB error handling. Adds GZip support for reading messages * Adds HitBTC support. Adds GetCurrencies, GetSymbols, GetTrades WS funcs. Adds super fun new parameter to GenerateMessageID for Unix and UnixNano * Adds GateIO id support * Adds Coinut support. Prevents nil reference error in constatus when there isnt one * Standardises all Exchange websockets to use the wshandler websocket. Removes the wsRequestMtx as wshandler handles that now. Makes the Dialer a dialer, its not externally referenced that I can see. * Fixes issue with coinut implementation. Updates bitmex currencies. Removes redundant log messages which are used to log messages * Starts testing. Renames files * Adds tests for websocket connection * Reverts request.go change * Linting everything * Fixes rebase issue * Final changes. Fixes variable names, removes log.Debug, removes lines, rearranges test types, removes order correlation websocket type * Final final commit, fixing ZB issues. * Adds traffic alerts where missed. Changes empty struct pointer addresses to nil instead. Removes empty lines * Fixed string conversion * Fixes issue with ZB not sending success codes * Fixes issue with coinut processing due to nonce handling with subscriptions * Fixes issue where ZB test failure was not caught. Removes unnecessary error handling from other ZB tests * Removes unused interface * Renames wshandler.Init() to wshandler.Run() * Updates template file * Capitalises cryptocurrencies in struct. Moves websocketResponseCheckTimeout and websocketResponseMaxLimit into config options. Moves connection configuration to main exchange Setup (where appropriate). Reverts currencylastupdated ticks. Improves reader close error checking * Fixes two inconsistent websocket delay times * Creates a default variable for websocket ResponseMaxLimit and ResponseCheckTimeout, then applies it to setdefaults and all tests * Updates exchange template to set and use default websocket response limits
This commit is contained in:
@@ -8,17 +8,15 @@ import (
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/currency"
|
||||
|
||||
"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/request"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/wshandler"
|
||||
log "github.com/thrasher-/gocryptotrader/logger"
|
||||
)
|
||||
|
||||
@@ -48,9 +46,8 @@ const (
|
||||
// 47.91.169.147 api.zb.com
|
||||
// 47.52.55.212 trade.zb.com
|
||||
type ZB struct {
|
||||
WebsocketConn *websocket.Conn
|
||||
WebsocketConn *wshandler.WebsocketConnection
|
||||
exchange.Base
|
||||
wsRequestMtx sync.Mutex
|
||||
}
|
||||
|
||||
// SetDefaults sets default values for the exchange
|
||||
@@ -77,15 +74,18 @@ func (z *ZB) SetDefaults() {
|
||||
z.APIUrl = z.APIUrlDefault
|
||||
z.APIUrlSecondaryDefault = zbMarketURL
|
||||
z.APIUrlSecondary = z.APIUrlSecondaryDefault
|
||||
z.WebsocketInit()
|
||||
z.Websocket.Functionality = exchange.WebsocketTickerSupported |
|
||||
exchange.WebsocketOrderbookSupported |
|
||||
exchange.WebsocketTradeDataSupported |
|
||||
exchange.WebsocketSubscribeSupported |
|
||||
exchange.WebsocketAuthenticatedEndpointsSupported |
|
||||
exchange.WebsocketAccountDataSupported |
|
||||
exchange.WebsocketCancelOrderSupported |
|
||||
exchange.WebsocketSubmitOrderSupported
|
||||
z.Websocket = wshandler.New()
|
||||
z.Websocket.Functionality = wshandler.WebsocketTickerSupported |
|
||||
wshandler.WebsocketOrderbookSupported |
|
||||
wshandler.WebsocketTradeDataSupported |
|
||||
wshandler.WebsocketSubscribeSupported |
|
||||
wshandler.WebsocketAuthenticatedEndpointsSupported |
|
||||
wshandler.WebsocketAccountDataSupported |
|
||||
wshandler.WebsocketCancelOrderSupported |
|
||||
wshandler.WebsocketSubmitOrderSupported |
|
||||
wshandler.WebsocketMessageCorrelationSupported
|
||||
z.WebsocketResponseMaxLimit = exchange.DefaultWebsocketResponseMaxLimit
|
||||
z.WebsocketResponseCheckTimeout = exchange.DefaultWebsocketResponseCheckTimeout
|
||||
}
|
||||
|
||||
// Setup sets user configuration
|
||||
@@ -127,17 +127,27 @@ func (z *ZB) Setup(exch *config.ExchangeConfig) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = z.WebsocketSetup(z.WsConnect,
|
||||
err = z.Websocket.Setup(z.WsConnect,
|
||||
z.Subscribe,
|
||||
nil,
|
||||
exch.Name,
|
||||
exch.Websocket,
|
||||
exch.Verbose,
|
||||
zbWebsocketAPI,
|
||||
exch.WebsocketURL)
|
||||
exch.WebsocketURL,
|
||||
exch.AuthenticatedWebsocketAPISupport)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
z.WebsocketConn = &wshandler.WebsocketConnection{
|
||||
ExchangeName: z.Name,
|
||||
URL: z.Websocket.GetWebsocketURL(),
|
||||
ProxyURL: z.Websocket.GetProxyAddress(),
|
||||
Verbose: z.Verbose,
|
||||
RateLimit: zbWebsocketRateLimit,
|
||||
ResponseCheckTimeout: exch.WebsocketResponseCheckTimeout,
|
||||
ResponseMaxLimit: exch.WebsocketResponseMaxLimit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,14 +4,13 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"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"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/wshandler"
|
||||
)
|
||||
|
||||
// Please supply you own test keys here for due diligence testing.
|
||||
@@ -50,12 +49,17 @@ func setupWsAuth(t *testing.T) {
|
||||
z.SetDefaults()
|
||||
TestSetup(t)
|
||||
if !z.Websocket.IsEnabled() && !z.AuthenticatedWebsocketAPISupport || !areTestAPIKeysSet() || !canManipulateRealOrders {
|
||||
t.Skip(exchange.WebsocketNotEnabled)
|
||||
t.Skip(wshandler.WebsocketNotEnabled)
|
||||
}
|
||||
z.WebsocketConn = &wshandler.WebsocketConnection{
|
||||
ExchangeName: z.Name,
|
||||
URL: zbWebsocketAPI,
|
||||
Verbose: z.Verbose,
|
||||
ResponseMaxLimit: exchange.DefaultWebsocketResponseMaxLimit,
|
||||
ResponseCheckTimeout: exchange.DefaultWebsocketResponseCheckTimeout,
|
||||
}
|
||||
var err error
|
||||
var dialer websocket.Dialer
|
||||
z.WebsocketConn, _, err = dialer.Dial(z.Websocket.GetWebsocketURL(),
|
||||
http.Header{})
|
||||
err := z.WebsocketConn.Dial(&dialer, http.Header{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -503,224 +507,116 @@ func TestZBInvalidJSON(t *testing.T) {
|
||||
var response WsGetSubUserListResponse
|
||||
err := common.JSONDecode(fixedJSON, &response)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
if response.Message[0].UserID != 1337 {
|
||||
t.Error("Expected extracted JSON USERID to equal 1337")
|
||||
t.Fatal("Expected extracted JSON USERID to equal 1337")
|
||||
}
|
||||
|
||||
json = `{"success":true,"code":1000,"channel":"createSubUserKey","message":"{"apiKey":"thisisnotareallykeyyousillybilly","apiSecret":"lol"}","no":"14728151154382111746154"}`
|
||||
json = `{"success":true,"code":1000,"channel":"createSubUserKey","message":"{"apiKey":"thisisnotareallykeyyousillybilly","apiSecret":"lol"}","no":"123"}`
|
||||
fixedJSON = z.wsFixInvalidJSON([]byte(json))
|
||||
var response2 WsRequestResponse
|
||||
err = common.JSONDecode(fixedJSON, &response2)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestWsTransferFunds ws test
|
||||
func TestWsTransferFunds(t *testing.T) {
|
||||
setupWsAuth(t)
|
||||
err := z.wsDoTransferFunds(currency.BTC,
|
||||
_, err := z.wsDoTransferFunds(currency.BTC,
|
||||
0.0001,
|
||||
"username1",
|
||||
"username2",
|
||||
)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
timer := time.NewTimer(sharedtestvalues.WebsocketResponseDefaultTimeout)
|
||||
select {
|
||||
case resp := <-z.Websocket.DataHandler:
|
||||
if resp.(WsRequestResponse).Code == 1002 || resp.(WsRequestResponse).Code == 1003 {
|
||||
t.Error("Hash not calculated correctly")
|
||||
}
|
||||
case <-timer.C:
|
||||
t.Error("Have not received a response")
|
||||
}
|
||||
timer.Stop()
|
||||
}
|
||||
|
||||
// TestWsCreateSuUserKey ws test
|
||||
func TestWsCreateSuUserKey(t *testing.T) {
|
||||
setupWsAuth(t)
|
||||
z.wsGetSubUserList()
|
||||
timer := time.NewTimer(sharedtestvalues.WebsocketResponseDefaultTimeout)
|
||||
var userID int64
|
||||
select {
|
||||
case resp := <-z.Websocket.DataHandler:
|
||||
if len(resp.(WsGetSubUserListResponse).Message) == 0 {
|
||||
t.Fatal("Expected a userID. Ensure you have made a subuserID before running this test")
|
||||
}
|
||||
userID = resp.(WsGetSubUserListResponse).Message[0].UserID
|
||||
case <-timer.C:
|
||||
t.Fatal("Have not received a response")
|
||||
}
|
||||
timer.Stop()
|
||||
err := z.wsCreateSubUserKey(true, true, true, true, "subu", fmt.Sprintf("%v", userID))
|
||||
subUsers, err := z.wsGetSubUserList()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
timer = time.NewTimer(sharedtestvalues.WebsocketResponseDefaultTimeout)
|
||||
select {
|
||||
case resp := <-z.Websocket.DataHandler:
|
||||
if resp.(WsRequestResponse).Code == 1002 || resp.(WsRequestResponse).Code == 1003 {
|
||||
t.Error("Hash not calculated correctly")
|
||||
}
|
||||
case <-timer.C:
|
||||
t.Error("Have not received a response")
|
||||
userID := subUsers.Message[0].UserID
|
||||
_, err = z.wsCreateSubUserKey(true, true, true, true, "subu", fmt.Sprintf("%v", userID))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
timer.Stop()
|
||||
}
|
||||
|
||||
// TestGetSubUserList ws test
|
||||
func TestGetSubUserList(t *testing.T) {
|
||||
setupWsAuth(t)
|
||||
err := z.wsGetSubUserList()
|
||||
_, err := z.wsGetSubUserList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
timer := time.NewTimer(sharedtestvalues.WebsocketResponseDefaultTimeout)
|
||||
select {
|
||||
case resp := <-z.Websocket.DataHandler:
|
||||
if resp.(WsGetSubUserListResponse).Code == 1002 || resp.(WsGetSubUserListResponse).Code == 1003 {
|
||||
t.Error("Hash not calculated correctly")
|
||||
}
|
||||
case <-timer.C:
|
||||
t.Error("Have not received a response")
|
||||
}
|
||||
timer.Stop()
|
||||
}
|
||||
|
||||
// TestAddSubUser ws test
|
||||
func TestAddSubUser(t *testing.T) {
|
||||
setupWsAuth(t)
|
||||
err := z.wsAddSubUser("abcde", "123456789101112aA!")
|
||||
_, err := z.wsAddSubUser("1", "123456789101112aA!")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
timer := time.NewTimer(sharedtestvalues.WebsocketResponseDefaultTimeout)
|
||||
select {
|
||||
case resp := <-z.Websocket.DataHandler:
|
||||
if resp.(WsRequestResponse).Code == 1002 || resp.(WsRequestResponse).Code == 1003 {
|
||||
t.Error("Hash not calculated correctly")
|
||||
}
|
||||
case <-timer.C:
|
||||
t.Error("Have not received a response")
|
||||
}
|
||||
timer.Stop()
|
||||
}
|
||||
|
||||
// TestWsSubmitOrder ws test
|
||||
func TestWsSubmitOrder(t *testing.T) {
|
||||
setupWsAuth(t)
|
||||
err := z.wsSubmitOrder(currency.NewPairWithDelimiter(currency.LTC.String(), currency.BTC.String(), "").Lower(), 1, 1, 1)
|
||||
_, err := z.wsSubmitOrder(currency.NewPairWithDelimiter(currency.LTC.String(), currency.BTC.String(), "").Lower(), 1, 1, 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
timer := time.NewTimer(sharedtestvalues.WebsocketResponseDefaultTimeout)
|
||||
select {
|
||||
case resp := <-z.Websocket.DataHandler:
|
||||
if resp.(WsSubmitOrderResponse).Code == 1002 || resp.(WsSubmitOrderResponse).Code == 1003 {
|
||||
t.Error("Hash not calculated correctly")
|
||||
}
|
||||
case <-timer.C:
|
||||
t.Error("Have not received a response")
|
||||
}
|
||||
timer.Stop()
|
||||
}
|
||||
|
||||
// TestWsCancelOrder ws test
|
||||
func TestWsCancelOrder(t *testing.T) {
|
||||
setupWsAuth(t)
|
||||
err := z.wsCancelOrder(currency.NewPairWithDelimiter(currency.LTC.String(), currency.BTC.String(), "").Lower(), 1234)
|
||||
_, err := z.wsCancelOrder(currency.NewPairWithDelimiter(currency.LTC.String(), currency.BTC.String(), "").Lower(), 1234)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
timer := time.NewTimer(sharedtestvalues.WebsocketResponseDefaultTimeout)
|
||||
select {
|
||||
case resp := <-z.Websocket.DataHandler:
|
||||
if resp.(WsCancelOrderResponse).Code == 1002 || resp.(WsCancelOrderResponse).Code == 1003 {
|
||||
t.Error("Hash not calculated correctly")
|
||||
}
|
||||
case <-timer.C:
|
||||
t.Error("Have not received a response")
|
||||
}
|
||||
timer.Stop()
|
||||
}
|
||||
|
||||
// TestWsGetAccountInfo ws test
|
||||
func TestWsGetAccountInfo(t *testing.T) {
|
||||
setupWsAuth(t)
|
||||
err := z.wsGetAccountInfoRequest()
|
||||
_, err := z.wsGetAccountInfoRequest()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
timer := time.NewTimer(sharedtestvalues.WebsocketResponseDefaultTimeout)
|
||||
select {
|
||||
case resp := <-z.Websocket.DataHandler:
|
||||
if resp.(WsGetAccountInfoResponse).Code == 1002 || resp.(WsGetAccountInfoResponse).Code == 1003 {
|
||||
t.Error("Hash not calculated correctly")
|
||||
}
|
||||
case <-timer.C:
|
||||
t.Error("Have not received a response")
|
||||
}
|
||||
timer.Stop()
|
||||
}
|
||||
|
||||
// TestWsGetOrder ws test
|
||||
func TestWsGetOrder(t *testing.T) {
|
||||
setupWsAuth(t)
|
||||
err := z.wsGetOrder(currency.NewPairWithDelimiter(currency.LTC.String(), currency.BTC.String(), "").Lower(), 1234)
|
||||
_, err := z.wsGetOrder(currency.NewPairWithDelimiter(currency.LTC.String(), currency.BTC.String(), "").Lower(), 1234)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
timer := time.NewTimer(sharedtestvalues.WebsocketResponseDefaultTimeout)
|
||||
select {
|
||||
case resp := <-z.Websocket.DataHandler:
|
||||
if resp.(WsGetOrderResponse).Code == 1002 || resp.(WsGetOrderResponse).Code == 1003 {
|
||||
t.Error("Hash not calculated correctly")
|
||||
}
|
||||
case <-timer.C:
|
||||
t.Error("Have not received a response")
|
||||
}
|
||||
timer.Stop()
|
||||
}
|
||||
|
||||
// TestWsGetOrders ws test
|
||||
func TestWsGetOrders(t *testing.T) {
|
||||
setupWsAuth(t)
|
||||
err := z.wsGetOrders(currency.NewPairWithDelimiter(currency.LTC.String(), currency.BTC.String(), "").Lower(), 1, 1)
|
||||
_, err := z.wsGetOrders(currency.NewPairWithDelimiter(currency.LTC.String(), currency.BTC.String(), "").Lower(), 1, 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
timer := time.NewTimer(sharedtestvalues.WebsocketResponseDefaultTimeout)
|
||||
select {
|
||||
case resp := <-z.Websocket.DataHandler:
|
||||
if resp.(WsGetOrdersResponse).Code == 1002 || resp.(WsGetOrdersResponse).Code == 1003 {
|
||||
t.Error("Hash not calculated correctly")
|
||||
}
|
||||
case <-timer.C:
|
||||
t.Error("Have not received a response")
|
||||
}
|
||||
timer.Stop()
|
||||
}
|
||||
|
||||
// TestWsGetOrdersIgnoreTradeType ws test
|
||||
func TestWsGetOrdersIgnoreTradeType(t *testing.T) {
|
||||
setupWsAuth(t)
|
||||
err := z.wsGetOrdersIgnoreTradeType(currency.NewPairWithDelimiter(currency.LTC.String(), currency.BTC.String(), "").Lower(), 1, 1)
|
||||
_, err := z.wsGetOrdersIgnoreTradeType(currency.NewPairWithDelimiter(currency.LTC.String(), currency.BTC.String(), "").Lower(), 1, 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
timer := time.NewTimer(sharedtestvalues.WebsocketResponseDefaultTimeout)
|
||||
select {
|
||||
case resp := <-z.Websocket.DataHandler:
|
||||
if resp.(WsGetOrdersResponse).Code == 1002 || resp.(WsGetOrdersResponse).Code == 1003 {
|
||||
t.Error("Hash not calculated correctly")
|
||||
}
|
||||
case <-timer.C:
|
||||
t.Error("Have not received a response")
|
||||
}
|
||||
timer.Stop()
|
||||
}
|
||||
|
||||
@@ -4,9 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
@@ -14,33 +12,23 @@ import (
|
||||
"github.com/thrasher-/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/wshandler"
|
||||
log "github.com/thrasher-/gocryptotrader/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
zbWebsocketAPI = "wss://api.zb.cn:9999/websocket"
|
||||
zWebsocketAddChannel = "addChannel"
|
||||
zbWebsocketRateLimit = 20
|
||||
)
|
||||
|
||||
// WsConnect initiates a websocket connection
|
||||
func (z *ZB) WsConnect() error {
|
||||
if !z.Websocket.IsEnabled() || !z.IsEnabled() {
|
||||
return errors.New(exchange.WebsocketNotEnabled)
|
||||
return errors.New(wshandler.WebsocketNotEnabled)
|
||||
}
|
||||
|
||||
var dialer websocket.Dialer
|
||||
if z.Websocket.GetProxyAddress() != "" {
|
||||
proxy, err := url.Parse(z.Websocket.GetProxyAddress())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dialer.Proxy = http.ProxyURL(proxy)
|
||||
}
|
||||
|
||||
var err error
|
||||
z.WebsocketConn, _, err = dialer.Dial(z.Websocket.GetWebsocketURL(),
|
||||
http.Header{})
|
||||
err := z.WebsocketConn.Dial(&dialer, http.Header{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -51,18 +39,6 @@ func (z *ZB) WsConnect() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// WsReadData reads from the websocket connection and returns the websocket
|
||||
// response
|
||||
func (z *ZB) WsReadData() (exchange.WebsocketResponse, error) {
|
||||
_, resp, err := z.WebsocketConn.ReadMessage()
|
||||
if err != nil {
|
||||
return exchange.WebsocketResponse{}, err
|
||||
}
|
||||
|
||||
z.Websocket.TrafficAlert <- struct{}{}
|
||||
return exchange.WebsocketResponse{Raw: resp}, nil
|
||||
}
|
||||
|
||||
// WsHandleData handles all the websocket data coming from the websocket
|
||||
// connection
|
||||
func (z *ZB) WsHandleData() {
|
||||
@@ -77,12 +53,12 @@ func (z *ZB) WsHandleData() {
|
||||
case <-z.Websocket.ShutdownC:
|
||||
return
|
||||
default:
|
||||
resp, err := z.WsReadData()
|
||||
resp, err := z.WebsocketConn.ReadMessage()
|
||||
if err != nil {
|
||||
z.Websocket.DataHandler <- err
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
return
|
||||
}
|
||||
z.Websocket.TrafficAlert <- struct{}{}
|
||||
fixedJSON := z.wsFixInvalidJSON(resp.Raw)
|
||||
var result Generic
|
||||
err = common.JSONDecode(fixedJSON, &result)
|
||||
@@ -90,13 +66,16 @@ func (z *ZB) WsHandleData() {
|
||||
z.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
if result.No > 0 {
|
||||
z.WebsocketConn.AddResponseWithID(result.No, fixedJSON)
|
||||
continue
|
||||
}
|
||||
if result.Code > 0 && result.Code != 1000 {
|
||||
z.Websocket.DataHandler <- fmt.Errorf("%v request failed, message: %v, error code: %v", z.Name, result.Message, wsErrCodes[result.Code])
|
||||
continue
|
||||
}
|
||||
switch {
|
||||
case common.StringContains(result.Channel, "markets"):
|
||||
if !result.Success {
|
||||
z.Websocket.DataHandler <- fmt.Errorf("zb_websocket.go error - unsuccessful market response %s", wsErrCodes[result.Code])
|
||||
continue
|
||||
}
|
||||
|
||||
var markets Markets
|
||||
err := common.JSONDecode(result.Data, &markets)
|
||||
if err != nil {
|
||||
@@ -106,16 +85,14 @@ func (z *ZB) WsHandleData() {
|
||||
|
||||
case common.StringContains(result.Channel, "ticker"):
|
||||
cPair := common.SplitStrings(result.Channel, "_")
|
||||
|
||||
var ticker WsTicker
|
||||
|
||||
err := common.JSONDecode(fixedJSON, &ticker)
|
||||
if err != nil {
|
||||
z.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
|
||||
z.Websocket.DataHandler <- exchange.TickerData{
|
||||
z.Websocket.DataHandler <- wshandler.TickerData{
|
||||
Timestamp: time.Unix(0, ticker.Date),
|
||||
Pair: currency.NewPairFromString(cPair[0]),
|
||||
AssetType: "SPOT",
|
||||
@@ -153,7 +130,6 @@ func (z *ZB) WsHandleData() {
|
||||
|
||||
channelInfo := common.SplitStrings(result.Channel, "_")
|
||||
cPair := currency.NewPairFromString(channelInfo[0])
|
||||
|
||||
var newOrderBook orderbook.Base
|
||||
newOrderBook.Asks = asks
|
||||
newOrderBook.Bids = bids
|
||||
@@ -168,7 +144,7 @@ func (z *ZB) WsHandleData() {
|
||||
continue
|
||||
}
|
||||
|
||||
z.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{
|
||||
z.Websocket.DataHandler <- wshandler.WebsocketOrderbookUpdate{
|
||||
Pair: cPair,
|
||||
Asset: "SPOT",
|
||||
Exchange: z.GetName(),
|
||||
@@ -181,17 +157,14 @@ func (z *ZB) WsHandleData() {
|
||||
z.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
|
||||
// Most up to date trade
|
||||
if len(trades.Data) == 0 {
|
||||
continue
|
||||
}
|
||||
t := trades.Data[len(trades.Data)-1]
|
||||
|
||||
channelInfo := common.SplitStrings(result.Channel, "_")
|
||||
cPair := currency.NewPairFromString(channelInfo[0])
|
||||
|
||||
z.Websocket.DataHandler <- exchange.TradeData{
|
||||
z.Websocket.DataHandler <- wshandler.TradeData{
|
||||
Timestamp: time.Unix(0, t.Date),
|
||||
CurrencyPair: cPair,
|
||||
AssetType: "SPOT",
|
||||
@@ -201,86 +174,6 @@ func (z *ZB) WsHandleData() {
|
||||
Amount: t.Amount,
|
||||
Side: t.TradeType,
|
||||
}
|
||||
case strings.EqualFold(result.Channel, "addSubUser"):
|
||||
var response WsRequestResponse
|
||||
err := common.JSONDecode(fixedJSON, &response)
|
||||
if err != nil {
|
||||
z.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
z.Websocket.DataHandler <- response
|
||||
case strings.EqualFold(result.Channel, "getSubUserList"):
|
||||
var response WsGetSubUserListResponse
|
||||
err := common.JSONDecode(fixedJSON, &response)
|
||||
if err != nil {
|
||||
z.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
z.Websocket.DataHandler <- response
|
||||
case strings.EqualFold(result.Channel, "doTransferFunds"):
|
||||
var response WsRequestResponse
|
||||
err := common.JSONDecode(fixedJSON, &response)
|
||||
if err != nil {
|
||||
z.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
z.Websocket.DataHandler <- response
|
||||
case strings.EqualFold(result.Channel, "createSubUserKey"):
|
||||
var response WsRequestResponse
|
||||
err := common.JSONDecode(fixedJSON, &response)
|
||||
if err != nil {
|
||||
z.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
z.Websocket.DataHandler <- response
|
||||
case common.StringContains(result.Channel, "_order"):
|
||||
var response WsSubmitOrderResponse
|
||||
err := common.JSONDecode(fixedJSON, &response)
|
||||
if err != nil {
|
||||
z.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
z.Websocket.DataHandler <- response
|
||||
case common.StringContains(result.Channel, "_cancelorder"):
|
||||
var response WsCancelOrderResponse
|
||||
err := common.JSONDecode(fixedJSON, &response)
|
||||
if err != nil {
|
||||
z.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
z.Websocket.DataHandler <- response
|
||||
case common.StringContains(result.Channel, "_getorders"):
|
||||
var response WsGetOrdersResponse
|
||||
err := common.JSONDecode(fixedJSON, &response)
|
||||
if err != nil {
|
||||
z.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
z.Websocket.DataHandler <- response
|
||||
case common.StringContains(result.Channel, "_getorder"):
|
||||
var response WsGetOrderResponse
|
||||
err := common.JSONDecode(fixedJSON, &response)
|
||||
if err != nil {
|
||||
z.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
z.Websocket.DataHandler <- response
|
||||
case common.StringContains(result.Channel, "_getordersignoretradetype"):
|
||||
var response WsGetOrdersIgnoreTradeTypeResponse
|
||||
err := common.JSONDecode(fixedJSON, &response)
|
||||
if err != nil {
|
||||
z.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
z.Websocket.DataHandler <- response
|
||||
case strings.EqualFold(result.Channel, "getAccountInfo"):
|
||||
var response WsGetAccountInfoResponse
|
||||
err := common.JSONDecode(fixedJSON, &response)
|
||||
if err != nil {
|
||||
z.Websocket.DataHandler <- err
|
||||
continue
|
||||
}
|
||||
z.Websocket.DataHandler <- response
|
||||
default:
|
||||
z.Websocket.DataHandler <- errors.New("zb_websocket.go error - unhandled websocket response")
|
||||
continue
|
||||
@@ -325,9 +218,9 @@ var wsErrCodes = map[int64]string{
|
||||
|
||||
// GenerateDefaultSubscriptions Adds default subscriptions to websocket to be handled by ManageSubscriptions()
|
||||
func (z *ZB) GenerateDefaultSubscriptions() {
|
||||
var subscriptions []exchange.WebsocketChannelSubscription
|
||||
var subscriptions []wshandler.WebsocketChannelSubscription
|
||||
// Tickerdata is its own channel
|
||||
subscriptions = append(subscriptions, exchange.WebsocketChannelSubscription{
|
||||
subscriptions = append(subscriptions, wshandler.WebsocketChannelSubscription{
|
||||
Channel: "markets",
|
||||
})
|
||||
channels := []string{"%s_ticker", "%s_depth", "%s_trades"}
|
||||
@@ -335,7 +228,7 @@ func (z *ZB) GenerateDefaultSubscriptions() {
|
||||
for i := range channels {
|
||||
for j := range enabledCurrencies {
|
||||
enabledCurrencies[j].Delimiter = ""
|
||||
subscriptions = append(subscriptions, exchange.WebsocketChannelSubscription{
|
||||
subscriptions = append(subscriptions, wshandler.WebsocketChannelSubscription{
|
||||
Channel: fmt.Sprintf(channels[i], enabledCurrencies[j].Lower().String()),
|
||||
Currency: enabledCurrencies[j].Lower(),
|
||||
})
|
||||
@@ -345,108 +238,24 @@ func (z *ZB) GenerateDefaultSubscriptions() {
|
||||
}
|
||||
|
||||
// Subscribe sends a websocket message to receive data from the channel
|
||||
func (z *ZB) Subscribe(channelToSubscribe exchange.WebsocketChannelSubscription) error {
|
||||
func (z *ZB) Subscribe(channelToSubscribe wshandler.WebsocketChannelSubscription) error {
|
||||
subscriptionRequest := Subscription{
|
||||
Event: zWebsocketAddChannel,
|
||||
Channel: channelToSubscribe.Channel,
|
||||
}
|
||||
return z.wsSend(subscriptionRequest)
|
||||
}
|
||||
|
||||
// WsSend sends data to the websocket server
|
||||
func (z *ZB) wsSend(data interface{}) error {
|
||||
z.wsRequestMtx.Lock()
|
||||
defer z.wsRequestMtx.Unlock()
|
||||
json, err := common.JSONEncode(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if z.Verbose {
|
||||
log.Debugf("%v sending message to websocket %v", z.Name, string(json))
|
||||
}
|
||||
return z.WebsocketConn.WriteMessage(websocket.TextMessage, json)
|
||||
}
|
||||
|
||||
func (z *ZB) wsAddSubUser(username, password string) error {
|
||||
if !z.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
|
||||
return fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
}
|
||||
request := WsAddSubUserRequest{
|
||||
Memo: "Memo",
|
||||
Password: password,
|
||||
SubUserName: username,
|
||||
}
|
||||
request.Channel = "addSubUser"
|
||||
request.Event = zWebsocketAddChannel
|
||||
request.Accesskey = z.APIKey
|
||||
request.Sign = z.wsGenerateSignature(request)
|
||||
|
||||
return z.wsSend(request)
|
||||
}
|
||||
|
||||
func (z *ZB) wsGetSubUserList() error {
|
||||
if !z.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
|
||||
return fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
}
|
||||
request := WsAuthenticatedRequest{}
|
||||
request.Channel = "getSubUserList"
|
||||
request.Event = zWebsocketAddChannel
|
||||
request.Accesskey = z.APIKey
|
||||
request.Sign = z.wsGenerateSignature(request)
|
||||
|
||||
return z.wsSend(request)
|
||||
}
|
||||
|
||||
func (z *ZB) wsDoTransferFunds(pair currency.Code, amount float64, fromUserName, toUserName string) error {
|
||||
if !z.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
|
||||
return fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
}
|
||||
request := WsDoTransferFundsRequest{
|
||||
Amount: amount,
|
||||
Currency: pair,
|
||||
FromUserName: fromUserName,
|
||||
ToUserName: toUserName,
|
||||
No: fmt.Sprintf("%v", time.Now().Unix()),
|
||||
}
|
||||
request.Channel = "doTransferFunds"
|
||||
request.Event = zWebsocketAddChannel
|
||||
request.Accesskey = z.APIKey
|
||||
request.Sign = z.wsGenerateSignature(request)
|
||||
|
||||
return z.wsSend(request)
|
||||
}
|
||||
|
||||
func (z *ZB) wsCreateSubUserKey(assetPerm, entrustPerm, leverPerm, moneyPerm bool, keyName, toUserID string) error {
|
||||
if !z.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
|
||||
return fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
}
|
||||
request := WsCreateSubUserKeyRequest{
|
||||
AssetPerm: assetPerm,
|
||||
EntrustPerm: entrustPerm,
|
||||
KeyName: keyName,
|
||||
LeverPerm: leverPerm,
|
||||
MoneyPerm: moneyPerm,
|
||||
No: fmt.Sprintf("%v", time.Now().Unix()),
|
||||
ToUserID: toUserID,
|
||||
}
|
||||
request.Channel = "createSubUserKey"
|
||||
request.Event = zWebsocketAddChannel
|
||||
request.Accesskey = z.APIKey
|
||||
request.Sign = z.wsGenerateSignature(request)
|
||||
|
||||
return z.wsSend(request)
|
||||
return z.WebsocketConn.SendMessage(subscriptionRequest)
|
||||
}
|
||||
|
||||
func (z *ZB) wsGenerateSignature(request interface{}) string {
|
||||
jsonResponse, err := common.JSONEncode(request)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return ""
|
||||
}
|
||||
hmac := common.GetHMAC(common.HashMD5,
|
||||
jsonResponse,
|
||||
[]byte(common.Sha1ToHex(z.APISecret)))
|
||||
return fmt.Sprintf("%x", hmac)
|
||||
|
||||
}
|
||||
|
||||
func (z *ZB) wsFixInvalidJSON(json []byte) []byte {
|
||||
@@ -463,97 +272,296 @@ func (z *ZB) wsFixInvalidJSON(json []byte) []byte {
|
||||
return []byte(common.ReplaceString(string(json), string(matchingResults), fixedJSON, 1))
|
||||
}
|
||||
|
||||
func (z *ZB) wsSubmitOrder(pair currency.Pair, amount, price float64, tradeType int64) error {
|
||||
func (z *ZB) wsAddSubUser(username, password string) (*WsGetSubUserListResponse, error) {
|
||||
if !z.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
|
||||
return fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
return nil, fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
}
|
||||
request := WsAddSubUserRequest{
|
||||
Memo: "memo",
|
||||
Password: password,
|
||||
SubUserName: username,
|
||||
}
|
||||
request.Channel = "addSubUser"
|
||||
request.Event = zWebsocketAddChannel
|
||||
request.Accesskey = z.APIKey
|
||||
request.No = z.WebsocketConn.GenerateMessageID(true)
|
||||
request.Sign = z.wsGenerateSignature(request)
|
||||
resp, err := z.WebsocketConn.SendMessageReturnResponse(request.No, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var genericResponse Generic
|
||||
err = common.JSONDecode(resp, &genericResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if genericResponse.Code > 0 && genericResponse.Code != 1000 {
|
||||
return nil, fmt.Errorf("%v request failed, message: %v, error code: %v", z.Name, genericResponse.Message, wsErrCodes[genericResponse.Code])
|
||||
}
|
||||
var response WsGetSubUserListResponse
|
||||
err = common.JSONDecode(resp, &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
func (z *ZB) wsGetSubUserList() (*WsGetSubUserListResponse, error) {
|
||||
if !z.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
|
||||
return nil, fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
}
|
||||
request := WsAuthenticatedRequest{}
|
||||
request.Channel = "getSubUserList"
|
||||
request.Event = zWebsocketAddChannel
|
||||
request.Accesskey = z.APIKey
|
||||
request.No = z.WebsocketConn.GenerateMessageID(true)
|
||||
request.Sign = z.wsGenerateSignature(request)
|
||||
|
||||
resp, err := z.WebsocketConn.SendMessageReturnResponse(request.No, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var response WsGetSubUserListResponse
|
||||
err = common.JSONDecode(resp, &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.Code > 0 && response.Code != 1000 {
|
||||
return &response, fmt.Errorf("%v request failed, message: %v, error code: %v", z.Name, response.Message, wsErrCodes[response.Code])
|
||||
}
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
func (z *ZB) wsDoTransferFunds(pair currency.Code, amount float64, fromUserName, toUserName string) (*WsRequestResponse, error) {
|
||||
if !z.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
|
||||
return nil, fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
}
|
||||
request := WsDoTransferFundsRequest{
|
||||
Amount: amount,
|
||||
Currency: pair,
|
||||
FromUserName: fromUserName,
|
||||
ToUserName: toUserName,
|
||||
No: z.WebsocketConn.GenerateMessageID(true),
|
||||
}
|
||||
request.Channel = "doTransferFunds"
|
||||
request.Event = zWebsocketAddChannel
|
||||
request.Accesskey = z.APIKey
|
||||
request.Sign = z.wsGenerateSignature(request)
|
||||
|
||||
resp, err := z.WebsocketConn.SendMessageReturnResponse(request.No, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var response WsRequestResponse
|
||||
err = common.JSONDecode(resp, &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.Code > 0 && response.Code != 1000 {
|
||||
return &response, fmt.Errorf("%v request failed, message: %v, error code: %v", z.Name, response.Message, wsErrCodes[response.Code])
|
||||
}
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
func (z *ZB) wsCreateSubUserKey(assetPerm, entrustPerm, leverPerm, moneyPerm bool, keyName, toUserID string) (*WsRequestResponse, error) {
|
||||
if !z.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
|
||||
return nil, fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
}
|
||||
request := WsCreateSubUserKeyRequest{
|
||||
AssetPerm: assetPerm,
|
||||
EntrustPerm: entrustPerm,
|
||||
KeyName: keyName,
|
||||
LeverPerm: leverPerm,
|
||||
MoneyPerm: moneyPerm,
|
||||
No: z.WebsocketConn.GenerateMessageID(true),
|
||||
ToUserID: toUserID,
|
||||
}
|
||||
request.Channel = "createSubUserKey"
|
||||
request.Event = zWebsocketAddChannel
|
||||
request.Accesskey = z.APIKey
|
||||
request.Sign = z.wsGenerateSignature(request)
|
||||
|
||||
resp, err := z.WebsocketConn.SendMessageReturnResponse(request.No, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var response WsRequestResponse
|
||||
err = common.JSONDecode(resp, &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.Code > 0 && response.Code != 1000 {
|
||||
return &response, fmt.Errorf("%v request failed, message: %v, error code: %v", z.Name, response.Message, wsErrCodes[response.Code])
|
||||
}
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
func (z *ZB) wsSubmitOrder(pair currency.Pair, amount, price float64, tradeType int64) (*WsSubmitOrderResponse, error) {
|
||||
if !z.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
|
||||
return nil, fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
}
|
||||
request := WsSubmitOrderRequest{
|
||||
Amount: amount,
|
||||
Price: price,
|
||||
TradeType: tradeType,
|
||||
No: fmt.Sprintf("%v", time.Now().Unix()),
|
||||
No: z.WebsocketConn.GenerateMessageID(true),
|
||||
}
|
||||
request.Channel = fmt.Sprintf("%v_order", pair.String())
|
||||
request.Event = zWebsocketAddChannel
|
||||
request.Accesskey = z.APIKey
|
||||
request.Sign = z.wsGenerateSignature(request)
|
||||
|
||||
return z.wsSend(request)
|
||||
resp, err := z.WebsocketConn.SendMessageReturnResponse(request.No, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var response WsSubmitOrderResponse
|
||||
err = common.JSONDecode(resp, &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.Code > 0 && response.Code != 1000 {
|
||||
return &response, fmt.Errorf("%v request failed, message: %v, error code: %v", z.Name, response.Message, wsErrCodes[response.Code])
|
||||
}
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
func (z *ZB) wsCancelOrder(pair currency.Pair, orderID int64) error {
|
||||
func (z *ZB) wsCancelOrder(pair currency.Pair, orderID int64) (*WsCancelOrderResponse, error) {
|
||||
if !z.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
|
||||
return fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
return nil, fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
}
|
||||
request := WsCancelOrderRequest{
|
||||
ID: orderID,
|
||||
No: z.WebsocketConn.GenerateMessageID(true),
|
||||
}
|
||||
request.Channel = fmt.Sprintf("%v_cancelorder", pair.String())
|
||||
request.Event = zWebsocketAddChannel
|
||||
request.Accesskey = z.APIKey
|
||||
request.Sign = z.wsGenerateSignature(request)
|
||||
|
||||
return z.wsSend(request)
|
||||
resp, err := z.WebsocketConn.SendMessageReturnResponse(request.No, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var response WsCancelOrderResponse
|
||||
err = common.JSONDecode(resp, &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.Code > 0 && response.Code != 1000 {
|
||||
return &response, fmt.Errorf("%v request failed, message: %v, error code: %v", z.Name, response.Message, wsErrCodes[response.Code])
|
||||
}
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
func (z *ZB) wsGetOrder(pair currency.Pair, orderID int64) error {
|
||||
func (z *ZB) wsGetOrder(pair currency.Pair, orderID int64) (*WsGetOrderResponse, error) {
|
||||
if !z.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
|
||||
return fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
return nil, fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
}
|
||||
request := WsGetOrderRequest{
|
||||
ID: orderID,
|
||||
No: z.WebsocketConn.GenerateMessageID(true),
|
||||
}
|
||||
request.Channel = fmt.Sprintf("%v_getorder", pair.String())
|
||||
request.Event = zWebsocketAddChannel
|
||||
request.Accesskey = z.APIKey
|
||||
request.Sign = z.wsGenerateSignature(request)
|
||||
|
||||
return z.wsSend(request)
|
||||
resp, err := z.WebsocketConn.SendMessageReturnResponse(request.No, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var response WsGetOrderResponse
|
||||
err = common.JSONDecode(resp, &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.Code > 0 && response.Code != 1000 {
|
||||
return &response, fmt.Errorf("%v request failed, message: %v, error code: %v", z.Name, response.Message, wsErrCodes[response.Code])
|
||||
}
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
func (z *ZB) wsGetOrders(pair currency.Pair, pageIndex, tradeType int64) error {
|
||||
func (z *ZB) wsGetOrders(pair currency.Pair, pageIndex, tradeType int64) (*WsGetOrdersResponse, error) {
|
||||
if !z.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
|
||||
return fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
return nil, fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
}
|
||||
request := WsGetOrdersRequest{
|
||||
PageIndex: pageIndex,
|
||||
TradeType: tradeType,
|
||||
No: z.WebsocketConn.GenerateMessageID(true),
|
||||
}
|
||||
request.Channel = fmt.Sprintf("%v_getorders", pair.String())
|
||||
request.Event = zWebsocketAddChannel
|
||||
request.Accesskey = z.APIKey
|
||||
request.Sign = z.wsGenerateSignature(request)
|
||||
|
||||
return z.wsSend(request)
|
||||
resp, err := z.WebsocketConn.SendMessageReturnResponse(request.No, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var response WsGetOrdersResponse
|
||||
err = common.JSONDecode(resp, &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.Code > 0 && response.Code != 1000 {
|
||||
return &response, fmt.Errorf("%v request failed, message: %v, error code: %v", z.Name, response.Message, wsErrCodes[response.Code])
|
||||
}
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
func (z *ZB) wsGetOrdersIgnoreTradeType(pair currency.Pair, pageIndex, pageSize int64) error {
|
||||
func (z *ZB) wsGetOrdersIgnoreTradeType(pair currency.Pair, pageIndex, pageSize int64) (*WsGetOrdersIgnoreTradeTypeResponse, error) {
|
||||
if !z.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
|
||||
return fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
return nil, fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
}
|
||||
request := WsGetOrdersIgnoreTradeTypeRequest{
|
||||
PageIndex: pageIndex,
|
||||
PageSize: pageSize,
|
||||
No: z.WebsocketConn.GenerateMessageID(true),
|
||||
}
|
||||
request.Channel = fmt.Sprintf("%v_getordersignoretradetype", pair.String())
|
||||
request.Event = zWebsocketAddChannel
|
||||
request.Accesskey = z.APIKey
|
||||
request.Sign = z.wsGenerateSignature(request)
|
||||
|
||||
return z.wsSend(request)
|
||||
resp, err := z.WebsocketConn.SendMessageReturnResponse(request.No, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var response WsGetOrdersIgnoreTradeTypeResponse
|
||||
err = common.JSONDecode(resp, &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.Code > 0 && response.Code != 1000 {
|
||||
return &response, fmt.Errorf("%v request failed, message: %v, error code: %v", z.Name, response.Message, wsErrCodes[response.Code])
|
||||
}
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
func (z *ZB) wsGetAccountInfoRequest() error {
|
||||
func (z *ZB) wsGetAccountInfoRequest() (*WsGetAccountInfoResponse, error) {
|
||||
if !z.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
|
||||
return fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
return nil, fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", z.Name)
|
||||
}
|
||||
request := WsAuthenticatedRequest{
|
||||
Channel: "getaccountinfo",
|
||||
Event: zWebsocketAddChannel,
|
||||
Accesskey: z.APIKey,
|
||||
No: fmt.Sprintf("%v", time.Now().Unix()),
|
||||
No: z.WebsocketConn.GenerateMessageID(true),
|
||||
}
|
||||
request.Sign = z.wsGenerateSignature(request)
|
||||
|
||||
return z.wsSend(request)
|
||||
resp, err := z.WebsocketConn.SendMessageReturnResponse(request.No, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var response WsGetAccountInfoResponse
|
||||
err = common.JSONDecode(resp, &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.Code > 0 && response.Code != 1000 {
|
||||
return &response, fmt.Errorf("%v request failed, message: %v, error code: %v", z.Name, response.Message, wsErrCodes[response.Code])
|
||||
}
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
@@ -10,15 +10,15 @@ import (
|
||||
type Subscription struct {
|
||||
Event string `json:"event"`
|
||||
Channel string `json:"channel"`
|
||||
No int64 `json:"no,string,omitempty"`
|
||||
}
|
||||
|
||||
// Generic defines a generic fields associated with many return types
|
||||
type Generic struct {
|
||||
Code int64 `json:"code"`
|
||||
Success bool `json:"success"`
|
||||
Channel string `json:"channel"`
|
||||
Message interface{} `json:"message"`
|
||||
No string `json:"no"`
|
||||
No int64 `json:"no,string,omitempty"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ type WsAuthenticatedRequest struct {
|
||||
Accesskey string `json:"accesskey"`
|
||||
Channel string `json:"channel"`
|
||||
Event string `json:"event"`
|
||||
No string `json:"no,omitempty"`
|
||||
No int64 `json:"no,string,omitempty"`
|
||||
Sign string `json:"sign,omitempty"`
|
||||
}
|
||||
|
||||
@@ -74,10 +74,11 @@ type WsAddSubUserRequest struct {
|
||||
Accesskey string `json:"accesskey"`
|
||||
Channel string `json:"channel"`
|
||||
Event string `json:"event"`
|
||||
Sign string `json:"sign,omitempty"`
|
||||
Memo string `json:"memo"`
|
||||
Password string `json:"password"`
|
||||
SubUserName string `json:"subUserName"`
|
||||
No int64 `json:"no,string,omtempty"`
|
||||
Sign string `json:"sign,omitempty"`
|
||||
}
|
||||
|
||||
// WsCreateSubUserKeyRequest data to add sub user keys
|
||||
@@ -90,7 +91,7 @@ type WsCreateSubUserKeyRequest struct {
|
||||
KeyName string `json:"keyName"`
|
||||
LeverPerm bool `json:"leverPerm,string"`
|
||||
MoneyPerm bool `json:"moneyPerm,string"`
|
||||
No string `json:"no"`
|
||||
No int64 `json:"no,string,omitempty"`
|
||||
Sign string `json:"sign,omitempty"`
|
||||
ToUserID string `json:"toUserId"`
|
||||
}
|
||||
@@ -103,7 +104,7 @@ type WsDoTransferFundsRequest struct {
|
||||
Currency currency.Code `json:"currency"`
|
||||
Event string `json:"event"`
|
||||
FromUserName string `json:"fromUserName"`
|
||||
No string `json:"no"`
|
||||
No int64 `json:"no,string"`
|
||||
Sign string `json:"sign,omitempty"`
|
||||
ToUserName string `json:"toUserName"`
|
||||
}
|
||||
@@ -114,7 +115,7 @@ type WsGetSubUserListResponse struct {
|
||||
Code int64 `json:"code"`
|
||||
Channel string `json:"channel"`
|
||||
Message []WsGetSubUserListResponseData `json:"message"`
|
||||
No string `json:"no"`
|
||||
No int64 `json:"no,string"`
|
||||
}
|
||||
|
||||
// WsGetSubUserListResponseData user data
|
||||
@@ -132,7 +133,7 @@ type WsRequestResponse struct {
|
||||
Code int64 `json:"code"`
|
||||
Channel string `json:"channel"`
|
||||
Message interface{} `json:"message"`
|
||||
No string `json:"no"`
|
||||
No int64 `json:"no,string"`
|
||||
}
|
||||
|
||||
// WsSubmitOrderRequest creates an order via ws
|
||||
@@ -141,7 +142,7 @@ type WsSubmitOrderRequest struct {
|
||||
Amount float64 `json:"amount,string"`
|
||||
Channel string `json:"channel"`
|
||||
Event string `json:"event"`
|
||||
No string `json:"no,omitempty"`
|
||||
No int64 `json:"no,string,omitempty"`
|
||||
Price float64 `json:"price,string"`
|
||||
Sign string `json:"sign,omitempty"`
|
||||
TradeType int64 `json:"tradeType,string"`
|
||||
@@ -150,7 +151,7 @@ type WsSubmitOrderRequest struct {
|
||||
// WsSubmitOrderResponse data about submitted order
|
||||
type WsSubmitOrderResponse struct {
|
||||
Message string `json:"message"`
|
||||
No string `json:"no"`
|
||||
No int64 `json:"no,string"`
|
||||
Data struct {
|
||||
EntrustID int64 `json:"intrustID"`
|
||||
} `json:"data"`
|
||||
@@ -166,12 +167,13 @@ type WsCancelOrderRequest struct {
|
||||
Event string `json:"event"`
|
||||
ID int64 `json:"id"`
|
||||
Sign string `json:"sign,omitempty"`
|
||||
No int64 `json:"no,string"`
|
||||
}
|
||||
|
||||
// WsCancelOrderResponse order cancel response
|
||||
type WsCancelOrderResponse struct {
|
||||
Message string `json:"message"`
|
||||
No string `json:"no"`
|
||||
No int64 `json:"no,string"`
|
||||
Code int64 `json:"code"`
|
||||
Channel string `json:"channel"`
|
||||
Success bool `json:"success"`
|
||||
@@ -184,12 +186,13 @@ type WsGetOrderRequest struct {
|
||||
Event string `json:"event"`
|
||||
ID int64 `json:"id"`
|
||||
Sign string `json:"sign,omitempty"`
|
||||
No int64 `json:"no,string"`
|
||||
}
|
||||
|
||||
// WsGetOrderResponse contains order data
|
||||
type WsGetOrderResponse struct {
|
||||
Message string `json:"message"`
|
||||
No string `json:"no"`
|
||||
No int64 `json:"no,string"`
|
||||
Code int64 `json:"code"`
|
||||
Channel string `json:"channel"`
|
||||
Success bool `json:"success"`
|
||||
@@ -209,6 +212,7 @@ type WsGetOrderResponseData struct {
|
||||
TradeDate int64 `json:"trade_date"`
|
||||
TradeMoney float64 `json:"trade_money"`
|
||||
Type int64 `json:"type"`
|
||||
No int64 `json:"no,string"`
|
||||
}
|
||||
|
||||
// WsGetOrdersRequest get more orders, with no orderID filtering
|
||||
@@ -216,6 +220,7 @@ type WsGetOrdersRequest struct {
|
||||
Accesskey string `json:"accesskey"`
|
||||
Channel string `json:"channel"`
|
||||
Event string `json:"event"`
|
||||
No int64 `json:"no,string"`
|
||||
PageIndex int64 `json:"pageIndex"`
|
||||
TradeType int64 `json:"tradeType"`
|
||||
Sign string `json:"sign,omitempty"`
|
||||
@@ -224,7 +229,7 @@ type WsGetOrdersRequest struct {
|
||||
// WsGetOrdersResponse contains orders data
|
||||
type WsGetOrdersResponse struct {
|
||||
Message string `json:"message"`
|
||||
No string `json:"no"`
|
||||
No int64 `json:"no,string"`
|
||||
Code int64 `json:"code"`
|
||||
Channel string `json:"channel"`
|
||||
Success bool `json:"success"`
|
||||
@@ -236,7 +241,7 @@ type WsGetOrdersIgnoreTradeTypeRequest struct {
|
||||
Accesskey string `json:"accesskey"`
|
||||
Channel string `json:"channel"`
|
||||
Event string `json:"event"`
|
||||
ID int64 `json:"id"`
|
||||
No int64 `json:"no,string"`
|
||||
PageIndex int64 `json:"pageIndex"`
|
||||
PageSize int64 `json:"pageSize"`
|
||||
Sign string `json:"sign,omitempty"`
|
||||
@@ -245,7 +250,7 @@ type WsGetOrdersIgnoreTradeTypeRequest struct {
|
||||
// WsGetOrdersIgnoreTradeTypeResponse contains orders data
|
||||
type WsGetOrdersIgnoreTradeTypeResponse struct {
|
||||
Message string `json:"message"`
|
||||
No string `json:"no"`
|
||||
No int64 `json:"no,string"`
|
||||
Code int64 `json:"code"`
|
||||
Channel string `json:"channel"`
|
||||
Success bool `json:"success"`
|
||||
@@ -255,12 +260,12 @@ type WsGetOrdersIgnoreTradeTypeResponse struct {
|
||||
// WsGetAccountInfoResponse contains account data
|
||||
type WsGetAccountInfoResponse struct {
|
||||
Message string `json:"message"`
|
||||
No string `json:"no"`
|
||||
No int64 `json:"no,string"`
|
||||
Data struct {
|
||||
Coins []struct {
|
||||
Freez float64 `json:"freez,string"`
|
||||
EnName string `json:"enName"`
|
||||
UnitDecimal int `json:"unitDecimal"`
|
||||
UnitDecimal int64 `json:"unitDecimal"`
|
||||
CnName string `json:"cnName"`
|
||||
UnitTag string `json:"unitTag"`
|
||||
Available float64 `json:"available,string"`
|
||||
@@ -273,7 +278,7 @@ type WsGetAccountInfoResponse struct {
|
||||
AuthMobileEnabled bool `json:"auth_mobile_enabled"`
|
||||
} `json:"base"`
|
||||
} `json:"data"`
|
||||
Code int `json:"code"`
|
||||
Code int64 `json:"code"`
|
||||
Channel string `json:"channel"`
|
||||
Success bool `json:"success"`
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
exchange "github.com/thrasher-/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/wshandler"
|
||||
log "github.com/thrasher-/gocryptotrader/logger"
|
||||
)
|
||||
|
||||
@@ -299,7 +300,7 @@ func (z *ZB) WithdrawFiatFundsToInternationalBank(withdrawRequest *exchange.With
|
||||
}
|
||||
|
||||
// GetWebsocket returns a pointer to the exchange websocket
|
||||
func (z *ZB) GetWebsocket() (*exchange.Websocket, error) {
|
||||
func (z *ZB) GetWebsocket() (*wshandler.Websocket, error) {
|
||||
return z.Websocket, nil
|
||||
}
|
||||
|
||||
@@ -414,19 +415,19 @@ func (z *ZB) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequest) ([]exc
|
||||
|
||||
// SubscribeToWebsocketChannels appends to ChannelsToSubscribe
|
||||
// which lets websocket.manageSubscriptions handle subscribing
|
||||
func (z *ZB) SubscribeToWebsocketChannels(channels []exchange.WebsocketChannelSubscription) error {
|
||||
func (z *ZB) SubscribeToWebsocketChannels(channels []wshandler.WebsocketChannelSubscription) error {
|
||||
z.Websocket.SubscribeToChannels(channels)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnsubscribeToWebsocketChannels removes from ChannelsToSubscribe
|
||||
// which lets websocket.manageSubscriptions handle unsubscribing
|
||||
func (z *ZB) UnsubscribeToWebsocketChannels(channels []exchange.WebsocketChannelSubscription) error {
|
||||
func (z *ZB) UnsubscribeToWebsocketChannels(channels []wshandler.WebsocketChannelSubscription) error {
|
||||
return common.ErrFunctionNotSupported
|
||||
}
|
||||
|
||||
// GetSubscriptions returns a copied list of subscriptions
|
||||
func (z *ZB) GetSubscriptions() ([]exchange.WebsocketChannelSubscription, error) {
|
||||
func (z *ZB) GetSubscriptions() ([]wshandler.WebsocketChannelSubscription, error) {
|
||||
return z.Websocket.GetSubscriptions(), nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user