Files
gocryptotrader/exchanges/asset/asset.go
Gareth Kirwan 1199f38546 subscriptions: Encapsulate, replace Pair with Pairs and refactor; improve exchange support
* Websocket: Use ErrSubscribedAlready

instead of errChannelAlreadySubscribed

* Subscriptions: Replace Pair with Pairs

Given that some subscriptions have multiple pairs, support that as the
standard.

* Docs: Update subscriptions in add new exch

* RPC: Update Subscription Pairs

* Linter: Disable testifylint.Len

We deliberately use Equal over Len to avoid spamming the contents of large Slices

* Websocket: Add suffix to state consts

* Binance: Subscription Pairs support

* Bitfinex: Subscription Pairs support

* Bithumb: Subscription Pairs support

* Bitmex: Subscription Pairs support

* Bitstamp: Subscription Pairs support

* BTCMarkets: Subscription Pairs support

* BTSE: Subscription Pairs support

* Coinbase: Subscription Pairs support

* Coinut: Subscription Pairs support

* GateIO: Subscription Pairs support

* Gemini: Subscription Pairs support and improvement

* Hitbtc: Subscription Pairs support

* Huboi: Subscription Pairs support

* Kucoin: Subscription Pairs support

* Okcoin: Subscription Pairs support

* Poloniex: Subscription Pairs support

* Kraken: Add subscription Pairs support

Note: This is a naieve implementation because we want to rebase the
kraken websocket rewrite on top of this

* Bybit: Subscription Pairs support

* Okx: Subscription Pairs support

* Bitmex: Subsription configuration

* Fixes unauthenticated websocket left as CanUseAuth
* Fixes auth subs happening privately

* CoinbasePro: Subscription Configuration

* Consolidate ProductIDs when all subscriptions are for the same list

* Websocket: Log actual sent message when Verbose

* Subscriptions: Improve clarity of which key is which in Match

* Subscriptions: Lint fix for HugeParam

* Subscriptions: Add AddPairs and move keys from test

* Subscriptions: Simplify subscription keys and add key types

* Subscriptions: Add List.GroupPairs Rename sub.AddPairs

* Subscription: Fix ExactKey not matching 0 pairs

* Subscriptions: Remove unused IdentityKey and HasPairKey

* Subscriptions: Fix GetKey test

* Subscriptions: Test coverage improvements

* Websocket: Change State on Add/Remove

* Subscriptions: Improve error context

* Subscriptions: Fix Enable: false subs not ignored

* Bitfinex: Fix WsAuth test failing on DataHandler

DataHandler is eaten by dataMonitor now, so we need to use ToRoutine

* Deribit: Subscription Pairs support

* Websocket: Accept nil lists for checkSubscriptions

If the user passes in a nil (implicitly empty) list, we would not panic.
Therefore the burden of correctness about that data lies with them.
The list of subscriptions is empty, and that's okay, and possibly
convenient

* Websocket: Add context to NilPointer errors

* Subscriptions: Add context to nil errors

* Exchange: Fix error expectations in UnsubToWSChans
2024-06-07 11:54:08 +10:00

251 lines
6.4 KiB
Go

package asset
import (
"encoding/json"
"errors"
"fmt"
"strings"
)
var (
// ErrNotSupported is an error for an unsupported asset type
ErrNotSupported = errors.New("unsupported asset type")
// ErrNotEnabled is an error for an asset not enabled
ErrNotEnabled = errors.New("asset type not enabled")
// ErrInvalidAsset is returned when the assist isn't valid
ErrInvalidAsset = errors.New("asset is invalid")
)
// Item stores the asset type
type Item uint32
// Items stores a list of assets types
type Items []Item
// Const vars for asset package
const (
Empty Item = 0
Spot Item = 1 << iota
Margin
CrossMargin
MarginFunding
Index
Binary
PerpetualContract
PerpetualSwap
Futures
DeliveryFutures
UpsideProfitContract
DownsideProfitContract
CoinMarginedFutures
USDTMarginedFutures
USDCMarginedFutures
Options
OptionCombo
FutureCombo
LinearContract // Added to represent a USDT and USDC based linear derivatives(futures/perpetual) assets in Bybit V5
All
optionsFlag = OptionCombo | Options
futuresFlag = PerpetualContract | PerpetualSwap | Futures | DeliveryFutures | UpsideProfitContract | DownsideProfitContract | CoinMarginedFutures | USDTMarginedFutures | USDCMarginedFutures | LinearContract | FutureCombo
supportedFlag = Spot | Margin | CrossMargin | MarginFunding | Index | Binary | PerpetualContract | PerpetualSwap | Futures | DeliveryFutures | UpsideProfitContract | DownsideProfitContract | CoinMarginedFutures | USDTMarginedFutures | USDCMarginedFutures | Options | LinearContract | OptionCombo | FutureCombo
spot = "spot"
margin = "margin"
crossMargin = "cross_margin" // for Gateio exchange
marginFunding = "marginfunding"
index = "index"
binary = "binary"
perpetualContract = "perpetualcontract"
perpetualSwap = "perpetualswap"
swap = "swap"
futures = "futures"
deliveryFutures = "delivery"
upsideProfitContract = "upsideprofitcontract"
downsideProfitContract = "downsideprofitcontract"
coinMarginedFutures = "coinmarginedfutures"
usdtMarginedFutures = "usdtmarginedfutures"
usdcMarginedFutures = "usdcmarginedfutures"
options = "options"
optionCombo = "option_combo"
futureCombo = "future_combo"
all = "all"
)
var (
supportedList = Items{Spot, Margin, CrossMargin, MarginFunding, Index, Binary, PerpetualContract, PerpetualSwap, Futures, DeliveryFutures, UpsideProfitContract, DownsideProfitContract, CoinMarginedFutures, USDTMarginedFutures, USDCMarginedFutures, Options, LinearContract, OptionCombo, FutureCombo}
)
// Supported returns a list of supported asset types
func Supported() Items {
return supportedList
}
// String converts an Item to its string representation
func (a Item) String() string {
switch a {
case Spot:
return spot
case Margin:
return margin
case CrossMargin:
return crossMargin
case MarginFunding:
return marginFunding
case Index:
return index
case Binary:
return binary
case PerpetualContract:
return perpetualContract
case PerpetualSwap:
return perpetualSwap
case Futures:
return futures
case DeliveryFutures:
return deliveryFutures
case UpsideProfitContract:
return upsideProfitContract
case DownsideProfitContract:
return downsideProfitContract
case CoinMarginedFutures:
return coinMarginedFutures
case USDTMarginedFutures:
return usdtMarginedFutures
case USDCMarginedFutures:
return usdcMarginedFutures
case Options:
return options
case OptionCombo:
return optionCombo
case FutureCombo:
return futureCombo
case All:
return all
default:
return ""
}
}
// Strings converts an asset type array to a string array
func (a Items) Strings() []string {
assets := make([]string, len(a))
for x := range a {
assets[x] = a[x].String()
}
return assets
}
// Contains returns whether or not the supplied asset exists
// in the list of Items
func (a Items) Contains(i Item) bool {
if i.IsValid() {
for x := range a {
if a[x] == i {
return true
}
}
}
return false
}
// JoinToString joins an asset type array and converts it to a string
// with the supplied separator
func (a Items) JoinToString(separator string) string {
return strings.Join(a.Strings(), separator)
}
// IsValid returns whether or not the supplied asset type is valid or
// not
func (a Item) IsValid() bool {
return a != Empty && supportedFlag&a == a
}
// UnmarshalJSON conforms type to the umarshaler interface
func (a *Item) UnmarshalJSON(d []byte) error {
var assetString string
err := json.Unmarshal(d, &assetString)
if err != nil {
return err
}
if assetString == "" {
return nil
}
ai, err := New(assetString)
if err != nil {
return err
}
*a = ai
return nil
}
// MarshalJSON conforms type to the marshaller interface
func (a Item) MarshalJSON() ([]byte, error) {
return json.Marshal(a.String())
}
// New takes an input matches to relevant package assets
func New(input string) (Item, error) {
input = strings.ToLower(input)
switch input {
case spot:
return Spot, nil
case margin:
return Margin, nil
case marginFunding:
return MarginFunding, nil
case crossMargin:
return CrossMargin, nil
case deliveryFutures:
return DeliveryFutures, nil
case index:
return Index, nil
case binary:
return Binary, nil
case perpetualContract:
return PerpetualContract, nil
case perpetualSwap, swap:
return PerpetualSwap, nil
case futures:
return Futures, nil
case upsideProfitContract:
return UpsideProfitContract, nil
case downsideProfitContract:
return DownsideProfitContract, nil
case coinMarginedFutures:
return CoinMarginedFutures, nil
case usdtMarginedFutures:
return USDTMarginedFutures, nil
case usdcMarginedFutures:
return USDCMarginedFutures, nil
case options, "option":
return Options, nil
case optionCombo:
return OptionCombo, nil
case futureCombo:
return FutureCombo, nil
case all:
return All, nil
default:
return 0, fmt.Errorf("%w '%v', only supports %s", ErrNotSupported, input, supportedList)
}
}
// UseDefault returns default asset type
func UseDefault() Item {
return Spot
}
// IsFutures checks if the asset type is a futures contract based asset
func (a Item) IsFutures() bool {
return a != Empty && futuresFlag&a == a
}
// IsOptions checks if the asset type is options contract based asset
func (a Item) IsOptions() bool {
return a != Empty && optionsFlag&a == a
}