From 61d720b72f9ad1de60bc71e74a7bb71b8f33a9cf Mon Sep 17 00:00:00 2001 From: Scott Date: Mon, 10 Nov 2025 13:21:54 +1100 Subject: [PATCH] exchanges: Use singular futures settlement currency (#2092) * Change settlement to singular currency * whoops.go * bitmex fix * minor updates * 64 divided by 2 * whoops2.go * ROBOT ROCK Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * ROCK ROCK ROCK ROCK ROBOT Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * shazNit * currencies unmarshal and code use * Update currency/currencies.go Co-authored-by: Gareth Kirwan * Update exchanges/btse/btse_wrapper.go Co-authored-by: Gareth Kirwan * reuse comment for better clarity * collapses entire thing * shazLint --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Gareth Kirwan --- currency/currencies.go | 16 +- currency/currencies_test.go | 44 ++---- exchanges/bitmex/bitmex.go | 13 +- exchanges/bitmex/bitmex_parameters.go | 2 +- exchanges/bitmex/bitmex_types.go | 202 ++++++++++++------------- exchanges/bitmex/bitmex_wrapper.go | 94 ++++++------ exchanges/btse/btse_test.go | 20 +-- exchanges/btse/btse_types.go | 70 ++++----- exchanges/btse/btse_wrapper.go | 95 +++++------- exchanges/bybit/bybit_types.go | 6 +- exchanges/bybit/bybit_wrapper.go | 86 +++++------ exchanges/coinbase/coinbase_wrapper.go | 18 +-- exchanges/deribit/deribit_types.go | 50 +++--- exchanges/deribit/deribit_wrapper.go | 24 +-- exchanges/futures/contract.go | 15 +- exchanges/gateio/gateio_wrapper.go | 45 +++--- exchanges/huobi/huobi_wrapper.go | 42 ++--- exchanges/kucoin/kucoin_wrapper.go | 26 ++-- exchanges/okx/okx_wrapper.go | 2 +- 19 files changed, 399 insertions(+), 471 deletions(-) diff --git a/currency/currencies.go b/currency/currencies.go index 3a46053a..cba31ce7 100644 --- a/currency/currencies.go +++ b/currency/currencies.go @@ -55,20 +55,10 @@ func (c Currencies) Join() string { // UnmarshalJSON conforms type to the umarshaler interface func (c *Currencies) UnmarshalJSON(d []byte) error { - var configCurrencies string - err := json.Unmarshal(d, &configCurrencies) - if err != nil { - return err + if d[0] != '[' { + d = []byte(`[` + string(d) + `]`) } - - curr := strings.Split(configCurrencies, ",") - allTheCurrencies := make(Currencies, len(curr)) - for i := range curr { - allTheCurrencies[i] = NewCode(curr[i]) - } - - *c = allTheCurrencies - return nil + return json.Unmarshal(d, (*[]Code)(c)) } // MarshalJSON conforms type to the marshaler interface diff --git a/currency/currencies_test.go b/currency/currencies_test.go index 81c25717..88a1453d 100644 --- a/currency/currencies_test.go +++ b/currency/currencies_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/thrasher-corp/gocryptotrader/encoding/json" ) @@ -11,24 +12,19 @@ func TestCurrenciesUnmarshalJSON(t *testing.T) { var unmarshalHere Currencies expected := "btc,usd,ltc,bro,things" encoded, err := json.Marshal(expected) - if err != nil { - t.Fatal("Currencies UnmarshalJSON() error", err) - } + require.NoError(t, err) err = json.Unmarshal(encoded, &unmarshalHere) - if err != nil { - t.Fatal("Currencies UnmarshalJSON() error", err) - } + require.NoError(t, err) err = json.Unmarshal(encoded, &unmarshalHere) - if err != nil { - t.Fatal("Currencies UnmarshalJSON() error", err) - } + require.NoError(t, err) + require.Equal(t, expected, unmarshalHere.Join()) - if unmarshalHere.Join() != expected { - t.Errorf("Currencies UnmarshalJSON() error expected %s but received %s", - expected, unmarshalHere.Join()) - } + j := []byte(`["btc","usd","ltc","bro","things"]`) + err = json.Unmarshal(j, &unmarshalHere) + require.NoError(t, err) + require.Len(t, unmarshalHere, 5) } func TestCurrenciesMarshalJSON(t *testing.T) { @@ -39,30 +35,18 @@ func TestCurrenciesMarshalJSON(t *testing.T) { } encoded, err := json.Marshal(quickStruct) - if err != nil { - t.Fatal("Currencies MarshalJSON() error", err) - } + require.NoError(t, err) expected := `{"amazingCurrencies":"btc,usd,ltc,bro,things"}` - if string(encoded) != expected { - t.Errorf("Currencies MarshalJSON() error expected %s but received %s", - expected, string(encoded)) - } + require.Equal(t, expected, string(encoded)) } func TestMatch(t *testing.T) { matchString := []string{"btc", "usd", "ltc", "bro", "things"} c := NewCurrenciesFromStringArray(matchString) - - if !c.Match(NewCurrenciesFromStringArray(matchString)) { - t.Fatal("should match") - } - if c.Match(NewCurrenciesFromStringArray([]string{"btc", "usd", "ltc", "bro"})) { - t.Fatal("should not match") - } - if c.Match(NewCurrenciesFromStringArray([]string{"btc", "usd", "ltc", "bro", "garbo"})) { - t.Fatal("should not match") - } + require.True(t, c.Match(NewCurrenciesFromStringArray(matchString))) + require.False(t, c.Match(NewCurrenciesFromStringArray([]string{"btc", "usd", "ltc", "bro"}))) + require.False(t, c.Match(NewCurrenciesFromStringArray([]string{"btc", "usd", "ltc", "bro", "garbo"}))) } func TestCurrenciesAdd(t *testing.T) { diff --git a/exchanges/bitmex/bitmex.go b/exchanges/bitmex/bitmex.go index 104e4c84..6a2bc654 100644 --- a/exchanges/bitmex/bitmex.go +++ b/exchanges/bitmex/bitmex.go @@ -43,7 +43,6 @@ const ( bitmexEndpointActiveIntervals = "/instrument/activeIntervals" bitmexEndpointCompositeIndex = "/instrument/compositeIndex" bitmexEndpointIndices = "/instrument/indices" - bitmexEndpointInsuranceHistory = "/insurance" bitmexEndpointLiquidation = "/liquidation" bitmexEndpointLeader = "/leaderboard" bitmexEndpointAlias = "/leaderboard/name" @@ -70,7 +69,6 @@ const ( bitmexEndpointCancelAllOrders = "/order/all" bitmexEndpointBulk = "/order/bulk" bitmexEndpointCancelOrderAfter = "/order/cancelAllAfter" - bitmexEndpointClosePosition = "/order/closePosition" bitmexEndpointPosition = "/position" bitmexEndpointIsolatePosition = "/position/isolate" bitmexEndpointLeveragePosition = "/position/leverage" @@ -82,7 +80,6 @@ const ( bitmexEndpointUserCommision = "/user/commission" bitmexEndpointUserConfirmEmail = "/user/confirmEmail" bitmexEndpointUserConfirmTFA = "/user/confirmEnableTFA" - bitmexEndpointUserConfirmWithdrawal = "/user/confirmWithdrawal" bitmexEndpointUserDepositAddress = "/user/depositAddress" bitmexEndpointUserDisableTFA = "/user/disableTFA" bitmexEndpointUserLogout = "/user/logout" @@ -96,15 +93,7 @@ const ( bitmexEndpointUserRequestWithdraw = "/user/requestWithdrawal" constSatoshiBTC = 1e-08 - - // ContractPerpetual perpetual contract type - ContractPerpetual = iota - // ContractFutures futures contract type - ContractFutures - // ContractDownsideProfit downside profit contract type - ContractDownsideProfit - // ContractUpsideProfit upside profit contract type - ContractUpsideProfit + countLimit = uint32(1000) perpetualContractID = "FFWCSX" spotID = "IFXXXP" diff --git a/exchanges/bitmex/bitmex_parameters.go b/exchanges/bitmex/bitmex_parameters.go index 1b0766e3..537847af 100644 --- a/exchanges/bitmex/bitmex_parameters.go +++ b/exchanges/bitmex/bitmex_parameters.go @@ -186,7 +186,7 @@ type GenericRequestParams struct { Columns string `json:"columns,omitempty"` // Count - Number of results to fetch. - Count int32 `json:"count,omitempty"` + Count uint32 `json:"count,omitempty"` // EndTime - Ending date filter for results. EndTime string `json:"endTime,omitempty"` diff --git a/exchanges/bitmex/bitmex_types.go b/exchanges/bitmex/bitmex_types.go index bf891106..969e1825 100644 --- a/exchanges/bitmex/bitmex_types.go +++ b/exchanges/bitmex/bitmex_types.go @@ -122,107 +122,107 @@ type Funding struct { // Instrument Tradeable Contracts, Indices, and History type Instrument struct { - AskPrice float64 `json:"askPrice"` - BankruptLimitDownPrice float64 `json:"bankruptLimitDownPrice"` - BankruptLimitUpPrice float64 `json:"bankruptLimitUpPrice"` - BidPrice float64 `json:"bidPrice"` - BuyLeg string `json:"buyLeg"` - CalcInterval string `json:"calcInterval"` - Capped bool `json:"capped"` - ClosingTimestamp time.Time `json:"closingTimestamp"` - Deleverage bool `json:"deleverage"` - Expiry string `json:"expiry"` - FairBasis float64 `json:"fairBasis"` - FairBasisRate float64 `json:"fairBasisRate"` - FairMethod string `json:"fairMethod"` - FairPrice float64 `json:"fairPrice"` - Front string `json:"front"` - FundingBaseSymbol string `json:"fundingBaseSymbol"` - FundingInterval time.Time `json:"fundingInterval"` - FundingPremiumSymbol string `json:"fundingPremiumSymbol"` - FundingQuoteSymbol string `json:"fundingQuoteSymbol"` - FundingRate float64 `json:"fundingRate"` - FundingTimestamp time.Time `json:"fundingTimestamp"` - HasLiquidity bool `json:"hasLiquidity"` - HighPrice float64 `json:"highPrice"` - ImpactAskPrice float64 `json:"impactAskPrice"` - ImpactBidPrice float64 `json:"impactBidPrice"` - ImpactMidPrice float64 `json:"impactMidPrice"` - IndicativeFundingRate float64 `json:"indicativeFundingRate"` - IndicativeSettlePrice float64 `json:"indicativeSettlePrice"` - IndicativeTaxRate float64 `json:"indicativeTaxRate"` - InitMargin float64 `json:"initMargin"` - InsuranceFee float64 `json:"insuranceFee"` - InverseLeg string `json:"inverseLeg"` - IsInverse bool `json:"isInverse"` - IsQuanto bool `json:"isQuanto"` - LastChangePcnt float64 `json:"lastChangePcnt"` - LastPrice float64 `json:"lastPrice"` - LastPriceProtected float64 `json:"lastPriceProtected"` - LastTickDirection string `json:"lastTickDirection"` - Limit float64 `json:"limit"` - LimitDownPrice float64 `json:"limitDownPrice"` - LimitUpPrice float64 `json:"limitUpPrice"` - Listing string `json:"listing"` - LotSize float64 `json:"lotSize"` - LowPrice float64 `json:"lowPrice"` - MaintMargin float64 `json:"maintMargin"` - MakerFee float64 `json:"makerFee"` - MarkMethod string `json:"markMethod"` - MarkPrice float64 `json:"markPrice"` - MaxOrderQty float64 `json:"maxOrderQty"` - MaxPrice float64 `json:"maxPrice"` - MidPrice float64 `json:"midPrice"` - Multiplier float64 `json:"multiplier"` - OpenInterest float64 `json:"openInterest"` - OpenValue float64 `json:"openValue"` - OpeningTimestamp time.Time `json:"openingTimestamp"` - OptionMultiplier float64 `json:"optionMultiplier"` - OptionStrikePcnt float64 `json:"optionStrikePcnt"` - OptionStrikePrice float64 `json:"optionStrikePrice"` - OptionStrikeRound float64 `json:"optionStrikeRound"` - OptionUnderlyingPrice float64 `json:"optionUnderlyingPrice"` - PositionCurrency string `json:"positionCurrency"` - PrevClosePrice float64 `json:"prevClosePrice"` - PrevPrice24h float64 `json:"prevPrice24h"` - PrevTotalTurnover float64 `json:"prevTotalTurnover"` - PrevTotalVolume float64 `json:"prevTotalVolume"` - PublishInterval string `json:"publishInterval"` - PublishTime time.Time `json:"publishTime"` - QuoteCurrency string `json:"quoteCurrency"` - QuoteToSettleMultiplier int64 `json:"quoteToSettleMultiplier"` - RebalanceInterval string `json:"rebalanceInterval"` - RebalanceTimestamp time.Time `json:"rebalanceTimestamp"` - Reference string `json:"reference"` - ReferenceSymbol string `json:"referenceSymbol"` - RelistInterval string `json:"relistInterval"` - RiskLimit float64 `json:"riskLimit"` - RiskStep float64 `json:"riskStep"` - RootSymbol string `json:"rootSymbol"` - SellLeg string `json:"sellLeg"` - SessionInterval string `json:"sessionInterval"` - SettlCurrency string `json:"settlCurrency"` - Settle string `json:"settle"` - SettledPrice float64 `json:"settledPrice"` - SettlementFee float64 `json:"settlementFee"` - State string `json:"state"` - Symbol string `json:"symbol"` - TakerFee float64 `json:"takerFee"` - Taxed bool `json:"taxed"` - TickSize float64 `json:"tickSize"` - Timestamp time.Time `json:"timestamp"` - TotalTurnover float64 `json:"totalTurnover"` - TotalVolume float64 `json:"totalVolume"` - Turnover float64 `json:"turnover"` - Turnover24h float64 `json:"turnover24h"` - Typ string `json:"typ"` - Underlying string `json:"underlying"` - UnderlyingSymbol string `json:"underlyingSymbol"` - UnderlyingToPositionMultiplier float64 `json:"underlyingToPositionMultiplier"` - UnderlyingToSettleMultiplier float64 `json:"underlyingToSettleMultiplier"` - Volume float64 `json:"volume"` - Volume24h float64 `json:"volume24h"` - Vwap float64 `json:"vwap"` + AskPrice float64 `json:"askPrice"` + BankruptLimitDownPrice float64 `json:"bankruptLimitDownPrice"` + BankruptLimitUpPrice float64 `json:"bankruptLimitUpPrice"` + BidPrice float64 `json:"bidPrice"` + BuyLeg string `json:"buyLeg"` + CalcInterval string `json:"calcInterval"` + Capped bool `json:"capped"` + ClosingTimestamp time.Time `json:"closingTimestamp"` + Deleverage bool `json:"deleverage"` + Expiry string `json:"expiry"` + FairBasis float64 `json:"fairBasis"` + FairBasisRate float64 `json:"fairBasisRate"` + FairMethod string `json:"fairMethod"` + FairPrice float64 `json:"fairPrice"` + Front string `json:"front"` + FundingBaseSymbol string `json:"fundingBaseSymbol"` + FundingInterval time.Time `json:"fundingInterval"` + FundingPremiumSymbol string `json:"fundingPremiumSymbol"` + FundingQuoteSymbol string `json:"fundingQuoteSymbol"` + FundingRate float64 `json:"fundingRate"` + FundingTimestamp time.Time `json:"fundingTimestamp"` + HasLiquidity bool `json:"hasLiquidity"` + HighPrice float64 `json:"highPrice"` + ImpactAskPrice float64 `json:"impactAskPrice"` + ImpactBidPrice float64 `json:"impactBidPrice"` + ImpactMidPrice float64 `json:"impactMidPrice"` + IndicativeFundingRate float64 `json:"indicativeFundingRate"` + IndicativeSettlePrice float64 `json:"indicativeSettlePrice"` + IndicativeTaxRate float64 `json:"indicativeTaxRate"` + InitMargin float64 `json:"initMargin"` + InsuranceFee float64 `json:"insuranceFee"` + InverseLeg string `json:"inverseLeg"` + IsInverse bool `json:"isInverse"` + IsQuanto bool `json:"isQuanto"` + LastChangePcnt float64 `json:"lastChangePcnt"` + LastPrice float64 `json:"lastPrice"` + LastPriceProtected float64 `json:"lastPriceProtected"` + LastTickDirection string `json:"lastTickDirection"` + Limit float64 `json:"limit"` + LimitDownPrice float64 `json:"limitDownPrice"` + LimitUpPrice float64 `json:"limitUpPrice"` + Listing string `json:"listing"` + LotSize float64 `json:"lotSize"` + LowPrice float64 `json:"lowPrice"` + MaintMargin float64 `json:"maintMargin"` + MakerFee float64 `json:"makerFee"` + MarkMethod string `json:"markMethod"` + MarkPrice float64 `json:"markPrice"` + MaxOrderQty float64 `json:"maxOrderQty"` + MaxPrice float64 `json:"maxPrice"` + MidPrice float64 `json:"midPrice"` + Multiplier float64 `json:"multiplier"` + OpenInterest float64 `json:"openInterest"` + OpenValue float64 `json:"openValue"` + OpeningTimestamp time.Time `json:"openingTimestamp"` + OptionMultiplier float64 `json:"optionMultiplier"` + OptionStrikePcnt float64 `json:"optionStrikePcnt"` + OptionStrikePrice float64 `json:"optionStrikePrice"` + OptionStrikeRound float64 `json:"optionStrikeRound"` + OptionUnderlyingPrice float64 `json:"optionUnderlyingPrice"` + PositionCurrency string `json:"positionCurrency"` + PrevClosePrice float64 `json:"prevClosePrice"` + PrevPrice24h float64 `json:"prevPrice24h"` + PrevTotalTurnover float64 `json:"prevTotalTurnover"` + PrevTotalVolume float64 `json:"prevTotalVolume"` + PublishInterval string `json:"publishInterval"` + PublishTime time.Time `json:"publishTime"` + QuoteCurrency string `json:"quoteCurrency"` + QuoteToSettleMultiplier int64 `json:"quoteToSettleMultiplier"` + RebalanceInterval string `json:"rebalanceInterval"` + RebalanceTimestamp time.Time `json:"rebalanceTimestamp"` + Reference string `json:"reference"` + ReferenceSymbol string `json:"referenceSymbol"` + RelistInterval string `json:"relistInterval"` + RiskLimit float64 `json:"riskLimit"` + RiskStep float64 `json:"riskStep"` + RootSymbol string `json:"rootSymbol"` + SellLeg string `json:"sellLeg"` + SessionInterval string `json:"sessionInterval"` + SettlementCurrency currency.Code `json:"settlCurrency"` + Settle string `json:"settle"` + SettledPrice float64 `json:"settledPrice"` + SettlementFee float64 `json:"settlementFee"` + State string `json:"state"` + Symbol string `json:"symbol"` + TakerFee float64 `json:"takerFee"` + Taxed bool `json:"taxed"` + TickSize float64 `json:"tickSize"` + Timestamp time.Time `json:"timestamp"` + TotalTurnover float64 `json:"totalTurnover"` + TotalVolume float64 `json:"totalVolume"` + Turnover float64 `json:"turnover"` + Turnover24h float64 `json:"turnover24h"` + Typ string `json:"typ"` + Underlying string `json:"underlying"` + UnderlyingSymbol string `json:"underlyingSymbol"` + UnderlyingToPositionMultiplier float64 `json:"underlyingToPositionMultiplier"` + UnderlyingToSettleMultiplier float64 `json:"underlyingToSettleMultiplier"` + Volume float64 `json:"volume"` + Volume24h float64 `json:"volume24h"` + Vwap float64 `json:"vwap"` } // InstrumentInterval instrument interval diff --git a/exchanges/bitmex/bitmex_wrapper.go b/exchanges/bitmex/bitmex_wrapper.go index 5376b86a..8c8af2e6 100644 --- a/exchanges/bitmex/bitmex_wrapper.go +++ b/exchanges/bitmex/bitmex_wrapper.go @@ -533,10 +533,9 @@ func (e *Exchange) GetHistoricTrades(ctx context.Context, p currency.Pair, asset if err != nil { return nil, err } - limit := 1000 req := &GenericRequestParams{ Symbol: p.String(), - Count: int32(limit), + Count: countLimit, EndTime: timestampEnd.UTC().Format("2006-01-02T15:04:05.000Z"), } ts := timestampStart @@ -581,7 +580,7 @@ allTrades: ts = tradeData[i].Timestamp } } - if len(tradeData) != limit { + if len(tradeData) != int(countLimit) { break allTrades } } @@ -984,25 +983,18 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, item asset.Ite if !e.SupportsAsset(item) || item == asset.Index { return nil, fmt.Errorf("%w %v", asset.ErrNotSupported, item) } - - marketInfo, err := e.GetInstruments(ctx, &GenericRequestParams{Reverse: true, Count: 500}) - if err != nil { - return nil, err - } - - resp := make([]futures.Contract, 0, len(marketInfo)) + var resp []futures.Contract switch item { case asset.PerpetualContract: + marketInfo, err := e.GetInstruments(ctx, &GenericRequestParams{ + Count: countLimit, + Filter: `{"typ": "` + perpetualContractID + `"}`, + }) + if err != nil { + return nil, err + } for x := range marketInfo { - if marketInfo[x].Typ != perpetualContractID { - continue - } - var cp, underlying currency.Pair - cp, err = currency.NewPairFromStrings(marketInfo[x].RootSymbol, marketInfo[x].QuoteCurrency) - if err != nil { - return nil, err - } - underlying, err = currency.NewPairFromStrings(marketInfo[x].RootSymbol, marketInfo[x].SettlCurrency) + cp, err := currency.NewPairFromStrings(marketInfo[x].RootSymbol, marketInfo[x].QuoteCurrency) if err != nil { return nil, err } @@ -1023,17 +1015,17 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, item asset.Ite contractSettlementType = futures.Inverse } resp = append(resp, futures.Contract{ - Exchange: e.Name, - Name: cp, - Underlying: underlying, - Asset: item, - StartDate: s, - IsActive: marketInfo[x].State == "Open", - Status: marketInfo[x].State, - Type: futures.Perpetual, - SettlementType: contractSettlementType, - SettlementCurrencies: currency.Currencies{currency.NewCode(marketInfo[x].SettlCurrency)}, - Multiplier: marketInfo[x].Multiplier, + Exchange: e.Name, + Name: cp, + Underlying: currency.NewPair(cp.Base, marketInfo[x].SettlementCurrency), + Asset: item, + StartDate: s, + IsActive: marketInfo[x].State == "Open", + Status: marketInfo[x].State, + Type: futures.Perpetual, + SettlementType: contractSettlementType, + SettlementCurrency: marketInfo[x].SettlementCurrency, + Multiplier: marketInfo[x].Multiplier, LatestRate: fundingrate.Rate{ Time: marketInfo[x].FundingTimestamp, Rate: decimal.NewFromFloat(marketInfo[x].FundingRate), @@ -1041,16 +1033,16 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, item asset.Ite }) } case asset.Futures: + marketInfo, err := e.GetInstruments(ctx, &GenericRequestParams{ + Count: countLimit, + Filter: `{"typ": "` + futuresID + `"}`, + }) + if err != nil { + return nil, err + } + for x := range marketInfo { - if marketInfo[x].Typ != futuresID { - continue - } - var cp, underlying currency.Pair - cp, err = currency.NewPairFromStrings(marketInfo[x].RootSymbol, marketInfo[x].Symbol[len(marketInfo[x].RootSymbol):]) - if err != nil { - return nil, err - } - underlying, err = currency.NewPairFromStrings(marketInfo[x].RootSymbol, marketInfo[x].SettlCurrency) + cp, err := currency.NewPairFromStrings(marketInfo[x].RootSymbol, marketInfo[x].Symbol[len(marketInfo[x].RootSymbol):]) if err != nil { return nil, err } @@ -1093,18 +1085,18 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, item asset.Ite contractSettlementType = futures.Quanto } resp = append(resp, futures.Contract{ - Exchange: e.Name, - Name: cp, - Underlying: underlying, - Asset: item, - StartDate: startTime, - EndDate: endTime, - IsActive: marketInfo[x].State == "Open", - Status: marketInfo[x].State, - Type: ct, - SettlementCurrencies: currency.Currencies{currency.NewCode(marketInfo[x].SettlCurrency)}, - Multiplier: marketInfo[x].Multiplier, - SettlementType: contractSettlementType, + Exchange: e.Name, + Name: cp, + Underlying: currency.NewPair(cp.Base, marketInfo[x].SettlementCurrency), + Asset: item, + StartDate: startTime, + EndDate: endTime, + IsActive: marketInfo[x].State == "Open", + Status: marketInfo[x].State, + Type: ct, + SettlementCurrency: marketInfo[x].SettlementCurrency, + Multiplier: marketInfo[x].Multiplier, + SettlementType: contractSettlementType, }) } } diff --git a/exchanges/btse/btse_test.go b/exchanges/btse/btse_test.go index 58a496f6..31057c68 100644 --- a/exchanges/btse/btse_test.go +++ b/exchanges/btse/btse_test.go @@ -15,7 +15,6 @@ import ( exchange "github.com/thrasher-corp/gocryptotrader/exchanges" "github.com/thrasher-corp/gocryptotrader/exchanges/asset" "github.com/thrasher-corp/gocryptotrader/exchanges/fundingrate" - "github.com/thrasher-corp/gocryptotrader/exchanges/futures" "github.com/thrasher-corp/gocryptotrader/exchanges/kline" "github.com/thrasher-corp/gocryptotrader/exchanges/order" "github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues" @@ -642,10 +641,7 @@ func TestWsUnexpectedData(t *testing.T) { func TestGetFuturesContractDetails(t *testing.T) { t.Parallel() - _, err := e.GetFuturesContractDetails(t.Context(), asset.Spot) - assert.ErrorIs(t, err, futures.ErrNotFuturesAsset, "GetFuturesContractDetails should error correctly on Spot") - - _, err = e.GetFuturesContractDetails(t.Context(), asset.USDTMarginedFutures) + _, err := e.GetFuturesContractDetails(t.Context(), asset.Margin) assert.ErrorIs(t, err, asset.ErrNotSupported, "GetFuturesContractDetails should error correctly on Margin") _, err = e.GetFuturesContractDetails(t.Context(), asset.Futures) @@ -771,18 +767,18 @@ func TestMarketPair(t *testing.T) { for _, tt := range []struct { symbol string - base string + base currency.Code futures bool expectedErr error expectedSymbol string }{ - {symbol: "RUNEPFC", base: currency.RUNE.String(), futures: true, expectedSymbol: "RUNEPFC"}, - {symbol: "TRUMPPFC", base: "TRUMPSOL", futures: true, expectedSymbol: "TRUMPPFC"}, - {symbol: "BTCUSD", base: "NAUGHTYBASE", futures: true, expectedErr: errInvalidPairSymbol}, - {symbol: "NAUGHTYSYMBOL", base: currency.BTC.String(), expectedErr: errInvalidPairSymbol}, - {symbol: "BTC-USD", base: currency.BTC.String(), expectedSymbol: "BTCUSD"}, + {symbol: "RUNEPFC", base: currency.RUNE, futures: true, expectedSymbol: "RUNEPFC"}, + {symbol: "TRUMPPFC", base: currency.NewCode("TRUMPSOL"), futures: true, expectedSymbol: "TRUMPPFC"}, + {symbol: "BTCUSD", base: currency.NewCode("NAUGHTYBASE"), futures: true, expectedErr: errInvalidPairSymbol}, + {symbol: "NAUGHTYSYMBOL", base: currency.BTC, expectedErr: errInvalidPairSymbol}, + {symbol: "BTC-USD", base: currency.BTC, expectedSymbol: "BTCUSD"}, } { - mp := MarketPair{Symbol: tt.symbol, Base: tt.base, Quote: "USD", Futures: tt.futures} + mp := MarketPair{Symbol: tt.symbol, Base: tt.base, Quote: currency.USD, Futures: tt.futures} p, err := mp.Pair() assert.ErrorIs(t, err, tt.expectedErr, "Pair should not error") assert.Equal(t, tt.expectedSymbol, p.String(), "Pair should return the expected symbol") diff --git a/exchanges/btse/btse_types.go b/exchanges/btse/btse_types.go index 52bd572f..74d32364 100644 --- a/exchanges/btse/btse_types.go +++ b/exchanges/btse/btse_types.go @@ -28,41 +28,41 @@ type MarketSummary []*MarketPair // MarketPair is a single pair in Market Summary type MarketPair struct { - Symbol string `json:"symbol"` - Last float64 `json:"last"` - LowestAsk float64 `json:"lowestAsk"` - HighestBid float64 `json:"highestBid"` - PercentageChange float64 `json:"percentageChange"` - Volume float64 `json:"volume"` - High24Hr float64 `json:"high24Hr"` - Low24Hr float64 `json:"low24Hr"` - Base string `json:"base"` - Quote string `json:"quote"` - Active bool `json:"active"` - Size float64 `json:"size"` - MinValidPrice float64 `json:"minValidPrice"` - MinPriceIncrement float64 `json:"minPriceIncrement"` - MinOrderSize float64 `json:"minOrderSize"` - MaxOrderSize float64 `json:"maxOrderSize"` - MinSizeIncrement float64 `json:"minSizeIncrement"` - OpenInterest float64 `json:"openInterest"` - OpenInterestUSD float64 `json:"openInterestUSD"` - ContractStart int64 `json:"contractStart"` - ContractEnd int64 `json:"contractEnd"` - TimeBasedContract bool `json:"timeBasedContract"` - OpenTime types.Time `json:"openTime"` - CloseTime types.Time `json:"closeTime"` - StartMatching int64 `json:"startMatching"` - InactiveTime types.Time `json:"inactiveTime"` - FundingRate float64 `json:"fundingRate"` - ContractSize float64 `json:"contractSize"` - MaxPosition int64 `json:"maxPosition"` - MinRiskLimit int `json:"minRiskLimit"` - MaxRiskLimit int `json:"maxRiskLimit"` - AvailableSettlement []string `json:"availableSettlement"` - Futures bool `json:"futures"` - IsMarketOpenToSpot bool `json:"isMarketOpenToSpot"` - IsMarketOpenToOTC bool `json:"isMarketOpenToOtc"` + Symbol string `json:"symbol"` + Last float64 `json:"last"` + LowestAsk float64 `json:"lowestAsk"` + HighestBid float64 `json:"highestBid"` + PercentageChange float64 `json:"percentageChange"` + Volume float64 `json:"volume"` + High24Hr float64 `json:"high24Hr"` + Low24Hr float64 `json:"low24Hr"` + Base currency.Code `json:"base"` + Quote currency.Code `json:"quote"` + Active bool `json:"active"` + Size float64 `json:"size"` + MinValidPrice float64 `json:"minValidPrice"` + MinPriceIncrement float64 `json:"minPriceIncrement"` + MinOrderSize float64 `json:"minOrderSize"` + MaxOrderSize float64 `json:"maxOrderSize"` + MinSizeIncrement float64 `json:"minSizeIncrement"` + OpenInterest float64 `json:"openInterest"` + OpenInterestUSD float64 `json:"openInterestUSD"` + ContractStart int64 `json:"contractStart"` + ContractEnd int64 `json:"contractEnd"` + TimeBasedContract bool `json:"timeBasedContract"` + OpenTime types.Time `json:"openTime"` + CloseTime types.Time `json:"closeTime"` + StartMatching int64 `json:"startMatching"` + InactiveTime types.Time `json:"inactiveTime"` + FundingRate float64 `json:"fundingRate"` + ContractSize float64 `json:"contractSize"` + MaxPosition int64 `json:"maxPosition"` + MinRiskLimit int `json:"minRiskLimit"` + MaxRiskLimit int `json:"maxRiskLimit"` + AvailableSettlement currency.Currencies `json:"availableSettlement"` + Futures bool `json:"futures"` + IsMarketOpenToSpot bool `json:"isMarketOpenToSpot"` + IsMarketOpenToOTC bool `json:"isMarketOpenToOtc"` } // OHLCV holds Open, High Low, Close, Volume data for set symbol diff --git a/exchanges/btse/btse_wrapper.go b/exchanges/btse/btse_wrapper.go index 96a6ca35..6ed31504 100644 --- a/exchanges/btse/btse_wrapper.go +++ b/exchanges/btse/btse_wrapper.go @@ -996,27 +996,28 @@ func (m *MarketPair) StripExponent() (string, error) { // Pair returns the currency Pair for a MarketPair func (m *MarketPair) Pair() (currency.Pair, error) { baseCurr := m.Base - var quoteCurr string + var quoteStr string if m.Futures { - if baseCurr == "TRUMPSOL" { // Only base currency which is different to the rest - baseCurr = "TRUMP" - quoteCurr = strings.TrimPrefix(m.Symbol, baseCurr) + if baseCurr.String() == "TRUMPSOL" { // Only base currency which is different to the rest + baseCurr = currency.TRUMP + quoteStr = strings.TrimPrefix(m.Symbol, baseCurr.String()) } else { - s := strings.Split(m.Symbol, m.Base) // e.g. RUNEPFC for RUNE-USD futures pair + // Quote field is the settlement currency, create the quote currency from the symbol + s := strings.Split(m.Symbol, m.Base.String()) if len(s) <= 1 { return currency.EMPTYPAIR, errInvalidPairSymbol } - quoteCurr = s[1] + quoteStr = s[1] } } else { s := strings.Split(m.Symbol, currency.DashDelimiter) if len(s) != 2 { return currency.EMPTYPAIR, errInvalidPairSymbol } - baseCurr = s[0] - quoteCurr = s[1] + baseCurr = currency.NewCode(s[0]) + quoteStr = s[1] } - return currency.NewPairFromStrings(baseCurr, quoteCurr) + return currency.NewPair(baseCurr, currency.NewCode(quoteStr)), nil } // GetMarketSummary returns filtered market pair details; Specifically: @@ -1055,9 +1056,6 @@ func (e *Exchange) GetMarketSummary(ctx context.Context, symbol string, spot boo // GetFuturesContractDetails returns details about futures contracts func (e *Exchange) GetFuturesContractDetails(ctx context.Context, item asset.Item) ([]futures.Contract, error) { - if !item.IsFutures() { - return nil, futures.ErrNotFuturesAsset - } if item != asset.Futures { return nil, fmt.Errorf("%w %v", asset.ErrNotSupported, item) } @@ -1065,67 +1063,46 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, item asset.Ite if err != nil { return nil, err } - resp := make([]futures.Contract, 0, len(marketSummary)) + resp := make([]futures.Contract, len(marketSummary)) for i := range marketSummary { - var cp currency.Pair - cp, err = currency.NewPairFromStrings(marketSummary[i].Base, marketSummary[i].Symbol[len(marketSummary[i].Base):]) - if err != nil { - return nil, err - } - settlementCurrencies := make(currency.Currencies, len(marketSummary[i].AvailableSettlement)) - var startTime, endTime time.Time - var ct futures.ContractType - if !marketSummary[i].OpenTime.Time().IsZero() { - startTime = marketSummary[i].OpenTime.Time() - } - if !marketSummary[i].CloseTime.Time().IsZero() { - endTime = marketSummary[i].CloseTime.Time() - } + // Quote field is the settlement currency, create the quote currency from the symbol + quote := currency.NewCode(marketSummary[i].Symbol[len(marketSummary[i].Base.String()):]) + cp := currency.NewPair(marketSummary[i].Base, quote) + startTime := marketSummary[i].OpenTime.Time() + endTime := marketSummary[i].CloseTime.Time() + ct := futures.Perpetual if marketSummary[i].TimeBasedContract { if endTime.Sub(startTime) > kline.OneMonth.Duration() { ct = futures.Quarterly } else { ct = futures.Monthly } - } else { - ct = futures.Perpetual } - var contractSettlementType futures.ContractSettlementType - for j := range marketSummary[i].AvailableSettlement { - settlementCurrencies[j] = currency.NewCode(marketSummary[i].AvailableSettlement[j]) - if contractSettlementType == futures.LinearOrInverse { - continue - } - containsUSD := strings.Contains(marketSummary[i].AvailableSettlement[j], "USD") - if !containsUSD { - contractSettlementType = futures.LinearOrInverse - continue - } - if containsUSD { - contractSettlementType = futures.Linear - } - } - - c := futures.Contract{ - Exchange: e.Name, - Name: cp, - Underlying: currency.NewPair(currency.NewCode(marketSummary[i].Base), currency.NewCode(marketSummary[i].Quote)), - Asset: item, - SettlementCurrencies: settlementCurrencies, - StartDate: startTime, - EndDate: endTime, - SettlementType: contractSettlementType, - IsActive: marketSummary[i].Active, - Type: ct, + contractSettlementType := futures.LinearOrInverse + if marketSummary[i].AvailableSettlement.Contains(currency.USD) { + contractSettlementType = futures.Linear } + var rate fundingrate.Rate if marketSummary[i].FundingRate > 0 { - c.LatestRate = fundingrate.Rate{ + rate = fundingrate.Rate{ Rate: decimal.NewFromFloat(marketSummary[i].FundingRate), Time: time.Now().Truncate(time.Hour), } } - - resp = append(resp, c) + resp[i] = futures.Contract{ + Exchange: e.Name, + Name: cp, + Underlying: currency.NewPair(marketSummary[i].Base, marketSummary[i].Quote), + Asset: item, + SettlementCurrency: currency.USDT, + AdditionalSettlementCurrencies: marketSummary[i].AvailableSettlement, + StartDate: startTime, + EndDate: endTime, + SettlementType: contractSettlementType, + IsActive: marketSummary[i].Active, + Type: ct, + LatestRate: rate, + } } return resp, nil } diff --git a/exchanges/bybit/bybit_types.go b/exchanges/bybit/bybit_types.go index 7f85aa08..526b1ecb 100644 --- a/exchanges/bybit/bybit_types.go +++ b/exchanges/bybit/bybit_types.go @@ -97,9 +97,9 @@ type InstrumentInfo struct { MinNotionalValue types.Number `json:"minNotionalValue"` MaxMarketOrderQuantity types.Number `json:"maxMktOrderQty"` } `json:"lotSizeFilter"` - UnifiedMarginTrade bool `json:"unifiedMarginTrade"` - FundingInterval int64 `json:"fundingInterval"` - SettleCoin string `json:"settleCoin"` + UnifiedMarginTrade bool `json:"unifiedMarginTrade"` + FundingInterval int64 `json:"fundingInterval"` + SettleCoin currency.Code `json:"settleCoin"` } // RestResponse represents a REST response instance. diff --git a/exchanges/bybit/bybit_wrapper.go b/exchanges/bybit/bybit_wrapper.go index 5c6ffc4e..a0cb3340 100644 --- a/exchanges/bybit/bybit_wrapper.go +++ b/exchanges/bybit/bybit_wrapper.go @@ -1771,7 +1771,7 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, item asset.Ite case asset.CoinMarginedFutures: resp := make([]futures.Contract, 0, len(inverseContracts.List)) for i := range inverseContracts.List { - if inverseContracts.List[i].SettleCoin == "USDT" || inverseContracts.List[i].SettleCoin == "USDC" { + if inverseContracts.List[i].SettleCoin.Equal(currency.USDT) || inverseContracts.List[i].SettleCoin.Equal(currency.USDC) { continue } var cp, underlying currency.Pair @@ -1810,18 +1810,18 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, item asset.Ite } resp = append(resp, futures.Contract{ - Exchange: e.Name, - Name: cp.Format(format), - Underlying: underlying, - Asset: item, - StartDate: start, - EndDate: end, - SettlementType: futures.Inverse, - IsActive: strings.EqualFold(inverseContracts.List[i].Status, "trading"), - Status: inverseContracts.List[i].Status, - Type: ct, - SettlementCurrencies: currency.Currencies{currency.NewCode(inverseContracts.List[i].SettleCoin)}, - MaxLeverage: inverseContracts.List[i].LeverageFilter.MaxLeverage.Float64(), + Exchange: e.Name, + Name: cp.Format(format), + Underlying: underlying, + Asset: item, + StartDate: start, + EndDate: end, + SettlementType: futures.Inverse, + IsActive: strings.EqualFold(inverseContracts.List[i].Status, "trading"), + Status: inverseContracts.List[i].Status, + Type: ct, + SettlementCurrency: inverseContracts.List[i].SettleCoin, + MaxLeverage: inverseContracts.List[i].LeverageFilter.MaxLeverage.Float64(), }) } return resp, nil @@ -1834,13 +1834,13 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, item asset.Ite var instruments []*InstrumentInfo for i := range linearContracts.List { - if linearContracts.List[i].SettleCoin != "USDC" { + if !linearContracts.List[i].SettleCoin.Equal(currency.USDC) { continue } instruments = append(instruments, linearContracts.List[i]) } for i := range inverseContracts.List { - if inverseContracts.List[i].SettleCoin != "USDC" { + if !inverseContracts.List[i].SettleCoin.Equal(currency.USDC) { continue } instruments = append(instruments, inverseContracts.List[i]) @@ -1888,19 +1888,19 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, item asset.Ite } resp = append(resp, futures.Contract{ - Exchange: e.Name, - Name: cp.Format(format), - Underlying: underlying, - Asset: item, - StartDate: instruments[i].LaunchTime.Time(), - EndDate: instruments[i].DeliveryTime.Time(), - SettlementType: futures.Linear, - IsActive: strings.EqualFold(instruments[i].Status, "trading"), - Status: instruments[i].Status, - Type: ct, - SettlementCurrencies: currency.Currencies{currency.USDC}, - MaxLeverage: instruments[i].LeverageFilter.MaxLeverage.Float64(), - Multiplier: instruments[i].LeverageFilter.LeverageStep.Float64(), + Exchange: e.Name, + Name: cp.Format(format), + Underlying: underlying, + Asset: item, + StartDate: instruments[i].LaunchTime.Time(), + EndDate: instruments[i].DeliveryTime.Time(), + SettlementType: futures.Linear, + IsActive: strings.EqualFold(instruments[i].Status, "trading"), + Status: instruments[i].Status, + Type: ct, + SettlementCurrency: currency.USDC, + MaxLeverage: instruments[i].LeverageFilter.MaxLeverage.Float64(), + Multiplier: instruments[i].LeverageFilter.LeverageStep.Float64(), }) } return resp, nil @@ -1913,13 +1913,13 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, item asset.Ite var instruments []*InstrumentInfo for i := range linearContracts.List { - if linearContracts.List[i].SettleCoin != "USDT" { + if !linearContracts.List[i].SettleCoin.Equal(currency.USDT) { continue } instruments = append(instruments, linearContracts.List[i]) } for i := range inverseContracts.List { - if inverseContracts.List[i].SettleCoin != "USDT" { + if !inverseContracts.List[i].SettleCoin.Equal(currency.USDT) { continue } instruments = append(instruments, inverseContracts.List[i]) @@ -1961,19 +1961,19 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, item asset.Ite } resp = append(resp, futures.Contract{ - Exchange: e.Name, - Name: cp.Format(format), - Underlying: underlying, - Asset: item, - StartDate: start, - EndDate: end, - SettlementType: futures.Linear, - IsActive: strings.EqualFold(instruments[i].Status, "trading"), - Status: instruments[i].Status, - Type: ct, - SettlementCurrencies: currency.Currencies{currency.USDT}, - MaxLeverage: instruments[i].LeverageFilter.MaxLeverage.Float64(), - Multiplier: instruments[i].LeverageFilter.LeverageStep.Float64(), + Exchange: e.Name, + Name: cp.Format(format), + Underlying: underlying, + Asset: item, + StartDate: start, + EndDate: end, + SettlementType: futures.Linear, + IsActive: strings.EqualFold(instruments[i].Status, "trading"), + Status: instruments[i].Status, + Type: ct, + SettlementCurrency: currency.USDT, + MaxLeverage: instruments[i].LeverageFilter.MaxLeverage.Float64(), + Multiplier: instruments[i].LeverageFilter.LeverageStep.Float64(), }) } return resp, nil diff --git a/exchanges/coinbase/coinbase_wrapper.go b/exchanges/coinbase/coinbase_wrapper.go index 3e5acd55..762664cc 100644 --- a/exchanges/coinbase/coinbase_wrapper.go +++ b/exchanges/coinbase/coinbase_wrapper.go @@ -873,15 +873,15 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, item asset.Ite Rate: decimal.NewFromFloat(products.Products[i].FutureProductDetails.PerpetualDetails.FundingRate.Float64()), } contracts[i] = futures.Contract{ - Exchange: e.Name, - Name: products.Products[i].ID, - Asset: item, - EndDate: products.Products[i].FutureProductDetails.ContractExpiry, - IsActive: !products.Products[i].IsDisabled, - Status: products.Products[i].Status, - SettlementCurrencies: currency.Currencies{products.Products[i].QuoteCurrencyID}, - Multiplier: products.Products[i].BaseIncrement.Float64(), - LatestRate: funRate, + Exchange: e.Name, + Name: products.Products[i].ID, + Asset: item, + EndDate: products.Products[i].FutureProductDetails.ContractExpiry, + IsActive: !products.Products[i].IsDisabled, + Status: products.Products[i].Status, + SettlementCurrency: products.Products[i].QuoteCurrencyID, + Multiplier: products.Products[i].BaseIncrement.Float64(), + LatestRate: funRate, } if i < perpStart { contracts[i].Type = futures.LongDated diff --git a/exchanges/deribit/deribit_types.go b/exchanges/deribit/deribit_types.go index a4c26264..f61ae96e 100644 --- a/exchanges/deribit/deribit_types.go +++ b/exchanges/deribit/deribit_types.go @@ -192,31 +192,31 @@ type IndexPriceData struct { // InstrumentData gets data for instruments type InstrumentData struct { - InstrumentName string `json:"instrument_name"` - BaseCurrency string `json:"base_currency"` - Kind string `json:"kind"` - OptionType string `json:"option_type"` - QuoteCurrency string `json:"quote_currency"` - BlockTradeCommission float64 `json:"block_trade_commission"` - ContractSize float64 `json:"contract_size"` - CreationTimestamp types.Time `json:"creation_timestamp"` - ExpirationTimestamp types.Time `json:"expiration_timestamp"` - IsActive bool `json:"is_active"` - Leverage float64 `json:"leverage"` - MaxLeverage float64 `json:"max_leverage"` - MakerCommission float64 `json:"maker_commission"` - MinimumTradeAmount float64 `json:"min_trade_amount"` - TickSize float64 `json:"tick_size"` - TakerCommission float64 `json:"taker_commission"` - Strike float64 `json:"strike"` - SettlementPeriod string `json:"settlement_period"` - SettlementCurrency string `json:"settlement_currency"` - RequestForQuote bool `json:"rfq"` - PriceIndex string `json:"price_index"` - InstrumentID int64 `json:"instrument_id"` - CounterCurrency string `json:"counter_currency"` - MaximumLiquidationCommission float64 `json:"max_liquidation_commission"` - FutureType string `json:"future_type"` + InstrumentName string `json:"instrument_name"` + BaseCurrency currency.Code `json:"base_currency"` + Kind string `json:"kind"` + OptionType string `json:"option_type"` + QuoteCurrency currency.Code `json:"quote_currency"` + BlockTradeCommission float64 `json:"block_trade_commission"` + ContractSize float64 `json:"contract_size"` + CreationTimestamp types.Time `json:"creation_timestamp"` + ExpirationTimestamp types.Time `json:"expiration_timestamp"` + IsActive bool `json:"is_active"` + Leverage float64 `json:"leverage"` + MaxLeverage float64 `json:"max_leverage"` + MakerCommission float64 `json:"maker_commission"` + MinimumTradeAmount float64 `json:"min_trade_amount"` + TickSize float64 `json:"tick_size"` + TakerCommission float64 `json:"taker_commission"` + Strike float64 `json:"strike"` + SettlementPeriod string `json:"settlement_period"` + SettlementCurrency currency.Code `json:"settlement_currency"` + RequestForQuote bool `json:"rfq"` + PriceIndex string `json:"price_index"` + InstrumentID int64 `json:"instrument_id"` + CounterCurrency string `json:"counter_currency"` + MaximumLiquidationCommission float64 `json:"max_liquidation_commission"` + FutureType string `json:"future_type"` TickSizeSteps []struct { AbovePrice float64 `json:"above_price"` TickSize float64 `json:"tick_size"` diff --git a/exchanges/deribit/deribit_wrapper.go b/exchanges/deribit/deribit_wrapper.go index 46f54065..5840a734 100644 --- a/exchanges/deribit/deribit_wrapper.go +++ b/exchanges/deribit/deribit_wrapper.go @@ -1177,18 +1177,18 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, item asset.Ite contractSettlementType = futures.Linear } resp = append(resp, futures.Contract{ - Exchange: e.Name, - Name: cp, - Underlying: currency.NewPair(currency.NewCode(inst.BaseCurrency), currency.NewCode(inst.QuoteCurrency)), - Asset: item, - SettlementCurrencies: []currency.Code{currency.NewCode(inst.SettlementCurrency)}, - StartDate: inst.CreationTimestamp.Time(), - EndDate: inst.ExpirationTimestamp.Time(), - Type: ct, - SettlementType: contractSettlementType, - IsActive: inst.IsActive, - MaxLeverage: inst.MaxLeverage, - Multiplier: inst.ContractSize, + Exchange: e.Name, + Name: cp, + Underlying: currency.NewPair(inst.BaseCurrency, inst.QuoteCurrency), + Asset: item, + SettlementCurrency: inst.SettlementCurrency, + StartDate: inst.CreationTimestamp.Time(), + EndDate: inst.ExpirationTimestamp.Time(), + Type: ct, + SettlementType: contractSettlementType, + IsActive: inst.IsActive, + MaxLeverage: inst.MaxLeverage, + Multiplier: inst.ContractSize, }) } } diff --git a/exchanges/futures/contract.go b/exchanges/futures/contract.go index f236a4ff..beea1db4 100644 --- a/exchanges/futures/contract.go +++ b/exchanges/futures/contract.go @@ -30,13 +30,14 @@ type Contract struct { Type ContractType SettlementType ContractSettlementType // Optional values if the exchange offers them - SettlementCurrencies currency.Currencies - MarginCurrency currency.Code - Multiplier float64 - MaxLeverage float64 - LatestRate fundingrate.Rate - FundingRateFloor decimal.Decimal - FundingRateCeiling decimal.Decimal + SettlementCurrency currency.Code + AdditionalSettlementCurrencies currency.Currencies + MarginCurrency currency.Code + Multiplier float64 + MaxLeverage float64 + LatestRate fundingrate.Rate + FundingRateFloor decimal.Decimal + FundingRateCeiling decimal.Decimal } // ContractSettlementType holds the various style of contracts offered by futures exchanges diff --git a/exchanges/gateio/gateio_wrapper.go b/exchanges/gateio/gateio_wrapper.go index f09c06ba..724dc896 100644 --- a/exchanges/gateio/gateio_wrapper.go +++ b/exchanges/gateio/gateio_wrapper.go @@ -1781,16 +1781,16 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, a asset.Item) contractSettlementType = futures.Quanto } c := futures.Contract{ - Exchange: e.Name, - Name: contracts[i].Name, - Underlying: contracts[i].Name, - Asset: a, - IsActive: contracts[i].DelistedTime.Time().IsZero() || contracts[i].DelistedTime.Time().After(time.Now()), - Type: futures.Perpetual, - SettlementType: contractSettlementType, - SettlementCurrencies: currency.Currencies{settle}, - Multiplier: contracts[i].QuantoMultiplier.Float64(), - MaxLeverage: contracts[i].LeverageMax.Float64(), + Exchange: e.Name, + Name: contracts[i].Name, + Underlying: contracts[i].Name, + Asset: a, + IsActive: contracts[i].DelistedTime.Time().IsZero() || contracts[i].DelistedTime.Time().After(time.Now()), + Type: futures.Perpetual, + SettlementType: contractSettlementType, + SettlementCurrency: settle, + Multiplier: contracts[i].QuantoMultiplier.Float64(), + MaxLeverage: contracts[i].LeverageMax.Float64(), } c.LatestRate = fundingrate.Rate{ Time: contracts[i].FundingNextApply.Time().Add(-time.Duration(contracts[i].FundingInterval) * time.Second), @@ -1834,19 +1834,18 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, a asset.Item) startTime = endTime.Add(-kline.SixMonth.Duration()) } resp[i] = futures.Contract{ - Exchange: e.Name, - Name: name, - Underlying: underlying, - Asset: a, - StartDate: startTime, - EndDate: endTime, - SettlementType: futures.Linear, - IsActive: !contracts[i].InDelisting, - Type: ct, - SettlementCurrencies: currency.Currencies{settle}, - MarginCurrency: currency.Code{}, - Multiplier: contracts[i].QuantoMultiplier.Float64(), - MaxLeverage: contracts[i].LeverageMax.Float64(), + Exchange: e.Name, + Name: name, + Underlying: underlying, + Asset: a, + StartDate: startTime, + EndDate: endTime, + SettlementType: futures.Linear, + IsActive: !contracts[i].InDelisting, + Type: ct, + SettlementCurrency: settle, + Multiplier: contracts[i].QuantoMultiplier.Float64(), + MaxLeverage: contracts[i].LeverageMax.Float64(), } } return resp, nil diff --git a/exchanges/huobi/huobi_wrapper.go b/exchanges/huobi/huobi_wrapper.go index d46ee37f..9b4f1703 100644 --- a/exchanges/huobi/huobi_wrapper.go +++ b/exchanges/huobi/huobi_wrapper.go @@ -2009,16 +2009,16 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, item asset.Ite } resp = append(resp, futures.Contract{ - Exchange: e.Name, - Name: cp, - Underlying: underlying, - Asset: item, - StartDate: s, - SettlementType: futures.Inverse, - IsActive: result[x].ContractStatus == 1, - Type: futures.Perpetual, - SettlementCurrencies: currency.Currencies{currency.USD}, - Multiplier: result[x].ContractSize, + Exchange: e.Name, + Name: cp, + Underlying: underlying, + Asset: item, + StartDate: s, + SettlementType: futures.Inverse, + IsActive: result[x].ContractStatus == 1, + Type: futures.Perpetual, + SettlementCurrency: currency.USD, + Multiplier: result[x].ContractSize, }) } return resp, nil @@ -2065,17 +2065,17 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, item asset.Ite } resp = append(resp, futures.Contract{ - Exchange: e.Name, - Name: cp, - Underlying: underlying, - Asset: item, - StartDate: startTime, - EndDate: endTime, - SettlementType: futures.Linear, - IsActive: result.Data[x].ContractStatus == 1, - Type: ct, - SettlementCurrencies: currency.Currencies{currency.USD}, - Multiplier: result.Data[x].ContractSize, + Exchange: e.Name, + Name: cp, + Underlying: underlying, + Asset: item, + StartDate: startTime, + EndDate: endTime, + SettlementType: futures.Linear, + IsActive: result.Data[x].ContractStatus == 1, + Type: ct, + SettlementCurrency: currency.USD, + Multiplier: result.Data[x].ContractSize, }) } return resp, nil diff --git a/exchanges/kucoin/kucoin_wrapper.go b/exchanges/kucoin/kucoin_wrapper.go index d43ddde5..d593a0c0 100644 --- a/exchanges/kucoin/kucoin_wrapper.go +++ b/exchanges/kucoin/kucoin_wrapper.go @@ -1897,19 +1897,19 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, item asset.Ite } timeOfCurrentFundingRate := time.Now().Add((time.Duration(contracts[i].NextFundingRateTime) * time.Millisecond) - fri).Truncate(time.Hour).UTC() resp[i] = futures.Contract{ - Exchange: e.Name, - Name: cp, - Underlying: underlying, - SettlementCurrencies: currency.Currencies{settleCurr}, - MarginCurrency: settleCurr, - Asset: item, - StartDate: contracts[i].FirstOpenDate.Time(), - EndDate: contracts[i].ExpireDate.Time(), - IsActive: !strings.EqualFold(contracts[i].Status, "closed"), - Status: contracts[i].Status, - Multiplier: contracts[i].Multiplier, - MaxLeverage: contracts[i].MaxLeverage, - SettlementType: contractSettlementType, + Exchange: e.Name, + Name: cp, + Underlying: underlying, + SettlementCurrency: settleCurr, + MarginCurrency: settleCurr, + Asset: item, + StartDate: contracts[i].FirstOpenDate.Time(), + EndDate: contracts[i].ExpireDate.Time(), + IsActive: !strings.EqualFold(contracts[i].Status, "closed"), + Status: contracts[i].Status, + Multiplier: contracts[i].Multiplier, + MaxLeverage: contracts[i].MaxLeverage, + SettlementType: contractSettlementType, LatestRate: fundingrate.Rate{ Rate: decimal.NewFromFloat(contracts[i].FundingFeeRate), Time: timeOfCurrentFundingRate, // kucoin pays every 8 hours diff --git a/exchanges/okx/okx_wrapper.go b/exchanges/okx/okx_wrapper.go index ce09087d..c689ffad 100644 --- a/exchanges/okx/okx_wrapper.go +++ b/exchanges/okx/okx_wrapper.go @@ -2814,7 +2814,7 @@ func (e *Exchange) GetFuturesContractDetails(ctx context.Context, item asset.Ite } if !settleCurr.IsEmpty() { - resp[i].SettlementCurrencies = currency.Currencies{settleCurr} + resp[i].SettlementCurrency = settleCurr } } return resp, nil