currency: Adds matching lookup table built from available pairs (#1312)

* currency: Add pair matching update (cherry-pick)

* exchange/currency: Add tests and update func

* linter fix, also if using json unmarshal functionality stop usage of string conversion without delimiter

* gemini: fix test

* currency/manager: potential optimisation

* exchanges: purge derive from wrapper cases and add warning comment

* glorious: nits

* glorious: nits

* linter: fix

* glorious: nits

* whoops

* whoops

* glorious: nits continued

* glorious: diff THANKS!

* hitbtc: fix update tradable pairs strings splitting. continue if not enabled tickers update pair.

* glorious: nits

* linter: fix

* Update exchanges/exmo/exmo_wrapper.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* bitstamp: fix test when 32 biterinos architecturinos

* capture more strings for speed

* swapsies because whos running 32bit \0/?

---------

Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io>
Co-authored-by: Scott <gloriousCode@users.noreply.github.com>
This commit is contained in:
Ryan O'Hara-Reid
2023-10-18 11:57:27 +11:00
committed by GitHub
parent d3bf4a460a
commit ceef7a14e0
32 changed files with 621 additions and 264 deletions

View File

@@ -356,20 +356,20 @@ func (b *Bitfinex) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item)
// UpdateTickers updates the ticker for all currency pairs of a given asset type
func (b *Bitfinex) UpdateTickers(ctx context.Context, a asset.Item) error {
enabled, err := b.GetEnabledPairs(a)
if err != nil {
return err
}
tickerNew, err := b.GetTickerBatch(ctx)
if err != nil {
return err
}
for key, val := range tickerNew {
pair, err := enabled.DeriveFrom(strings.Replace(key, ":", "", 1)[1:])
pair, enabled, err := b.MatchSymbolCheckEnabled(key[1:], a, true)
if err != nil {
// GetTickerBatch returns all pairs in call across all asset types.
if !errors.Is(err, currency.ErrPairNotFound) {
return err
}
}
if !enabled {
continue
}

View File

@@ -1098,6 +1098,7 @@ func TestGetHistoricTrades(t *testing.T) {
}
func TestUpdateTicker(t *testing.T) {
t.Parallel()
cp := currency.NewPair(currency.ETH, currency.USD)
_, err := b.UpdateTicker(context.Background(), cp, asset.PerpetualContract)
if err != nil {

View File

@@ -364,11 +364,7 @@ func (b *Bitmex) UpdateTickers(ctx context.Context, a asset.Item) error {
return err
}
enabled, err := b.GetEnabledPairs(a)
if err != nil {
return err
}
var enabled bool
instruments:
for j := range tick {
var pair currency.Pair
@@ -377,7 +373,7 @@ instruments:
if tick[j].Typ != futuresID {
continue instruments
}
pair, err = enabled.DeriveFrom(tick[j].Symbol)
pair, enabled, err = b.MatchSymbolCheckEnabled(tick[j].Symbol, a, false)
case asset.Index:
switch tick[j].Typ {
case bitMEXBasketIndexID,
@@ -392,23 +388,27 @@ instruments:
// contain an underscore. Calling DeriveFrom will then error and
// the instruments will be missed.
tick[j].Symbol = strings.Replace(tick[j].Symbol, currency.UnderscoreDelimiter, "", 1)
pair, err = enabled.DeriveFrom(tick[j].Symbol)
pair, enabled, err = b.MatchSymbolCheckEnabled(tick[j].Symbol, a, false)
case asset.PerpetualContract:
if tick[j].Typ != perpetualContractID {
continue instruments
}
pair, err = enabled.DeriveFrom(tick[j].Symbol)
pair, enabled, err = b.MatchSymbolCheckEnabled(tick[j].Symbol, a, false)
case asset.Spot:
if tick[j].Typ != spotID {
continue instruments
}
tick[j].Symbol = strings.Replace(tick[j].Symbol, currency.UnderscoreDelimiter, "", 1)
pair, err = enabled.DeriveFrom(tick[j].Symbol)
pair, enabled, err = b.MatchSymbolCheckEnabled(tick[j].Symbol, a, false)
}
if err != nil {
if !errors.Is(err, currency.ErrPairNotFound) {
return err
}
}
if !enabled {
continue
}

View File

@@ -44,13 +44,22 @@ func (t *microTimestamp) UnmarshalJSON(data []byte) error {
return err
}
if strconv.IntSize == 32 && len(s) >= 10 {
i, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return err
}
*t = microTimestamp(time.UnixMicro(i))
return nil
}
// Has Fast path optimisation when int == 64
i, err := strconv.Atoi(s)
if err != nil {
return err
}
*t = microTimestamp(time.UnixMicro(int64(i)))
return nil
}

View File

@@ -2042,7 +2042,7 @@ func TestUpdateTicker(t *testing.T) {
var pairs currency.Pairs
if mockTests {
var pair2 currency.Pair
pair2, err = currency.NewPairFromString("BTCUSD-U23")
pair2, err = currency.NewPairFromString("BTCUSD-Z23")
if err != nil {
t.Fatal(err)
}
@@ -2230,7 +2230,7 @@ func TestGetHistoricCandles(t *testing.T) {
}
var pair2 currency.Pair
if mockTests {
pair2, err = currency.NewPairFromString("BTCUSD-U23")
pair2, err = currency.NewPairFromString("BTCUSD-Z23")
if err != nil {
t.Fatal(err)
}
@@ -2292,7 +2292,7 @@ func TestGetHistoricCandlesExtended(t *testing.T) {
}
var pair2 currency.Pair
if mockTests {
pair2, err = currency.NewPairFromString("BTCUSD-U23")
pair2, err = currency.NewPairFromString("BTCUSD-Z23")
if err != nil {
t.Fatal(err)
}

View File

@@ -266,11 +266,15 @@ func (by *Bybit) wsHandleData(respRaw []byte) error {
if err != nil {
return err
}
p, err := by.extractCurrencyPair(data.OBData.Symbol, asset.Spot)
p, enabled, err := by.MatchSymbolCheckEnabled(data.OBData.Symbol, asset.Spot, false)
if err != nil {
return err
}
if !enabled {
return nil
}
err = by.wsUpdateOrderbook(&data.OBData, p, asset.Spot)
if err != nil {
return err
@@ -286,11 +290,15 @@ func (by *Bybit) wsHandleData(respRaw []byte) error {
return err
}
p, err := by.extractCurrencyPair(data.Parameters.Symbol, asset.Spot)
p, enabled, err := by.MatchSymbolCheckEnabled(data.Parameters.Symbol, asset.Spot, false)
if err != nil {
return err
}
if !enabled {
return nil
}
side := order.Sell
if data.TradeData.Side {
side = order.Buy
@@ -313,11 +321,15 @@ func (by *Bybit) wsHandleData(respRaw []byte) error {
return err
}
p, err := by.extractCurrencyPair(data.Ticker.Symbol, asset.Spot)
p, enabled, err := by.MatchSymbolCheckEnabled(data.Ticker.Symbol, asset.Spot, false)
if err != nil {
return err
}
if !enabled {
return nil
}
by.Websocket.DataHandler <- &ticker.Price{
ExchangeName: by.Name,
Bid: data.Ticker.Bid.Float64(),
@@ -334,11 +346,15 @@ func (by *Bybit) wsHandleData(respRaw []byte) error {
return err
}
p, err := by.extractCurrencyPair(data.Kline.Symbol, asset.Spot)
p, enabled, err := by.MatchSymbolCheckEnabled(data.Kline.Symbol, asset.Spot, false)
if err != nil {
return err
}
if !enabled {
return nil
}
by.Websocket.DataHandler <- stream.KlineData{
Pair: p,
AssetType: asset.Spot,
@@ -425,11 +441,15 @@ func (by *Bybit) wsHandleData(respRaw []byte) error {
}
}
p, err := by.extractCurrencyPair(data[j].Symbol, asset.Spot)
p, enabled, err := by.MatchSymbolCheckEnabled(data[j].Symbol, asset.Spot, false)
if err != nil {
return err
}
if !enabled {
continue
}
by.Websocket.DataHandler <- order.Detail{
Price: data[j].Price.Float64(),
Amount: data[j].Quantity.Float64(),
@@ -475,11 +495,15 @@ func (by *Bybit) wsHandleData(respRaw []byte) error {
}
}
p, err := by.extractCurrencyPair(data[j].Symbol, asset.Spot)
p, enabled, err := by.MatchSymbolCheckEnabled(data[j].Symbol, asset.Spot, false)
if err != nil {
return err
}
if !enabled {
continue
}
by.Websocket.DataHandler <- &order.Detail{
Exchange: by.Name,
OrderID: data[j].OrderID,

View File

@@ -2,6 +2,7 @@ package bybit
import (
"context"
"errors"
"fmt"
"sort"
"strconv"
@@ -416,16 +417,6 @@ func (by *Bybit) UpdateTradablePairs(ctx context.Context, forceUpdate bool) erro
// UpdateTickers updates the ticker for all currency pairs of a given asset type
func (by *Bybit) UpdateTickers(ctx context.Context, assetType asset.Item) error {
avail, err := by.GetAvailablePairs(assetType)
if err != nil {
return err
}
enabled, err := by.GetEnabledPairs(assetType)
if err != nil {
return err
}
switch assetType {
case asset.Spot:
ticks, err := by.GetTickersV5(ctx, "spot", "", "")
@@ -434,17 +425,19 @@ func (by *Bybit) UpdateTickers(ctx context.Context, assetType asset.Item) error
}
for x := range ticks.List {
pair, err := avail.DeriveFrom(ticks.List[x].Symbol)
pair, enabled, err := by.MatchSymbolCheckEnabled(ticks.List[x].Symbol, assetType, false)
if err != nil {
// These symbols below do not have a spot market but are in fact
// perpetuals.
if ticks.List[x].Symbol == "ZECUSDT" || ticks.List[x].Symbol == "DASHUSDT" {
continue
}
return err
if !errors.Is(err, currency.ErrPairNotFound) {
return err
}
}
if !enabled.Contains(pair, true) {
if !enabled {
continue
}
@@ -465,6 +458,11 @@ func (by *Bybit) UpdateTickers(ctx context.Context, assetType asset.Item) error
}
}
case asset.CoinMarginedFutures, asset.USDTMarginedFutures, asset.Futures:
enabled, err := by.GetEnabledPairs(assetType)
if err != nil {
return err
}
tick, err := by.GetFuturesSymbolPriceTicker(ctx, currency.EMPTYPAIR)
if err != nil {
return err
@@ -480,7 +478,8 @@ func (by *Bybit) UpdateTickers(ctx context.Context, assetType asset.Item) error
if tick[y].Symbol != formattedPair.String() {
continue
}
cp, err := by.extractCurrencyPair(tick[y].Symbol, assetType)
// Don't need to check if this pair is enabled due to call above.
cp, err := by.MatchSymbolWithAvailablePairs(tick[y].Symbol, assetType, false)
if err != nil {
return err
}
@@ -501,6 +500,11 @@ func (by *Bybit) UpdateTickers(ctx context.Context, assetType asset.Item) error
}
}
case asset.USDCMarginedFutures:
enabled, err := by.GetEnabledPairs(assetType)
if err != nil {
return err
}
for x := range enabled {
formattedPair, err := by.FormatExchangeCurrency(enabled[x], assetType)
if err != nil {
@@ -512,7 +516,8 @@ func (by *Bybit) UpdateTickers(ctx context.Context, assetType asset.Item) error
return err
}
cp, err := by.extractCurrencyPair(tick.Symbol, assetType)
// Don't need to check if this pair is enabled due to call above.
cp, err := by.MatchSymbolWithAvailablePairs(tick.Symbol, assetType, false)
if err != nil {
return err
}
@@ -551,10 +556,13 @@ func (by *Bybit) UpdateTicker(ctx context.Context, p currency.Pair, assetType as
}
for y := range tick {
cp, err := by.extractCurrencyPair(tick[y].Symbol, assetType)
cp, enabled, err := by.MatchSymbolCheckEnabled(tick[y].Symbol, assetType, false)
if err != nil {
return nil, err
}
if !enabled {
continue
}
err = ticker.ProcessTicker(&ticker.Price{
Last: tick[y].LastPrice.Float64(),
High: tick[y].HighPrice.Float64(),
@@ -572,7 +580,6 @@ func (by *Bybit) UpdateTicker(ctx context.Context, p currency.Pair, assetType as
return nil, err
}
}
case asset.CoinMarginedFutures, asset.USDTMarginedFutures, asset.Futures:
tick, err := by.GetFuturesSymbolPriceTicker(ctx, formattedPair)
if err != nil {
@@ -580,10 +587,13 @@ func (by *Bybit) UpdateTicker(ctx context.Context, p currency.Pair, assetType as
}
for y := range tick {
cp, err := by.extractCurrencyPair(tick[y].Symbol, assetType)
cp, enabled, err := by.MatchSymbolCheckEnabled(tick[y].Symbol, assetType, false)
if err != nil {
return nil, err
}
if !enabled {
continue
}
err = ticker.ProcessTicker(&ticker.Price{
Last: tick[y].LastPrice.Float64(),
High: tick[y].HighPrice24h.Float64(),
@@ -606,10 +616,13 @@ func (by *Bybit) UpdateTicker(ctx context.Context, p currency.Pair, assetType as
return nil, err
}
cp, err := by.extractCurrencyPair(tick.Symbol, assetType)
cp, enabled, err := by.MatchSymbolCheckEnabled(tick.Symbol, assetType, false)
if err != nil {
return nil, err
}
if !enabled {
return nil, fmt.Errorf("%v %v not enabled", formattedPair, assetType)
}
err = ticker.ProcessTicker(&ticker.Price{
Last: tick.LastPrice.Float64(),
High: tick.High24h.Float64(),
@@ -2097,30 +2110,12 @@ func (by *Bybit) GetServerTime(ctx context.Context, a asset.Item) (time.Time, er
return time.Time{}, fmt.Errorf("%s %w", a, asset.ErrNotSupported)
}
func (by *Bybit) extractCurrencyPair(symbol string, item asset.Item) (currency.Pair, error) {
pairs, err := by.CurrencyPairs.GetPairs(item, true)
if err != nil {
return currency.EMPTYPAIR, err
}
pair, err := pairs.DeriveFrom(symbol)
if err != nil {
return currency.EMPTYPAIR, err
}
return pair, nil
}
// UpdateOrderExecutionLimits sets exchange executions for a required asset type
func (by *Bybit) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item) error {
avail, err := by.GetAvailablePairs(a)
if err != nil {
return err
}
var limits []order.MinMaxLevel
switch a {
case asset.Spot:
var pairsData []PairData
pairsData, err = by.GetAllSpotPairs(ctx)
pairsData, err := by.GetAllSpotPairs(ctx)
if err != nil {
return err
}
@@ -2128,11 +2123,15 @@ func (by *Bybit) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item) e
limits = make([]order.MinMaxLevel, 0, len(pairsData))
for x := range pairsData {
var pair currency.Pair
pair, err = avail.DeriveFrom(pairsData[x].Name)
var enabled bool
pair, enabled, err = by.MatchSymbolCheckEnabled(pairsData[x].Name, a, false)
if err != nil {
log.Warnf(log.ExchangeSys, "%s unable to load limits for %v, pair data missing", by.Name, pairsData[x].Name)
continue
}
if !enabled {
continue
}
limits = append(limits, order.MinMaxLevel{
Asset: a,

View File

@@ -215,6 +215,7 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
if wsType, ok := multiStreamData["type"].(string); ok {
switch topics[0] {
case wsOrder25, wsOrder200:
var enabled bool
switch wsType {
case wsOperationSnapshot:
var response WsFuturesOrderbook
@@ -224,11 +225,15 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
}
var p currency.Pair
p, err = by.extractCurrencyPair(response.OBData[0].Symbol, asset.CoinMarginedFutures)
p, enabled, err = by.MatchSymbolCheckEnabled(response.OBData[0].Symbol, asset.CoinMarginedFutures, false)
if err != nil {
return err
}
if !enabled {
return nil
}
err = by.processOrderbook(response.OBData,
response.Type,
p,
@@ -236,7 +241,6 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
if err != nil {
return err
}
case wsOperationDelta:
var response WsCoinDeltaOrderbook
err = json.Unmarshal(respRaw, &response)
@@ -246,11 +250,15 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
if len(response.OBData.Delete) > 0 {
var p currency.Pair
p, err = by.extractCurrencyPair(response.OBData.Delete[0].Symbol, asset.CoinMarginedFutures)
p, enabled, err = by.MatchSymbolCheckEnabled(response.OBData.Delete[0].Symbol, asset.CoinMarginedFutures, false)
if err != nil {
return err
}
if !enabled {
return nil
}
err = by.processOrderbook(response.OBData.Delete,
wsOrderbookActionDelete,
p,
@@ -262,11 +270,15 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
if len(response.OBData.Update) > 0 {
var p currency.Pair
p, err = by.extractCurrencyPair(response.OBData.Update[0].Symbol, asset.CoinMarginedFutures)
p, enabled, err = by.MatchSymbolCheckEnabled(response.OBData.Update[0].Symbol, asset.CoinMarginedFutures, false)
if err != nil {
return err
}
if !enabled {
return nil
}
err = by.processOrderbook(response.OBData.Update,
wsOrderbookActionUpdate,
p,
@@ -278,11 +290,15 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
if len(response.OBData.Insert) > 0 {
var p currency.Pair
p, err = by.extractCurrencyPair(response.OBData.Insert[0].Symbol, asset.CoinMarginedFutures)
p, enabled, err = by.MatchSymbolCheckEnabled(response.OBData.Insert[0].Symbol, asset.CoinMarginedFutures, false)
if err != nil {
return err
}
if !enabled {
return nil
}
err = by.processOrderbook(response.OBData.Insert,
wsOrderbookActionInsert,
p,
@@ -308,7 +324,7 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
trades := make([]trade.Data, len(response.TradeData))
for i := range response.TradeData {
var p currency.Pair
p, err = by.extractCurrencyPair(response.TradeData[0].Symbol, asset.CoinMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.TradeData[0].Symbol, asset.CoinMarginedFutures, false)
if err != nil {
return err
}
@@ -344,7 +360,7 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
}
var p currency.Pair
p, err = by.extractCurrencyPair(topics[len(topics)-1], asset.CoinMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(topics[len(topics)-1], asset.CoinMarginedFutures, false)
if err != nil {
return err
}
@@ -382,7 +398,7 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
}
var p currency.Pair
p, err = by.extractCurrencyPair(response.Ticker.Symbol, asset.CoinMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.Ticker.Symbol, asset.CoinMarginedFutures, false)
if err != nil {
return err
}
@@ -411,7 +427,7 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
if len(response.Data.Delete) > 0 {
for x := range response.Data.Delete {
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data.Delete[x].Symbol, asset.CoinMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data.Delete[x].Symbol, asset.CoinMarginedFutures, false)
if err != nil {
return err
}
@@ -435,7 +451,7 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
if len(response.Data.Update) > 0 {
for x := range response.Data.Update {
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data.Update[x].Symbol, asset.CoinMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data.Update[x].Symbol, asset.CoinMarginedFutures, false)
if err != nil {
return err
}
@@ -459,7 +475,7 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
if len(response.Data.Insert) > 0 {
for x := range response.Data.Insert {
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data.Insert[x].Symbol, asset.CoinMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data.Insert[x].Symbol, asset.CoinMarginedFutures, false)
if err != nil {
return err
}
@@ -510,7 +526,7 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
for i := range response.Data {
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data[i].Symbol, asset.CoinMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data[i].Symbol, asset.CoinMarginedFutures, false)
if err != nil {
return err
}
@@ -566,7 +582,7 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
}
for x := range response.Data {
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data[x].Symbol, asset.CoinMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data[x].Symbol, asset.CoinMarginedFutures, false)
if err != nil {
return err
}
@@ -628,7 +644,7 @@ func (by *Bybit) wsCoinHandleData(respRaw []byte) error {
}
for x := range response.Data {
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data[x].Symbol, asset.CoinMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data[x].Symbol, asset.CoinMarginedFutures, false)
if err != nil {
return err
}

View File

@@ -176,7 +176,7 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
}
var p currency.Pair
p, err = by.extractCurrencyPair(response.OBData[0].Symbol, asset.Futures)
p, err = by.MatchSymbolWithAvailablePairs(response.OBData[0].Symbol, asset.Futures, false)
if err != nil {
return err
}
@@ -198,7 +198,7 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
if len(response.OBData.Delete) > 0 {
var p currency.Pair
p, err = by.extractCurrencyPair(response.OBData.Delete[0].Symbol, asset.Futures)
p, err = by.MatchSymbolWithAvailablePairs(response.OBData.Delete[0].Symbol, asset.Futures, false)
if err != nil {
return err
}
@@ -213,7 +213,7 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
if len(response.OBData.Update) > 0 {
var p currency.Pair
p, err = by.extractCurrencyPair(response.OBData.Update[0].Symbol, asset.Futures)
p, err = by.MatchSymbolWithAvailablePairs(response.OBData.Update[0].Symbol, asset.Futures, false)
if err != nil {
return err
}
@@ -229,7 +229,7 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
if len(response.OBData.Insert) > 0 {
var p currency.Pair
p, err = by.extractCurrencyPair(response.OBData.Insert[0].Symbol, asset.Futures)
p, err = by.MatchSymbolWithAvailablePairs(response.OBData.Insert[0].Symbol, asset.Futures, false)
if err != nil {
return err
}
@@ -261,7 +261,7 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
trades := make([]trade.Data, len(response.TradeData))
for i := range response.TradeData {
var p currency.Pair
p, err = by.extractCurrencyPair(response.TradeData[0].Symbol, asset.Futures)
p, err = by.MatchSymbolWithAvailablePairs(response.TradeData[0].Symbol, asset.Futures, false)
if err != nil {
return err
}
@@ -297,7 +297,7 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
}
var p currency.Pair
p, err = by.extractCurrencyPair(topics[len(topics)-1], asset.Futures)
p, err = by.MatchSymbolWithAvailablePairs(topics[len(topics)-1], asset.Futures, false)
if err != nil {
return err
}
@@ -327,7 +327,7 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
}
var p currency.Pair
p, err = by.extractCurrencyPair(response.Ticker.Symbol, asset.Futures)
p, err = by.MatchSymbolWithAvailablePairs(response.Ticker.Symbol, asset.Futures, false)
if err != nil {
return err
}
@@ -356,7 +356,7 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
if len(response.Data.Delete) > 0 {
for x := range response.Data.Delete {
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data.Delete[x].Symbol, asset.Futures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data.Delete[x].Symbol, asset.Futures, false)
if err != nil {
return err
}
@@ -380,7 +380,7 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
if len(response.Data.Update) > 0 {
for x := range response.Data.Update {
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data.Update[x].Symbol, asset.Futures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data.Update[x].Symbol, asset.Futures, false)
if err != nil {
return err
}
@@ -404,7 +404,7 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
if len(response.Data.Insert) > 0 {
for x := range response.Data.Insert {
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data.Insert[x].Symbol, asset.Futures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data.Insert[x].Symbol, asset.Futures, false)
if err != nil {
return err
}
@@ -455,7 +455,7 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
for i := range response.Data {
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data[i].Symbol, asset.Futures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data[i].Symbol, asset.Futures, false)
if err != nil {
return err
}
@@ -509,7 +509,7 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
}
for x := range response.Data {
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data[x].Symbol, asset.Futures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data[x].Symbol, asset.Futures, false)
if err != nil {
return err
}
@@ -571,7 +571,7 @@ func (by *Bybit) wsFuturesHandleData(respRaw []byte) error {
}
for x := range response.Data {
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data[x].Symbol, asset.Futures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data[x].Symbol, asset.Futures, false)
if err != nil {
return err
}

View File

@@ -184,7 +184,7 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
}
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data.OBData[0].Symbol, asset.USDTMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data.OBData[0].Symbol, asset.USDTMarginedFutures, false)
if err != nil {
return err
}
@@ -206,7 +206,7 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
if len(response.OBData.Delete) > 0 {
var p currency.Pair
p, err = by.extractCurrencyPair(response.OBData.Delete[0].Symbol, asset.USDTMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.OBData.Delete[0].Symbol, asset.USDTMarginedFutures, false)
if err != nil {
return err
}
@@ -222,7 +222,7 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
if len(response.OBData.Update) > 0 {
var p currency.Pair
p, err = by.extractCurrencyPair(response.OBData.Update[0].Symbol, asset.USDTMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.OBData.Update[0].Symbol, asset.USDTMarginedFutures, false)
if err != nil {
return err
}
@@ -238,7 +238,7 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
if len(response.OBData.Insert) > 0 {
var p currency.Pair
p, err = by.extractCurrencyPair(response.OBData.Insert[0].Symbol, asset.USDTMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.OBData.Insert[0].Symbol, asset.USDTMarginedFutures, false)
if err != nil {
return err
}
@@ -268,7 +268,7 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
trades := make([]trade.Data, len(response.TradeData))
for i := range response.TradeData {
var p currency.Pair
p, err = by.extractCurrencyPair(response.TradeData[0].Symbol, asset.USDTMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.TradeData[0].Symbol, asset.USDTMarginedFutures, false)
if err != nil {
return err
}
@@ -303,7 +303,7 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
}
var p currency.Pair
p, err = by.extractCurrencyPair(topics[len(topics)-1], asset.USDTMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(topics[len(topics)-1], asset.USDTMarginedFutures, false)
if err != nil {
return err
}
@@ -333,7 +333,7 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
}
var p currency.Pair
p, err = by.extractCurrencyPair(response.Ticker.Symbol, asset.USDTMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.Ticker.Symbol, asset.USDTMarginedFutures, false)
if err != nil {
return err
}
@@ -362,7 +362,7 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
if len(response.Data.Delete) > 0 {
for x := range response.Data.Delete {
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data.Delete[x].Symbol, asset.USDTMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data.Delete[x].Symbol, asset.USDTMarginedFutures, false)
if err != nil {
return err
}
@@ -386,7 +386,7 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
if len(response.Data.Update) > 0 {
for x := range response.Data.Update {
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data.Update[x].Symbol, asset.USDTMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data.Update[x].Symbol, asset.USDTMarginedFutures, false)
if err != nil {
return err
}
@@ -410,7 +410,7 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
if len(response.Data.Insert) > 0 {
for x := range response.Data.Insert {
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data.Insert[x].Symbol, asset.USDTMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data.Insert[x].Symbol, asset.USDTMarginedFutures, false)
if err != nil {
return err
}
@@ -461,7 +461,7 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
for i := range response.Data {
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data[i].Symbol, asset.USDTMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data[i].Symbol, asset.USDTMarginedFutures, false)
if err != nil {
return err
}
@@ -515,7 +515,7 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
}
for x := range response.Data {
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data[x].Symbol, asset.USDTMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data[x].Symbol, asset.USDTMarginedFutures, false)
if err != nil {
return err
}
@@ -577,7 +577,7 @@ func (by *Bybit) wsUSDTHandleData(respRaw []byte) error {
}
for x := range response.Data {
var p currency.Pair
p, err = by.extractCurrencyPair(response.Data[x].Symbol, asset.USDTMarginedFutures)
p, err = by.MatchSymbolWithAvailablePairs(response.Data[x].Symbol, asset.USDTMarginedFutures, false)
if err != nil {
return err
}

View File

@@ -125,8 +125,8 @@ type OrderResponse struct {
// Commission holds trade commission structure
type Commission struct {
Currency currency.Pair `json:"currency"`
Amount float64 `json:"amount,string"`
Currency string `json:"currency"`
Amount float64 `json:"amount,string"`
}
// OrderFilledResponse contains order filled response
@@ -545,8 +545,8 @@ type WsOrderData struct {
// WsOrderFilledCommissionData ws response data
type WsOrderFilledCommissionData struct {
Amount float64 `json:"amount,string"`
Currency currency.Pair `json:"currency"`
Amount float64 `json:"amount,string"`
Currency string `json:"currency"`
}
// WsOrderRejectedResponse ws response
@@ -594,8 +594,8 @@ type WsTradeHistoryResponse struct {
// WsTradeHistoryCommissionData ws response data
type WsTradeHistoryCommissionData struct {
Amount float64 `json:"amount,string"`
Currency currency.Pair `json:"currency"`
Amount float64 `json:"amount,string"`
Currency string `json:"currency"`
}
// WsTradeHistoryTradeData ws response data

View File

@@ -9,6 +9,7 @@ import (
"strconv"
"strings"
"time"
"unicode"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/convert"
@@ -1731,3 +1732,38 @@ func (b *Base) SetLeverage(_ context.Context, _ asset.Item, _ currency.Pair, _ m
func (b *Base) GetLeverage(_ context.Context, _ asset.Item, _ currency.Pair, _ margin.Type, _ order.Side) (float64, error) {
return -1, common.ErrNotYetImplemented
}
// MatchSymbolWithAvailablePairs returns a currency pair based on the supplied
// symbol and asset type. If the string is expected to have a delimiter this
// will attempt to screen it out.
func (b *Base) MatchSymbolWithAvailablePairs(symbol string, a asset.Item, hasDelimiter bool) (currency.Pair, error) {
if hasDelimiter {
for x := range symbol {
if unicode.IsPunct(rune(symbol[x])) {
symbol = symbol[:x] + symbol[x+1:]
break
}
}
}
return b.CurrencyPairs.Match(symbol, a)
}
// MatchSymbolCheckEnabled returns a currency pair based on the supplied symbol
// and asset type against the available pairs list. If the string is expected to
// have a delimiter this will attempt to screen it out. It will also check if
// the pair is enabled.
func (b *Base) MatchSymbolCheckEnabled(symbol string, a asset.Item, hasDelimiter bool) (pair currency.Pair, enabled bool, err error) {
pair, err = b.MatchSymbolWithAvailablePairs(symbol, a, hasDelimiter)
if err != nil {
return pair, false, err
}
enabled, err = b.IsPairEnabled(pair, a)
return
}
// IsPairEnabled checks if a pair is enabled for an enabled asset type.
// TODO: Optimisation map for enabled pair matching, instead of linear traversal.
func (b *Base) IsPairEnabled(pair currency.Pair, a asset.Item) (bool, error) {
return b.CurrencyPairs.IsPairEnabled(pair, a)
}

View File

@@ -3089,3 +3089,139 @@ func TestGetStandardConfig(t *testing.T) {
t.Fatalf("received: '%v' but expected: '%v'", cfg.WebsocketTrafficTimeout, config.DefaultWebsocketTrafficTimeout)
}
}
func TestMatchSymbolWithAvailablePairs(t *testing.T) {
t.Parallel()
b := Base{Name: "test"}
whatIWant := currency.NewPair(currency.BTC, currency.USDT)
err := b.CurrencyPairs.Store(asset.Spot, &currency.PairStore{
AssetEnabled: convert.BoolPtr(true),
Available: []currency.Pair{whatIWant}})
if err != nil {
t.Fatal(err)
}
_, err = b.MatchSymbolWithAvailablePairs("sillBillies", asset.Futures, false)
if !errors.Is(err, currency.ErrPairNotFound) {
t.Fatalf("received: '%v' but expected: '%v'", err, currency.ErrPairNotFound)
}
whatIGot, err := b.MatchSymbolWithAvailablePairs("btcusdT", asset.Spot, false)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}
if !whatIGot.Equal(whatIWant) {
t.Fatalf("received: '%v' but expected: '%v'", whatIGot, whatIWant)
}
whatIGot, err = b.MatchSymbolWithAvailablePairs("btc-usdT", asset.Spot, true)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}
if !whatIGot.Equal(whatIWant) {
t.Fatalf("received: '%v' but expected: '%v'", whatIGot, whatIWant)
}
}
func TestMatchSymbolCheckEnabled(t *testing.T) {
t.Parallel()
b := Base{Name: "test"}
whatIWant := currency.NewPair(currency.BTC, currency.USDT)
availButNoEnabled := currency.NewPair(currency.BTC, currency.AUD)
err := b.CurrencyPairs.Store(asset.Spot, &currency.PairStore{
AssetEnabled: convert.BoolPtr(true),
Available: []currency.Pair{whatIWant, availButNoEnabled},
Enabled: []currency.Pair{whatIWant},
})
if err != nil {
t.Fatal(err)
}
_, _, err = b.MatchSymbolCheckEnabled("sillBillies", asset.Futures, false)
if !errors.Is(err, currency.ErrPairNotFound) {
t.Fatalf("received: '%v' but expected: '%v'", err, currency.ErrPairNotFound)
}
whatIGot, enabled, err := b.MatchSymbolCheckEnabled("btcusdT", asset.Spot, false)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}
if !enabled {
t.Fatal("expected true")
}
if !whatIGot.Equal(whatIWant) {
t.Fatalf("received: '%v' but expected: '%v'", whatIGot, whatIWant)
}
whatIGot, enabled, err = b.MatchSymbolCheckEnabled("btc-usdT", asset.Spot, true)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}
if !whatIGot.Equal(whatIWant) {
t.Fatalf("received: '%v' but expected: '%v'", whatIGot, whatIWant)
}
if !enabled {
t.Fatal("expected true")
}
whatIGot, enabled, err = b.MatchSymbolCheckEnabled("btc-AUD", asset.Spot, true)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}
if !whatIGot.Equal(availButNoEnabled) {
t.Fatalf("received: '%v' but expected: '%v'", whatIGot, whatIWant)
}
if enabled {
t.Fatal("expected false")
}
}
func TestIsPairEnabled(t *testing.T) {
t.Parallel()
b := Base{Name: "test"}
whatIWant := currency.NewPair(currency.BTC, currency.USDT)
availButNoEnabled := currency.NewPair(currency.BTC, currency.AUD)
err := b.CurrencyPairs.Store(asset.Spot, &currency.PairStore{
AssetEnabled: convert.BoolPtr(true),
Available: []currency.Pair{whatIWant, availButNoEnabled},
Enabled: []currency.Pair{whatIWant},
})
if err != nil {
t.Fatal(err)
}
enabled, err := b.IsPairEnabled(currency.NewPair(currency.AAA, currency.CYC), asset.Spot)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}
if enabled {
t.Fatal("expected false")
}
enabled, err = b.IsPairEnabled(availButNoEnabled, asset.Spot)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}
if enabled {
t.Fatal("expected false")
}
enabled, err = b.IsPairEnabled(whatIWant, asset.Spot)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}
if !enabled {
t.Fatal("expected true")
}
}

View File

@@ -48,22 +48,6 @@ func TestMain(m *testing.M) {
e.API.AuthenticatedSupport = true
e.SetCredentials(APIKey, APISecret, "", "", "", "")
err = e.UpdateTradablePairs(context.Background(), false)
if err != nil {
log.Fatal("Exmo UpdateTradablePairs error", err)
}
avail, err := e.GetAvailablePairs(asset.Spot)
if err != nil {
log.Fatal("Exmo GetAvailablePairs error", err)
}
err = e.CurrencyPairs.StorePairs(asset.Spot, avail, true)
if err != nil {
log.Fatal("Exmo StorePairs error", err)
}
os.Exit(m.Run())
}
@@ -513,18 +497,19 @@ func TestUpdateTicker(t *testing.T) {
func TestUpdateTickers(t *testing.T) {
t.Parallel()
err := e.UpdateTickers(context.Background(), asset.Spot)
if err != nil {
t.Error(err)
}
avail, err := e.GetAvailablePairs(asset.Spot)
enabled, err := e.GetEnabledPairs(asset.Spot)
if err != nil {
t.Fatal(err)
}
for x := range avail {
_, err := ticker.GetTicker(e.Name, avail[x], asset.Spot)
for x := range enabled {
_, err := ticker.GetTicker(e.Name, enabled[x], asset.Spot)
if err != nil {
t.Error(err)
}

View File

@@ -206,28 +206,21 @@ func (e *EXMO) UpdateTradablePairs(ctx context.Context, forceUpdate bool) error
// UpdateTickers updates the ticker for all currency pairs of a given asset type
func (e *EXMO) UpdateTickers(ctx context.Context, a asset.Item) error {
avail, err := e.GetAvailablePairs(a)
if err != nil {
return err
}
enabled, err := e.GetEnabledPairs(a)
if err != nil {
return err
}
result, err := e.GetTicker(ctx)
if err != nil {
return err
}
var enabled bool
for symbol, tick := range result {
var pair currency.Pair
pair, err = avail.DeriveFrom(strings.Replace(symbol, "_", "", 1))
pair, enabled, err = e.MatchSymbolCheckEnabled(symbol, asset.Spot, true)
if err != nil {
return err
if !errors.Is(err, currency.ErrPairNotFound) {
return err
}
}
if !enabled.Contains(pair, true) {
if !enabled {
continue
}
err = ticker.ProcessTicker(&ticker.Price{

View File

@@ -2112,11 +2112,6 @@ func (g *Gateio) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item) e
return fmt.Errorf("%s %w", a, asset.ErrNotSupported)
}
avail, err := g.GetAvailablePairs(a)
if err != nil {
return err
}
var limits []order.MinMaxLevel
switch a {
case asset.Spot:
@@ -2132,7 +2127,7 @@ func (g *Gateio) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item) e
continue
}
var pair currency.Pair
pair, err = avail.DeriveFrom(strings.ReplaceAll(pairsData[x].ID, "_", ""))
pair, err = g.MatchSymbolWithAvailablePairs(pairsData[x].ID, a, true)
if err != nil {
return err
}

View File

@@ -31,17 +31,17 @@ type Ticker struct {
// TickerV2 holds returned ticker data from the exchange
type TickerV2 struct {
Ask float64 `json:"ask,string"`
Bid float64 `json:"bid,string"`
Changes []string `json:"changes"`
Close float64 `json:"close,string"`
High float64 `json:"high,string"`
Low float64 `json:"low,string"`
Open float64 `json:"open,string"`
Message string `json:"message,omitempty"`
Reason string `json:"reason,omitempty"`
Result string `json:"result,omitempty"`
Symbol currency.Pair `json:"symbol"`
Ask float64 `json:"ask,string"`
Bid float64 `json:"bid,string"`
Changes []string `json:"changes"`
Close float64 `json:"close,string"`
High float64 `json:"high,string"`
Low float64 `json:"low,string"`
Open float64 `json:"open,string"`
Message string `json:"message,omitempty"`
Reason string `json:"reason,omitempty"`
Result string `json:"result,omitempty"`
Symbol string `json:"symbol"`
}
// Orderbook contains orderbook information for both bid and ask side

View File

@@ -186,23 +186,18 @@ func TestUpdateTicker(t *testing.T) {
}
func TestUpdateTickers(t *testing.T) {
avail, err := h.GetAvailablePairs(asset.Spot)
if err != nil {
t.Fatal(err)
}
err = h.CurrencyPairs.StorePairs(asset.Spot, avail, true)
if err != nil {
t.Fatal(err)
}
err = h.UpdateTickers(context.Background(), asset.Spot)
err := h.UpdateTickers(context.Background(), asset.Spot)
if err != nil {
t.Error(err)
}
for j := range avail {
_, err = h.FetchTicker(context.Background(), avail[j], asset.Spot)
enabled, err := h.GetEnabledPairs(asset.Spot)
if err != nil {
t.Fatal(err)
}
for j := range enabled {
_, err = h.FetchTicker(context.Background(), enabled[j], asset.Spot)
if err != nil {
t.Error(err)
}

View File

@@ -291,9 +291,9 @@ func (h *HitBTC) FetchTradablePairs(ctx context.Context, _ asset.Item) (currency
pairs := make([]currency.Pair, len(symbols))
for x := range symbols {
quote := strings.Replace(symbols[x].ID, symbols[x].BaseCurrency, "", 1)
index := strings.Index(symbols[x].ID, symbols[x].QuoteCurrency)
var pair currency.Pair
pair, err = currency.NewPairFromStrings(symbols[x].BaseCurrency, quote)
pair, err = currency.NewPairFromStrings(symbols[x].ID[:index], symbols[x].ID[index:])
if err != nil {
return nil, err
}
@@ -322,23 +322,18 @@ func (h *HitBTC) UpdateTickers(ctx context.Context, a asset.Item) error {
if err != nil {
return err
}
avail, err := h.GetAvailablePairs(a)
if err != nil {
return err
}
enabled, err := h.GetEnabledPairs(a)
if err != nil {
return err
}
for x := range tick {
pair, err := avail.DeriveFrom(tick[x].Symbol)
var pair currency.Pair
var enabled bool
pair, enabled, err = h.MatchSymbolCheckEnabled(tick[x].Symbol, a, false)
if err != nil {
return err
if !errors.Is(err, currency.ErrPairNotFound) {
return err
}
}
if !enabled.Contains(pair, true) {
if !enabled {
continue
}

View File

@@ -97,6 +97,18 @@ type IBotExchange interface {
CurrencyStateManagement
FuturesManagement
MarginManagement
// MatchSymbolWithAvailablePairs returns a currency pair based on the supplied
// symbol and asset type. If the string is expected to have a delimiter this
// will attempt to screen it out.
MatchSymbolWithAvailablePairs(symbol string, a asset.Item, hasDelimiter bool) (currency.Pair, error)
// MatchSymbolCheckEnabled returns a currency pair based on the supplied symbol
// and asset type against the available pairs list. If the string is expected to
// have a delimiter this will attempt to screen it out. It will also check if
// the pair is enabled.
MatchSymbolCheckEnabled(symbol string, a asset.Item, hasDelimiter bool) (pair currency.Pair, enabled bool, err error)
// IsPairEnabled checks if a pair is enabled for an enabled asset type
IsPairEnabled(pair currency.Pair, a asset.Item) (bool, error)
}
// OrderManagement defines functionality for order management

View File

@@ -4328,10 +4328,18 @@ func (ok *Okx) GetAssetsFromInstrumentTypeOrID(instType, instrumentID string) ([
switch {
case len(splitSymbol) == 2:
resp := make([]asset.Item, 0, 2)
if err := ok.CurrencyPairs.IsAssetPairEnabled(asset.Spot, pair); err == nil {
enabled, err := ok.IsPairEnabled(pair, asset.Spot)
if err != nil {
return nil, err
}
if enabled {
resp = append(resp, asset.Spot)
}
if err := ok.CurrencyPairs.IsAssetPairEnabled(asset.Margin, pair); err == nil {
enabled, err = ok.IsPairEnabled(pair, asset.Margin)
if err != nil {
return nil, err
}
if enabled {
resp = append(resp, asset.Margin)
}
if len(resp) > 0 {
@@ -4340,15 +4348,27 @@ func (ok *Okx) GetAssetsFromInstrumentTypeOrID(instType, instrumentID string) ([
case len(splitSymbol) > 2:
switch splitSymbol[len(splitSymbol)-1] {
case "SWAP", "swap":
if err := ok.CurrencyPairs.IsAssetPairEnabled(asset.PerpetualSwap, pair); err == nil {
enabled, err := ok.IsPairEnabled(pair, asset.PerpetualSwap)
if err != nil {
return nil, err
}
if enabled {
return []asset.Item{asset.PerpetualSwap}, nil
}
case "C", "P", "c", "p":
if err := ok.CurrencyPairs.IsAssetPairEnabled(asset.Options, pair); err == nil {
enabled, err := ok.IsPairEnabled(pair, asset.Options)
if err != nil {
return nil, err
}
if enabled {
return []asset.Item{asset.Options}, nil
}
default:
if err := ok.CurrencyPairs.IsAssetPairEnabled(asset.Futures, pair); err == nil {
enabled, err := ok.IsPairEnabled(pair, asset.Futures)
if err != nil {
return nil, err
}
if enabled {
return []asset.Item{asset.Futures}, nil
}
}