Improve ticker batching and websocket pair consistency

This commit is contained in:
Adrian Gallagher
2019-09-06 11:24:38 +10:00
parent 2307834fb6
commit c041c990a9
24 changed files with 519 additions and 399 deletions

View File

@@ -73,6 +73,20 @@ func NewPairFromString(currencyPair string) Pair {
return NewPairFromStrings(currencyPair[0:3], currencyPair[3:])
}
// NewPairFromFormattedPairs matches a supplied currency pair to a list of pairs
// with a specific format. This is helpful for exchanges which
// provide currency pairs with no delimiter so we can match it with a list and
// apply the same format
func NewPairFromFormattedPairs(currencyPair string, pairs Pairs, pairFmt PairFormat) Pair {
for x := range pairs {
if strings.EqualFold(pairs[x].Format(pairFmt.Delimiter,
pairFmt.Uppercase).String(), currencyPair) {
return pairs[x]
}
}
return NewPairFromString(currencyPair)
}
// Pair holds currency pair information
type Pair struct {
Delimiter string `json:"delimiter"`
@@ -133,7 +147,8 @@ func (p Pair) Format(delimiter string, uppercase bool) Pair {
// Equal compares two currency pairs and returns whether or not they are equal
func (p Pair) Equal(cPair Pair) bool {
return p.Base.Item == cPair.Base.Item && p.Quote.Item == cPair.Quote.Item
return strings.EqualFold(p.Base.String(), cPair.Base.String()) &&
strings.EqualFold(p.Quote.String(), cPair.Quote.String())
}
// EqualIncludeReciprocal compares two currency pairs and returns whether or not

View File

@@ -407,6 +407,30 @@ func TestNewPairFromString(t *testing.T) {
}
}
func TestNewPairFromFormattedPairs(t *testing.T) {
t.Parallel()
pairs := Pairs{
NewPairDelimiter("BTC-USDT", "-"),
NewPairDelimiter("LTC-USD", "-"),
}
p := NewPairFromFormattedPairs("BTCUSDT", pairs, PairFormat{Uppercase: true})
if p.String() != "BTC-USDT" {
t.Error("Test failed. TestNewPairFromFormattedPairs: Expected currency was not found")
}
p = NewPairFromFormattedPairs("btcusdt", pairs, PairFormat{Uppercase: false})
if p.String() != "BTC-USDT" {
t.Error("Test failed. TestNewPairFromFormattedPairs: Expected currency was not found")
}
// Now a wrong one, will default to NewPairFromString
p = NewPairFromFormattedPairs("ethusdt", pairs, PairFormat{})
if p.String() != "ethusdt" && p.Base.String() != "eth" {
t.Error("Test failed. TestNewPairFromFormattedPairs: Expected currency was not found")
}
}
func TestContainsCurrency(t *testing.T) {
p := NewPair(BTC, USD)

View File

@@ -167,29 +167,29 @@ type KlineStream struct {
// TickerStream holds the ticker stream data
type TickerStream struct {
EventType string `json:"e"`
EventTime int64 `json:"E"`
Symbol currency.Pair `json:"s"`
PriceChange float64 `json:"p,string"`
PriceChangePercent float64 `json:"P,string"`
WeightedAvgPrice float64 `json:"w,string"`
ClosePrice float64 `json:"x,string"`
LastPrice float64 `json:"c,string"`
LastPriceQuantity float64 `json:"Q,string"`
BestBidPrice float64 `json:"b,string"`
BestBidQuantity float64 `json:"B,string"`
BestAskPrice float64 `json:"a,string"`
BestAskQuantity float64 `json:"A,string"`
OpenPrice float64 `json:"o,string"`
HighPrice float64 `json:"h,string"`
LowPrice float64 `json:"l,string"`
TotalTradedVolume float64 `json:"v,string"`
TotalTradedQuoteVolume float64 `json:"q,string"`
OpenTime int64 `json:"O"`
CloseTime int64 `json:"C"`
FirstTradeID int64 `json:"F"`
LastTradeID int64 `json:"L"`
NumberOfTrades int64 `json:"n"`
EventType string `json:"e"`
EventTime int64 `json:"E"`
Symbol string `json:"s"`
PriceChange float64 `json:"p,string"`
PriceChangePercent float64 `json:"P,string"`
WeightedAvgPrice float64 `json:"w,string"`
ClosePrice float64 `json:"x,string"`
LastPrice float64 `json:"c,string"`
LastPriceQuantity float64 `json:"Q,string"`
BestBidPrice float64 `json:"b,string"`
BestBidQuantity float64 `json:"B,string"`
BestAskPrice float64 `json:"a,string"`
BestAskQuantity float64 `json:"A,string"`
OpenPrice float64 `json:"o,string"`
HighPrice float64 `json:"h,string"`
LowPrice float64 `json:"l,string"`
TotalTradedVolume float64 `json:"v,string"`
TotalTradedQuoteVolume float64 `json:"q,string"`
OpenTime int64 `json:"O"`
CloseTime int64 `json:"C"`
FirstTradeID int64 `json:"F"`
LastTradeID int64 `json:"L"`
NumberOfTrades int64 `json:"n"`
}
// HistoricalTrade holds recent trade data
@@ -239,25 +239,25 @@ type AveragePrice struct {
// PriceChangeStats contains statistics for the last 24 hours trade
type PriceChangeStats struct {
Symbol currency.Pair `json:"symbol"`
PriceChange float64 `json:"priceChange,string"`
PriceChangePercent float64 `json:"priceChangePercent,string"`
WeightedAvgPrice float64 `json:"weightedAvgPrice,string"`
PrevClosePrice float64 `json:"prevClosePrice,string"`
LastPrice float64 `json:"lastPrice,string"`
LastQty float64 `json:"lastQty,string"`
BidPrice float64 `json:"bidPrice,string"`
AskPrice float64 `json:"askPrice,string"`
OpenPrice float64 `json:"openPrice,string"`
HighPrice float64 `json:"highPrice,string"`
LowPrice float64 `json:"lowPrice,string"`
Volume float64 `json:"volume,string"`
QuoteVolume float64 `json:"quoteVolume,string"`
OpenTime int64 `json:"openTime"`
CloseTime int64 `json:"closeTime"`
FirstID int64 `json:"fristId"`
LastID int64 `json:"lastId"`
Count int64 `json:"count"`
Symbol string `json:"symbol"`
PriceChange float64 `json:"priceChange,string"`
PriceChangePercent float64 `json:"priceChangePercent,string"`
WeightedAvgPrice float64 `json:"weightedAvgPrice,string"`
PrevClosePrice float64 `json:"prevClosePrice,string"`
LastPrice float64 `json:"lastPrice,string"`
LastQty float64 `json:"lastQty,string"`
BidPrice float64 `json:"bidPrice,string"`
AskPrice float64 `json:"askPrice,string"`
OpenPrice float64 `json:"openPrice,string"`
HighPrice float64 `json:"highPrice,string"`
LowPrice float64 `json:"lowPrice,string"`
Volume float64 `json:"volume,string"`
QuoteVolume float64 `json:"quoteVolume,string"`
OpenTime int64 `json:"openTime"`
CloseTime int64 `json:"closeTime"`
FirstID int64 `json:"fristId"`
LastID int64 `json:"lastId"`
Count int64 `json:"count"`
}
// SymbolPrice holds basic symbol price

View File

@@ -128,13 +128,14 @@ func (b *Binance) WsHandleData() {
}
b.Websocket.DataHandler <- wshandler.TradeData{
CurrencyPair: currency.NewPairFromString(trade.Symbol),
Timestamp: time.Unix(0, trade.TimeStamp),
Price: price,
Amount: amount,
Exchange: b.GetName(),
AssetType: asset.Spot,
Side: trade.EventType,
CurrencyPair: currency.NewPairFromFormattedPairs(trade.Symbol, b.GetEnabledPairs(asset.Spot),
b.GetPairFormat(asset.Spot, true)),
Timestamp: time.Unix(0, trade.TimeStamp),
Price: price,
Amount: amount,
Exchange: b.GetName(),
AssetType: asset.Spot,
Side: trade.EventType,
}
continue
case "ticker":
@@ -160,7 +161,8 @@ func (b *Binance) WsHandleData() {
Last: t.LastPrice,
Timestamp: time.Unix(0, t.EventTime),
AssetType: asset.Spot,
Pair: t.Symbol,
Pair: currency.NewPairFromFormattedPairs(t.Symbol, b.GetEnabledPairs(asset.Spot),
b.GetPairFormat(asset.Spot, true)),
}
continue
@@ -176,7 +178,8 @@ func (b *Binance) WsHandleData() {
var wsKline wshandler.KlineData
wsKline.Timestamp = time.Unix(0, kline.EventTime)
wsKline.Pair = currency.NewPairFromString(kline.Symbol)
wsKline.Pair = currency.NewPairFromFormattedPairs(kline.Symbol, b.GetEnabledPairs(asset.Spot),
b.GetPairFormat(asset.Spot, true))
wsKline.AssetType = asset.Spot
wsKline.Exchange = b.GetName()
wsKline.StartTime = time.Unix(0, kline.Kline.StartTime)
@@ -207,7 +210,8 @@ func (b *Binance) WsHandleData() {
continue
}
currencyPair := currency.NewPairFromString(depth.Pair)
currencyPair := currency.NewPairFromFormattedPairs(depth.Pair, b.GetEnabledPairs(asset.Spot),
b.GetPairFormat(asset.Spot, true))
b.Websocket.DataHandler <- wshandler.WebsocketOrderbookUpdate{
Pair: currencyPair,
Asset: asset.Spot,
@@ -222,10 +226,9 @@ func (b *Binance) WsHandleData() {
// SeedLocalCache seeds depth data
func (b *Binance) SeedLocalCache(p currency.Pair) error {
var newOrderBook orderbook.Base
formattedPair := b.FormatExchangeCurrency(p, asset.Spot)
orderbookNew, err := b.GetOrderBook(
OrderBookDataRequestParams{
Symbol: formattedPair.String(),
Symbol: b.FormatExchangeCurrency(p, asset.Spot).String(),
Limit: 1000,
})
if err != nil {
@@ -242,7 +245,7 @@ func (b *Binance) SeedLocalCache(p currency.Pair) error {
}
newOrderBook.LastUpdated = time.Unix(orderbookNew.LastUpdateID, 0)
newOrderBook.Pair = currency.NewPairFromString(formattedPair.String())
newOrderBook.Pair = p
newOrderBook.AssetType = asset.Spot
return b.Websocket.Orderbook.LoadSnapshot(&newOrderBook, false)
@@ -276,7 +279,8 @@ func (b *Binance) UpdateLocalCache(wsdp *WebsocketDepthStream) error {
}
updateAsk = append(updateAsk, priceToBeUpdated)
}
currencyPair := currency.NewPairFromString(wsdp.Pair)
currencyPair := currency.NewPairFromFormattedPairs(wsdp.Pair, b.GetEnabledPairs(asset.Spot),
b.GetPairFormat(asset.Spot, true))
return b.Websocket.Orderbook.Update(&wsorderbook.WebsocketOrderbookUpdate{
Bids: updateBid,

View File

@@ -167,7 +167,7 @@ func (b *Binance) Run() {
!common.StringDataContains(b.GetAvailablePairs(asset.Spot).Strings(), b.GetPairFormat(asset.Spot, false).Delimiter) {
enabledPairs := currency.NewPairsFromStrings([]string{fmt.Sprintf("BTC%vUSDT", b.GetPairFormat(asset.Spot, false).Delimiter)})
log.Warn(log.ExchangeSys,
"Available pairs for Binance reset due to config upgrade, please enable the ones you would like again")
"Available pairs for Binance reset due to config upgrade, please enable the ones you would like to use again")
forceUpdate = true
err := b.UpdatePairs(enabledPairs, asset.Spot, true, true)
@@ -227,7 +227,8 @@ func (b *Binance) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Pr
pairs := b.GetEnabledPairs(assetType)
for i := range pairs {
for y := range tick {
if !tick[y].Symbol.Equal(pairs[i]) {
pairFmt := b.FormatExchangeCurrency(pairs[i], assetType).String()
if tick[y].Symbol != pairFmt {
continue
}
tickerPrice := ticker.Price{

View File

@@ -562,7 +562,8 @@ func (b *Bitfinex) Subscribe(channelToSubscribe wshandler.WebsocketChannelSubscr
req["event"] = "subscribe"
req["channel"] = channelToSubscribe.Channel
if channelToSubscribe.Currency.String() != "" {
req["pair"] = channelToSubscribe.Currency.String()
req["pair"] = b.FormatExchangeCurrency(channelToSubscribe.Currency,
asset.Spot).String()
}
if len(channelToSubscribe.Params) > 0 {
for k, v := range channelToSubscribe.Params {

View File

@@ -62,6 +62,7 @@ func (c *CoinbasePro) SetDefaults() {
Uppercase: true,
},
ConfigFormat: &currency.PairFormat{
Delimiter: "-",
Uppercase: true,
},
}
@@ -162,11 +163,25 @@ func (c *CoinbasePro) Run() {
c.PrintEnabledPairs()
}
if !c.GetEnabledFeatures().AutoPairUpdates {
forceUpdate := false
if !common.StringDataContains(c.GetEnabledPairs(asset.Spot).Strings(), c.GetPairFormat(asset.Spot, false).Delimiter) ||
!common.StringDataContains(c.GetAvailablePairs(asset.Spot).Strings(), c.GetPairFormat(asset.Spot, false).Delimiter) {
enabledPairs := currency.NewPairsFromStrings([]string{fmt.Sprintf("BTC%vUSD", c.GetPairFormat(asset.Spot, false).Delimiter)})
log.Warn(log.ExchangeSys,
"Enabled pairs for CoinbasePro reset due to config upgrade, please enable the ones you would like to use again")
forceUpdate = true
err := c.UpdatePairs(enabledPairs, asset.Spot, true, true)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to update currencies. Err: %s\n", c.Name, err)
}
}
if !c.GetEnabledFeatures().AutoPairUpdates && !forceUpdate {
return
}
err := c.UpdateTradablePairs(false)
err := c.UpdateTradablePairs(forceUpdate)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to update tradable pairs. Err: %s", c.Name, err)
}
@@ -181,7 +196,8 @@ func (c *CoinbasePro) FetchTradablePairs(asset asset.Item) ([]string, error) {
var products []string
for x := range pairs {
products = append(products, pairs[x].BaseCurrency+pairs[x].QuoteCurrency)
products = append(products, fmt.Sprintf("%s%s%s", pairs[x].BaseCurrency,
c.GetPairFormat(asset, false).Delimiter, pairs[x].QuoteCurrency))
}
return products, nil

View File

@@ -262,7 +262,6 @@ func (e *Base) SetCurrencyPairFormat() {
if e.Config.CurrencyPairs.RequestFormat == nil {
e.Config.CurrencyPairs.RequestFormat = e.CurrencyPairs.RequestFormat
}
return
}

View File

@@ -338,7 +338,8 @@ func (g *Gateio) GenerateDefaultSubscriptions() {
// Subscribe sends a websocket message to receive data from the channel
func (g *Gateio) Subscribe(channelToSubscribe wshandler.WebsocketChannelSubscription) error {
params := []interface{}{channelToSubscribe.Currency.String()}
params := []interface{}{g.FormatExchangeCurrency(channelToSubscribe.Currency,
asset.Spot).String()}
for i := range channelToSubscribe.Params {
params = append(params, channelToSubscribe.Params[i])
}
@@ -370,7 +371,8 @@ func (g *Gateio) Unsubscribe(channelToSubscribe wshandler.WebsocketChannelSubscr
subscribe := WebsocketRequest{
ID: g.WebsocketConn.GenerateMessageID(true),
Method: unsbuscribeText,
Params: []interface{}{channelToSubscribe.Currency.String(), 1800},
Params: []interface{}{g.FormatExchangeCurrency(channelToSubscribe.Currency,
asset.Spot).String(), 1800},
}
resp, err := g.WebsocketConn.SendMessageReturnResponse(subscribe.ID, subscribe)
if err != nil {

View File

@@ -10,6 +10,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/config"
"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/sharedtestvalues"
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wshandler"
)
@@ -97,6 +98,22 @@ func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
}
}
func TestUpdateTicker(t *testing.T) {
h.SetDefaults()
TestSetup(t)
h.CurrencyPairs.StorePairs(asset.Spot, currency.NewPairsFromStrings([]string{"BTC-USD", "XRP-USD"}), true)
_, err := h.UpdateTicker(currency.NewPair(currency.BTC, currency.USD), asset.Spot)
if err != nil {
t.Error(err)
}
_, err = h.FetchTicker(currency.NewPair(currency.XRP, currency.USD), asset.Spot)
if err != nil {
t.Error(err)
}
}
func TestGetAllTickers(t *testing.T) {
_, err := h.GetTickers()
if err != nil {

View File

@@ -8,16 +8,16 @@ import (
// TickerResponse is the response type
type TickerResponse struct {
Ask float64 `json:"ask,string"`
Bid float64 `json:"bid,string"`
High float64 `json:"high,string"`
Last float64 `json:"last,string"`
Low float64 `json:"low,string"`
Open float64 `json:"open,string"`
Volume float64 `json:"volume,string"`
VolumeQuote float64 `json:"volumeQuote,string"`
Symbol currency.Pair `json:"symbol"`
Timestamp time.Time `json:"timestamp"`
Ask float64 `json:"ask,string"`
Bid float64 `json:"bid,string"`
High float64 `json:"high,string"`
Last float64 `json:"last,string"`
Low float64 `json:"low,string"`
Open float64 `json:"open,string"`
Volume float64 `json:"volume,string"`
VolumeQuote float64 `json:"volumeQuote,string"`
Symbol string `json:"symbol"`
Timestamp time.Time `json:"timestamp"`
}
// Symbol holds symbol data
@@ -322,16 +322,16 @@ type params struct {
// 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 currency.Pair `json:"symbol"`
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"`
}
@@ -387,20 +387,20 @@ type WsActiveOrdersResponse struct {
// WsActiveOrdersResponseData Active order data for WsActiveOrdersResponse
type WsActiveOrdersResponseData struct {
ID string `json:"id"`
ClientOrderID string `json:"clientOrderId,omitempty"`
Symbol currency.Pair `json:"symbol"`
Side string `json:"side"`
Status string `json:"status"`
Type string `json:"type"`
TimeInForce string `json:"timeInForce"`
Quantity float64 `json:"quantity,string"`
Price float64 `json:"price,string"`
CumQuantity float64 `json:"cumQuantity,string"`
PostOnly bool `json:"postOnly"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
ReportType string `json:"reportType"`
ID string `json:"id"`
ClientOrderID string `json:"clientOrderId,omitempty"`
Symbol string `json:"symbol"`
Side string `json:"side"`
Status string `json:"status"`
Type string `json:"type"`
TimeInForce string `json:"timeInForce"`
Quantity float64 `json:"quantity,string"`
Price float64 `json:"price,string"`
CumQuantity float64 `json:"cumQuantity,string"`
PostOnly bool `json:"postOnly"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
ReportType string `json:"reportType"`
}
// WsReportResponse report response for auth subscription to reports
@@ -411,24 +411,24 @@ type WsReportResponse struct {
// WsReportResponseData Report data for WsReportResponse
type WsReportResponseData struct {
ID string `json:"id"`
ClientOrderID string `json:"clientOrderId,omitempty"`
Symbol currency.Pair `json:"symbol"`
Side string `json:"side"`
Status string `json:"status"`
Type string `json:"type"`
TimeInForce string `json:"timeInForce"`
Quantity float64 `json:"quantity,string"`
Price float64 `json:"price,string"`
CumQuantity float64 `json:"cumQuantity,string"`
PostOnly bool `json:"postOnly"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
ReportType string `json:"reportType"`
TradeQuantity float64 `json:"tradeQuantity,string"`
TradePrice float64 `json:"tradePrice,string"`
TradeID int64 `json:"tradeId"`
TradeFee float64 `json:"tradeFee,string"`
ID string `json:"id"`
ClientOrderID string `json:"clientOrderId,omitempty"`
Symbol string `json:"symbol"`
Side string `json:"side"`
Status string `json:"status"`
Type string `json:"type"`
TimeInForce string `json:"timeInForce"`
Quantity float64 `json:"quantity,string"`
Price float64 `json:"price,string"`
CumQuantity float64 `json:"cumQuantity,string"`
PostOnly bool `json:"postOnly"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
ReportType string `json:"reportType"`
TradeQuantity float64 `json:"tradeQuantity,string"`
TradePrice float64 `json:"tradePrice,string"`
TradeID int64 `json:"tradeId"`
TradeFee float64 `json:"tradeFee,string"`
}
// WsSubmitOrderRequest WS request
@@ -440,11 +440,11 @@ type WsSubmitOrderRequest struct {
// WsSubmitOrderRequestData WS request data
type WsSubmitOrderRequestData struct {
ClientOrderID int64 `json:"clientOrderId,string,omitempty"`
Symbol currency.Pair `json:"symbol"`
Side string `json:"side"`
Price float64 `json:"price,string"`
Quantity float64 `json:"quantity,string"`
ClientOrderID int64 `json:"clientOrderId,string,omitempty"`
Symbol string `json:"symbol"`
Side string `json:"side"`
Price float64 `json:"price,string"`
Quantity float64 `json:"quantity,string"`
}
// WsSubmitOrderSuccessResponse WS response
@@ -494,20 +494,20 @@ type WsCancelOrderResponse struct {
// WsCancelOrderResponseData WS response data
type WsCancelOrderResponseData struct {
ID string `json:"id"`
ClientOrderID string `json:"clientOrderId,omitempty"`
Symbol currency.Pair `json:"symbol"`
Side string `json:"side"`
Status string `json:"status"`
Type string `json:"type"`
TimeInForce string `json:"timeInForce"`
Quantity float64 `json:"quantity,string"`
Price float64 `json:"price,string"`
CumQuantity float64 `json:"cumQuantity,string"`
PostOnly bool `json:"postOnly"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
ReportType string `json:"reportType"`
ID string `json:"id"`
ClientOrderID string `json:"clientOrderId,omitempty"`
Symbol string `json:"symbol"`
Side string `json:"side"`
Status string `json:"status"`
Type string `json:"type"`
TimeInForce string `json:"timeInForce"`
Quantity float64 `json:"quantity,string"`
Price float64 `json:"price,string"`
CumQuantity float64 `json:"cumQuantity,string"`
PostOnly bool `json:"postOnly"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
ReportType string `json:"reportType"`
}
// WsReplaceOrderResponse WS response
@@ -519,21 +519,21 @@ type WsReplaceOrderResponse struct {
// WsReplaceOrderResponseData WS response data
type WsReplaceOrderResponseData struct {
ID string `json:"id"`
ClientOrderID string `json:"clientOrderId,omitempty"`
Symbol currency.Pair `json:"symbol"`
Side string `json:"side"`
Status string `json:"status"`
Type string `json:"type"`
TimeInForce string `json:"timeInForce"`
Quantity float64 `json:"quantity,string"`
Price float64 `json:"price,string"`
CumQuantity float64 `json:"cumQuantity,string"`
PostOnly bool `json:"postOnly"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
ReportType string `json:"reportType"`
OriginalRequestClientOrderID string `json:"originalRequestClientOrderId"`
ID string `json:"id"`
ClientOrderID string `json:"clientOrderId,omitempty"`
Symbol string `json:"symbol"`
Side string `json:"side"`
Status string `json:"status"`
Type string `json:"type"`
TimeInForce string `json:"timeInForce"`
Quantity float64 `json:"quantity,string"`
Price float64 `json:"price,string"`
CumQuantity float64 `json:"cumQuantity,string"`
PostOnly bool `json:"postOnly"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
ReportType string `json:"reportType"`
OriginalRequestClientOrderID string `json:"originalRequestClientOrderId"`
}
// WsGetActiveOrdersResponse WS response
@@ -545,21 +545,21 @@ type WsGetActiveOrdersResponse struct {
// WsGetActiveOrdersResponseData WS response data
type WsGetActiveOrdersResponseData struct {
ID string `json:"id"`
ClientOrderID string `json:"clientOrderId,omitempty"`
Symbol currency.Pair `json:"symbol"`
Side string `json:"side"`
Status string `json:"status"`
Type string `json:"type"`
TimeInForce string `json:"timeInForce"`
Quantity float64 `json:"quantity,string"`
Price float64 `json:"price,string"`
CumQuantity float64 `json:"cumQuantity,string"`
PostOnly bool `json:"postOnly"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
ReportType string `json:"reportType"`
OriginalRequestClientOrderID string `json:"originalRequestClientOrderId"`
ID string `json:"id"`
ClientOrderID string `json:"clientOrderId,omitempty"`
Symbol string `json:"symbol"`
Side string `json:"side"`
Status string `json:"status"`
Type string `json:"type"`
TimeInForce string `json:"timeInForce"`
Quantity float64 `json:"quantity,string"`
Price float64 `json:"price,string"`
CumQuantity float64 `json:"cumQuantity,string"`
PostOnly bool `json:"postOnly"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
ReportType string `json:"reportType"`
OriginalRequestClientOrderID string `json:"originalRequestClientOrderId"`
}
// WsGetTradingBalanceResponse WS response
@@ -646,7 +646,7 @@ type WsGetSymbolsRequest struct {
// WsGetSymbolsRequestParameters request parameters
type WsGetSymbolsRequestParameters struct {
Symbol currency.Pair `json:"symbol"`
Symbol string `json:"symbol"`
}
// WsGetSymbolsResponse symbol response
@@ -658,7 +658,7 @@ type WsGetSymbolsResponse struct {
// WsGetSymbolsResponseData symbol response data
type WsGetSymbolsResponseData struct {
ID currency.Pair `json:"id"`
ID string `json:"id"`
BaseCurrency currency.Code `json:"baseCurrency"`
QuoteCurrency currency.Code `json:"quoteCurrency"`
QuantityIncrement float64 `json:"quantityIncrement,string"`
@@ -677,10 +677,10 @@ type WsGetTradesRequest struct {
// WsGetTradesRequestParameters trade request params
type WsGetTradesRequestParameters struct {
Symbol currency.Pair `json:"symbol"`
Limit int64 `json:"limit"`
Sort string `json:"sort"`
By string `json:"by"`
Symbol string `json:"symbol"`
Limit int64 `json:"limit"`
Sort string `json:"sort"`
By string `json:"by"`
}
// WsGetTradesResponse response

View File

@@ -127,7 +127,8 @@ func (h *HitBTC) handleSubscriptionUpdates(resp wshandler.WebsocketResponse, ini
Last: ticker.Params.Last,
Timestamp: ts,
AssetType: asset.Spot,
Pair: ticker.Params.Symbol,
Pair: currency.NewPairFromFormattedPairs(ticker.Params.Symbol,
h.GetEnabledPairs(asset.Spot), h.GetPairFormat(asset.Spot, true)),
}
case "snapshotOrderbook":
var obSnapshot WsOrderbook
@@ -241,7 +242,8 @@ func (h *HitBTC) WsProcessOrderbookSnapshot(ob WsOrderbook) error {
asks = append(asks, orderbook.Item{Amount: ob.Params.Ask[i].Size, Price: ob.Params.Ask[i].Price})
}
p := currency.NewPairFromString(ob.Params.Symbol)
p := currency.NewPairFromFormattedPairs(ob.Params.Symbol,
h.GetEnabledPairs(asset.Spot), h.GetPairFormat(asset.Spot, true))
var newOrderBook orderbook.Base
newOrderBook.Asks = asks
@@ -278,7 +280,8 @@ func (h *HitBTC) WsProcessOrderbookUpdate(update WsOrderbook) error {
asks = append(asks, orderbook.Item{Price: update.Params.Ask[i].Price, Amount: update.Params.Ask[i].Size})
}
p := currency.NewPairFromString(update.Params.Symbol)
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,
@@ -327,17 +330,20 @@ func (h *HitBTC) Subscribe(channelToSubscribe wshandler.WebsocketChannelSubscrip
}
if channelToSubscribe.Currency.String() != "" {
subscribe.Params = params{
Symbol: channelToSubscribe.Currency.String(),
Symbol: h.FormatExchangeCurrency(channelToSubscribe.Currency,
asset.Spot).String(),
}
}
if strings.EqualFold(channelToSubscribe.Channel, "subscribeTrades") {
subscribe.Params = params{
Symbol: channelToSubscribe.Currency.String(),
Limit: 100,
Symbol: h.FormatExchangeCurrency(channelToSubscribe.Currency,
asset.Spot).String(),
Limit: 100,
}
} else if strings.EqualFold(channelToSubscribe.Channel, "subscribeCandles") {
subscribe.Params = params{
Symbol: channelToSubscribe.Currency.String(),
Symbol: h.FormatExchangeCurrency(channelToSubscribe.Currency,
asset.Spot).String(),
Period: "M30",
Limit: 100,
}
@@ -353,17 +359,20 @@ func (h *HitBTC) Unsubscribe(channelToSubscribe wshandler.WebsocketChannelSubscr
JSONRPCVersion: rpcVersion,
Method: unsubscribeChannel,
Params: params{
Symbol: channelToSubscribe.Currency.String(),
Symbol: h.FormatExchangeCurrency(channelToSubscribe.Currency,
asset.Spot).String(),
},
}
if strings.EqualFold(unsubscribeChannel, "unsubscribeTrades") {
subscribe.Params = params{
Symbol: channelToSubscribe.Currency.String(),
Limit: 100,
Symbol: h.FormatExchangeCurrency(channelToSubscribe.Currency,
asset.Spot).String(),
Limit: 100,
}
} else if strings.EqualFold(unsubscribeChannel, "unsubscribeCandles") {
subscribe.Params = params{
Symbol: channelToSubscribe.Currency.String(),
Symbol: h.FormatExchangeCurrency(channelToSubscribe.Currency,
asset.Spot).String(),
Period: "M30",
Limit: 100,
}
@@ -408,7 +417,7 @@ func (h *HitBTC) wsPlaceOrder(pair currency.Pair, side string, price, quantity f
Method: "newOrder",
Params: WsSubmitOrderRequestData{
ClientOrderID: id,
Symbol: pair,
Symbol: h.FormatExchangeCurrency(pair, asset.Spot).String(),
Side: strings.ToLower(side),
Price: price,
Quantity: quantity,
@@ -566,7 +575,7 @@ func (h *HitBTC) wsGetSymbols(currencyItem currency.Pair) (*WsGetSymbolsResponse
request := WsGetSymbolsRequest{
Method: "getSymbol",
Params: WsGetSymbolsRequestParameters{
Symbol: currencyItem,
Symbol: h.FormatExchangeCurrency(currencyItem, asset.Spot).String(),
},
ID: h.WebsocketConn.GenerateMessageID(false),
}
@@ -590,7 +599,7 @@ func (h *HitBTC) wsGetTrades(currencyItem currency.Pair, limit int64, sort, by s
request := WsGetTradesRequest{
Method: "getTrades",
Params: WsGetTradesRequestParameters{
Symbol: currencyItem,
Symbol: h.FormatExchangeCurrency(currencyItem, asset.Spot).String(),
Limit: limit,
Sort: sort,
By: by,

View File

@@ -196,7 +196,8 @@ func (h *HitBTC) FetchTradablePairs(asset asset.Item) ([]string, error) {
var pairs []string
for x := range symbols {
pairs = append(pairs, fmt.Sprintf("%v%v%v", symbols[x].BaseCurrency, h.GetPairFormat(asset, false).Delimiter, symbols[x].QuoteCurrency))
pairs = append(pairs, fmt.Sprintf("%v%v%v", symbols[x].BaseCurrency,
h.GetPairFormat(asset, false).Delimiter, symbols[x].QuoteCurrency))
}
return pairs, nil
}
@@ -222,8 +223,17 @@ func (h *HitBTC) UpdateTicker(currencyPair currency.Pair, assetType asset.Item)
pairs := h.GetEnabledPairs(assetType)
for i := range pairs {
for j := range tick {
if !tick[j].Symbol.Equal(pairs[i]) {
continue
pairFmt := h.FormatExchangeCurrency(pairs[i], assetType).String()
if tick[j].Symbol != pairFmt {
found := false
if strings.Contains(tick[j].Symbol, "USDT") {
if pairFmt == tick[j].Symbol[0:len(tick[j].Symbol)-1] {
found = true
}
}
if !found {
continue
}
}
tickerPrice := ticker.Price{
Last: tick[j].Last,

View File

@@ -1,7 +1,5 @@
package huobi
import "github.com/thrasher-corp/gocryptotrader/currency"
// Response stores the Huobi response information
type Response struct {
Status string `json:"status"`
@@ -49,14 +47,14 @@ type Tickers struct {
// Ticker latest ticker data
type Ticker struct {
Amount float64 `json:"amount"`
Close float64 `json:"close"`
Count int64 `json:"count"`
High float64 `json:"high"`
Low float64 `json:"low"`
Open float64 `json:"open"`
Symbol currency.Pair `json:"symbol"`
Volume float64 `json:"vol"`
Amount float64 `json:"amount"`
Close float64 `json:"close"`
Count int64 `json:"count"`
High float64 `json:"high"`
Low float64 `json:"low"`
Open float64 `json:"open"`
Symbol string `json:"symbol"`
Volume float64 `json:"vol"`
}
// OrderBookDataRequestParamsType var for request param types
@@ -118,11 +116,17 @@ type Detail struct {
// Symbol stores the symbol data
type Symbol struct {
BaseCurrency string `json:"base-currency"`
QuoteCurrency string `json:"quote-currency"`
PricePrecision int `json:"price-precision"`
AmountPrecision int `json:"amount-precision"`
SymbolPartition string `json:"symbol-partition"`
BaseCurrency string `json:"base-currency"`
QuoteCurrency string `json:"quote-currency"`
PricePrecision int `json:"price-precision"`
AmountPrecision int `json:"amount-precision"`
SymbolPartition string `json:"symbol-partition"`
Innovation string `json:"innovation"`
State string `json:"state"`
ValuePrecision int `json:"value-precision"`
MinimumOrderAmount float64 `json:"min-order-amt"`
MaximumOrderAmount float64 `json:"max-order-amt"`
MinimumOrderValue float64 `json:"min-order-value"`
}
// Account stores the account data
@@ -339,6 +343,7 @@ type WsKline struct {
}
}
// WsTick stores websocket ticker data
type WsTick struct {
Channel string `json:"ch"`
Timestamp int64 `json:"ts"`
@@ -403,15 +408,15 @@ type WsAuthenticatedSubscriptionRequest struct {
// WsAuthenticatedAccountsListRequest request for account list authenticated connection
type WsAuthenticatedAccountsListRequest struct {
Op string `json:"op"`
AccessKeyID string `json:"AccessKeyId"`
SignatureMethod string `json:"SignatureMethod"`
SignatureVersion string `json:"SignatureVersion"`
Timestamp string `json:"Timestamp"`
Signature string `json:"Signature"`
Topic string `json:"topic"`
Symbol currency.Pair `json:"symbol"`
ClientID int64 `json:"cid,string,omitempty"`
Op string `json:"op"`
AccessKeyID string `json:"AccessKeyId"`
SignatureMethod string `json:"SignatureMethod"`
SignatureVersion string `json:"SignatureVersion"`
Timestamp string `json:"Timestamp"`
Signature string `json:"Signature"`
Topic string `json:"topic"`
Symbol string `json:"symbol"`
ClientID int64 `json:"cid,string,omitempty"`
}
// WsAuthenticatedOrderDetailsRequest request for order details authenticated connection
@@ -429,17 +434,17 @@ type WsAuthenticatedOrderDetailsRequest struct {
// WsAuthenticatedOrdersListRequest request for orderslist authenticated connection
type WsAuthenticatedOrdersListRequest struct {
Op string `json:"op"`
AccessKeyID string `json:"AccessKeyId"`
SignatureMethod string `json:"SignatureMethod"`
SignatureVersion string `json:"SignatureVersion"`
Timestamp string `json:"Timestamp"`
Signature string `json:"Signature"`
Topic string `json:"topic"`
States string `json:"states"`
AccountID int64 `json:"account-id"`
Symbol currency.Pair `json:"symbol"`
ClientID int64 `json:"cid,string,omitempty"`
Op string `json:"op"`
AccessKeyID string `json:"AccessKeyId"`
SignatureMethod string `json:"SignatureMethod"`
SignatureVersion string `json:"SignatureVersion"`
Timestamp string `json:"Timestamp"`
Signature string `json:"Signature"`
Topic string `json:"topic"`
States string `json:"states"`
AccountID int64 `json:"account-id"`
Symbol string `json:"symbol"`
ClientID int64 `json:"cid,string,omitempty"`
}
// WsAuthenticatedDataResponse response from authenticated connection
@@ -481,15 +486,15 @@ type WsAuthenticatedOrdersUpdateResponse struct {
// WsAuthenticatedOrdersUpdateResponseData order updatedata
type WsAuthenticatedOrdersUpdateResponseData struct {
UnfilledAmount float64 `json:"unfilled-amount,string"`
FilledAmount float64 `json:"filled-amount,string"`
Price float64 `json:"price,string"`
OrderID int64 `json:"order-id"`
Symbol currency.Pair `json:"symbol"`
MatchID int64 `json:"match-id"`
FilledCashAmount float64 `json:"filled-cash-amount,string"`
Role string `json:"role"`
OrderState string `json:"order-state"`
UnfilledAmount float64 `json:"unfilled-amount,string"`
FilledAmount float64 `json:"filled-amount,string"`
Price float64 `json:"price,string"`
OrderID int64 `json:"order-id"`
Symbol string `json:"symbol"`
MatchID int64 `json:"match-id"`
FilledCashAmount float64 `json:"filled-cash-amount,string"`
Role string `json:"role"`
OrderState string `json:"order-state"`
}
// WsAuthenticatedOrdersResponse response from Orders authenticated subscription
@@ -500,22 +505,22 @@ type WsAuthenticatedOrdersResponse struct {
// WsAuthenticatedOrdersResponseData order data
type WsAuthenticatedOrdersResponseData struct {
SeqID int64 `json:"seq-id"`
OrderID int64 `json:"order-id"`
Symbol currency.Pair `json:"symbol"`
AccountID int64 `json:"account-id"`
OrderAmount float64 `json:"order-amount,string"`
OrderPrice float64 `json:"order-price,string"`
CreatedAt int64 `json:"created-at"`
OrderType string `json:"order-type"`
OrderSource string `json:"order-source"`
OrderState string `json:"order-state"`
Role string `json:"role"`
Price float64 `json:"price,string"`
FilledAmount float64 `json:"filled-amount,string"`
UnfilledAmount float64 `json:"unfilled-amount,string"`
FilledCashAmount float64 `json:"filled-cash-amount,string"`
FilledFees float64 `json:"filled-fees,string"`
SeqID int64 `json:"seq-id"`
OrderID int64 `json:"order-id"`
Symbol string `json:"symbol"`
AccountID int64 `json:"account-id"`
OrderAmount float64 `json:"order-amount,string"`
OrderPrice float64 `json:"order-price,string"`
CreatedAt int64 `json:"created-at"`
OrderType string `json:"order-type"`
OrderSource string `json:"order-source"`
OrderState string `json:"order-state"`
Role string `json:"role"`
Price float64 `json:"price,string"`
FilledAmount float64 `json:"filled-amount,string"`
UnfilledAmount float64 `json:"unfilled-amount,string"`
FilledCashAmount float64 `json:"filled-cash-amount,string"`
FilledFees float64 `json:"filled-fees,string"`
}
// WsAuthenticatedAccountsListResponse response from AccountsList authenticated endpoint
@@ -547,20 +552,20 @@ type WsAuthenticatedOrdersListResponse struct {
// WsAuthenticatedOrdersListResponseData contains order details
type WsAuthenticatedOrdersListResponseData struct {
ID int64 `json:"id"`
Symbol currency.Pair `json:"symbol"`
AccountID int64 `json:"account-id"`
Amount float64 `json:"amount,string"`
Price float64 `json:"price,string"`
CreatedAt int64 `json:"created-at"`
Type string `json:"type"`
FilledAmount float64 `json:"filled-amount,string"`
FilledCashAmount float64 `json:"filled-cash-amount,string"`
FilledFees float64 `json:"filled-fees,string"`
FinishedAt int64 `json:"finished-at"`
Source string `json:"source"`
State string `json:"state"`
CanceledAt int64 `json:"canceled-at"`
ID int64 `json:"id"`
Symbol string `json:"symbol"`
AccountID int64 `json:"account-id"`
Amount float64 `json:"amount,string"`
Price float64 `json:"price,string"`
CreatedAt int64 `json:"created-at"`
Type string `json:"type"`
FilledAmount float64 `json:"filled-amount,string"`
FilledCashAmount float64 `json:"filled-cash-amount,string"`
FilledFees float64 `json:"filled-fees,string"`
FinishedAt int64 `json:"finished-at"`
Source string `json:"source"`
State string `json:"state"`
CanceledAt int64 `json:"canceled-at"`
}
// WsAuthenticatedOrderDetailResponse response from OrderDetail authenticated endpoint

View File

@@ -244,10 +244,11 @@ func (h *HUOBI) wsHandleMarketData(resp WsMessage) {
}
data := strings.Split(kline.Channel, ".")
h.Websocket.DataHandler <- wshandler.KlineData{
Timestamp: time.Unix(0, kline.Timestamp),
Exchange: h.GetName(),
AssetType: asset.Spot,
Pair: currency.NewPairFromString(data[1]),
Timestamp: time.Unix(0, kline.Timestamp),
Exchange: h.GetName(),
AssetType: asset.Spot,
Pair: currency.NewPairFromFormattedPairs(data[1],
h.GetEnabledPairs(asset.Spot), h.GetPairFormat(asset.Spot, true)),
OpenPrice: kline.Tick.Open,
ClosePrice: kline.Tick.Close,
HighPrice: kline.Tick.High,
@@ -263,10 +264,11 @@ func (h *HUOBI) wsHandleMarketData(resp WsMessage) {
}
data := strings.Split(trade.Channel, ".")
h.Websocket.DataHandler <- wshandler.TradeData{
Exchange: h.GetName(),
AssetType: asset.Spot,
CurrencyPair: currency.NewPairFromString(data[1]),
Timestamp: time.Unix(0, trade.Tick.Timestamp),
Exchange: h.GetName(),
AssetType: asset.Spot,
CurrencyPair: currency.NewPairFromFormattedPairs(data[1],
h.GetEnabledPairs(asset.Spot), h.GetPairFormat(asset.Spot, true)),
Timestamp: time.Unix(0, trade.Tick.Timestamp),
}
case strings.Contains(init.Channel, "detail"):
var ticker WsTick
@@ -286,14 +288,16 @@ func (h *HUOBI) wsHandleMarketData(resp WsMessage) {
Low: ticker.Tick.Low,
Timestamp: time.Unix(0, ticker.Timestamp),
AssetType: asset.Spot,
Pair: currency.NewPairFromString(data[1]),
Pair: currency.NewPairFromFormattedPairs(data[1],
h.GetEnabledPairs(asset.Spot), h.GetPairFormat(asset.Spot, true)),
}
}
}
// WsProcessOrderbook processes new orderbook data
func (h *HUOBI) WsProcessOrderbook(update *WsDepth, symbol string) error {
p := currency.NewPairFromString(symbol)
p := currency.NewPairFromFormattedPairs(symbol,
h.GetEnabledPairs(asset.Spot), h.GetPairFormat(asset.Spot, true))
var bids, asks []orderbook.Item
for i := 0; i < len(update.Tick.Bids); i++ {
bidLevel := update.Tick.Bids[i].([]interface{})
@@ -428,7 +432,7 @@ func (h *HUOBI) wsGetAccountsList(pair currency.Pair) (*WsAuthenticatedAccountsL
SignatureVersion: signatureVersion,
Timestamp: timestamp,
Topic: wsAccountsList,
Symbol: pair,
Symbol: h.FormatExchangeCurrency(pair, asset.Spot).String(),
}
hmac := h.wsGenerateSignature(timestamp, wsAccountListEndpoint)
request.Signature = crypto.Base64Encode(hmac)
@@ -455,7 +459,7 @@ func (h *HUOBI) wsGetOrdersList(accountID int64, pair currency.Pair) (*WsAuthent
Timestamp: timestamp,
Topic: wsOrdersList,
AccountID: accountID,
Symbol: pair.Lower(),
Symbol: h.FormatExchangeCurrency(pair, asset.Spot).String(),
States: "submitted,partial-filled",
}
hmac := h.wsGenerateSignature(timestamp, wsOrdersListEndpoint)

View File

@@ -228,7 +228,11 @@ func (h *HUOBI) FetchTradablePairs(asset asset.Item) ([]string, error) {
var pairs []string
for x := range symbols {
pairs = append(pairs, fmt.Sprintf("%v%v%v", symbols[x].BaseCurrency, h.GetPairFormat(asset, false).Delimiter, symbols[x].QuoteCurrency))
if symbols[x].State != "online" {
continue
}
pairs = append(pairs, fmt.Sprintf("%v%v%v", symbols[x].BaseCurrency,
h.GetPairFormat(asset, false).Delimiter, symbols[x].QuoteCurrency))
}
return pairs, nil
@@ -255,7 +259,8 @@ func (h *HUOBI) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Pric
pairs := h.GetEnabledPairs(assetType)
for i := range pairs {
for j := range tickers.Data {
if !pairs[i].Equal(tickers.Data[j].Symbol) {
pairFmt := h.FormatExchangeCurrency(pairs[i], assetType).String()
if pairFmt != tickers.Data[j].Symbol {
continue
}
tickerPrice := ticker.Price{
@@ -264,7 +269,7 @@ func (h *HUOBI) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Pric
Volume: tickers.Data[j].Volume,
Open: tickers.Data[j].Open,
Close: tickers.Data[j].Close,
Pair: tickers.Data[j].Symbol,
Pair: pairs[i],
}
err = ticker.ProcessTicker(h.GetName(), &tickerPrice, assetType)
if err != nil {

View File

@@ -1,9 +1,5 @@
package huobihadax
import (
"github.com/thrasher-corp/gocryptotrader/currency"
)
// Response stores the Huobi response information
type Response struct {
Status string `json:"status"`
@@ -25,6 +21,7 @@ type KlineItem struct {
Count int `json:"count"`
}
// WsTick stores websocket ticker data
type WsTick struct {
Channel string `json:"ch"`
Timestamp int64 `json:"ts"`
@@ -48,14 +45,14 @@ type Tickers struct {
// Ticker latest ticker data
type Ticker struct {
Amount float64 `json:"amount"`
Close float64 `json:"close"`
Count int64 `json:"count"`
High float64 `json:"high"`
Low float64 `json:"low"`
Open float64 `json:"open"`
Symbol currency.Pair `json:"symbol"`
Volume float64 `json:"vol"`
Amount float64 `json:"amount"`
Close float64 `json:"close"`
Count int64 `json:"count"`
High float64 `json:"high"`
Low float64 `json:"low"`
Open float64 `json:"open"`
Symbol string `json:"symbol"`
Volume float64 `json:"vol"`
}
// DetailMerged stores the ticker detail merged data
@@ -121,6 +118,7 @@ type Symbol struct {
PricePrecision int `json:"price-precision"`
AmountPrecision int `json:"amount-precision"`
SymbolPartition string `json:"symbol-partition"`
Symbol string `json:"innovation"`
}
// Account stores the account data
@@ -396,15 +394,15 @@ type WsAuthenticatedSubscriptionRequest struct {
// WsAuthenticatedAccountsListRequest request for account list authenticated connection
type WsAuthenticatedAccountsListRequest struct {
Op string `json:"op"`
AccessKeyID string `json:"AccessKeyId"`
SignatureMethod string `json:"SignatureMethod"`
SignatureVersion string `json:"SignatureVersion"`
Timestamp string `json:"Timestamp"`
Signature string `json:"Signature"`
Topic string `json:"topic"`
Symbol currency.Pair `json:"symbol"`
ClientID int64 `json:"cid,string,omitempty"`
Op string `json:"op"`
AccessKeyID string `json:"AccessKeyId"`
SignatureMethod string `json:"SignatureMethod"`
SignatureVersion string `json:"SignatureVersion"`
Timestamp string `json:"Timestamp"`
Signature string `json:"Signature"`
Topic string `json:"topic"`
Symbol string `json:"symbol"`
ClientID int64 `json:"cid,string,omitempty"`
}
// WsAuthenticatedOrderDetailsRequest request for order details authenticated connection
@@ -422,17 +420,17 @@ type WsAuthenticatedOrderDetailsRequest struct {
// WsAuthenticatedOrdersListRequest request for orderslist authenticated connection
type WsAuthenticatedOrdersListRequest struct {
Op string `json:"op"`
AccessKeyID string `json:"AccessKeyId"`
SignatureMethod string `json:"SignatureMethod"`
SignatureVersion string `json:"SignatureVersion"`
Timestamp string `json:"Timestamp"`
Signature string `json:"Signature"`
Topic string `json:"topic"`
States string `json:"states"`
AccountID int64 `json:"account-id"`
Symbol currency.Pair `json:"symbol"`
ClientID int64 `json:"cid,string,omitempty"`
Op string `json:"op"`
AccessKeyID string `json:"AccessKeyId"`
SignatureMethod string `json:"SignatureMethod"`
SignatureVersion string `json:"SignatureVersion"`
Timestamp string `json:"Timestamp"`
Signature string `json:"Signature"`
Topic string `json:"topic"`
States string `json:"states"`
AccountID int64 `json:"account-id"`
Symbol string `json:"symbol"`
ClientID int64 `json:"cid,string,omitempty"`
}
// WsAuthenticatedDataResponse response from authenticated connection
@@ -474,15 +472,15 @@ type WsAuthenticatedOrdersUpdateResponse struct {
// WsAuthenticatedOrdersUpdateResponseData order updatedata
type WsAuthenticatedOrdersUpdateResponseData struct {
UnfilledAmount float64 `json:"unfilled-amount,string"`
FilledAmount float64 `json:"filled-amount,string"`
Price float64 `json:"price,string"`
OrderID int64 `json:"order-id"`
Symbol currency.Pair `json:"symbol"`
MatchID int64 `json:"match-id"`
FilledCashAmount float64 `json:"filled-cash-amount,string"`
Role string `json:"role"`
OrderState string `json:"order-state"`
UnfilledAmount float64 `json:"unfilled-amount,string"`
FilledAmount float64 `json:"filled-amount,string"`
Price float64 `json:"price,string"`
OrderID int64 `json:"order-id"`
Symbol string `json:"symbol"`
MatchID int64 `json:"match-id"`
FilledCashAmount float64 `json:"filled-cash-amount,string"`
Role string `json:"role"`
OrderState string `json:"order-state"`
}
// WsAuthenticatedOrdersResponse response from Orders authenticated subscription
@@ -493,22 +491,22 @@ type WsAuthenticatedOrdersResponse struct {
// WsAuthenticatedOrdersResponseData order data
type WsAuthenticatedOrdersResponseData struct {
SeqID int64 `json:"seq-id"`
OrderID int64 `json:"order-id"`
Symbol currency.Pair `json:"symbol"`
AccountID int64 `json:"account-id"`
OrderAmount float64 `json:"order-amount,string"`
OrderPrice float64 `json:"order-price,string"`
CreatedAt int64 `json:"created-at"`
OrderType string `json:"order-type"`
OrderSource string `json:"order-source"`
OrderState string `json:"order-state"`
Role string `json:"role"`
Price float64 `json:"price,string"`
FilledAmount float64 `json:"filled-amount,string"`
UnfilledAmount float64 `json:"unfilled-amount,string"`
FilledCashAmount float64 `json:"filled-cash-amount,string"`
FilledFees float64 `json:"filled-fees,string"`
SeqID int64 `json:"seq-id"`
OrderID int64 `json:"order-id"`
Symbol string `json:"symbol"`
AccountID int64 `json:"account-id"`
OrderAmount float64 `json:"order-amount,string"`
OrderPrice float64 `json:"order-price,string"`
CreatedAt int64 `json:"created-at"`
OrderType string `json:"order-type"`
OrderSource string `json:"order-source"`
OrderState string `json:"order-state"`
Role string `json:"role"`
Price float64 `json:"price,string"`
FilledAmount float64 `json:"filled-amount,string"`
UnfilledAmount float64 `json:"unfilled-amount,string"`
FilledCashAmount float64 `json:"filled-cash-amount,string"`
FilledFees float64 `json:"filled-fees,string"`
}
// WsAuthenticatedAccountsListResponse response from AccountsList authenticated endpoint
@@ -540,20 +538,20 @@ type WsAuthenticatedOrdersListResponse struct {
// WsAuthenticatedOrdersListResponseData contains order details
type WsAuthenticatedOrdersListResponseData struct {
ID int64 `json:"id"`
Symbol currency.Pair `json:"symbol"`
AccountID int64 `json:"account-id"`
Amount float64 `json:"amount,string"`
Price float64 `json:"price,string"`
CreatedAt int64 `json:"created-at"`
Type string `json:"type"`
FilledAmount float64 `json:"filled-amount,string"`
FilledCashAmount float64 `json:"filled-cash-amount,string"`
FilledFees float64 `json:"filled-fees,string"`
FinishedAt int64 `json:"finished-at"`
Source string `json:"source"`
State string `json:"state"`
CanceledAt int64 `json:"canceled-at"`
ID int64 `json:"id"`
Symbol string `json:"symbol"`
AccountID int64 `json:"account-id"`
Amount float64 `json:"amount,string"`
Price float64 `json:"price,string"`
CreatedAt int64 `json:"created-at"`
Type string `json:"type"`
FilledAmount float64 `json:"filled-amount,string"`
FilledCashAmount float64 `json:"filled-cash-amount,string"`
FilledFees float64 `json:"filled-fees,string"`
FinishedAt int64 `json:"finished-at"`
Source string `json:"source"`
State string `json:"state"`
CanceledAt int64 `json:"canceled-at"`
}
// WsAuthenticatedOrderDetailResponse response from OrderDetail authenticated endpoint

View File

@@ -245,10 +245,11 @@ func (h *HUOBIHADAX) wsHandleMarketData(resp WsMessage) {
}
data := strings.Split(kline.Channel, ".")
h.Websocket.DataHandler <- wshandler.KlineData{
Timestamp: time.Unix(0, kline.Timestamp),
Exchange: h.GetName(),
AssetType: asset.Spot,
Pair: currency.NewPairFromString(data[1]),
Timestamp: time.Unix(0, kline.Timestamp),
Exchange: h.GetName(),
AssetType: asset.Spot,
Pair: currency.NewPairFromFormattedPairs(data[1],
h.GetEnabledPairs(asset.Spot), h.GetPairFormat(asset.Spot, true)),
OpenPrice: kline.Tick.Open,
ClosePrice: kline.Tick.Close,
HighPrice: kline.Tick.High,
@@ -264,10 +265,11 @@ func (h *HUOBIHADAX) wsHandleMarketData(resp WsMessage) {
}
data := strings.Split(trade.Channel, ".")
h.Websocket.DataHandler <- wshandler.TradeData{
Exchange: h.GetName(),
AssetType: asset.Spot,
CurrencyPair: currency.NewPairFromString(data[1]),
Timestamp: time.Unix(0, trade.Tick.Timestamp),
Exchange: h.GetName(),
AssetType: asset.Spot,
CurrencyPair: currency.NewPairFromFormattedPairs(data[1],
h.GetEnabledPairs(asset.Spot), h.GetPairFormat(asset.Spot, true)),
Timestamp: time.Unix(0, trade.Tick.Timestamp),
}
case strings.Contains(init.Channel, "detail"):
var ticker WsTick
@@ -287,14 +289,16 @@ func (h *HUOBIHADAX) wsHandleMarketData(resp WsMessage) {
Low: ticker.Tick.Low,
Timestamp: time.Unix(0, ticker.Timestamp),
AssetType: asset.Spot,
Pair: currency.NewPairFromString(data[1]),
Pair: currency.NewPairFromFormattedPairs(data[1],
h.GetEnabledPairs(asset.Spot), h.GetPairFormat(asset.Spot, true)),
}
}
}
// WsProcessOrderbook processes new orderbook data
func (h *HUOBIHADAX) WsProcessOrderbook(update *WsDepth, symbol string) error {
p := currency.NewPairFromString(symbol)
p := currency.NewPairFromFormattedPairs(symbol,
h.GetEnabledPairs(asset.Spot), h.GetPairFormat(asset.Spot, true))
var bids, asks []orderbook.Item
for i := 0; i < len(update.Tick.Bids); i++ {
bidLevel := update.Tick.Bids[i].([]interface{})
@@ -429,7 +433,7 @@ func (h *HUOBIHADAX) wsGetAccountsList(pair currency.Pair) (*WsAuthenticatedAcco
SignatureVersion: signatureVersion,
Timestamp: timestamp,
Topic: wsAccountsList,
Symbol: pair,
Symbol: h.FormatExchangeCurrency(pair, asset.Spot).String(),
}
hmac := h.wsGenerateSignature(timestamp, wsAccountListEndpoint)
request.Signature = crypto.Base64Encode(hmac)
@@ -456,7 +460,7 @@ func (h *HUOBIHADAX) wsGetOrdersList(accountID int64, pair currency.Pair) (*WsAu
Timestamp: timestamp,
Topic: wsOrdersList,
AccountID: accountID,
Symbol: pair.Lower(),
Symbol: h.FormatExchangeCurrency(pair, asset.Spot).String(),
States: "submitted,partial-filled",
}
hmac := h.wsGenerateSignature(timestamp, wsOrdersListEndpoint)

View File

@@ -191,7 +191,8 @@ func (h *HUOBIHADAX) FetchTradablePairs(asset asset.Item) ([]string, error) {
var pairs []string
for x := range symbols {
pairs = append(pairs, fmt.Sprintf("%v%v%v", symbols[x].BaseCurrency, h.GetPairFormat(asset, false).Delimiter, symbols[x].QuoteCurrency))
pairs = append(pairs, fmt.Sprintf("%v%v%v", symbols[x].BaseCurrency,
h.GetPairFormat(asset, false).Delimiter, symbols[x].QuoteCurrency))
}
return pairs, nil
@@ -218,7 +219,8 @@ func (h *HUOBIHADAX) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker
pairs := h.GetEnabledPairs(assetType)
for i := range pairs {
for j := range tickers.Data {
if !pairs[i].Equal(tickers.Data[j].Symbol) {
pairFmt := h.FormatExchangeCurrency(pairs[i], assetType).String()
if pairFmt != tickers.Data[j].Symbol {
continue
}
tickerPrice := ticker.Price{
@@ -227,7 +229,7 @@ func (h *HUOBIHADAX) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker
Volume: tickers.Data[j].Volume,
Open: tickers.Data[j].Open,
Close: tickers.Data[j].Close,
Pair: tickers.Data[j].Symbol,
Pair: pairs[i],
}
err = ticker.ProcessTicker(h.GetName(), &tickerPrice, assetType)
if err != nil {

View File

@@ -220,7 +220,8 @@ func (k *Kraken) WsHandleEventResponse(response *WebsocketEventResponse, rawResp
// allowing correlation between subscriptions and returned data
func addNewSubscriptionChannelData(response *WebsocketEventResponse) {
// We change the / to - to maintain compatibility with REST/config
pair := currency.NewPairWithDelimiter(response.Pair.Base.String(), response.Pair.Quote.String(), "-")
pair := currency.NewPairWithDelimiter(response.Pair.Base.String(),
response.Pair.Quote.String(), "-")
subscriptionChannelPair = append(subscriptionChannelPair, WebsocketChannelData{
Subscription: response.Subscription.Name,
Pair: pair,

View File

@@ -170,7 +170,7 @@ func (k *Kraken) Run() {
forceUpdate := false
if !common.StringDataContains(k.GetEnabledPairs(asset.Spot).Strings(), k.GetPairFormat(asset.Spot, false).Delimiter) ||
!common.StringDataContains(k.GetAvailablePairs(asset.Spot).Strings(), k.GetPairFormat(asset.Spot, false).Delimiter) {
enabledPairs := currency.NewPairsFromStrings([]string{fmt.Sprintf("BTC%vUSD", k.GetPairFormat(asset.Spot, false).Delimiter)})
enabledPairs := currency.NewPairsFromStrings([]string{fmt.Sprintf("XBT%vUSD", k.GetPairFormat(asset.Spot, false).Delimiter)})
log.Warn(log.ExchangeSys, "Available pairs for Kraken reset due to config upgrade, please enable the ones you would like again")
forceUpdate = true
@@ -242,13 +242,14 @@ func (k *Kraken) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Pri
for i := range pairs {
for curr, v := range tickers {
if !strings.EqualFold(pairs[i].String(), curr) {
pairFmt := k.FormatExchangeCurrency(pairs[i], assetType).String()
if !strings.EqualFold(pairFmt, curr) {
var altCurrency string
var ok bool
if altCurrency, ok = assetPairMap[curr]; !ok {
continue
}
if !strings.EqualFold(pairs[i].String(), altCurrency) {
if !strings.EqualFold(pairFmt, altCurrency) {
continue
}
}

View File

@@ -491,8 +491,9 @@ func TestWsTradeProcessing(t *testing.T) {
func TestWsTickerProcessing(t *testing.T) {
TestSetDefaults(t)
TestSetup(t)
l.Websocket.DataHandler = sharedtestvalues.GetWebsocketInterfaceChannelOverride()
l.Websocket.TrafficAlert = sharedtestvalues.GetWebsocketStructChannelOverride()
const testChanSize = 26
l.Websocket.DataHandler = make(chan interface{}, testChanSize)
l.Websocket.TrafficAlert = make(chan struct{}, testChanSize)
json := `{"btcusd":{"low":"10990.05","high":"11966.24","last":"11903.29","volume":"1803.967079","sell":"11912.39","buy":"11902.2"},"btceur":{"low":"9886.87","high":"10732.72","last":"10691.44","volume":"87.994478","sell":"10711.62","buy":"10691.44"},"btchkd":{"low":null,"high":null,"last":"51776.98","volume":null,"sell":"93307.37","buy":"93177.56"},"btcjpy":{"low":"1176039.0","high":"1272246.0","last":"1265680.0","volume":"129.021421","sell":"1266764.0","buy":"1265680.0"},"btcgbp":{"low":"9157.12","high":"9953.43","last":"9941.28","volume":"10.4997","sell":"10007.89","buy":"9941.28"},"btcaud":{"low":"16102.57","high":"17594.22","last":"17548.16","volume":"7.338316","sell":"17616.67","buy":"17549.69"},"btccad":{"low":"14541.69","high":"15834.87","last":"15763.54","volume":"30.480309","sell":"15793.45","buy":"15756.13"},"btcsgd":{"low":"15133.82","high":"16501.62","last":"16455.53","volume":"4.044026","sell":"16484.37","buy":"16462.18"},"btcchf":{"low":"10800.58","high":"11526.24","last":"11526.24","volume":"0.1765","sell":"11675.34","buy":"11632.02"},"btcnzd":{"low":null,"high":null,"last":"8340.98","volume":null,"sell":"18315.49","buy":"18221.37"},"btcngn":{"low":null,"high":null,"last":"600000.0","volume":null,"sell":null,"buy":null},"eurusd":{"low":"1.1088","high":"1.1138","last":"1.1125","volume":"2680.105249","sell":"1.1142","buy":"1.1121"},"gbpusd":{"low":"1.1934","high":"1.1958","last":"1.1934","volume":"1493.923823","sell":"1.1979","buy":"1.1903"},"usdjpy":{"low":"105.26","high":"107.25","last":"106.33","volume":"114490.2179","sell":"106.34","buy":"106.27"},"usdhkd":{"low":null,"high":null,"last":"7.851","volume":null,"sell":"7.8328","buy":"7.8286"},"usdcad":{"low":"1.3225","high":"1.3272","last":"1.3255","volume":"11033.9877","sell":"1.3258","buy":"1.3238"},"usdsgd":{"low":"1.3776","high":"1.3839","last":"1.3838","volume":"2523.75","sell":"1.3838","buy":"1.3819"},"audusd":{"low":"0.6764","high":"0.6853","last":"0.6771","volume":"5442.608321","sell":"0.6782","buy":"0.6762"},"nzdusd":{"low":null,"high":null,"last":"0.6758","volume":null,"sell":"0.6532","buy":"0.6504"},"usdchf":{"low":"0.9838","high":"0.9838","last":"0.9838","volume":"108.3352","sell":"0.9801","buy":"0.9773"},"usdngn":{"low":null,"high":null,"last":"200.0","volume":null,"sell":null,"buy":null},"ethbtc":{"low":"0.0205","high":"0.025","last":"0.0205","volume":null,"sell":"0.03","buy":"0.0194"},"ltcbtc":{"low":null,"high":null,"last":"0.0114","volume":null,"sell":"0.009","buy":"0.0073"},"bchbtc":{"low":null,"high":null,"last":"0.0544","volume":null,"sell":"0.0322","buy":"0.0274"},"xrpbtc":{"low":"0.000042","high":"0.000042","last":"0.000042","volume":null,"sell":"0.000037","buy":"0.000022"},"baceth":{"low":"0.000035","high":"0.000035","last":"0.000035","volume":null,"sell":"0.0015","buy":null}}`
err := l.processTicker(json)
if err != nil {

View File

@@ -21,9 +21,12 @@ const (
marketGlobalEndpoint = "market-global"
marketSubstring = "market-"
globalSubstring = "-global"
volumeString = "volume"
highString = "high"
lowString = "low"
tickerBuyString = "buy"
tickerHighString = "high"
tickerLastString = "last"
tickerLowString = "low"
tickerSellString = "sell"
tickerVolumeString = "volume"
wssSchem = "wss"
)
@@ -220,29 +223,28 @@ func (l *LakeBTC) processTicker(ticker string) error {
}
for k, v := range tUpdate {
tickerData := v.(map[string]interface{})
if tickerData[highString] == nil || tickerData[lowString] == nil || tickerData[volumeString] == nil {
continue
}
high, err := strconv.ParseFloat(tickerData[highString].(string), 64)
if err != nil {
l.Websocket.DataHandler <- fmt.Errorf("%v error parsing ticker data 'high' %v", l.Name, tickerData)
continue
}
low, err := strconv.ParseFloat(tickerData[lowString].(string), 64)
if err != nil {
l.Websocket.DataHandler <- fmt.Errorf("%v error parsing ticker data 'low' %v", l.Name, tickerData)
continue
}
vol, err := strconv.ParseFloat(tickerData[volumeString].(string), 64)
if err != nil {
l.Websocket.DataHandler <- fmt.Errorf("%v error parsing ticker data 'volume' %v", l.Name, tickerData)
continue
processTickerItem := func(tick map[string]interface{}, item string) float64 {
if tick[item] == nil {
return 0
}
p, err := strconv.ParseFloat(tick[item].(string), 64)
if err != nil {
l.Websocket.DataHandler <- fmt.Errorf("%s error parsing ticker data '%s' %v", l.Name, item, tickerData)
return 0
}
return p
}
l.Websocket.DataHandler <- wshandler.TickerData{
Exchange: l.Name,
Volume: vol,
High: high,
Low: low,
Bid: processTickerItem(tickerData, tickerBuyString),
High: processTickerItem(tickerData, tickerHighString),
Last: processTickerItem(tickerData, tickerLastString),
Low: processTickerItem(tickerData, tickerLowString),
Ask: processTickerItem(tickerData, tickerSellString),
Volume: processTickerItem(tickerData, tickerVolumeString),
AssetType: asset.Spot,
Pair: currency.NewPairFromString(k),
}

View File

@@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"strconv"
"strings"
"sync"
"time"
@@ -188,9 +187,8 @@ func (z *ZB) FetchTradablePairs(asset asset.Item) ([]string, error) {
func (z *ZB) UpdateTradablePairs(forceUpdate bool) error {
pairs, err := z.FetchTradablePairs(asset.Spot)
if err != nil {
return nil
return err
}
return z.UpdatePairs(currency.NewPairsFromStrings(pairs), asset.Spot, false, forceUpdate)
}
@@ -204,8 +202,9 @@ func (z *ZB) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price,
}
for _, x := range z.GetEnabledPairs(assetType) {
currencySplit := strings.Split(z.FormatExchangeCurrency(x, assetType).String(), z.GetPairFormat(assetType, false).Delimiter)
curr := currencySplit[0] + currencySplit[1]
// We can't use either pair format here, so format it to lower-
// case and without any delimiter
curr := x.Format("", false).String()
if _, ok := result[curr]; !ok {
continue
}