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:
Scott
2023-07-26 14:25:43 +10:00
committed by GitHub
parent 2ad9304045
commit 471f4f21c4
39 changed files with 5785 additions and 3416 deletions

View File

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