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 <gbjkirwan@gmail.com>

* Update exchanges/btse/btse_wrapper.go

Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com>

* reuse comment for better clarity

* collapses entire thing

* shazLint

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com>
This commit is contained in:
Scott
2025-11-10 13:21:54 +11:00
committed by GitHub
parent 9441f33f42
commit 61d720b72f
19 changed files with 399 additions and 471 deletions

View File

@@ -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

View File

@@ -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) {

View File

@@ -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"

View File

@@ -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"`

View File

@@ -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

View File

@@ -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,
})
}
}

View File

@@ -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")

View File

@@ -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

View File

@@ -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
}

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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"`

View File

@@ -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,
})
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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