mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-06 07:26:47 +00:00
Binance,OKx: Implement fetching funding rates (#1239)
* adds basic groundwork for rates on binance * more into rates on binance * rm redudant redundancy, add payments * mini commit before merging with testnet ability branch * changes function signature and fixes resulting build * gets billing data too * funding rates package, features use, testnet reimpl * new endpoint, refinements and tests * cli fix, rpc impl, testing, payments * fixups from looking at code * typo fix * niteroos * merge fixes * adds test, fixes cli issues * woah nelly
This commit is contained in:
@@ -24,6 +24,7 @@ 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/kline"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/margin"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
@@ -512,13 +513,13 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config)
|
||||
Response: jsonifyInterface([]interface{}{""}),
|
||||
})
|
||||
|
||||
fundingRateRequest := &order.FundingRatesRequest{
|
||||
fundingRateRequest := &fundingrate.RatesRequest{
|
||||
Asset: assetTypes[i],
|
||||
Pairs: currency.Pairs{p},
|
||||
Pair: p,
|
||||
StartDate: time.Now().Add(-time.Hour),
|
||||
EndDate: time.Now(),
|
||||
}
|
||||
var fundingRateResponse []order.FundingRates
|
||||
var fundingRateResponse *fundingrate.Rates
|
||||
fundingRateResponse, err = e.GetFundingRates(context.TODO(), fundingRateRequest)
|
||||
msg = ""
|
||||
if err != nil {
|
||||
|
||||
@@ -472,37 +472,39 @@ type assetPair struct {
|
||||
// currently tested under this suite due to irrelevance
|
||||
// or not worth checking yet
|
||||
var excludedMethodNames = map[string]struct{}{
|
||||
"Setup": {}, // Is run via test setup
|
||||
"Start": {}, // Is run via test setup
|
||||
"SetDefaults": {}, // Is run via test setup
|
||||
"UpdateTradablePairs": {}, // Is run via test setup
|
||||
"GetDefaultConfig": {}, // Is run via test setup
|
||||
"FetchTradablePairs": {}, // Is run via test setup
|
||||
"GetCollateralCurrencyForContract": {}, // Not widely supported/implemented futures endpoint
|
||||
"GetCurrencyForRealisedPNL": {}, // Not widely supported/implemented futures endpoint
|
||||
"GetFuturesPositions": {}, // Not widely supported/implemented futures endpoint
|
||||
"GetFundingRates": {}, // Not widely supported/implemented futures endpoint
|
||||
"IsPerpetualFutureCurrency": {}, // Not widely supported/implemented futures endpoint
|
||||
"GetMarginRatesHistory": {}, // Not widely supported/implemented futures endpoint
|
||||
"CalculatePNL": {}, // Not widely supported/implemented futures endpoint
|
||||
"CalculateTotalCollateral": {}, // Not widely supported/implemented futures endpoint
|
||||
"ScaleCollateral": {}, // Not widely supported/implemented futures endpoint
|
||||
"GetPositionSummary": {}, // Not widely supported/implemented futures endpoint
|
||||
"AuthenticateWebsocket": {}, // Unnecessary websocket test
|
||||
"FlushWebsocketChannels": {}, // Unnecessary websocket test
|
||||
"UnsubscribeToWebsocketChannels": {}, // Unnecessary websocket test
|
||||
"SubscribeToWebsocketChannels": {}, // Unnecessary websocket test
|
||||
"GetOrderExecutionLimits": {}, // Not widely supported/implemented feature
|
||||
"UpdateCurrencyStates": {}, // Not widely supported/implemented feature
|
||||
"CheckOrderExecutionLimits": {}, // Not widely supported/implemented feature
|
||||
"UpdateOrderExecutionLimits": {}, // Not widely supported/implemented feature
|
||||
"CanTradePair": {}, // Not widely supported/implemented feature
|
||||
"CanTrade": {}, // Not widely supported/implemented feature
|
||||
"CanWithdraw": {}, // Not widely supported/implemented feature
|
||||
"CanDeposit": {}, // Not widely supported/implemented feature
|
||||
"GetCurrencyStateSnapshot": {}, // Not widely supported/implemented feature
|
||||
"SetHTTPClientUserAgent": {}, // standard base implementation
|
||||
"SetClientProxyAddress": {}, // standard base implementation
|
||||
"Setup": {}, // Is run via test setup
|
||||
"Start": {}, // Is run via test setup
|
||||
"SetDefaults": {}, // Is run via test setup
|
||||
"UpdateTradablePairs": {}, // Is run via test setup
|
||||
"GetDefaultConfig": {}, // Is run via test setup
|
||||
"FetchTradablePairs": {}, // Is run via test setup
|
||||
"AuthenticateWebsocket": {}, // Unnecessary websocket test
|
||||
"FlushWebsocketChannels": {}, // Unnecessary websocket test
|
||||
"UnsubscribeToWebsocketChannels": {}, // Unnecessary websocket test
|
||||
"SubscribeToWebsocketChannels": {}, // Unnecessary websocket test
|
||||
"GetOrderExecutionLimits": {}, // Not widely supported/implemented feature
|
||||
"UpdateCurrencyStates": {}, // Not widely supported/implemented feature
|
||||
"UpdateOrderExecutionLimits": {}, // Not widely supported/implemented feature
|
||||
"CheckOrderExecutionLimits": {}, // Not widely supported/implemented feature
|
||||
"CanTradePair": {}, // Not widely supported/implemented feature
|
||||
"CanTrade": {}, // Not widely supported/implemented feature
|
||||
"CanWithdraw": {}, // Not widely supported/implemented feature
|
||||
"CanDeposit": {}, // Not widely supported/implemented feature
|
||||
"GetCurrencyStateSnapshot": {}, // Not widely supported/implemented feature
|
||||
"SetHTTPClientUserAgent": {}, // standard base implementation
|
||||
"SetClientProxyAddress": {}, // standard base implementation
|
||||
// Not widely supported/implemented futures endpoints
|
||||
"GetCollateralCurrencyForContract": {},
|
||||
"GetCurrencyForRealisedPNL": {},
|
||||
"GetFuturesPositions": {},
|
||||
"GetFundingRates": {},
|
||||
"IsPerpetualFutureCurrency": {},
|
||||
"GetMarginRatesHistory": {},
|
||||
"CalculatePNL": {},
|
||||
"CalculateTotalCollateral": {},
|
||||
"ScaleCollateral": {},
|
||||
"GetPositionSummary": {},
|
||||
"GetLatestFundingRate": {},
|
||||
}
|
||||
|
||||
// blockedCIExchanges are exchanges that are not able to be tested on CI
|
||||
|
||||
@@ -215,7 +215,7 @@ var futuresCommands = &cli.Command{
|
||||
Name: "getfundingrates",
|
||||
Aliases: []string{"funding", "f"},
|
||||
Usage: "returns funding rate data between two dates",
|
||||
ArgsUsage: "<exchange> <asset> <pairs> <start> <end> <includepredicted> <includepayments>",
|
||||
ArgsUsage: "<exchange> <asset> <pair> <start> <end> <paymentcurrency> <includepredicted> <includepayments> <respecthistorylimits>",
|
||||
Action: getFundingRates,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
@@ -228,34 +228,73 @@ var futuresCommands = &cli.Command{
|
||||
Aliases: []string{"a"},
|
||||
Usage: "the asset type of the currency pair, must be a futures type",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "pairs",
|
||||
&cli.StringFlag{
|
||||
Name: "pair",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "comma delimited list of pairs you wish to get funding rate data for",
|
||||
Usage: "currency pair",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "start",
|
||||
Aliases: []string{"sd"},
|
||||
Usage: "<start> rounded down to the nearest hour, ensure your starting position is within this window for accurate calculations",
|
||||
Value: time.Now().AddDate(-1, 0, 0).Truncate(time.Hour).Format(time.DateTime),
|
||||
Usage: "<start> rounded down to the nearest hour",
|
||||
Value: time.Now().AddDate(0, -1, 0).Truncate(time.Hour).Format(time.DateTime),
|
||||
Destination: &startTime,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "end",
|
||||
Aliases: []string{"ed"},
|
||||
Usage: "<end> rounded down to the nearest hour, ensure your last position is within this window for accurate calculations",
|
||||
Value: time.Now().Format(time.DateTime),
|
||||
Usage: "<end> rounded down to the nearest hour",
|
||||
Value: time.Now().Truncate(time.Hour).Format(time.DateTime),
|
||||
Destination: &endTime,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "paymentcurrency",
|
||||
Aliases: []string{"pc"},
|
||||
Usage: "optional - if you are paid in a currency that isn't easily inferred from the Pair, eg BTCUSD-PERP use this field",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "includepredicted",
|
||||
Aliases: []string{"ip", "predicted"},
|
||||
Usage: "include the predicted next funding rate",
|
||||
Usage: "optional - include the predicted next funding rate",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "includepayments",
|
||||
Aliases: []string{"pay"},
|
||||
Usage: "include funding rate payments",
|
||||
Usage: "optional - include funding rate payments, must be authenticated",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "respecthistorylimits",
|
||||
Aliases: []string{"respect", "r"},
|
||||
Usage: "optional - if true, will change the starting date to the maximum allowable limit if start date exceeds it",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "getlatestfundingrate",
|
||||
Aliases: []string{"latestrate", "lr", "r8"},
|
||||
Usage: "returns the latest funding rate data",
|
||||
ArgsUsage: "<exchange> <asset> <pair> <includepredicted>",
|
||||
Action: getLatestFundingRate,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "exchange",
|
||||
Aliases: []string{"e"},
|
||||
Usage: "the exchange to retrieve futures positions from",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "asset",
|
||||
Aliases: []string{"a"},
|
||||
Usage: "the asset type of the currency pair, must be a futures type",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "pair",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "currency pair",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "includepredicted",
|
||||
Aliases: []string{"ip", "predicted"},
|
||||
Usage: "optional - include the predicted next funding rate",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -710,12 +749,11 @@ func getFundingRates(c *cli.Context) error {
|
||||
return cli.ShowSubcommandHelp(c)
|
||||
}
|
||||
var (
|
||||
exchangeName, assetType string
|
||||
currencyPairs []string
|
||||
includePredicted, includePayments bool
|
||||
p currency.Pair
|
||||
s, e time.Time
|
||||
err error
|
||||
exchangeName, assetType, currencyPair, paymentCurrency string
|
||||
includePredicted, includePayments, respectFundingRateHistoryLimits bool
|
||||
p currency.Pair
|
||||
s, e time.Time
|
||||
err error
|
||||
)
|
||||
if c.IsSet("exchange") {
|
||||
exchangeName = c.String("exchange")
|
||||
@@ -733,20 +771,17 @@ func getFundingRates(c *cli.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.IsSet("pairs") {
|
||||
currencyPairs = c.StringSlice("pairs")
|
||||
if c.IsSet("pair") {
|
||||
currencyPair = c.String("pair")
|
||||
} else {
|
||||
currencyPairs = strings.Split(c.Args().Get(2), ",")
|
||||
currencyPair = c.Args().Get(2)
|
||||
}
|
||||
for i := range currencyPairs {
|
||||
if !validPair(currencyPairs[i]) {
|
||||
return errInvalidPair
|
||||
}
|
||||
p, err = currency.NewPairDelimiter(currencyPairs[i], pairDelimiter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
currencyPairs[i] = p.String()
|
||||
if !validPair(currencyPair) {
|
||||
return errInvalidPair
|
||||
}
|
||||
p, err = currency.NewPairDelimiter(currencyPair, pairDelimiter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !c.IsSet("start") {
|
||||
if c.Args().Get(3) != "" {
|
||||
@@ -758,22 +793,38 @@ func getFundingRates(c *cli.Context) error {
|
||||
endTime = c.Args().Get(4)
|
||||
}
|
||||
}
|
||||
|
||||
if c.IsSet("paymentcurrency") {
|
||||
paymentCurrency = c.String("paymentcurrency")
|
||||
} else {
|
||||
paymentCurrency = c.Args().Get(5)
|
||||
}
|
||||
|
||||
if c.IsSet("includepredicted") {
|
||||
includePredicted = c.Bool("includepredicted")
|
||||
} else if c.Args().Get(5) != "" {
|
||||
includePredicted, err = strconv.ParseBool(c.Args().Get(5))
|
||||
} else if c.Args().Get(6) != "" {
|
||||
includePredicted, err = strconv.ParseBool(c.Args().Get(6))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if c.IsSet("includepayments") {
|
||||
includePayments = c.Bool("includepayments")
|
||||
} else if c.Args().Get(6) != "" {
|
||||
includePayments, err = strconv.ParseBool(c.Args().Get(6))
|
||||
} else if c.Args().Get(7) != "" {
|
||||
includePayments, err = strconv.ParseBool(c.Args().Get(7))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if c.IsSet("respecthistorylimits") {
|
||||
respectFundingRateHistoryLimits = c.Bool("respecthistorylimits")
|
||||
} else if c.Args().Get(8) != "" {
|
||||
respectFundingRateHistoryLimits, err = strconv.ParseBool(c.Args().Get(8))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
s, err = time.ParseInLocation(time.DateTime, startTime, time.Local)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid time format for start: %v", err)
|
||||
@@ -796,13 +847,93 @@ func getFundingRates(c *cli.Context) error {
|
||||
client := gctrpc.NewGoCryptoTraderServiceClient(conn)
|
||||
result, err := client.GetFundingRates(c.Context,
|
||||
&gctrpc.GetFundingRatesRequest{
|
||||
Exchange: exchangeName,
|
||||
Asset: assetType,
|
||||
Pairs: currencyPairs,
|
||||
StartDate: s.Format(common.SimpleTimeFormatWithTimezone),
|
||||
EndDate: e.Format(common.SimpleTimeFormatWithTimezone),
|
||||
IncludePredicted: includePredicted,
|
||||
IncludePayments: includePayments,
|
||||
Exchange: exchangeName,
|
||||
Asset: assetType,
|
||||
Pair: &gctrpc.CurrencyPair{
|
||||
Delimiter: p.Delimiter,
|
||||
Base: p.Base.String(),
|
||||
Quote: p.Quote.String(),
|
||||
},
|
||||
StartDate: s.Format(common.SimpleTimeFormatWithTimezone),
|
||||
EndDate: e.Format(common.SimpleTimeFormatWithTimezone),
|
||||
IncludePredicted: includePredicted,
|
||||
IncludePayments: includePayments,
|
||||
RespectHistoryLimits: respectFundingRateHistoryLimits,
|
||||
PaymentCurrency: paymentCurrency,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonOutput(result)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getLatestFundingRate(c *cli.Context) error {
|
||||
if c.NArg() == 0 && c.NumFlags() == 0 {
|
||||
return cli.ShowSubcommandHelp(c)
|
||||
}
|
||||
var (
|
||||
exchangeName, assetType, currencyPair string
|
||||
includePredicted bool
|
||||
p currency.Pair
|
||||
err error
|
||||
)
|
||||
if c.IsSet("exchange") {
|
||||
exchangeName = c.String("exchange")
|
||||
} else {
|
||||
exchangeName = c.Args().First()
|
||||
}
|
||||
|
||||
if c.IsSet("asset") {
|
||||
assetType = c.String("asset")
|
||||
} else {
|
||||
assetType = c.Args().Get(1)
|
||||
}
|
||||
|
||||
err = isFuturesAsset(assetType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.IsSet("pair") {
|
||||
currencyPair = c.String("pair")
|
||||
} else {
|
||||
currencyPair = c.Args().Get(2)
|
||||
}
|
||||
if !validPair(currencyPair) {
|
||||
return errInvalidPair
|
||||
}
|
||||
p, err = currency.NewPairDelimiter(currencyPair, pairDelimiter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.IsSet("includepredicted") {
|
||||
includePredicted = c.Bool("includepredicted")
|
||||
} else if c.Args().Get(3) != "" {
|
||||
includePredicted, err = strconv.ParseBool(c.Args().Get(3))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
conn, cancel, err := setupClient(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeConn(conn, cancel)
|
||||
|
||||
client := gctrpc.NewGoCryptoTraderServiceClient(conn)
|
||||
result, err := client.GetLatestFundingRate(c.Context,
|
||||
&gctrpc.GetLatestFundingRateRequest{
|
||||
Exchange: exchangeName,
|
||||
Asset: assetType,
|
||||
Pair: &gctrpc.CurrencyPair{
|
||||
Delimiter: p.Delimiter,
|
||||
Base: p.Base.String(),
|
||||
Quote: p.Quote.String(),
|
||||
},
|
||||
IncludePredicted: includePredicted,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user