mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-19 23:16:48 +00:00
* Renames func. Creates new func to setup pinghander either via gorilla style or our own
* Cleans up all ping pong handlers.......
* Clears up issues, makes naming a bit better
* Adds tests
* Adds ping support to binance
* Cleans up ping pongs and adds a comment
* Cleans up waitgroup stuff.
* DISCREETLY cleans up woeful function
* Fixes Kraken ping message type. Removes unnecessary test property. Adds `if err == websocket.ErrCloseSent {` to ping func
* +1 for +v
633 lines
19 KiB
Go
633 lines
19 KiB
Go
package hitbtc
|
|
|
|
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/nonce"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wshandler"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wsorderbook"
|
|
log "github.com/thrasher-corp/gocryptotrader/logger"
|
|
)
|
|
|
|
const (
|
|
hitbtcWebsocketAddress = "wss://api.hitbtc.com/api/2/ws"
|
|
rpcVersion = "2.0"
|
|
rateLimit = 20
|
|
)
|
|
|
|
var requestID nonce.Nonce
|
|
|
|
// WsConnect starts a new connection with the websocket API
|
|
func (h *HitBTC) WsConnect() error {
|
|
if !h.Websocket.IsEnabled() || !h.IsEnabled() {
|
|
return errors.New(wshandler.WebsocketNotEnabled)
|
|
}
|
|
var dialer websocket.Dialer
|
|
err := h.WebsocketConn.Dial(&dialer, http.Header{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
go h.WsHandleData()
|
|
err = h.wsLogin()
|
|
if err != nil {
|
|
log.Errorf(log.ExchangeSys, "%v - authentication failed: %v\n", h.Name, err)
|
|
}
|
|
|
|
h.GenerateDefaultSubscriptions()
|
|
|
|
return nil
|
|
}
|
|
|
|
// WsHandleData handles websocket data
|
|
func (h *HitBTC) WsHandleData() {
|
|
h.Websocket.Wg.Add(1)
|
|
|
|
defer func() {
|
|
h.Websocket.Wg.Done()
|
|
}()
|
|
|
|
for {
|
|
select {
|
|
case <-h.Websocket.ShutdownC:
|
|
return
|
|
|
|
default:
|
|
resp, err := h.WebsocketConn.ReadMessage()
|
|
if err != nil {
|
|
h.Websocket.ReadMessageErrors <- err
|
|
return
|
|
}
|
|
h.Websocket.TrafficAlert <- struct{}{}
|
|
|
|
var init capture
|
|
err = json.Unmarshal(resp.Raw, &init)
|
|
if err != nil {
|
|
h.Websocket.DataHandler <- err
|
|
continue
|
|
}
|
|
if init.Error.Code == 1002 {
|
|
h.Websocket.SetCanUseAuthenticatedEndpoints(false)
|
|
}
|
|
if init.ID > 0 {
|
|
h.WebsocketConn.AddResponseWithID(init.ID, resp.Raw)
|
|
continue
|
|
}
|
|
if init.Error.Message != "" || init.Error.Code != 0 {
|
|
h.Websocket.DataHandler <- fmt.Errorf("hitbtc.go error - Code: %d, Message: %s",
|
|
init.Error.Code,
|
|
init.Error.Message)
|
|
continue
|
|
}
|
|
if _, ok := init.Result.(bool); ok {
|
|
continue
|
|
}
|
|
if init.Method != "" {
|
|
h.handleSubscriptionUpdates(resp, init)
|
|
} else {
|
|
h.handleCommandResponses(resp, init)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (h *HitBTC) handleSubscriptionUpdates(resp wshandler.WebsocketResponse, init capture) {
|
|
switch init.Method {
|
|
case "ticker":
|
|
var wsTicker WsTicker
|
|
err := json.Unmarshal(resp.Raw, &wsTicker)
|
|
if err != nil {
|
|
h.Websocket.DataHandler <- err
|
|
return
|
|
}
|
|
ts, err := time.Parse(time.RFC3339, wsTicker.Params.Timestamp)
|
|
if err != nil {
|
|
h.Websocket.DataHandler <- err
|
|
return
|
|
}
|
|
h.Websocket.DataHandler <- &ticker.Price{
|
|
ExchangeName: h.Name,
|
|
Open: wsTicker.Params.Open,
|
|
Volume: wsTicker.Params.Volume,
|
|
QuoteVolume: wsTicker.Params.VolumeQuote,
|
|
High: wsTicker.Params.High,
|
|
Low: wsTicker.Params.Low,
|
|
Bid: wsTicker.Params.Bid,
|
|
Ask: wsTicker.Params.Ask,
|
|
Last: wsTicker.Params.Last,
|
|
LastUpdated: ts,
|
|
AssetType: asset.Spot,
|
|
Pair: currency.NewPairFromFormattedPairs(wsTicker.Params.Symbol,
|
|
h.GetEnabledPairs(asset.Spot), h.GetPairFormat(asset.Spot, true)),
|
|
}
|
|
case "snapshotOrderbook":
|
|
var obSnapshot WsOrderbook
|
|
err := json.Unmarshal(resp.Raw, &obSnapshot)
|
|
if err != nil {
|
|
h.Websocket.DataHandler <- err
|
|
}
|
|
err = h.WsProcessOrderbookSnapshot(obSnapshot)
|
|
if err != nil {
|
|
h.Websocket.DataHandler <- err
|
|
}
|
|
case "updateOrderbook":
|
|
var obUpdate WsOrderbook
|
|
err := json.Unmarshal(resp.Raw, &obUpdate)
|
|
if err != nil {
|
|
h.Websocket.DataHandler <- err
|
|
}
|
|
h.WsProcessOrderbookUpdate(obUpdate)
|
|
case "snapshotTrades":
|
|
var tradeSnapshot WsTrade
|
|
err := json.Unmarshal(resp.Raw, &tradeSnapshot)
|
|
if err != nil {
|
|
h.Websocket.DataHandler <- err
|
|
}
|
|
case "updateTrades":
|
|
var tradeUpdates WsTrade
|
|
err := json.Unmarshal(resp.Raw, &tradeUpdates)
|
|
if err != nil {
|
|
h.Websocket.DataHandler <- err
|
|
}
|
|
case "activeOrders":
|
|
var activeOrders WsActiveOrdersResponse
|
|
err := json.Unmarshal(resp.Raw, &activeOrders)
|
|
if err != nil {
|
|
h.Websocket.DataHandler <- err
|
|
}
|
|
h.Websocket.DataHandler <- activeOrders
|
|
case "report":
|
|
var reportData WsReportResponse
|
|
err := json.Unmarshal(resp.Raw, &reportData)
|
|
if err != nil {
|
|
h.Websocket.DataHandler <- err
|
|
}
|
|
h.Websocket.DataHandler <- reportData
|
|
}
|
|
}
|
|
|
|
func (h *HitBTC) handleCommandResponses(resp wshandler.WebsocketResponse, init capture) {
|
|
switch resultType := init.Result.(type) {
|
|
case map[string]interface{}:
|
|
switch resultType["reportType"].(string) {
|
|
case "new":
|
|
var response WsSubmitOrderSuccessResponse
|
|
err := json.Unmarshal(resp.Raw, &response)
|
|
if err != nil {
|
|
h.Websocket.DataHandler <- err
|
|
}
|
|
h.Websocket.DataHandler <- response
|
|
case "canceled":
|
|
var response WsCancelOrderResponse
|
|
err := json.Unmarshal(resp.Raw, &response)
|
|
if err != nil {
|
|
h.Websocket.DataHandler <- err
|
|
}
|
|
h.Websocket.DataHandler <- response
|
|
case "replaced":
|
|
var response WsReplaceOrderResponse
|
|
err := json.Unmarshal(resp.Raw, &response)
|
|
if err != nil {
|
|
h.Websocket.DataHandler <- err
|
|
}
|
|
h.Websocket.DataHandler <- response
|
|
}
|
|
case []interface{}:
|
|
if len(resultType) == 0 {
|
|
h.Websocket.DataHandler <- fmt.Sprintf("No data returned. ID: %v", init.ID)
|
|
return
|
|
}
|
|
data := resultType[0].(map[string]interface{})
|
|
if _, ok := data["clientOrderId"]; ok {
|
|
var response WsActiveOrdersResponse
|
|
err := json.Unmarshal(resp.Raw, &response)
|
|
if err != nil {
|
|
h.Websocket.DataHandler <- err
|
|
}
|
|
h.Websocket.DataHandler <- response
|
|
} else if _, ok := data["available"]; ok {
|
|
var response WsGetTradingBalanceResponse
|
|
err := json.Unmarshal(resp.Raw, &response)
|
|
if err != nil {
|
|
h.Websocket.DataHandler <- err
|
|
}
|
|
h.Websocket.DataHandler <- response
|
|
}
|
|
}
|
|
}
|
|
|
|
// WsProcessOrderbookSnapshot processes a full orderbook snapshot to a local cache
|
|
func (h *HitBTC) WsProcessOrderbookSnapshot(ob WsOrderbook) error {
|
|
if len(ob.Params.Bid) == 0 || len(ob.Params.Ask) == 0 {
|
|
return errors.New("hitbtc.go error - no orderbooks to process")
|
|
}
|
|
|
|
var newOrderBook orderbook.Base
|
|
for i := range ob.Params.Bid {
|
|
newOrderBook.Bids = append(newOrderBook.Bids, orderbook.Item{
|
|
Amount: ob.Params.Bid[i].Size,
|
|
Price: ob.Params.Bid[i].Price,
|
|
})
|
|
}
|
|
|
|
for i := range ob.Params.Ask {
|
|
newOrderBook.Asks = append(newOrderBook.Asks, orderbook.Item{
|
|
Amount: ob.Params.Ask[i].Size,
|
|
Price: ob.Params.Ask[i].Price,
|
|
})
|
|
}
|
|
|
|
p := currency.NewPairFromFormattedPairs(ob.Params.Symbol,
|
|
h.GetEnabledPairs(asset.Spot), h.GetPairFormat(asset.Spot, true))
|
|
newOrderBook.AssetType = asset.Spot
|
|
newOrderBook.Pair = p
|
|
newOrderBook.ExchangeName = h.Name
|
|
|
|
err := h.Websocket.Orderbook.LoadSnapshot(&newOrderBook)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
h.Websocket.DataHandler <- wshandler.WebsocketOrderbookUpdate{
|
|
Exchange: h.Name,
|
|
Asset: asset.Spot,
|
|
Pair: p,
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// WsProcessOrderbookUpdate updates a local cache
|
|
func (h *HitBTC) WsProcessOrderbookUpdate(update WsOrderbook) error {
|
|
if len(update.Params.Bid) == 0 && len(update.Params.Ask) == 0 {
|
|
return errors.New("hitbtc_websocket.go error - no data")
|
|
}
|
|
|
|
var bids, asks []orderbook.Item
|
|
for i := range update.Params.Bid {
|
|
bids = append(bids, orderbook.Item{
|
|
Price: update.Params.Bid[i].Price,
|
|
Amount: update.Params.Bid[i].Size,
|
|
})
|
|
}
|
|
|
|
for i := range update.Params.Ask {
|
|
asks = append(asks, orderbook.Item{
|
|
Price: update.Params.Ask[i].Price,
|
|
Amount: update.Params.Ask[i].Size,
|
|
})
|
|
}
|
|
|
|
p := currency.NewPairFromFormattedPairs(update.Params.Symbol,
|
|
h.GetEnabledPairs(asset.Spot), h.GetPairFormat(asset.Spot, true))
|
|
err := h.Websocket.Orderbook.Update(&wsorderbook.WebsocketOrderbookUpdate{
|
|
Asks: asks,
|
|
Bids: bids,
|
|
Pair: p,
|
|
UpdateID: update.Params.Sequence,
|
|
Asset: asset.Spot,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
h.Websocket.DataHandler <- wshandler.WebsocketOrderbookUpdate{
|
|
Exchange: h.Name,
|
|
Asset: asset.Spot,
|
|
Pair: p,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GenerateDefaultSubscriptions Adds default subscriptions to websocket to be handled by ManageSubscriptions()
|
|
func (h *HitBTC) GenerateDefaultSubscriptions() {
|
|
var channels = []string{"subscribeTicker", "subscribeOrderbook", "subscribeTrades", "subscribeCandles"}
|
|
var subscriptions []wshandler.WebsocketChannelSubscription
|
|
if h.Websocket.CanUseAuthenticatedEndpoints() {
|
|
subscriptions = append(subscriptions, wshandler.WebsocketChannelSubscription{
|
|
Channel: "subscribeReports",
|
|
})
|
|
}
|
|
enabledCurrencies := h.GetEnabledPairs(asset.Spot)
|
|
for i := range channels {
|
|
for j := range enabledCurrencies {
|
|
enabledCurrencies[j].Delimiter = ""
|
|
subscriptions = append(subscriptions, wshandler.WebsocketChannelSubscription{
|
|
Channel: channels[i],
|
|
Currency: enabledCurrencies[j],
|
|
})
|
|
}
|
|
}
|
|
h.Websocket.SubscribeToChannels(subscriptions)
|
|
}
|
|
|
|
// Subscribe sends a websocket message to receive data from the channel
|
|
func (h *HitBTC) Subscribe(channelToSubscribe wshandler.WebsocketChannelSubscription) error {
|
|
subscribe := WsNotification{
|
|
Method: channelToSubscribe.Channel,
|
|
}
|
|
if channelToSubscribe.Currency.String() != "" {
|
|
subscribe.Params = params{
|
|
Symbol: h.FormatExchangeCurrency(channelToSubscribe.Currency,
|
|
asset.Spot).String(),
|
|
}
|
|
}
|
|
if strings.EqualFold(channelToSubscribe.Channel, "subscribeTrades") {
|
|
subscribe.Params = params{
|
|
Symbol: h.FormatExchangeCurrency(channelToSubscribe.Currency,
|
|
asset.Spot).String(),
|
|
Limit: 100,
|
|
}
|
|
} else if strings.EqualFold(channelToSubscribe.Channel, "subscribeCandles") {
|
|
subscribe.Params = params{
|
|
Symbol: h.FormatExchangeCurrency(channelToSubscribe.Currency,
|
|
asset.Spot).String(),
|
|
Period: "M30",
|
|
Limit: 100,
|
|
}
|
|
}
|
|
|
|
return h.WebsocketConn.SendJSONMessage(subscribe)
|
|
}
|
|
|
|
// Unsubscribe sends a websocket message to stop receiving data from the channel
|
|
func (h *HitBTC) Unsubscribe(channelToSubscribe wshandler.WebsocketChannelSubscription) error {
|
|
unsubscribeChannel := strings.Replace(channelToSubscribe.Channel, "subscribe", "unsubscribe", 1)
|
|
subscribe := WsNotification{
|
|
JSONRPCVersion: rpcVersion,
|
|
Method: unsubscribeChannel,
|
|
Params: params{
|
|
Symbol: h.FormatExchangeCurrency(channelToSubscribe.Currency,
|
|
asset.Spot).String(),
|
|
},
|
|
}
|
|
if strings.EqualFold(unsubscribeChannel, "unsubscribeTrades") {
|
|
subscribe.Params = params{
|
|
Symbol: h.FormatExchangeCurrency(channelToSubscribe.Currency,
|
|
asset.Spot).String(),
|
|
Limit: 100,
|
|
}
|
|
} else if strings.EqualFold(unsubscribeChannel, "unsubscribeCandles") {
|
|
subscribe.Params = params{
|
|
Symbol: h.FormatExchangeCurrency(channelToSubscribe.Currency,
|
|
asset.Spot).String(),
|
|
Period: "M30",
|
|
Limit: 100,
|
|
}
|
|
}
|
|
|
|
return h.WebsocketConn.SendJSONMessage(subscribe)
|
|
}
|
|
|
|
// Unsubscribe sends a websocket message to stop receiving data from the channel
|
|
func (h *HitBTC) wsLogin() error {
|
|
if !h.GetAuthenticatedAPISupport(exchange.WebsocketAuthentication) {
|
|
return fmt.Errorf("%v AuthenticatedWebsocketAPISupport not enabled", h.Name)
|
|
}
|
|
h.Websocket.SetCanUseAuthenticatedEndpoints(true)
|
|
nonce := strconv.FormatInt(time.Now().Unix(), 10)
|
|
hmac := crypto.GetHMAC(crypto.HashSHA256, []byte(nonce), []byte(h.API.Credentials.Secret))
|
|
request := WsLoginRequest{
|
|
Method: "login",
|
|
Params: WsLoginData{
|
|
Algo: "HS256",
|
|
PKey: h.API.Credentials.Key,
|
|
Nonce: nonce,
|
|
Signature: crypto.HexEncodeToString(hmac),
|
|
},
|
|
}
|
|
|
|
err := h.WebsocketConn.SendJSONMessage(request)
|
|
if err != nil {
|
|
h.Websocket.SetCanUseAuthenticatedEndpoints(false)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// wsPlaceOrder sends a websocket message to submit an order
|
|
func (h *HitBTC) wsPlaceOrder(pair currency.Pair, side string, price, quantity float64) (*WsSubmitOrderSuccessResponse, error) {
|
|
if !h.Websocket.CanUseAuthenticatedEndpoints() {
|
|
return nil, fmt.Errorf("%v not authenticated, cannot place order", h.Name)
|
|
}
|
|
id := h.WebsocketConn.GenerateMessageID(false)
|
|
request := WsSubmitOrderRequest{
|
|
Method: "newOrder",
|
|
Params: WsSubmitOrderRequestData{
|
|
ClientOrderID: id,
|
|
Symbol: h.FormatExchangeCurrency(pair, asset.Spot).String(),
|
|
Side: strings.ToLower(side),
|
|
Price: price,
|
|
Quantity: quantity,
|
|
},
|
|
ID: id,
|
|
}
|
|
resp, err := h.WebsocketConn.SendMessageReturnResponse(id, request)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%v %v", h.Name, err)
|
|
}
|
|
var response WsSubmitOrderSuccessResponse
|
|
err = json.Unmarshal(resp, &response)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%v %v", h.Name, err)
|
|
}
|
|
if response.Error.Code > 0 || response.Error.Message != "" {
|
|
return &response, fmt.Errorf("%v Error:%v Message:%v", h.Name, response.Error.Code, response.Error.Message)
|
|
}
|
|
return &response, nil
|
|
}
|
|
|
|
// wsCancelOrder sends a websocket message to cancel an order
|
|
func (h *HitBTC) wsCancelOrder(clientOrderID string) (*WsCancelOrderResponse, error) {
|
|
if !h.Websocket.CanUseAuthenticatedEndpoints() {
|
|
return nil, fmt.Errorf("%v not authenticated, cannot place order", h.Name)
|
|
}
|
|
request := WsCancelOrderRequest{
|
|
Method: "cancelOrder",
|
|
Params: WsCancelOrderRequestData{
|
|
ClientOrderID: clientOrderID,
|
|
},
|
|
ID: h.WebsocketConn.GenerateMessageID(false),
|
|
}
|
|
resp, err := h.WebsocketConn.SendMessageReturnResponse(request.ID, request)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%v %v", h.Name, err)
|
|
}
|
|
var response WsCancelOrderResponse
|
|
err = json.Unmarshal(resp, &response)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%v %v", h.Name, err)
|
|
}
|
|
if response.Error.Code > 0 || response.Error.Message != "" {
|
|
return &response, fmt.Errorf("%v Error:%v Message:%v", h.Name, response.Error.Code, response.Error.Message)
|
|
}
|
|
return &response, nil
|
|
}
|
|
|
|
// wsReplaceOrder sends a websocket message to replace an order
|
|
func (h *HitBTC) wsReplaceOrder(clientOrderID string, quantity, price float64) (*WsReplaceOrderResponse, error) {
|
|
if !h.Websocket.CanUseAuthenticatedEndpoints() {
|
|
return nil, fmt.Errorf("%v not authenticated, cannot place order", h.Name)
|
|
}
|
|
request := WsReplaceOrderRequest{
|
|
Method: "cancelReplaceOrder",
|
|
Params: WsReplaceOrderRequestData{
|
|
ClientOrderID: clientOrderID,
|
|
RequestClientID: strconv.FormatInt(time.Now().Unix(), 10),
|
|
Quantity: quantity,
|
|
Price: price,
|
|
},
|
|
ID: h.WebsocketConn.GenerateMessageID(false),
|
|
}
|
|
resp, err := h.WebsocketConn.SendMessageReturnResponse(request.ID, request)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%v %v", h.Name, err)
|
|
}
|
|
var response WsReplaceOrderResponse
|
|
err = json.Unmarshal(resp, &response)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%v %v", h.Name, err)
|
|
}
|
|
if response.Error.Code > 0 || response.Error.Message != "" {
|
|
return &response, fmt.Errorf("%v Error:%v Message:%v", h.Name, response.Error.Code, response.Error.Message)
|
|
}
|
|
return &response, nil
|
|
}
|
|
|
|
// wsGetActiveOrders sends a websocket message to get all active orders
|
|
func (h *HitBTC) wsGetActiveOrders() (*WsActiveOrdersResponse, error) {
|
|
if !h.Websocket.CanUseAuthenticatedEndpoints() {
|
|
return nil, fmt.Errorf("%v not authenticated, cannot place order", h.Name)
|
|
}
|
|
request := WsReplaceOrderRequest{
|
|
Method: "getOrders",
|
|
Params: WsReplaceOrderRequestData{},
|
|
ID: h.WebsocketConn.GenerateMessageID(false),
|
|
}
|
|
resp, err := h.WebsocketConn.SendMessageReturnResponse(request.ID, request)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%v %v", h.Name, err)
|
|
}
|
|
var response WsActiveOrdersResponse
|
|
err = json.Unmarshal(resp, &response)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%v %v", h.Name, err)
|
|
}
|
|
if response.Error.Code > 0 || response.Error.Message != "" {
|
|
return &response, fmt.Errorf("%v Error:%v Message:%v", h.Name, response.Error.Code, response.Error.Message)
|
|
}
|
|
return &response, nil
|
|
}
|
|
|
|
// wsGetTradingBalance sends a websocket message to get trading balance
|
|
func (h *HitBTC) wsGetTradingBalance() (*WsGetTradingBalanceResponse, error) {
|
|
if !h.Websocket.CanUseAuthenticatedEndpoints() {
|
|
return nil, fmt.Errorf("%v not authenticated, cannot place order", h.Name)
|
|
}
|
|
request := WsReplaceOrderRequest{
|
|
Method: "getTradingBalance",
|
|
Params: WsReplaceOrderRequestData{},
|
|
ID: h.WebsocketConn.GenerateMessageID(false),
|
|
}
|
|
resp, err := h.WebsocketConn.SendMessageReturnResponse(request.ID, request)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%v %v", h.Name, err)
|
|
}
|
|
var response WsGetTradingBalanceResponse
|
|
err = json.Unmarshal(resp, &response)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%v %v", h.Name, err)
|
|
}
|
|
if response.Error.Code > 0 || response.Error.Message != "" {
|
|
return &response, fmt.Errorf("%v Error:%v Message:%v", h.Name, response.Error.Code, response.Error.Message)
|
|
}
|
|
return &response, nil
|
|
}
|
|
|
|
// wsGetCurrencies sends a websocket message to get trading balance
|
|
func (h *HitBTC) wsGetCurrencies(currencyItem currency.Code) (*WsGetCurrenciesResponse, error) {
|
|
request := WsGetCurrenciesRequest{
|
|
Method: "getCurrency",
|
|
Params: WsGetCurrenciesRequestParameters{
|
|
Currency: currencyItem,
|
|
},
|
|
ID: h.WebsocketConn.GenerateMessageID(false),
|
|
}
|
|
resp, err := h.WebsocketConn.SendMessageReturnResponse(request.ID, request)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%v %v", h.Name, err)
|
|
}
|
|
var response WsGetCurrenciesResponse
|
|
err = json.Unmarshal(resp, &response)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%v %v", h.Name, err)
|
|
}
|
|
if response.Error.Code > 0 || response.Error.Message != "" {
|
|
return &response, fmt.Errorf("%v Error:%v Message:%v", h.Name, response.Error.Code, response.Error.Message)
|
|
}
|
|
return &response, nil
|
|
}
|
|
|
|
// wsGetSymbols sends a websocket message to get trading balance
|
|
func (h *HitBTC) wsGetSymbols(currencyItem currency.Pair) (*WsGetSymbolsResponse, error) {
|
|
request := WsGetSymbolsRequest{
|
|
Method: "getSymbol",
|
|
Params: WsGetSymbolsRequestParameters{
|
|
Symbol: h.FormatExchangeCurrency(currencyItem, asset.Spot).String(),
|
|
},
|
|
ID: h.WebsocketConn.GenerateMessageID(false),
|
|
}
|
|
resp, err := h.WebsocketConn.SendMessageReturnResponse(request.ID, request)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%v %v", h.Name, err)
|
|
}
|
|
var response WsGetSymbolsResponse
|
|
err = json.Unmarshal(resp, &response)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%v %v", h.Name, err)
|
|
}
|
|
if response.Error.Code > 0 || response.Error.Message != "" {
|
|
return &response, fmt.Errorf("%v Error:%v Message:%v", h.Name, response.Error.Code, response.Error.Message)
|
|
}
|
|
return &response, nil
|
|
}
|
|
|
|
// wsGetSymbols sends a websocket message to get trading balance
|
|
func (h *HitBTC) wsGetTrades(currencyItem currency.Pair, limit int64, sort, by string) (*WsGetTradesResponse, error) {
|
|
request := WsGetTradesRequest{
|
|
Method: "getTrades",
|
|
Params: WsGetTradesRequestParameters{
|
|
Symbol: h.FormatExchangeCurrency(currencyItem, asset.Spot).String(),
|
|
Limit: limit,
|
|
Sort: sort,
|
|
By: by,
|
|
},
|
|
ID: h.WebsocketConn.GenerateMessageID(false),
|
|
}
|
|
resp, err := h.WebsocketConn.SendMessageReturnResponse(request.ID, request)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%v %v", h.Name, err)
|
|
}
|
|
var response WsGetTradesResponse
|
|
err = json.Unmarshal(resp, &response)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%v %v", h.Name, err)
|
|
}
|
|
if response.Error.Code > 0 || response.Error.Message != "" {
|
|
return &response, fmt.Errorf("%v Error:%v Message:%v", h.Name, response.Error.Code, response.Error.Message)
|
|
}
|
|
return &response, nil
|
|
}
|