futures: add GetFuturesContractDetails wrapper function (#1274)

* all in a days work

* cleanup

* cleanup for real, also stop it binance.json

* minor coverage

* adds gateio to the slurry

* cleanup of types

* verbose verbose verbose verbose verbose verbose

* fixes huobi parsing issue

* fix bybit contract identification

* cleanup

* merge fixes

* addresses many big problems raised by SHAZ

* tracking errors and fixes

* funding rate if avail, fixes currency formatting

* Addresses nits and sneaks in extra fixes

* lint

* minor fixes after rebase

* better contract splitter for currencies like T-USDT

* forgot to add the exchange name like a fool

* merge fixes x1

* kucoin, direction, contract size

* rn direction, fix kucoin time

* WHOOPS

* Update exchanges/kucoin/kucoin_wrapper.go

Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>

* misdirection

---------

Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>
This commit is contained in:
Scott
2023-10-03 15:04:45 +10:00
committed by GitHub
parent 08c27afded
commit 7f0faf7850
98 changed files with 5034 additions and 3273 deletions

View File

@@ -17,6 +17,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/futures"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
@@ -1232,3 +1233,25 @@ func TestCancelBatchOrders(t *testing.T) {
t.Error(err)
}
}
func TestGetFuturesContractDetails(t *testing.T) {
t.Parallel()
_, err := b.GetFuturesContractDetails(context.Background(), asset.Spot)
if !errors.Is(err, futures.ErrNotFuturesAsset) {
t.Error(err)
}
_, err = b.GetFuturesContractDetails(context.Background(), asset.USDTMarginedFutures)
if !errors.Is(err, asset.ErrNotSupported) {
t.Error(err)
}
_, err = b.GetFuturesContractDetails(context.Background(), asset.Futures)
if !errors.Is(err, nil) {
t.Error(err)
}
_, err = b.GetFuturesContractDetails(context.Background(), asset.PerpetualContract)
if !errors.Is(err, nil) {
t.Error(err)
}
}

View File

@@ -137,7 +137,7 @@ type Instrument struct {
FairPrice float64 `json:"fairPrice"`
Front string `json:"front"`
FundingBaseSymbol string `json:"fundingBaseSymbol"`
FundingInterval string `json:"fundingInterval"`
FundingInterval time.Time `json:"fundingInterval"`
FundingPremiumSymbol string `json:"fundingPremiumSymbol"`
FundingQuoteSymbol string `json:"fundingQuoteSymbol"`
FundingRate float64 `json:"fundingRate"`

View File

@@ -11,6 +11,7 @@ import (
"sync"
"time"
"github.com/shopspring/decimal"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/currency"
@@ -18,6 +19,8 @@ import (
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/deposit"
"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/orderbook"
@@ -1103,3 +1106,138 @@ func (b *Bitmex) getOrderType(id int64) (order.Type, error) {
}
return o, nil
}
// GetFuturesContractDetails returns details about futures contracts
func (b *Bitmex) GetFuturesContractDetails(ctx context.Context, item asset.Item) ([]futures.Contract, error) {
if !item.IsFutures() {
return nil, futures.ErrNotFuturesAsset
}
if !b.SupportsAsset(item) || item == asset.Index {
return nil, fmt.Errorf("%w %v", asset.ErrNotSupported, item)
}
marketInfo, err := b.GetInstruments(ctx, &GenericRequestParams{Reverse: true, Count: 500})
if err != nil {
return nil, err
}
resp := make([]futures.Contract, 0, len(marketInfo))
switch item {
case asset.PerpetualContract:
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)
if err != nil {
return nil, err
}
var s time.Time
if marketInfo[x].Front != "" {
s, err = time.Parse(time.RFC3339, marketInfo[x].Front)
if err != nil {
return nil, err
}
}
var contractSettlementType futures.ContractSettlementType
switch {
case cp.Quote.Equal(currency.USDT):
contractSettlementType = futures.Linear
case cp.Quote.Equal(currency.USD):
contractSettlementType = futures.Quanto
default:
contractSettlementType = futures.Inverse
}
resp = append(resp, futures.Contract{
Exchange: b.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: float64(marketInfo[x].Multiplier),
LatestRate: fundingrate.Rate{
Time: marketInfo[x].FundingTimestamp,
Rate: decimal.NewFromFloat(marketInfo[x].FundingRate),
},
})
}
case asset.Futures:
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)
if err != nil {
return nil, err
}
var s, e time.Time
if marketInfo[x].Front != "" {
s, err = time.Parse(time.RFC3339, marketInfo[x].Front)
if err != nil {
return nil, err
}
}
if marketInfo[x].Expiry != "" {
e, err = time.Parse(time.RFC3339, marketInfo[x].Expiry)
if err != nil {
return nil, err
}
}
var ct futures.ContractType
contractDuration := e.Sub(s)
switch {
case contractDuration <= kline.OneWeek.Duration()+kline.ThreeDay.Duration():
ct = futures.Weekly
case contractDuration <= kline.TwoWeek.Duration()+kline.ThreeDay.Duration():
ct = futures.Fortnightly
case contractDuration <= kline.OneMonth.Duration()+kline.ThreeWeek.Duration():
ct = futures.Monthly
case contractDuration <= kline.ThreeMonth.Duration()+kline.ThreeWeek.Duration():
ct = futures.Quarterly
case contractDuration <= kline.SixMonth.Duration()+kline.ThreeWeek.Duration():
ct = futures.HalfYearly
case contractDuration <= kline.NineMonth.Duration()+kline.ThreeWeek.Duration():
ct = futures.NineMonthly
case contractDuration <= kline.OneYear.Duration()+kline.ThreeWeek.Duration():
ct = futures.Yearly
}
contractSettlementType := futures.Inverse
switch {
case strings.Contains(cp.Quote.String(), "USDT"):
contractSettlementType = futures.Linear
case strings.Contains(cp.Quote.String(), "USD"):
contractSettlementType = futures.Quanto
}
resp = append(resp, futures.Contract{
Exchange: b.Name,
Name: cp,
Underlying: underlying,
Asset: item,
StartDate: s,
EndDate: e,
IsActive: marketInfo[x].State == "Open",
Status: marketInfo[x].State,
Type: ct,
SettlementCurrencies: currency.Currencies{currency.NewCode(marketInfo[x].SettlCurrency)},
Multiplier: float64(marketInfo[x].Multiplier),
SettlementType: contractSettlementType,
})
}
}
return resp, nil
}