mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-06 07:26:47 +00:00
futures: Implement GetLatestFundingRates across exchanges (#1339)
* adds funding rate implementations and improvements * merge fixes x1 * lint * kucoin funding rates func make * migrate sync-manager to keys * some kucoin work * adds some kucoin wrapper funcs * ehhh, todo * kucoin position * start of orders * adds the kucoin tests yay * multiplier * nits, EWS includes order limits * NotYetImplemented, IsPerp improvements, cleaning * lint, test fix, huobi time * fixes issues, improves testing * fixes linters I WRECKED * local lint but remote lint, lint, lint, lint * fixes err * skip CI * lint * Supported rates, binance endpoints * fixes weird mocktest problems * no, CZ is invalid * fixes some new EWS test errors
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/core"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"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"
|
||||
@@ -3154,7 +3155,17 @@ func getFirstTradablePairOfAssets() {
|
||||
if err != nil {
|
||||
log.Fatalf("GateIO %v, trying to get %v enabled pairs error", err, asset.Futures)
|
||||
}
|
||||
futuresTradablePair = enabledPairs[len(enabledPairs)-1]
|
||||
|
||||
if len(enabledPairs) == 0 {
|
||||
var availPairs currency.Pairs
|
||||
availPairs, err = g.GetAvailablePairs(asset.Futures)
|
||||
if err != nil {
|
||||
log.Fatalf("GateIO %v, trying to get %v enabled pairs error", err, asset.Futures)
|
||||
}
|
||||
futuresTradablePair = availPairs[len(availPairs)-1]
|
||||
} else {
|
||||
futuresTradablePair = enabledPairs[len(enabledPairs)-1]
|
||||
}
|
||||
enabledPairs, err = g.GetEnabledPairs(asset.Options)
|
||||
if err != nil {
|
||||
log.Fatalf("GateIO %v, trying to get %v enabled pairs error", err, asset.Options)
|
||||
@@ -3419,3 +3430,28 @@ func TestGetFuturesContractDetails(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetLatestFundingRates(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := g.GetLatestFundingRates(context.Background(), &fundingrate.LatestRateRequest{
|
||||
Asset: asset.USDTMarginedFutures,
|
||||
Pair: currency.NewPair(currency.BTC, currency.USDT),
|
||||
IncludePredictedRate: true,
|
||||
})
|
||||
if !errors.Is(err, asset.ErrNotSupported) {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = g.GetLatestFundingRates(context.Background(), &fundingrate.LatestRateRequest{
|
||||
Asset: asset.Futures,
|
||||
Pair: currency.NewPair(currency.BTC, currency.USD),
|
||||
})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = g.GetLatestFundingRates(context.Background(), &fundingrate.LatestRateRequest{
|
||||
Asset: asset.Futures,
|
||||
})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +94,8 @@ func (g *Gateio) SetDefaults() {
|
||||
CryptoWithdrawalFee: true,
|
||||
MultiChainDeposits: true,
|
||||
MultiChainWithdrawals: true,
|
||||
PredictedFundingRate: true,
|
||||
FundingRateFetching: true,
|
||||
},
|
||||
WebsocketCapabilities: protocol.Features{
|
||||
TickerFetching: true,
|
||||
@@ -112,6 +114,16 @@ func (g *Gateio) SetDefaults() {
|
||||
Kline: kline.ExchangeCapabilitiesSupported{
|
||||
Intervals: true,
|
||||
},
|
||||
FuturesCapabilities: exchange.FuturesCapabilities{
|
||||
FundingRates: true,
|
||||
SupportedFundingRateFrequencies: map[kline.Interval]bool{
|
||||
kline.FourHour: true,
|
||||
kline.EightHour: true,
|
||||
},
|
||||
FundingRateBatching: map[asset.Item]bool{
|
||||
asset.Futures: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
Enabled: exchange.FeaturesEnabled{
|
||||
AutoPairUpdates: true,
|
||||
@@ -2155,3 +2167,96 @@ func (g *Gateio) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item) e
|
||||
|
||||
return g.LoadLimits(limits)
|
||||
}
|
||||
|
||||
// GetLatestFundingRates returns the latest funding rates data
|
||||
func (g *Gateio) GetLatestFundingRates(ctx context.Context, r *fundingrate.LatestRateRequest) ([]fundingrate.LatestRateResponse, error) {
|
||||
if r == nil {
|
||||
return nil, fmt.Errorf("%w LatestRateRequest", common.ErrNilPointer)
|
||||
}
|
||||
if r.Asset != asset.Futures {
|
||||
return nil, fmt.Errorf("%w %v", asset.ErrNotSupported, r.Asset)
|
||||
}
|
||||
|
||||
if !r.Pair.IsEmpty() {
|
||||
resp := make([]fundingrate.LatestRateResponse, 1)
|
||||
fPair, err := g.FormatExchangeCurrency(r.Pair, r.Asset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var settle string
|
||||
settle, err = g.getSettlementFromCurrency(fPair, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
contract, err := g.GetSingleContract(ctx, settle, fPair.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp[0] = contractToFundingRate(g.Name, r.Asset, fPair, contract, r.IncludePredictedRate)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
var resp []fundingrate.LatestRateResponse
|
||||
settleCurrencies := []string{"btc", "usdt", "usd"}
|
||||
pairs, err := g.GetEnabledPairs(asset.Futures)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := range settleCurrencies {
|
||||
contracts, err := g.GetAllFutureContracts(ctx, settleCurrencies[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for j := range contracts {
|
||||
p := strings.ToUpper(contracts[j].Name)
|
||||
if !g.IsValidPairString(p) {
|
||||
continue
|
||||
}
|
||||
cp, err := currency.NewPairFromString(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !pairs.Contains(cp, false) {
|
||||
continue
|
||||
}
|
||||
var isPerp bool
|
||||
isPerp, err = g.IsPerpetualFutureCurrency(r.Asset, cp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !isPerp {
|
||||
continue
|
||||
}
|
||||
resp = append(resp, contractToFundingRate(g.Name, r.Asset, cp, &contracts[j], r.IncludePredictedRate))
|
||||
}
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func contractToFundingRate(name string, item asset.Item, fPair currency.Pair, contract *FuturesContract, includeUpcomingRate bool) fundingrate.LatestRateResponse {
|
||||
resp := fundingrate.LatestRateResponse{
|
||||
Exchange: name,
|
||||
Asset: item,
|
||||
Pair: fPair,
|
||||
LatestRate: fundingrate.Rate{
|
||||
Time: contract.FundingNextApply.Time().Add(-time.Duration(contract.FundingInterval) * time.Second),
|
||||
Rate: contract.FundingRate.Decimal(),
|
||||
},
|
||||
TimeOfNextRate: contract.FundingNextApply.Time(),
|
||||
TimeChecked: time.Now(),
|
||||
}
|
||||
if includeUpcomingRate {
|
||||
resp.PredictedUpcomingRate = fundingrate.Rate{
|
||||
Time: contract.FundingNextApply.Time(),
|
||||
Rate: contract.FundingRateIndicative.Decimal(),
|
||||
}
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
// IsPerpetualFutureCurrency ensures a given asset and currency is a perpetual future
|
||||
func (g *Gateio) IsPerpetualFutureCurrency(a asset.Item, _ currency.Pair) (bool, error) {
|
||||
return a == asset.Futures, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user