mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-09 07:26:48 +00:00
Initial overhaul of websocket connection and feeds (#189)
* Initial overhaul of websocket connection and feeds * Added proxy support * Piped to routines.go * Added new websocket file in exchanges Refactored orderbook handling into exchange_websocket.go Added better error responses for binance_websocket.go General clean for binance_websocket.go * General fixes - bitfinex_websocket.go Refactored orderbook cache code - bitfinex_websocket.go Removed fatal error with unhandled type - routines.go * Added general improvements to bitmex_websocket.go Refactored orderbook handling to exchange_websocket.go Added variable in Item struct in orderbook.go for looking up orders by ID * Fix issue when routines are blocked due to Data Handler not started Updated traffic handler General fixes for bitstamp_websocket.go * General fixes for coinbasepro_websocket.go * General fixes for coinut_websocket.go Fixed error return in exchange_websocket.go * Removed comments in coinut_wrapper.go Refactor orderbook logic from hitbtc_websocket.go to exchange_websocket.go * General fixes * Removed comments General fixes * Updated routines.go * After rebase fix * Fixed update config pairs in okcoin.go * fixed config currency issue in okcoin.go for okcoin China * exchange_websocket.go *Removed unused const dec *Removed state change routine *Improved trafficMonitor routine *Increased verbosity for error returns *Removed uneeded mutex locks exchange_websocket_test.go *Added new tests for websocket and orderbook updating routines.go *Removed string cased * Fixed race conditions on sync.waitgroup in exchanges_websocket.go * Changes variable name in config.go * Removes unnecessary comment * Removes indefinite lock on error return * Removes unnecessary comment * Adds support for BTCC websocket Drops support for BTCC REST * Rewords comment in exchange_websocket.go Moves types to poloniex_types.go * Moves types to coinut_types.go * Removes uneeded range for accessing array variables for coinbase_websocket.go Removes comments in coinut_types.go * Adds verbosity flag to GCT Suppresses verbose output from routines.go * Fixes setting proxy for REST and Websocket per exchange Upgrades error handling Drops unused *url.Url variable in exchange type * Adds test for setting proxy * Fixes bug that closes connection due to incorrect timeout time through a proxy connection * Clarify verbose flag message
This commit is contained in:
committed by
Adrian Gallagher
parent
7315e6604c
commit
d3c2800fe0
@@ -9,6 +9,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/config"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges"
|
||||
@@ -49,6 +50,7 @@ const (
|
||||
// HitBTC is the overarching type across the hitbtc package
|
||||
type HitBTC struct {
|
||||
exchange.Base
|
||||
WebsocketConn *websocket.Conn
|
||||
}
|
||||
|
||||
// SetDefaults sets default settings for hitbtc
|
||||
@@ -57,7 +59,6 @@ func (p *HitBTC) SetDefaults() {
|
||||
p.Enabled = false
|
||||
p.Fee = 0
|
||||
p.Verbose = false
|
||||
p.Websocket = false
|
||||
p.RESTPollingDelay = 10
|
||||
p.RequestCurrencyPairFormat.Delimiter = ""
|
||||
p.RequestCurrencyPairFormat.Uppercase = true
|
||||
@@ -72,6 +73,7 @@ func (p *HitBTC) SetDefaults() {
|
||||
common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout))
|
||||
p.APIUrlDefault = apiURL
|
||||
p.APIUrl = p.APIUrlDefault
|
||||
p.WebsocketInit()
|
||||
}
|
||||
|
||||
// Setup sets user exchange configuration settings
|
||||
@@ -86,7 +88,7 @@ func (p *HitBTC) Setup(exch config.ExchangeConfig) {
|
||||
p.SetHTTPClientUserAgent(exch.HTTPUserAgent)
|
||||
p.RESTPollingDelay = exch.RESTPollingDelay // Max 60000ms
|
||||
p.Verbose = exch.Verbose
|
||||
p.Websocket = exch.Websocket
|
||||
p.Websocket.SetEnabled(exch.Websocket)
|
||||
p.BaseCurrencies = common.SplitStrings(exch.BaseCurrencies, ",")
|
||||
p.AvailablePairs = common.SplitStrings(exch.AvailablePairs, ",")
|
||||
p.EnabledPairs = common.SplitStrings(exch.EnabledPairs, ",")
|
||||
@@ -106,6 +108,18 @@ func (p *HitBTC) Setup(exch config.ExchangeConfig) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = p.SetClientProxyAddress(exch.ProxyAddress)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = p.WebsocketSetup(p.WsConnect,
|
||||
exch.Name,
|
||||
exch.Websocket,
|
||||
hitbtcWebsocketAddress,
|
||||
exch.WebsocketURL)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,188 +1,372 @@
|
||||
package hitbtc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/beatgammit/turnpike"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/thrasher-/gocryptotrader/common"
|
||||
"github.com/thrasher-/gocryptotrader/currency/pair"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
|
||||
)
|
||||
|
||||
const (
|
||||
hitbtcWebsocketAddress = "wss://api.hitbtc.com"
|
||||
hitbtcWebsocketRealm = "realm1"
|
||||
hitbtcWebsocketTicker = "ticker"
|
||||
hitbtcWebsocketTrollbox = "trollbox"
|
||||
hitbtcWebsocketAddress = "wss://api.hitbtc.com/api/2/ws"
|
||||
rpcVersion = "2.0"
|
||||
)
|
||||
|
||||
// WebsocketTicker holds ticker data
|
||||
type WebsocketTicker struct {
|
||||
CurrencyPair string
|
||||
Last float64
|
||||
LowestAsk float64
|
||||
HighestBid float64
|
||||
PercentChange float64
|
||||
BaseVolume float64
|
||||
QuoteVolume float64
|
||||
IsFrozen bool
|
||||
High float64
|
||||
Low float64
|
||||
}
|
||||
|
||||
// OnTicker converts ticker to websocket ticker
|
||||
func OnTicker(args []interface{}, kwargs map[string]interface{}) {
|
||||
ticker := WebsocketTicker{}
|
||||
ticker.CurrencyPair = args[0].(string)
|
||||
ticker.Last, _ = strconv.ParseFloat(args[1].(string), 64)
|
||||
ticker.LowestAsk, _ = strconv.ParseFloat(args[2].(string), 64)
|
||||
ticker.HighestBid, _ = strconv.ParseFloat(args[3].(string), 64)
|
||||
ticker.PercentChange, _ = strconv.ParseFloat(args[4].(string), 64)
|
||||
ticker.BaseVolume, _ = strconv.ParseFloat(args[5].(string), 64)
|
||||
ticker.QuoteVolume, _ = strconv.ParseFloat(args[6].(string), 64)
|
||||
|
||||
if args[7].(float64) != 0 {
|
||||
ticker.IsFrozen = true
|
||||
} else {
|
||||
ticker.IsFrozen = false
|
||||
// WsConnect starts a new connection with the websocket API
|
||||
func (h *HitBTC) WsConnect() error {
|
||||
if !h.Websocket.IsEnabled() || !h.IsEnabled() {
|
||||
return errors.New(exchange.WebsocketNotEnabled)
|
||||
}
|
||||
|
||||
ticker.High, _ = strconv.ParseFloat(args[8].(string), 64)
|
||||
ticker.Low, _ = strconv.ParseFloat(args[9].(string), 64)
|
||||
}
|
||||
var dialer websocket.Dialer
|
||||
|
||||
// WebsocketTrollboxMessage contains trollbox message information
|
||||
type WebsocketTrollboxMessage struct {
|
||||
MessageNumber float64
|
||||
Username string
|
||||
Message string
|
||||
Reputation float64
|
||||
}
|
||||
|
||||
// OnTrollbox converts trollbox messages
|
||||
func OnTrollbox(args []interface{}, kwargs map[string]interface{}) {
|
||||
message := WebsocketTrollboxMessage{}
|
||||
message.MessageNumber, _ = args[1].(float64)
|
||||
message.Username = args[2].(string)
|
||||
message.Message = args[3].(string)
|
||||
if len(args) == 5 {
|
||||
message.Reputation = args[4].(float64)
|
||||
}
|
||||
}
|
||||
|
||||
// OnDepthOrTrade converts depth and trade data
|
||||
func OnDepthOrTrade(args []interface{}, kwargs map[string]interface{}) {
|
||||
for x := range args {
|
||||
data := args[x].(map[string]interface{})
|
||||
msgData := data["data"].(map[string]interface{})
|
||||
msgType := data["type"].(string)
|
||||
|
||||
switch msgType {
|
||||
case "orderBookModify":
|
||||
{
|
||||
type HitBTCWebsocketOrderbookModify struct {
|
||||
Type string
|
||||
Rate float64
|
||||
Amount float64
|
||||
}
|
||||
|
||||
orderModify := HitBTCWebsocketOrderbookModify{}
|
||||
orderModify.Type = msgData["type"].(string)
|
||||
|
||||
rateStr := msgData["rate"].(string)
|
||||
orderModify.Rate, _ = strconv.ParseFloat(rateStr, 64)
|
||||
|
||||
amountStr := msgData["amount"].(string)
|
||||
orderModify.Amount, _ = strconv.ParseFloat(amountStr, 64)
|
||||
}
|
||||
case "orderBookRemove":
|
||||
{
|
||||
type HitBTCWebsocketOrderbookRemove struct {
|
||||
Type string
|
||||
Rate float64
|
||||
}
|
||||
|
||||
orderRemoval := HitBTCWebsocketOrderbookRemove{}
|
||||
orderRemoval.Type = msgData["type"].(string)
|
||||
|
||||
rateStr := msgData["rate"].(string)
|
||||
orderRemoval.Rate, _ = strconv.ParseFloat(rateStr, 64)
|
||||
}
|
||||
case "newTrade":
|
||||
{
|
||||
type HitBTCWebsocketNewTrade struct {
|
||||
Type string
|
||||
TradeID int64
|
||||
Rate float64
|
||||
Amount float64
|
||||
Date string
|
||||
Total float64
|
||||
}
|
||||
|
||||
trade := HitBTCWebsocketNewTrade{}
|
||||
trade.Type = msgData["type"].(string)
|
||||
|
||||
tradeIDstr := msgData["tradeID"].(string)
|
||||
trade.TradeID, _ = strconv.ParseInt(tradeIDstr, 10, 64)
|
||||
|
||||
rateStr := msgData["rate"].(string)
|
||||
trade.Rate, _ = strconv.ParseFloat(rateStr, 64)
|
||||
|
||||
amountStr := msgData["amount"].(string)
|
||||
trade.Amount, _ = strconv.ParseFloat(amountStr, 64)
|
||||
|
||||
totalStr := msgData["total"].(string)
|
||||
trade.Rate, _ = strconv.ParseFloat(totalStr, 64)
|
||||
|
||||
trade.Date = msgData["date"].(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WebsocketClient initiates a websocket client
|
||||
func (p *HitBTC) WebsocketClient() {
|
||||
for p.Enabled && p.Websocket {
|
||||
c, err := turnpike.NewWebsocketClient(turnpike.JSON, hitbtcWebsocketAddress, nil)
|
||||
if h.Websocket.GetProxyAddress() != "" {
|
||||
proxy, err := url.Parse(h.Websocket.GetProxyAddress())
|
||||
if err != nil {
|
||||
log.Printf("%s Unable to connect to Websocket. Error: %s\n", p.GetName(), err)
|
||||
continue
|
||||
return err
|
||||
}
|
||||
|
||||
if p.Verbose {
|
||||
log.Printf("%s Connected to Websocket.\n", p.GetName())
|
||||
}
|
||||
dialer.Proxy = http.ProxyURL(proxy)
|
||||
}
|
||||
|
||||
_, err = c.JoinRealm(hitbtcWebsocketRealm, nil)
|
||||
var err error
|
||||
h.WebsocketConn, _, err = dialer.Dial(hitbtcWebsocketAddress, http.Header{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go h.WsReadData()
|
||||
go h.WsHandleData()
|
||||
|
||||
err = h.WsSubscribe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WsSubscribe subscribes to the relevant channels
|
||||
func (h *HitBTC) WsSubscribe() error {
|
||||
enabledPairs := h.GetEnabledCurrencies()
|
||||
for _, p := range enabledPairs {
|
||||
pF := exchange.FormatExchangeCurrency(h.GetName(), p)
|
||||
|
||||
tickerSubReq, err := common.JSONEncode(WsNotification{
|
||||
JSONRPCVersion: rpcVersion,
|
||||
Method: "subscribeTicker",
|
||||
Params: params{Symbol: pF.String()},
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("%s Unable to join realm. Error: %s\n", p.GetName(), err)
|
||||
continue
|
||||
return err
|
||||
}
|
||||
|
||||
if p.Verbose {
|
||||
log.Printf("%s Joined Websocket realm.\n", p.GetName())
|
||||
err = h.WebsocketConn.WriteMessage(websocket.TextMessage, tickerSubReq)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.ReceiveDone = make(chan bool)
|
||||
|
||||
if err := c.Subscribe(hitbtcWebsocketTicker, OnTicker); err != nil {
|
||||
log.Printf("%s Error subscribing to ticker channel: %s\n", p.GetName(), err)
|
||||
orderbookSubReq, err := common.JSONEncode(WsNotification{
|
||||
JSONRPCVersion: rpcVersion,
|
||||
Method: "subscribeOrderbook",
|
||||
Params: params{Symbol: pF.String()},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.Subscribe(hitbtcWebsocketTrollbox, OnTrollbox); err != nil {
|
||||
log.Printf("%s Error subscribing to trollbox channel: %s\n", p.GetName(), err)
|
||||
err = h.WebsocketConn.WriteMessage(websocket.TextMessage, orderbookSubReq)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for x := range p.EnabledPairs {
|
||||
currency := p.EnabledPairs[x]
|
||||
if err := c.Subscribe(currency, OnDepthOrTrade); err != nil {
|
||||
log.Printf("%s Error subscribing to %s channel: %s\n", p.GetName(), currency, err)
|
||||
tradeSubReq, err := common.JSONEncode(WsNotification{
|
||||
JSONRPCVersion: rpcVersion,
|
||||
Method: "subscribeTrades",
|
||||
Params: params{Symbol: pF.String()},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = h.WebsocketConn.WriteMessage(websocket.TextMessage, tradeSubReq)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WsReadData reads from the websocket connection
|
||||
func (h *HitBTC) WsReadData() {
|
||||
h.Websocket.Wg.Add(1)
|
||||
|
||||
defer func() {
|
||||
err := h.WebsocketConn.Close()
|
||||
if err != nil {
|
||||
h.Websocket.DataHandler <- fmt.Errorf("hitbtc_websocket.go - Unable to to close Websocket connection. Error: %s",
|
||||
err)
|
||||
}
|
||||
h.Websocket.Wg.Done()
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-h.Websocket.ShutdownC:
|
||||
return
|
||||
|
||||
default:
|
||||
_, resp, err := h.WebsocketConn.ReadMessage()
|
||||
if err != nil {
|
||||
h.Websocket.DataHandler <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if p.Verbose {
|
||||
log.Printf("%s Subscribed to websocket channels.\n", p.GetName())
|
||||
h.Websocket.TrafficAlert <- struct{}{}
|
||||
h.Websocket.Intercomm <- exchange.WebsocketResponse{Raw: resp}
|
||||
}
|
||||
|
||||
<-c.ReceiveDone
|
||||
log.Printf("%s Websocket client disconnected.\n", p.GetName())
|
||||
}
|
||||
}
|
||||
|
||||
// WsHandleData handles websocket data
|
||||
func (h *HitBTC) WsHandleData() {
|
||||
h.Websocket.Wg.Add(1)
|
||||
defer h.Websocket.Wg.Done()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-h.Websocket.ShutdownC:
|
||||
|
||||
case resp := <-h.Websocket.Intercomm:
|
||||
var init capture
|
||||
err := common.JSONDecode(resp.Raw, &init)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
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 init.Result {
|
||||
continue
|
||||
}
|
||||
|
||||
switch init.Method {
|
||||
case "ticker":
|
||||
var ticker WsTicker
|
||||
err := common.JSONDecode(resp.Raw, &ticker)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
ts, err := time.Parse(time.RFC3339, ticker.Params.Timestamp)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
h.Websocket.DataHandler <- exchange.TickerData{
|
||||
Exchange: h.GetName(),
|
||||
AssetType: "SPOT",
|
||||
Pair: pair.NewCurrencyPairFromString(ticker.Params.Symbol),
|
||||
Quantity: ticker.Params.Volume,
|
||||
Timestamp: ts,
|
||||
OpenPrice: ticker.Params.Open,
|
||||
HighPrice: ticker.Params.High,
|
||||
LowPrice: ticker.Params.Low,
|
||||
}
|
||||
|
||||
case "snapshotOrderbook":
|
||||
var obSnapshot WsOrderbook
|
||||
err := common.JSONDecode(resp.Raw, &obSnapshot)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = h.WsProcessOrderbookSnapshot(obSnapshot)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
case "updateOrderbook":
|
||||
var obUpdate WsOrderbook
|
||||
err := common.JSONDecode(resp.Raw, &obUpdate)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
h.WsProcessOrderbookUpdate(obUpdate)
|
||||
|
||||
case "snapshotTrades":
|
||||
var tradeSnapshot WsTrade
|
||||
err := common.JSONDecode(resp.Raw, &tradeSnapshot)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
case "updateTrades":
|
||||
var tradeUpdates WsTrade
|
||||
err := common.JSONDecode(resp.Raw, &tradeUpdates)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 bids []orderbook.Item
|
||||
for _, bid := range ob.Params.Bid {
|
||||
bids = append(bids, orderbook.Item{Amount: bid.Size, Price: bid.Price})
|
||||
}
|
||||
|
||||
var asks []orderbook.Item
|
||||
for _, ask := range ob.Params.Ask {
|
||||
asks = append(asks, orderbook.Item{Amount: ask.Size, Price: ask.Price})
|
||||
}
|
||||
|
||||
p := pair.NewCurrencyPairFromString(ob.Params.Symbol)
|
||||
|
||||
var newOrderbook orderbook.Base
|
||||
newOrderbook.Asks = asks
|
||||
newOrderbook.Bids = bids
|
||||
newOrderbook.AssetType = "SPOT"
|
||||
newOrderbook.CurrencyPair = ob.Params.Symbol
|
||||
newOrderbook.LastUpdated = time.Now()
|
||||
newOrderbook.Pair = p
|
||||
|
||||
err := h.Websocket.Orderbook.LoadSnapshot(newOrderbook, h.GetName())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{
|
||||
Exchange: h.GetName(),
|
||||
Asset: "SPOT",
|
||||
Pair: p,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WsProcessOrderbookUpdate updates a local cache
|
||||
func (h *HitBTC) WsProcessOrderbookUpdate(ob WsOrderbook) error {
|
||||
if len(ob.Params.Bid) == 0 && len(ob.Params.Ask) == 0 {
|
||||
return errors.New("hitbtc_websocket.go error - no data")
|
||||
}
|
||||
|
||||
var bids, asks []orderbook.Item
|
||||
for _, bid := range ob.Params.Bid {
|
||||
bids = append(bids, orderbook.Item{Price: bid.Price, Amount: bid.Size})
|
||||
}
|
||||
|
||||
for _, ask := range ob.Params.Ask {
|
||||
asks = append(asks, orderbook.Item{Price: ask.Price, Amount: ask.Size})
|
||||
}
|
||||
|
||||
p := pair.NewCurrencyPairFromString(ob.Params.Symbol)
|
||||
|
||||
err := h.Websocket.Orderbook.Update(bids, asks, p, time.Now(), h.GetName(), "SPOT")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h.Websocket.DataHandler <- exchange.WebsocketOrderbookUpdate{
|
||||
Exchange: h.GetName(),
|
||||
Asset: "SPOT",
|
||||
Pair: p,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type capture struct {
|
||||
Method string `json:"method"`
|
||||
Result bool `json:"result"`
|
||||
Error struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
} `json:"error"`
|
||||
}
|
||||
|
||||
// WsRequest defines a request obj for the JSON-RPC and gets a websocket
|
||||
// response
|
||||
type WsRequest struct {
|
||||
Method string `json:"method"`
|
||||
Params interface{} `json:"params,omitempty"`
|
||||
ID interface{} `json:"id"`
|
||||
}
|
||||
|
||||
// WsNotification defines a notification obj for the JSON-RPC this does not get
|
||||
// a websocket response
|
||||
type WsNotification struct {
|
||||
JSONRPCVersion string `json:"jsonrpc"`
|
||||
Method string `json:"method"`
|
||||
Params interface{} `json:"params"`
|
||||
}
|
||||
|
||||
type params struct {
|
||||
Symbol string `json:"symbol"`
|
||||
}
|
||||
|
||||
// WsTicker defines websocket ticker feed return params
|
||||
type WsTicker struct {
|
||||
Params struct {
|
||||
Ask float64 `json:"ask,string"`
|
||||
Bid float64 `json:"bid,string"`
|
||||
Last float64 `json:"last,string"`
|
||||
Open float64 `json:"open,string"`
|
||||
Low float64 `json:"low,string"`
|
||||
High float64 `json:"high,string"`
|
||||
Volume float64 `json:"volume,string"`
|
||||
VolumeQuote float64 `json:"volumeQuote,string"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
Symbol string `json:"symbol"`
|
||||
} `json:"params"`
|
||||
}
|
||||
|
||||
// WsOrderbook defines websocket orderbook feed return params
|
||||
type WsOrderbook struct {
|
||||
Params struct {
|
||||
Ask []struct {
|
||||
Price float64 `json:"price,string"`
|
||||
Size float64 `json:"size,string"`
|
||||
} `json:"ask"`
|
||||
Bid []struct {
|
||||
Price float64 `json:"price,string"`
|
||||
Size float64 `json:"size,string"`
|
||||
} `json:"bid"`
|
||||
Symbol string `json:"symbol"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
} `json:"params"`
|
||||
}
|
||||
|
||||
// WsTrade defines websocket trade feed return params
|
||||
type WsTrade struct {
|
||||
Params struct {
|
||||
Data []struct {
|
||||
ID int64 `json:"id"`
|
||||
Price float64 `json:"price,string"`
|
||||
Quantity float64 `json:"quantity,string"`
|
||||
Side string `json:"side"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
} `json:"data"`
|
||||
Symbol string `json:"symbol"`
|
||||
} `json:"params"`
|
||||
}
|
||||
|
||||
@@ -24,15 +24,11 @@ func (h *HitBTC) Start(wg *sync.WaitGroup) {
|
||||
// Run implements the HitBTC wrapper
|
||||
func (h *HitBTC) Run() {
|
||||
if h.Verbose {
|
||||
log.Printf("%s Websocket: %s (url: %s).\n", h.GetName(), common.IsEnabled(h.Websocket), hitbtcWebsocketAddress)
|
||||
log.Printf("%s Websocket: %s (url: %s).\n", h.GetName(), common.IsEnabled(h.Websocket.IsEnabled()), hitbtcWebsocketAddress)
|
||||
log.Printf("%s polling delay: %ds.\n", h.GetName(), h.RESTPollingDelay)
|
||||
log.Printf("%s %d currencies enabled: %s.\n", h.GetName(), len(h.EnabledPairs), h.EnabledPairs)
|
||||
}
|
||||
|
||||
if h.Websocket {
|
||||
go h.WebsocketClient()
|
||||
}
|
||||
|
||||
exchangeProducts, err := h.GetSymbolsDetailed()
|
||||
if err != nil {
|
||||
log.Printf("%s Failed to get available symbols.\n", h.GetName())
|
||||
@@ -207,3 +203,8 @@ func (h *HitBTC) WithdrawFiatExchangeFunds(currency pair.CurrencyItem, amount fl
|
||||
func (h *HitBTC) WithdrawFiatExchangeFundsToInternationalBank(currency pair.CurrencyItem, amount float64) (string, error) {
|
||||
return "", errors.New("not yet implemented")
|
||||
}
|
||||
|
||||
// GetWebsocket returns a pointer to the exchange websocket
|
||||
func (h *HitBTC) GetWebsocket() (*exchange.Websocket, error) {
|
||||
return h.Websocket, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user