mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-14 07:26:47 +00:00
Huobi: Implement ticker batching (#1439)
* Add huobi ticker batching and tests * sneaky funding rate fix, don't look * better processing, better tests * inline structs per shazbaz * formatting expansion * weird * introduce time param, mini fixes * linter splinter * merge fix, kraken fix * move comment, use require, add len
This commit is contained in:
@@ -28,44 +28,47 @@ const (
|
||||
huobiAPIVersion2 = "2"
|
||||
|
||||
// Spot endpoints
|
||||
huobiMarketHistoryKline = "/market/history/kline"
|
||||
huobiMarketDetail = "/market/detail"
|
||||
huobiMarketDetailMerged = "/market/detail/merged"
|
||||
huobi24HrMarketSummary = "/market/detail?"
|
||||
huobiMarketDepth = "/market/depth"
|
||||
huobiMarketTrade = "/market/trade"
|
||||
huobiMarketTickers = "/market/tickers"
|
||||
huobiMarketTradeHistory = "/market/history/trade"
|
||||
huobiSymbols = "/v1/common/symbols"
|
||||
huobiCurrencies = "/v1/common/currencys"
|
||||
huobiTimestamp = "/common/timestamp"
|
||||
huobiAccounts = "/account/accounts"
|
||||
huobiAccountBalance = "/account/accounts/%s/balance"
|
||||
huobiAccountDepositAddress = "/account/deposit/address"
|
||||
huobiAccountWithdrawQuota = "/account/withdraw/quota"
|
||||
huobiAccountQueryWithdrawAddress = "/account/withdraw/"
|
||||
huobiAggregatedBalance = "/subuser/aggregate-balance"
|
||||
huobiOrderPlace = "/order/orders/place"
|
||||
huobiOrderCancel = "/order/orders/%s/submitcancel"
|
||||
huobiOrderCancelBatch = "/order/orders/batchcancel"
|
||||
huobiBatchCancelOpenOrders = "/order/orders/batchCancelOpenOrders"
|
||||
huobiGetOrder = "/order/orders/getClientOrder"
|
||||
huobiGetOrderMatch = "/order/orders/%s/matchresults"
|
||||
huobiGetOrders = "/order/orders"
|
||||
huobiGetOpenOrders = "/order/openOrders"
|
||||
huobiGetOrdersMatch = "/orders/matchresults"
|
||||
huobiMarginTransferIn = "/dw/transfer-in/margin"
|
||||
huobiMarginTransferOut = "/dw/transfer-out/margin"
|
||||
huobiMarginOrders = "/margin/orders"
|
||||
huobiMarginRepay = "/margin/orders/%s/repay"
|
||||
huobiMarginLoanOrders = "/margin/loan-orders"
|
||||
huobiMarginAccountBalance = "/margin/accounts/balance"
|
||||
huobiWithdrawCreate = "/dw/withdraw/api/create"
|
||||
huobiWithdrawCancel = "/dw/withdraw-virtual/%s/cancel"
|
||||
huobiStatusError = "error"
|
||||
huobiMarginRates = "/margin/loan-info"
|
||||
huobiCurrenciesReference = "/v2/reference/currencies"
|
||||
huobiWithdrawHistory = "/query/deposit-withdraw"
|
||||
huobiMarketHistoryKline = "/market/history/kline"
|
||||
huobiMarketDetail = "/market/detail"
|
||||
huobiMarketDetailMerged = "/market/detail/merged"
|
||||
huobi24HrMarketSummary = "/market/detail?"
|
||||
huobiMarketDepth = "/market/depth"
|
||||
huobiMarketTrade = "/market/trade"
|
||||
huobiMarketTickers = "/market/tickers"
|
||||
huobiMarketTradeHistory = "/market/history/trade"
|
||||
huobiSymbols = "/v1/common/symbols"
|
||||
huobiCurrencies = "/v1/common/currencys"
|
||||
huobiTimestamp = "/common/timestamp"
|
||||
huobiAccounts = "/account/accounts"
|
||||
huobiAccountBalance = "/account/accounts/%s/balance"
|
||||
huobiAccountDepositAddress = "/account/deposit/address"
|
||||
huobiAccountWithdrawQuota = "/account/withdraw/quota"
|
||||
huobiAccountQueryWithdrawAddress = "/account/withdraw/"
|
||||
huobiAggregatedBalance = "/subuser/aggregate-balance"
|
||||
huobiOrderPlace = "/order/orders/place"
|
||||
huobiOrderCancel = "/order/orders/%s/submitcancel"
|
||||
huobiOrderCancelBatch = "/order/orders/batchcancel"
|
||||
huobiBatchCancelOpenOrders = "/order/orders/batchCancelOpenOrders"
|
||||
huobiGetOrder = "/order/orders/getClientOrder"
|
||||
huobiGetOrderMatch = "/order/orders/%s/matchresults"
|
||||
huobiGetOrders = "/order/orders"
|
||||
huobiGetOpenOrders = "/order/openOrders"
|
||||
huobiGetOrdersMatch = "/orders/matchresults"
|
||||
huobiMarginTransferIn = "/dw/transfer-in/margin"
|
||||
huobiMarginTransferOut = "/dw/transfer-out/margin"
|
||||
huobiMarginOrders = "/margin/orders"
|
||||
huobiMarginRepay = "/margin/orders/%s/repay"
|
||||
huobiMarginLoanOrders = "/margin/loan-orders"
|
||||
huobiMarginAccountBalance = "/margin/accounts/balance"
|
||||
huobiWithdrawCreate = "/dw/withdraw/api/create"
|
||||
huobiWithdrawCancel = "/dw/withdraw-virtual/%s/cancel"
|
||||
huobiStatusError = "error"
|
||||
huobiMarginRates = "/margin/loan-info"
|
||||
huobiCurrenciesReference = "/v2/reference/currencies"
|
||||
huobiWithdrawHistory = "/query/deposit-withdraw"
|
||||
huobiBatchCoinMarginSwapContracts = "/v2/swap-ex/market/detail/batch_merged"
|
||||
huobiBatchLinearSwapContracts = "/linear-swap-ex/market/detail/batch_merged"
|
||||
huobiBatchContracts = "/v2/market/detail/batch_merged"
|
||||
)
|
||||
|
||||
// HUOBI is the overarching type across this package
|
||||
@@ -129,6 +132,33 @@ func (h *HUOBI) Get24HrMarketSummary(ctx context.Context, symbol currency.Pair)
|
||||
return result, h.SendHTTPRequest(ctx, exchange.RestSpot, huobi24HrMarketSummary+params.Encode(), &result)
|
||||
}
|
||||
|
||||
// GetBatchCoinMarginSwapContracts returns the tickers for coin margined swap contracts
|
||||
func (h *HUOBI) GetBatchCoinMarginSwapContracts(ctx context.Context) ([]FuturesBatchTicker, error) {
|
||||
var result struct {
|
||||
Data []FuturesBatchTicker `json:"ticks"`
|
||||
}
|
||||
err := h.SendHTTPRequest(ctx, exchange.RestFutures, huobiBatchCoinMarginSwapContracts, &result)
|
||||
return result.Data, err
|
||||
}
|
||||
|
||||
// GetBatchLinearSwapContracts returns the tickers for linear swap contracts
|
||||
func (h *HUOBI) GetBatchLinearSwapContracts(ctx context.Context) ([]FuturesBatchTicker, error) {
|
||||
var result struct {
|
||||
Data []FuturesBatchTicker `json:"ticks"`
|
||||
}
|
||||
err := h.SendHTTPRequest(ctx, exchange.RestFutures, huobiBatchLinearSwapContracts, &result)
|
||||
return result.Data, err
|
||||
}
|
||||
|
||||
// GetBatchFuturesContracts returns the tickers for futures contracts
|
||||
func (h *HUOBI) GetBatchFuturesContracts(ctx context.Context) ([]FuturesBatchTicker, error) {
|
||||
var result struct {
|
||||
Data []FuturesBatchTicker `json:"ticks"`
|
||||
}
|
||||
err := h.SendHTTPRequest(ctx, exchange.RestFutures, huobiBatchContracts, &result)
|
||||
return result.Data, err
|
||||
}
|
||||
|
||||
// GetTickers returns the ticker for the specified symbol
|
||||
func (h *HUOBI) GetTickers(ctx context.Context) (Tickers, error) {
|
||||
var result Tickers
|
||||
|
||||
@@ -81,6 +81,8 @@ const (
|
||||
fContractDateFormat = "060102"
|
||||
)
|
||||
|
||||
var errInvalidContractType = errors.New("invalid contract type")
|
||||
|
||||
// FGetContractInfo gets contract info for futures
|
||||
func (h *HUOBI) FGetContractInfo(ctx context.Context, symbol, contractType string, code currency.Pair) (FContractInfoData, error) {
|
||||
var resp FContractInfoData
|
||||
@@ -191,11 +193,11 @@ func (h *HUOBI) FContractOpenInterest(ctx context.Context, symbol, contractType
|
||||
params.Set("contract_type", contractType)
|
||||
}
|
||||
if !code.IsEmpty() {
|
||||
codeValue, err := h.convertContractShortHandToExpiry(code)
|
||||
codeValue, err := h.formatFuturesPair(code, true)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
params.Set("contract_code", codeValue.String())
|
||||
params.Set("contract_code", codeValue)
|
||||
}
|
||||
path := common.EncodeURLValues(fContractOpenInterest, params)
|
||||
return resp, h.SendHTTPRequest(ctx, exchange.RestFutures, path, &resp)
|
||||
@@ -374,7 +376,7 @@ func (h *HUOBI) FQueryHisOpenInterest(ctx context.Context, symbol, contractType,
|
||||
params.Set("symbol", symbol)
|
||||
}
|
||||
if !common.StringDataCompareInsensitive(validContractTypes, contractType) {
|
||||
return resp, fmt.Errorf("invalid contract type")
|
||||
return resp, fmt.Errorf("%w %v", errInvalidContractType, contractType)
|
||||
}
|
||||
params.Set("contract_type", contractType)
|
||||
if !common.StringDataCompareInsensitive(validPeriods, period) {
|
||||
@@ -1256,7 +1258,7 @@ func (h *HUOBI) formatFuturesCode(p currency.Code) (string, error) {
|
||||
func (h *HUOBI) formatFuturesPair(p currency.Pair, convertQuoteToExpiry bool) (string, error) {
|
||||
if common.StringDataCompareInsensitive(validContractShortTypes, p.Quote.String()) {
|
||||
if convertQuoteToExpiry {
|
||||
cp, err := h.convertContractShortHandToExpiry(p)
|
||||
cp, err := h.convertContractShortHandToExpiry(p, time.Now())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -1273,12 +1275,12 @@ func (h *HUOBI) formatFuturesPair(p currency.Pair, convertQuoteToExpiry bool) (s
|
||||
|
||||
// convertContractShortHandToExpiry converts a contract shorthand eg BTC-CW into a full expiry date
|
||||
// eg BTC240329 to associate with tradable pair formatting
|
||||
func (h *HUOBI) convertContractShortHandToExpiry(pair currency.Pair) (currency.Pair, error) {
|
||||
if !common.StringDataCompareInsensitive(validContractShortTypes, pair.Quote.String()) {
|
||||
return currency.EMPTYPAIR, fmt.Errorf("%s invalid contract type", pair)
|
||||
func (h *HUOBI) convertContractShortHandToExpiry(pair currency.Pair, tt time.Time) (currency.Pair, error) {
|
||||
loc, err := time.LoadLocation("Asia/Singapore")
|
||||
if err != nil {
|
||||
return currency.EMPTYPAIR, err
|
||||
}
|
||||
|
||||
tt := time.Now()
|
||||
tt = tt.In(loc)
|
||||
switch pair.Quote.Item.Symbol {
|
||||
case "NW":
|
||||
tt = tt.AddDate(0, 0, 7)
|
||||
@@ -1304,6 +1306,8 @@ func (h *HUOBI) convertContractShortHandToExpiry(pair currency.Pair) (currency.P
|
||||
for tt.Weekday() != time.Friday {
|
||||
tt = tt.AddDate(0, 0, -1)
|
||||
}
|
||||
default:
|
||||
return currency.EMPTYPAIR, fmt.Errorf(" %w %v", errInvalidContractType, pair)
|
||||
}
|
||||
pair.Quote = currency.NewCode(tt.Format(fContractDateFormat))
|
||||
return pair, nil
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/common/key"
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
@@ -26,6 +27,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/stream"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
|
||||
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
|
||||
)
|
||||
|
||||
@@ -2686,7 +2688,6 @@ func TestGetAvailableTransferChains(t *testing.T) {
|
||||
t.Error("expected more than one result")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatFuturesPair(t *testing.T) {
|
||||
r, err := h.formatFuturesPair(futuresTestPair, false)
|
||||
if err != nil {
|
||||
@@ -2858,6 +2859,101 @@ func TestGetSwapFundingRates(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetBatchCoinMarginSwapContracts(t *testing.T) {
|
||||
t.Parallel()
|
||||
resp, err := h.GetBatchCoinMarginSwapContracts(context.Background())
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, resp)
|
||||
}
|
||||
|
||||
func TestGetBatchLinearSwapContracts(t *testing.T) {
|
||||
t.Parallel()
|
||||
resp, err := h.GetBatchLinearSwapContracts(context.Background())
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, resp)
|
||||
}
|
||||
|
||||
func TestGetBatchFuturesContracts(t *testing.T) {
|
||||
t.Parallel()
|
||||
resp, err := h.GetBatchFuturesContracts(context.Background())
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, resp)
|
||||
}
|
||||
|
||||
func TestUpdateTickers(t *testing.T) {
|
||||
t.Parallel()
|
||||
for _, a := range h.GetAssetTypes(false) {
|
||||
err := h.UpdateTickers(context.Background(), a)
|
||||
assert.NoErrorf(t, err, "asset %s", a)
|
||||
|
||||
avail, err := h.GetAvailablePairs(a)
|
||||
require.NoError(t, err)
|
||||
for x := range avail {
|
||||
_, err = ticker.GetTicker(h.Name, avail[x], a)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertContractShortHandToExpiry(t *testing.T) {
|
||||
t.Parallel()
|
||||
tt := time.Now()
|
||||
cp := currency.NewPair(currency.BTC, currency.NewCode("CW"))
|
||||
cp, err := h.convertContractShortHandToExpiry(cp, tt)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, cp.Quote.String(), "CW")
|
||||
tick, err := h.FetchTicker(context.Background(), cp, asset.Futures)
|
||||
if assert.NoError(t, err) {
|
||||
assert.NotZero(t, tick.Close)
|
||||
}
|
||||
|
||||
cp = currency.NewPair(currency.BTC, currency.NewCode("NW"))
|
||||
cp, err = h.convertContractShortHandToExpiry(cp, tt)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, cp.Quote.String(), "NW")
|
||||
tick, err = h.FetchTicker(context.Background(), cp, asset.Futures)
|
||||
if assert.NoError(t, err) {
|
||||
assert.NotZero(t, tick.Close)
|
||||
}
|
||||
|
||||
cp = currency.NewPair(currency.BTC, currency.NewCode("CQ"))
|
||||
cp, err = h.convertContractShortHandToExpiry(cp, tt)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, cp.Quote.String(), "CQ")
|
||||
tick, err = h.FetchTicker(context.Background(), cp, asset.Futures)
|
||||
if assert.NoError(t, err) {
|
||||
assert.NotZero(t, tick.Close)
|
||||
}
|
||||
|
||||
// calculate a specific date
|
||||
cp = currency.NewPair(currency.BTC, currency.NewCode("CQ"))
|
||||
tt = time.Date(2021, 6, 3, 0, 0, 0, 0, time.UTC)
|
||||
cp, err = h.convertContractShortHandToExpiry(cp, tt)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, cp.Quote.String(), "210625")
|
||||
|
||||
cp = currency.NewPair(currency.BTC, currency.NewCode("CW"))
|
||||
cp, err = h.convertContractShortHandToExpiry(cp, tt)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, cp.Quote.String(), "210604")
|
||||
|
||||
cp = currency.NewPair(currency.BTC, currency.NewCode("CWif hat"))
|
||||
_, err = h.convertContractShortHandToExpiry(cp, tt)
|
||||
assert.ErrorIs(t, err, errInvalidContractType)
|
||||
|
||||
tt = time.Now()
|
||||
cp = currency.NewPair(currency.BTC, currency.NewCode("NQ"))
|
||||
cp, err = h.convertContractShortHandToExpiry(cp, tt)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, cp.Quote.String(), "NQ")
|
||||
tick, err = h.FetchTicker(context.Background(), cp, asset.Futures)
|
||||
if err != nil {
|
||||
// Huobi doesn't always have a next-quarter contract, return if no data found
|
||||
return
|
||||
}
|
||||
assert.NotZero(t, tick.Close)
|
||||
}
|
||||
|
||||
func TestGetOpenInterest(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := h.GetOpenInterest(context.Background(), key.PairAsset{
|
||||
@@ -2911,41 +3007,3 @@ func TestContractOpenInterestUSDT(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, resp)
|
||||
}
|
||||
|
||||
func TestConvertContractShortHandToExpiry(t *testing.T) {
|
||||
t.Parallel()
|
||||
cp := currency.NewPair(currency.BTC, currency.NewCode("CW"))
|
||||
cp, err := h.convertContractShortHandToExpiry(cp)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, cp.Quote.String(), "CW")
|
||||
tick, err := h.FetchTicker(context.Background(), cp, asset.Futures)
|
||||
assert.NoError(t, err)
|
||||
assert.NotZero(t, tick.Close)
|
||||
|
||||
cp = currency.NewPair(currency.BTC, currency.NewCode("NW"))
|
||||
cp, err = h.convertContractShortHandToExpiry(cp)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, cp.Quote.String(), "NW")
|
||||
tick, err = h.FetchTicker(context.Background(), cp, asset.Futures)
|
||||
assert.NoError(t, err)
|
||||
assert.NotZero(t, tick.Close)
|
||||
|
||||
cp = currency.NewPair(currency.BTC, currency.NewCode("CQ"))
|
||||
cp, err = h.convertContractShortHandToExpiry(cp)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, cp.Quote.String(), "CQ")
|
||||
tick, err = h.FetchTicker(context.Background(), cp, asset.Futures)
|
||||
assert.NoError(t, err)
|
||||
assert.NotZero(t, tick.Close)
|
||||
|
||||
cp = currency.NewPair(currency.BTC, currency.NewCode("NQ"))
|
||||
cp, err = h.convertContractShortHandToExpiry(cp)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, cp.Quote.String(), "NQ")
|
||||
tick, err = h.FetchTicker(context.Background(), cp, asset.Futures)
|
||||
if err != nil {
|
||||
// Huobi doesn't always have a next-quarter contract
|
||||
return
|
||||
}
|
||||
assert.NotZero(t, tick.Close)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package huobi
|
||||
import (
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/types"
|
||||
)
|
||||
|
||||
type errorCapture struct {
|
||||
@@ -520,16 +521,40 @@ type Tickers struct {
|
||||
Data []Ticker `json:"data"`
|
||||
}
|
||||
|
||||
// FuturesBatchTicker holds ticker data
|
||||
type FuturesBatchTicker struct {
|
||||
ID float64 `json:"id"`
|
||||
Timestamp int64 `json:"ts"`
|
||||
Ask [2]float64 `json:"ask"`
|
||||
Bid [2]float64 `json:"bid"`
|
||||
BusinessType string `json:"business_type"`
|
||||
ContractCode string `json:"contract_code"`
|
||||
Open types.Number `json:"open"`
|
||||
Close types.Number `json:"close"`
|
||||
Low types.Number `json:"low"`
|
||||
High types.Number `json:"high"`
|
||||
Amount types.Number `json:"amount"`
|
||||
Count float64 `json:"count"`
|
||||
Volume types.Number `json:"vol"`
|
||||
TradeTurnover types.Number `json:"trade_turnover"`
|
||||
TradePartition string `json:"trade_partition"`
|
||||
Symbol string `json:"symbol"` // If ContractCode is empty, Symbol is populated
|
||||
}
|
||||
|
||||
// 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 string `json:"symbol"`
|
||||
Volume float64 `json:"vol"`
|
||||
Symbol string `json:"symbol"`
|
||||
Open float64 `json:"open"`
|
||||
High float64 `json:"high"`
|
||||
Low float64 `json:"low"`
|
||||
Close float64 `json:"close"`
|
||||
Amount float64 `json:"amount"`
|
||||
Volume float64 `json:"vol"`
|
||||
Count float64 `json:"count"`
|
||||
Bid float64 `json:"bid"`
|
||||
BidSize float64 `json:"bidSize"`
|
||||
Ask float64 `json:"ask"`
|
||||
AskSize float64 `json:"askSize"`
|
||||
}
|
||||
|
||||
// OrderBookDataRequestParamsType var for request param types
|
||||
|
||||
@@ -109,6 +109,7 @@ func (h *HUOBI) SetDefaults() {
|
||||
Websocket: true,
|
||||
RESTCapabilities: protocol.Features{
|
||||
TickerFetching: true,
|
||||
TickerBatching: true,
|
||||
KlineFetching: true,
|
||||
TradeFetching: true,
|
||||
OrderbookFetching: true,
|
||||
@@ -141,7 +142,6 @@ func (h *HUOBI) SetDefaults() {
|
||||
GetOrders: true,
|
||||
TickerFetching: true,
|
||||
FundingRateFetching: false, // supported but not implemented // TODO when multi-websocket support added
|
||||
|
||||
},
|
||||
WithdrawPermissions: exchange.AutoWithdrawCryptoWithSetup |
|
||||
exchange.NoFiatWithdrawals,
|
||||
@@ -445,8 +445,141 @@ func (h *HUOBI) UpdateTradablePairs(ctx context.Context, forceUpdate bool) error
|
||||
}
|
||||
|
||||
// UpdateTickers updates the ticker for all currency pairs of a given asset type
|
||||
func (h *HUOBI) UpdateTickers(_ context.Context, _ asset.Item) error {
|
||||
return common.ErrFunctionNotSupported
|
||||
func (h *HUOBI) UpdateTickers(ctx context.Context, a asset.Item) error {
|
||||
switch a {
|
||||
case asset.Spot:
|
||||
ticks, err := h.GetTickers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := range ticks.Data {
|
||||
var cp currency.Pair
|
||||
cp, _, err = h.MatchSymbolCheckEnabled(ticks.Data[i].Symbol, a, false)
|
||||
if err != nil {
|
||||
if errors.Is(err, currency.ErrPairNotFound) {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
err = ticker.ProcessTicker(&ticker.Price{
|
||||
High: ticks.Data[i].High,
|
||||
Low: ticks.Data[i].Low,
|
||||
Bid: ticks.Data[i].Bid,
|
||||
Ask: ticks.Data[i].Ask,
|
||||
Volume: ticks.Data[i].Volume,
|
||||
QuoteVolume: ticks.Data[i].Amount,
|
||||
Open: ticks.Data[i].Open,
|
||||
Close: ticks.Data[i].Close,
|
||||
BidSize: ticks.Data[i].BidSize,
|
||||
AskSize: ticks.Data[i].AskSize,
|
||||
Pair: cp,
|
||||
ExchangeName: h.Name,
|
||||
AssetType: a,
|
||||
LastUpdated: time.Now(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case asset.CoinMarginedFutures:
|
||||
ticks, err := h.GetBatchCoinMarginSwapContracts(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := range ticks {
|
||||
var cp currency.Pair
|
||||
cp, _, err = h.MatchSymbolCheckEnabled(ticks[i].ContractCode, a, true)
|
||||
if err != nil {
|
||||
if errors.Is(err, currency.ErrPairNotFound) {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
tt := time.UnixMilli(ticks[i].Timestamp)
|
||||
err = ticker.ProcessTicker(&ticker.Price{
|
||||
High: ticks[i].High.Float64(),
|
||||
Low: ticks[i].Low.Float64(),
|
||||
Volume: ticks[i].Volume.Float64(),
|
||||
QuoteVolume: ticks[i].Amount.Float64(),
|
||||
Open: ticks[i].Open.Float64(),
|
||||
Close: ticks[i].Close.Float64(),
|
||||
Bid: ticks[i].Bid[0],
|
||||
BidSize: ticks[i].Bid[1],
|
||||
Ask: ticks[i].Ask[0],
|
||||
AskSize: ticks[i].Ask[1],
|
||||
Pair: cp,
|
||||
ExchangeName: h.Name,
|
||||
AssetType: a,
|
||||
LastUpdated: tt,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case asset.Futures:
|
||||
linearTicks, err := h.GetBatchLinearSwapContracts(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ticks, err := h.GetBatchFuturesContracts(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
allTicks := make([]FuturesBatchTicker, 0, len(linearTicks)+len(ticks))
|
||||
allTicks = append(allTicks, linearTicks...)
|
||||
allTicks = append(allTicks, ticks...)
|
||||
for i := range allTicks {
|
||||
var cp currency.Pair
|
||||
if allTicks[i].Symbol != "" {
|
||||
cp, err = currency.NewPairFromString(allTicks[i].Symbol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cp, err = h.convertContractShortHandToExpiry(cp, time.Now())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cp, _, err = h.MatchSymbolCheckEnabled(cp.String(), a, true)
|
||||
if err != nil {
|
||||
if errors.Is(err, currency.ErrPairNotFound) {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
cp, _, err = h.MatchSymbolCheckEnabled(allTicks[i].ContractCode, a, true)
|
||||
if err != nil {
|
||||
if errors.Is(err, currency.ErrPairNotFound) {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
tt := time.UnixMilli(allTicks[i].Timestamp)
|
||||
err = ticker.ProcessTicker(&ticker.Price{
|
||||
High: allTicks[i].High.Float64(),
|
||||
Low: allTicks[i].Low.Float64(),
|
||||
Volume: allTicks[i].Volume.Float64(),
|
||||
QuoteVolume: allTicks[i].Amount.Float64(),
|
||||
Open: allTicks[i].Open.Float64(),
|
||||
Close: allTicks[i].Close.Float64(),
|
||||
Bid: allTicks[i].Bid[0],
|
||||
BidSize: allTicks[i].Bid[1],
|
||||
Ask: allTicks[i].Ask[0],
|
||||
AskSize: allTicks[i].Ask[1],
|
||||
Pair: cp,
|
||||
ExchangeName: h.Name,
|
||||
AssetType: a,
|
||||
LastUpdated: tt,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("%w %v", asset.ErrNotSupported, a)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateTicker updates and returns the ticker for a currency pair
|
||||
@@ -2281,7 +2414,7 @@ func (h *HUOBI) GetLatestFundingRates(ctx context.Context, r *fundingrate.Latest
|
||||
rate := fundingrate.LatestRateResponse{
|
||||
Exchange: h.Name,
|
||||
Asset: r.Asset,
|
||||
Pair: r.Pair,
|
||||
Pair: cp,
|
||||
LatestRate: fundingrate.Rate{
|
||||
Time: ft,
|
||||
Rate: decimal.NewFromFloat(rates[i].FundingRate),
|
||||
|
||||
@@ -2298,7 +2298,7 @@ func TestGetOpenInterest(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, resp)
|
||||
|
||||
_, err = k.GetOpenInterest(context.Background())
|
||||
resp, err = k.GetOpenInterest(context.Background())
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, resp)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user