From 6afccd20bf91d9b8179972820625e3479cbc6329 Mon Sep 17 00:00:00 2001 From: Gareth Kirwan Date: Fri, 8 Nov 2024 10:40:25 +0700 Subject: [PATCH] Huobi: Fix invalid contract type err when autoUpdatePairs is false We were relying on autoUpdatePairs to fetch contract types before we need them. If the user disables it in config, we'll lazily fetch just the relevant Futures. --- exchanges/huobi/huobi_futures.go | 5 +++++ exchanges/huobi/huobi_wrapper.go | 19 ++++++++++--------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/exchanges/huobi/huobi_futures.go b/exchanges/huobi/huobi_futures.go index ff1ffd60570..fc0611c7499 100644 --- a/exchanges/huobi/huobi_futures.go +++ b/exchanges/huobi/huobi_futures.go @@ -1249,6 +1249,11 @@ func (h *HUOBI) formatFuturesPair(p currency.Pair, convertQuoteToExpiry bool) (s // We need this because some apis, such as ticker, use BTC_CW, NW, CQ, NQ // Other apis, such as contract_info, use contract type of this_week, next_week, quarter (sic), and next_quater func (h *HUOBI) pairFromContractExpiryCode(p currency.Pair) (currency.Pair, error) { + if h.futureContractCodes == nil { // Worst race-case here is that we fetch twice. No avoiding it. + if _, err := h.FetchTradablePairs(context.Background(), asset.Futures); err != nil { + return p, err + } + } h.futureContractCodesMutex.RLock() defer h.futureContractCodesMutex.RUnlock() exp, ok := h.futureContractCodes[p.Quote.String()] diff --git a/exchanges/huobi/huobi_wrapper.go b/exchanges/huobi/huobi_wrapper.go index f0deb80ad87..e71e34ba1eb 100644 --- a/exchanges/huobi/huobi_wrapper.go +++ b/exchanges/huobi/huobi_wrapper.go @@ -283,12 +283,19 @@ func (h *HUOBI) FetchTradablePairs(ctx context.Context, a asset.Item) (currency. pairs = append(pairs, pair) } case asset.Futures: + // We cache contract expiries on the exchange locally right now because there's no exchange base holder for them + // It's not as dangerous as it seems, because when contracts change, so would tradeable pairs, + // so by caching them in FetchTradablePairs we're not adding any extra-layer of out-of-date data + // Note: Until this runs the first time the futureContractCodes is nil, which acts as an uninitialized flag for pairFromContractExpiryCode + h.futureContractCodesMutex.Lock() + defer h.futureContractCodesMutex.Unlock() + h.futureContractCodes = map[string]currency.Code{} + symbols, err := h.FGetContractInfo(ctx, "", "", currency.EMPTYPAIR) if err != nil { return nil, err } pairs = make([]currency.Pair, 0, len(symbols.Data)) - expiryCodeDates := map[string]currency.Code{} for _, c := range symbols.Data { if c.ContractStatus != 1 { continue @@ -299,19 +306,13 @@ func (h *HUOBI) FetchTradablePairs(ctx context.Context, a asset.Item) (currency. } pairs = append(pairs, pair) if cType, ok := contractExpiryNames[c.ContractType]; ok { - if v, ok := expiryCodeDates[cType]; !ok { - expiryCodeDates[cType] = currency.NewCode(pair.Quote.String()) + if v, ok := h.futureContractCodes[cType]; !ok { + h.futureContractCodes[cType] = currency.NewCode(pair.Quote.String()) } else if v.String() != pair.Quote.String() { return nil, fmt.Errorf("%w: %s (%s vs %s)", errInconsistentContractExpiry, cType, v.String(), pair.Quote.String()) } } } - // We cache contract expiries on the exchange locally right now because there's no exchange base holder for them - // It's not as dangerous as it seems, because when contracts change, so would tradeable pairs, - // so by caching them in FetchTradablePairs we're not adding any extra-layer of out-of-date data - h.futureContractCodesMutex.Lock() - h.futureContractCodes = expiryCodeDates - h.futureContractCodesMutex.Unlock() } return pairs, nil }