Engine: Protocol Features, coverage, types, BTC markets websocket (#368)

* Attempts to update orderbook so it doesn't need to sort

* Reverts the ws ob stuff. Gets rid of sorting because it happens later. Adds some exchange features

* update existing feature lists. Expands list definition to match my emotions

* Adds bithumb bitmex and bitstamp. adds a couple more types

* Features for you, features for me, features for bittrex, btcmarkets, btse, coinbasepro, coinut, exmo, gateio and gemini

* Features for hitbtc, huobi, itbit, kraken, lakebtc, lbank, localbitcoins, okcoin, okex, poloniex, yobit, zb

* Who can forget good old alphapoint?

* Adds btcmarksets websocket :glitch_crab: fixes alphapoint features

* Adds extra data not in the documentation :/

* Replaces websocket features by using protocol features. However, it breaks it due to import cycles. I'm not sure what I'll do just yet

* Removes import cycle via duplicate structs.

* Increases coverage of config with `TestCheckCurrencyConfigValues`. Moves all currency pair package types into their own files or places it at the bottom of files if necessary

* Increase coverage in code.go

* One way of determining a test has failed, is when to it fails. Removed redundant explanation

* Increases code coverage of conversion

* Lint fixes

* Fixes orderbook tests

* Re-adds sorting because its important to still have the internal pre-processed orderbook to be representative of a real orderbook

* Secret lints that did not show up via Windows linting

* Adds protocol package to contain exchange features

* Fixes protocol implementation

* Fixes ws tests

* Addresses the following: Removes st-st-stutters in config types, changes GetAvailableForexProviders -> GetSupportedForexProviders, removes errors from tests where error is nil, removes orderbook setup when not necessary, removes import newlines, removes false bools from declaration, changes should of to should have

* imports and casing

* Fixes two more nil error checks
This commit is contained in:
Scott
2019-10-22 10:56:20 +11:00
committed by Adrian Gallagher
parent ec0ed1c1e5
commit ccfcdf26aa
156 changed files with 5228 additions and 4337 deletions

View File

@@ -12,6 +12,7 @@ import (
"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/websocket/wshandler"
log "github.com/thrasher-corp/gocryptotrader/logger"
)
@@ -46,6 +47,7 @@ const (
// BTCMarkets is the overarching type across the BTCMarkets package
type BTCMarkets struct {
exchange.Base
WebsocketConn *wshandler.WebsocketConnection
}
// GetMarkets returns the BTCMarkets instruments

View File

@@ -27,11 +27,11 @@ func TestSetup(t *testing.T) {
cfg := config.GetConfig()
err := cfg.LoadConfig("../../testdata/configtest.json", true)
if err != nil {
t.Fatal("Test Failed - BTC Markets load config error", err)
t.Fatal("BTC Markets load config error", err)
}
bConfig, err := cfg.GetExchangeConfig("BTC Markets")
if err != nil {
t.Error("Test Failed - BTC Markets Setup() init error")
t.Error("BTC Markets Setup() init error")
}
bConfig.API.Credentials.Key = apiKey
bConfig.API.Credentials.Secret = apiSecret
@@ -39,7 +39,7 @@ func TestSetup(t *testing.T) {
err = b.Setup(bConfig)
if err != nil {
t.Fatal("Test Failed - BTC Markets setup error", err)
t.Fatal("BTC Markets setup error", err)
}
}
@@ -47,7 +47,7 @@ func TestGetMarkets(t *testing.T) {
t.Parallel()
_, err := b.GetMarkets()
if err != nil {
t.Error("Test failed - GetMarkets() error", err)
t.Error("GetMarkets() error", err)
}
}
@@ -55,7 +55,7 @@ func TestGetTicker(t *testing.T) {
t.Parallel()
_, err := b.GetTicker("BTC", "AUD")
if err != nil {
t.Error("Test failed - GetTicker() error", err)
t.Error("GetTicker() error", err)
}
}
@@ -63,7 +63,7 @@ func TestGetOrderbook(t *testing.T) {
t.Parallel()
_, err := b.GetOrderbook("BTC", "AUD")
if err != nil {
t.Error("Test failed - GetOrderbook() error", err)
t.Error("GetOrderbook() error", err)
}
}
@@ -71,14 +71,14 @@ func TestGetTrades(t *testing.T) {
t.Parallel()
_, err := b.GetTrades("BTC", "AUD", nil)
if err != nil {
t.Error("Test failed - GetTrades() error", err)
t.Error("GetTrades() error", err)
}
val := url.Values{}
val.Set("since", "0")
_, err = b.GetTrades("BTC", "AUD", val)
if err != nil {
t.Error("Test failed - GetTrades() error", err)
t.Error("GetTrades() error", err)
}
}
@@ -87,7 +87,7 @@ func TestNewOrder(t *testing.T) {
_, err := b.NewOrder("AUD", "BTC", 0, 0, "Bid",
exchange.LimitOrderType.ToLower().ToString(), "testTest")
if err == nil {
t.Error("Test failed - NewOrder() error", err)
t.Error("NewOrder() Expected error")
}
}
@@ -95,7 +95,7 @@ func TestCancelExistingOrder(t *testing.T) {
t.Parallel()
_, err := b.CancelExistingOrder([]int64{1337})
if err == nil {
t.Error("Test failed - CancelExistingOrder() error", err)
t.Error("CancelExistingOrder() Expected error")
}
}
@@ -103,11 +103,11 @@ func TestGetOrders(t *testing.T) {
t.Parallel()
_, err := b.GetOrders("AUD", "BTC", 10, 0, false)
if err == nil {
t.Error("Test failed - GetOrders() error", err)
t.Error("GetOrders() Expected error")
}
_, err = b.GetOrders("AUD", "BTC", 10, 0, true)
if err == nil {
t.Error("Test failed - GetOrders() error", err)
t.Error("GetOrders() Expected error")
}
}
@@ -115,7 +115,7 @@ func TestGetOrderDetail(t *testing.T) {
t.Parallel()
_, err := b.GetOrderDetail([]int64{1337})
if err == nil {
t.Error("Test failed - GetOrderDetail() error", err)
t.Error("GetOrderDetail() Expected error")
}
}
@@ -123,7 +123,7 @@ func TestGetAccountBalance(t *testing.T) {
t.Parallel()
_, err := b.GetAccountBalance()
if err == nil {
t.Error("Test failed - GetAccountBalance() error", err)
t.Error("GetAccountBalance() Expected error")
}
}
@@ -131,7 +131,7 @@ func TestWithdrawCrypto(t *testing.T) {
t.Parallel()
_, err := b.WithdrawCrypto(0, "BTC", "LOLOLOL")
if err == nil {
t.Error("Test failed - WithdrawCrypto() error", err)
t.Error("WithdrawCrypto() Expected error")
}
}
@@ -139,21 +139,21 @@ func TestWithdrawAUD(t *testing.T) {
t.Parallel()
_, err := b.WithdrawAUD("BLA", "1337", "blawest", "1336", 10000000)
if err == nil {
t.Error("Test failed - WithdrawAUD() error", err)
t.Error("WithdrawAUD() Expected error")
}
}
func TestGetAccountInfo(t *testing.T) {
_, err := b.GetAccountInfo()
if err == nil {
t.Error("Test failed - GetAccountInfo() error", err)
t.Error("GetAccountInfo() Expected error")
}
}
func TestGetFundingHistory(t *testing.T) {
_, err := b.GetFundingHistory()
if err == nil {
t.Error("Test failed - GetAccountInfo() error", err)
t.Error("GetAccountInfo() Expected error")
}
}
@@ -161,14 +161,14 @@ func TestCancelOrder(t *testing.T) {
_, err := b.CancelExistingOrder([]int64{1337})
if err == nil {
t.Error("Test failed - CancelgOrder() error", err)
t.Error("CancelgOrder() Expected error")
}
}
func TestGetOrderInfo(t *testing.T) {
_, err := b.GetOrderInfo("1337")
if err == nil {
t.Error("Test failed - GetOrderInfo() error", err)
t.Error("GetOrderInfo() Expected error")
}
}
@@ -208,14 +208,14 @@ func TestGetFee(t *testing.T) {
feeBuilder.Pair.Quote = currency.USD
if resp, err := b.GetFee(feeBuilder); resp != float64(0.00849999) || err != nil {
t.Error(err)
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.00849999), resp)
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0.00849999), resp)
}
// CryptocurrencyTradeFee Basic
feeBuilder = setFeeBuilder()
if resp, err := b.GetFee(feeBuilder); resp != float64(0.0022) || err != nil {
t.Error(err)
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.0022), resp)
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0.0022), resp)
}
// CryptocurrencyTradeFee High quantity
@@ -223,7 +223,7 @@ func TestGetFee(t *testing.T) {
feeBuilder.Amount = 1000
feeBuilder.PurchasePrice = 1000
if resp, err := b.GetFee(feeBuilder); resp != float64(2200) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(22000), resp)
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(22000), resp)
t.Error(err)
}
@@ -231,7 +231,7 @@ func TestGetFee(t *testing.T) {
feeBuilder = setFeeBuilder()
feeBuilder.IsMaker = true
if resp, err := b.GetFee(feeBuilder); resp != float64(0.0022) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.0022), resp)
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0.0022), resp)
t.Error(err)
}
@@ -239,7 +239,7 @@ func TestGetFee(t *testing.T) {
feeBuilder = setFeeBuilder()
feeBuilder.PurchasePrice = -1000
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
}
}
@@ -248,7 +248,7 @@ func TestGetFee(t *testing.T) {
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
if resp, err := b.GetFee(feeBuilder); resp != float64(0.001) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0.001), resp)
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0.001), resp)
t.Error(err)
}
@@ -256,7 +256,7 @@ func TestGetFee(t *testing.T) {
feeBuilder = setFeeBuilder()
feeBuilder.FeeType = exchange.CyptocurrencyDepositFee
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
}
@@ -265,7 +265,7 @@ func TestGetFee(t *testing.T) {
feeBuilder.FeeType = exchange.InternationalBankDepositFee
feeBuilder.FiatCurrency = currency.AUD
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
}
@@ -274,7 +274,7 @@ func TestGetFee(t *testing.T) {
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
feeBuilder.FiatCurrency = currency.AUD
if resp, err := b.GetFee(feeBuilder); resp != float64(0) || err != nil {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Errorf("GetFee() error. Expected: %f, Received: %f", float64(0), resp)
t.Error(err)
}
}
@@ -418,7 +418,7 @@ func TestCancelAllExchangeOrders(t *testing.T) {
func TestModifyOrder(t *testing.T) {
_, err := b.ModifyOrder(&exchange.ModifyOrder{})
if err == nil {
t.Error("Test failed - ModifyOrder() error")
t.Error("ModifyOrder() Expected error")
}
}
@@ -500,6 +500,6 @@ func TestWithdrawInternationalBank(t *testing.T) {
func TestGetDepositAddress(t *testing.T) {
_, err := b.GetDepositAddress(currency.BTC, "")
if err == nil {
t.Error("Test Failed - GetDepositAddress() error cannot be nil")
t.Error("GetDepositAddress() error cannot be nil")
}
}

View File

@@ -1,6 +1,10 @@
package btcmarkets
import "github.com/thrasher-corp/gocryptotrader/currency"
import (
"time"
"github.com/thrasher-corp/gocryptotrader/currency"
)
// Response is the genralized response type
type Response struct {
@@ -143,3 +147,54 @@ var WithdrawalFees = map[currency.Code]float64{
currency.OMG: 0.15,
currency.POWR: 5,
}
// WsSubscribe message sent via ws to subscribe
type WsSubscribe struct {
MarketIDs []string `json:"marketIds,omitempty"`
Channels []string `json:"channels"`
MessageType string `json:"messageType"`
}
// WsMessageType message sent via ws to determine type
type WsMessageType struct {
MessageType string `json:"messageType"`
}
// WsTick message received for ticker data
type WsTick struct {
Currency string `json:"marketId"`
Timestamp time.Time `json:"timestamp"`
Bid float64 `json:"bestBid,string"`
Ask float64 `json:"bestAsk,string"`
Last float64 `json:"lastPrice,string"`
Volume float64 `json:"volume24h,string"`
Price24h float64 `json:"price24h,string"`
Low24h float64 `json:"low24h,string"`
High24 float64 `json:"high24h,string"`
MessageType string `json:"messageType"`
}
// WsTrade message received for trade data
type WsTrade struct {
Currency string `json:"marketId"`
Timestamp time.Time `json:"timestamp"`
TradeID int64 `json:"tradeId"`
Price float64 `json:"price,string"`
Volume float64 `json:"volume,string"`
MessageType string `json:"messageType"`
}
// WsOrderbook message received for orderbook data
type WsOrderbook struct {
Currency string `json:"marketId"`
Timestamp time.Time `json:"timestamp"`
Bids [][]string `json:"bids"`
Asks [][]string `json:"asks"`
MessageType string `json:"messageType"`
}
type WsError struct {
MessageType string `json:"messageType"`
Code int64 `json:"code"`
Message string `json:"message"`
}

View File

@@ -0,0 +1,207 @@
package btcmarkets
import (
"errors"
"fmt"
"net/http"
"strconv"
"github.com/gorilla/websocket"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wshandler"
log "github.com/thrasher-corp/gocryptotrader/logger"
)
const (
btcMarketsWSURL = "wss://socket.btcmarkets.net/v2"
)
// WsConnect connects to a websocket feed
func (b *BTCMarkets) WsConnect() error {
if !b.Websocket.IsEnabled() || !b.IsEnabled() {
return errors.New(wshandler.WebsocketNotEnabled)
}
var dialer websocket.Dialer
err := b.WebsocketConn.Dial(&dialer, http.Header{})
if err != nil {
return err
}
if b.Verbose {
log.Debugf(log.ExchangeSys, "%s Connected to Websocket.\n", b.GetName())
}
b.generateDefaultSubscriptions()
go b.WsHandleData()
return nil
}
// WsHandleData handles websocket data from WsReadData
func (b *BTCMarkets) WsHandleData() {
b.Websocket.Wg.Add(1)
defer func() {
b.Websocket.Wg.Done()
}()
for {
select {
case <-b.Websocket.ShutdownC:
return
default:
resp, err := b.WebsocketConn.ReadMessage()
if err != nil {
b.Websocket.ReadMessageErrors <- err
return
}
b.Websocket.TrafficAlert <- struct{}{}
var wsResponse WsMessageType
err = common.JSONDecode(resp.Raw, &wsResponse)
if err != nil {
b.Websocket.DataHandler <- err
continue
}
switch wsResponse.MessageType {
case "heartbeat":
if b.Verbose {
log.Debugf(log.ExchangeSys, "%v - Websocket heartbeat received %s", b.GetName(), resp.Raw)
}
case "orderbook":
var ob WsOrderbook
err := common.JSONDecode(resp.Raw, &ob)
if err != nil {
b.Websocket.DataHandler <- err
continue
}
p := currency.NewPairFromString(ob.Currency)
var bids, asks []orderbook.Item
for x := range ob.Bids {
var price, amount float64
price, err = strconv.ParseFloat(ob.Bids[x][0], 64)
if err != nil {
b.Websocket.DataHandler <- err
continue
}
amount, err = strconv.ParseFloat(ob.Bids[x][1], 64)
if err != nil {
b.Websocket.DataHandler <- err
continue
}
bids = append(bids, orderbook.Item{
Amount: amount,
Price: price,
})
}
for x := range ob.Asks {
var price, amount float64
price, err = strconv.ParseFloat(ob.Asks[x][0], 64)
if err != nil {
b.Websocket.DataHandler <- err
continue
}
amount, err = strconv.ParseFloat(ob.Asks[x][1], 64)
if err != nil {
b.Websocket.DataHandler <- err
continue
}
asks = append(asks, orderbook.Item{
Amount: amount,
Price: price,
})
}
err = b.Websocket.Orderbook.LoadSnapshot(&orderbook.Base{
Pair: p,
Bids: bids,
Asks: asks,
LastUpdated: ob.Timestamp,
AssetType: asset.Spot,
ExchangeName: b.Name,
})
if err != nil {
b.Websocket.DataHandler <- err
continue
}
b.Websocket.DataHandler <- wshandler.WebsocketOrderbookUpdate{
Pair: p,
Asset: asset.Spot,
Exchange: b.GetName(),
}
case "trade":
var trade WsTrade
err := common.JSONDecode(resp.Raw, &trade)
if err != nil {
b.Websocket.DataHandler <- err
continue
}
p := currency.NewPairFromString(trade.Currency)
b.Websocket.DataHandler <- wshandler.TradeData{
Timestamp: trade.Timestamp,
CurrencyPair: p,
AssetType: asset.Spot,
Exchange: b.GetName(),
Price: trade.Price,
Amount: trade.Volume,
}
case "tick":
var tick WsTick
err := common.JSONDecode(resp.Raw, &tick)
if err != nil {
b.Websocket.DataHandler <- err
continue
}
p := currency.NewPairFromString(tick.Currency)
b.Websocket.DataHandler <- wshandler.TickerData{
Exchange: b.GetName(),
Volume: tick.Volume,
High: tick.High24,
Low: tick.Low24h,
Bid: tick.Bid,
Ask: tick.Ask,
Last: tick.Last,
Timestamp: tick.Timestamp,
AssetType: asset.Spot,
Pair: p,
}
case "error":
var wsErr WsError
err := common.JSONDecode(resp.Raw, &wsErr)
if err != nil {
b.Websocket.DataHandler <- err
continue
}
b.Websocket.DataHandler <- fmt.Errorf("%v websocket error. Code: %v Message: %v", b.Name, wsErr.Code, wsErr.Message)
default:
b.Websocket.DataHandler <- fmt.Errorf("%v Unhandled websocket message %s", b.Name, resp.Raw)
}
}
}
}
func (b *BTCMarkets) generateDefaultSubscriptions() {
var channels = []string{"tick", "trade", "orderbook"}
enabledCurrencies := b.GetEnabledPairs(asset.Spot)
var subscriptions []wshandler.WebsocketChannelSubscription
for i := range channels {
for j := range enabledCurrencies {
subscriptions = append(subscriptions, wshandler.WebsocketChannelSubscription{
Channel: channels[i],
Currency: enabledCurrencies[j],
})
}
}
b.Websocket.SubscribeToChannels(subscriptions)
}
// Subscribe sends a websocket message to receive data from the channel
func (b *BTCMarkets) Subscribe(channelToSubscribe wshandler.WebsocketChannelSubscription) error {
req := WsSubscribe{
MarketIDs: []string{channelToSubscribe.Currency.String()},
Channels: []string{channelToSubscribe.Channel},
MessageType: "subscribe",
}
return b.WebsocketConn.SendMessage(req)
}

View File

@@ -14,6 +14,7 @@ import (
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-corp/gocryptotrader/exchanges/protocol"
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wshandler"
@@ -71,10 +72,31 @@ func (b *BTCMarkets) SetDefaults() {
b.Features = exchange.Features{
Supports: exchange.FeaturesSupported{
REST: true,
Websocket: false,
RESTCapabilities: exchange.ProtocolFeatures{
AutoPairUpdates: true,
TickerBatching: false,
Websocket: true,
RESTCapabilities: protocol.Features{
TickerFetching: true,
TradeFetching: true,
OrderbookFetching: true,
AutoPairUpdates: true,
AccountInfo: true,
GetOrder: true,
GetOrders: true,
CancelOrder: true,
SubmitOrder: true,
UserTradeHistory: true,
CryptoWithdrawal: true,
FiatWithdraw: true,
TradeFee: true,
FiatWithdrawalFee: true,
CryptoWithdrawalFee: true,
},
WebsocketCapabilities: protocol.Features{
TickerFetching: true,
TradeFetching: true,
OrderbookFetching: true,
AccountInfo: true,
Subscribe: true,
AuthenticatedEndpoints: true,
},
WithdrawPermissions: exchange.AutoWithdrawCrypto |
exchange.AutoWithdrawFiat,
@@ -88,6 +110,12 @@ func (b *BTCMarkets) SetDefaults() {
request.NewRateLimit(time.Second*10, btcmarketsAuthLimit),
request.NewRateLimit(time.Second*10, btcmarketsUnauthLimit),
common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout))
b.API.Endpoints.WebsocketURL = btcMarketsWSURL
b.Websocket = wshandler.New()
b.WebsocketResponseMaxLimit = exchange.DefaultWebsocketResponseMaxLimit
b.WebsocketResponseCheckTimeout = exchange.DefaultWebsocketResponseCheckTimeout
b.WebsocketOrderbookBufferLimit = exchange.DefaultWebsocketOrderbookBufferLimit
}
// Setup takes in an exchange configuration and sets all parameters
@@ -97,7 +125,38 @@ func (b *BTCMarkets) Setup(exch *config.ExchangeConfig) error {
return nil
}
return b.SetupDefaults(exch)
err := b.SetupDefaults(exch)
if err != nil {
return err
}
err = b.Websocket.Setup(
&wshandler.WebsocketSetup{
Enabled: exch.Features.Enabled.Websocket,
Verbose: exch.Verbose,
AuthenticatedWebsocketAPISupport: exch.API.AuthenticatedWebsocketSupport,
WebsocketTimeout: exch.WebsocketTrafficTimeout,
DefaultURL: btcMarketsWSURL,
ExchangeName: exch.Name,
RunningURL: exch.API.Endpoints.WebsocketURL,
Connector: b.WsConnect,
Subscriber: b.Subscribe,
Features: &b.Features.Supports.WebsocketCapabilities,
})
if err != nil {
return err
}
b.WebsocketConn = &wshandler.WebsocketConnection{
ExchangeName: b.Name,
URL: b.Websocket.GetWebsocketURL(),
ProxyURL: b.Websocket.GetProxyAddress(),
Verbose: b.Verbose,
ResponseCheckTimeout: exch.WebsocketResponseCheckTimeout,
ResponseMaxLimit: exch.WebsocketResponseMaxLimit,
}
return nil
}
// Start starts the BTC Markets go routine
@@ -440,7 +499,7 @@ func (b *BTCMarkets) WithdrawFiatFundsToInternationalBank(withdrawRequest *excha
// GetWebsocket returns a pointer to the exchange websocket
func (b *BTCMarkets) GetWebsocket() (*wshandler.Websocket, error) {
return nil, common.ErrNotYetImplemented
return b.Websocket, nil
}
// GetFeeByType returns an estimate of fee based on type of transaction