mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
binance: convert loans and repays to global types
This commit is contained in:
parent
409ad9b75c
commit
70f0dccb9f
|
@ -1,11 +1,23 @@
|
||||||
---
|
---
|
||||||
sessions:
|
sessions:
|
||||||
|
# cross margin
|
||||||
|
binance_margin:
|
||||||
|
exchange: binance
|
||||||
|
margin: true
|
||||||
|
|
||||||
|
# isolated margin
|
||||||
binance_margin_linkusdt:
|
binance_margin_linkusdt:
|
||||||
exchange: binance
|
exchange: binance
|
||||||
margin: true
|
margin: true
|
||||||
isolatedMargin: true
|
isolatedMargin: true
|
||||||
isolatedMarginSymbol: LINKUSDT
|
isolatedMarginSymbol: LINKUSDT
|
||||||
|
|
||||||
|
binance_margin_dotusdt:
|
||||||
|
exchange: binance
|
||||||
|
margin: true
|
||||||
|
isolatedMargin: true
|
||||||
|
isolatedMarginSymbol: DOTUSDT
|
||||||
|
|
||||||
exchangeStrategies:
|
exchangeStrategies:
|
||||||
|
|
||||||
- on: binance_margin_linkusdt
|
- on: binance_margin_linkusdt
|
||||||
|
|
103
pkg/cmd/margin.go
Normal file
103
pkg/cmd/margin.go
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/bbgo"
|
||||||
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
var selectedSession *bbgo.ExchangeSession
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
marginLoansCmd.Flags().String("asset", "", "asset")
|
||||||
|
marginLoansCmd.Flags().String("session", "", "exchange session name")
|
||||||
|
marginCmd.AddCommand(marginLoansCmd)
|
||||||
|
|
||||||
|
RootCmd.AddCommand(marginCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// go run ./cmd/bbgo margin --session=binance
|
||||||
|
var marginCmd = &cobra.Command{
|
||||||
|
Use: "margin",
|
||||||
|
Short: "margin related history",
|
||||||
|
SilenceUsage: true,
|
||||||
|
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if err := cobraLoadDotenv(cmd, args); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cobraLoadConfig(cmd, args); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ctx := context.Background()
|
||||||
|
environ := bbgo.NewEnvironment()
|
||||||
|
|
||||||
|
if userConfig == nil {
|
||||||
|
return errors.New("user config is not loaded")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := environ.ConfigureExchangeSessions(userConfig); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionName, err := cmd.Flags().GetString("session")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
session, ok := environ.Session(sessionName)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("session %s not found", sessionName)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedSession = session
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// go run ./cmd/bbgo margin loans --session=binance
|
||||||
|
var marginLoansCmd = &cobra.Command{
|
||||||
|
Use: "loans --session=SESSION_NAME --asset=ASSET",
|
||||||
|
Short: "query loans history",
|
||||||
|
SilenceUsage: true,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
asset, err := cmd.Flags().GetString("asset")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't get the symbol from flags: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if selectedSession == nil {
|
||||||
|
return errors.New("session is not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
marginHistoryService, ok := selectedSession.Exchange.(types.MarginHistory)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("exchange %s does not support MarginHistory service", selectedSession.ExchangeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
startTime := now.AddDate(0, -5, 0)
|
||||||
|
endTime := now
|
||||||
|
loans, err := marginHistoryService.QueryLoanHistory(ctx, asset, &startTime, &endTime)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("%d loans", len(loans))
|
||||||
|
for _, loan := range loans {
|
||||||
|
log.Infof("LOAN %+v", loan)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
|
@ -32,24 +32,10 @@ var RootCmd = &cobra.Command{
|
||||||
SilenceUsage: true,
|
SilenceUsage: true,
|
||||||
|
|
||||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
disableDotEnv, err := cmd.Flags().GetBool("no-dotenv")
|
if err := cobraLoadDotenv(cmd, args) ; err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !disableDotEnv {
|
|
||||||
dotenvFile, err := cmd.Flags().GetString("dotenv")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := os.Stat(dotenvFile); err == nil {
|
|
||||||
if err := godotenv.Load(dotenvFile); err != nil {
|
|
||||||
return errors.Wrap(err, "error loading dotenv file")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if viper.GetBool("debug") {
|
if viper.GetBool("debug") {
|
||||||
log.Infof("debug mode is enabled")
|
log.Infof("debug mode is enabled")
|
||||||
log.SetLevel(log.DebugLevel)
|
log.SetLevel(log.DebugLevel)
|
||||||
|
@ -67,6 +53,35 @@ var RootCmd = &cobra.Command{
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return cobraLoadConfig(cmd, args)
|
||||||
|
},
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func cobraLoadDotenv(cmd *cobra.Command, args []string) error {
|
||||||
|
disableDotEnv, err := cmd.Flags().GetBool("no-dotenv")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !disableDotEnv {
|
||||||
|
dotenvFile, err := cmd.Flags().GetString("dotenv")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := os.Stat(dotenvFile); err == nil {
|
||||||
|
if err := godotenv.Load(dotenvFile); err != nil {
|
||||||
|
return errors.Wrap(err, "error loading dotenv file")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func cobraLoadConfig(cmd *cobra.Command, args []string) error {
|
||||||
configFile, err := cmd.Flags().GetString("config")
|
configFile, err := cmd.Flags().GetString("config")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "failed to get the config flag")
|
return errors.Wrapf(err, "failed to get the config flag")
|
||||||
|
@ -75,7 +90,7 @@ var RootCmd = &cobra.Command{
|
||||||
// load config file nicely
|
// load config file nicely
|
||||||
if len(configFile) > 0 {
|
if len(configFile) > 0 {
|
||||||
// if config file exists, use the config loaded from the config file.
|
// if config file exists, use the config loaded from the config file.
|
||||||
// otherwise, use a empty config object
|
// otherwise, use an empty config object
|
||||||
if _, err := os.Stat(configFile); err == nil {
|
if _, err := os.Stat(configFile); err == nil {
|
||||||
// load successfully
|
// load successfully
|
||||||
userConfig, err = bbgo.Load(configFile, false)
|
userConfig, err = bbgo.Load(configFile, false)
|
||||||
|
@ -93,11 +108,6 @@ var RootCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
|
||||||
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
@ -4,6 +4,9 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/c9s/requestgen"
|
"github.com/c9s/requestgen"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RepayStatus one of PENDING (pending execution), CONFIRMED (successfully loaned), FAILED (execution failed, nothing happened to your account);
|
// RepayStatus one of PENDING (pending execution), CONFIRMED (successfully loaned), FAILED (execution failed, nothing happened to your account);
|
||||||
|
@ -17,13 +20,13 @@ const (
|
||||||
|
|
||||||
type MarginRepayRecord struct {
|
type MarginRepayRecord struct {
|
||||||
IsolatedSymbol string `json:"isolatedSymbol"`
|
IsolatedSymbol string `json:"isolatedSymbol"`
|
||||||
Amount string `json:"amount"`
|
Amount fixedpoint.Value `json:"amount"`
|
||||||
Asset string `json:"asset"`
|
Asset string `json:"asset"`
|
||||||
Interest string `json:"interest"`
|
Interest fixedpoint.Value `json:"interest"`
|
||||||
Principal string `json:"principal"`
|
Principal fixedpoint.Value `json:"principal"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Timestamp int64 `json:"timestamp"`
|
Timestamp types.MillisecondTimestamp `json:"timestamp"`
|
||||||
TxId int64 `json:"txId"`
|
TxId uint64 `json:"txId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:generate requestgen -method GET -url "/sapi/v1/margin/repay" -type GetMarginRepayHistoryRequest -responseType .RowsResponse -responseDataField Rows -responseDataType []MarginRepayRecord
|
//go:generate requestgen -method GET -url "/sapi/v1/margin/repay" -type GetMarginRepayHistoryRequest -responseType .RowsResponse -responseDataField Rows -responseDataType []MarginRepayRecord
|
||||||
|
|
|
@ -106,6 +106,8 @@ func New(key, secret string) *Exchange {
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if len(key) > 0 && len(secret) > 0 {
|
if len(key) > 0 && len(secret) > 0 {
|
||||||
|
client2.Auth(key, secret)
|
||||||
|
|
||||||
timeSetter.Do(func() {
|
timeSetter.Do(func() {
|
||||||
_, err = client.NewSetServerTimeService().Do(context.Background())
|
_, err = client.NewSetServerTimeService().Do(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -4,16 +4,32 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/exchange/binance/binanceapi"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (e *Exchange) QueryLoanHistory(ctx context.Context, asset string, startTime, endTime *time.Time) ([]types.MarginLoanRecord, error) {
|
func (e *Exchange) QueryLoanHistory(ctx context.Context, asset string, startTime, endTime *time.Time) ([]types.MarginLoanRecord, error) {
|
||||||
req := e.client2.NewGetMarginLoanHistoryRequest()
|
req := e.client2.NewGetMarginLoanHistoryRequest()
|
||||||
req.Asset(asset)
|
req.Asset(asset)
|
||||||
|
req.Size(100)
|
||||||
|
|
||||||
if startTime != nil {
|
if startTime != nil {
|
||||||
req.StartTime(*startTime)
|
req.StartTime(*startTime)
|
||||||
|
|
||||||
|
// 6 months
|
||||||
|
if time.Since(*startTime) > time.Hour*24*30*6 {
|
||||||
|
req.Archived(true)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if startTime != nil && endTime != nil {
|
||||||
|
duration := endTime.Sub(*startTime)
|
||||||
|
if duration > time.Hour*24*30 {
|
||||||
|
t := startTime.Add(time.Hour * 24 * 30)
|
||||||
|
endTime = &t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if endTime != nil {
|
if endTime != nil {
|
||||||
req.EndTime(*endTime)
|
req.EndTime(*endTime)
|
||||||
}
|
}
|
||||||
|
@ -22,18 +38,51 @@ func (e *Exchange) QueryLoanHistory(ctx context.Context, asset string, startTime
|
||||||
req.IsolatedSymbol(e.MarginSettings.IsolatedMarginSymbol)
|
req.IsolatedSymbol(e.MarginSettings.IsolatedMarginSymbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
loans, err := req.Do(ctx)
|
records, err := req.Do(ctx)
|
||||||
_ = loans
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var loans []types.MarginLoanRecord
|
||||||
|
for _, record := range records {
|
||||||
|
loans = append(loans, toGlobalLoan(record))
|
||||||
|
}
|
||||||
|
|
||||||
|
return loans, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func toGlobalLoan(record binanceapi.MarginLoanRecord) types.MarginLoanRecord {
|
||||||
|
return types.MarginLoanRecord{
|
||||||
|
TransactionID: uint64(record.TxId),
|
||||||
|
Asset: record.Asset,
|
||||||
|
Principle: record.Principal,
|
||||||
|
Time: types.Time(record.Timestamp),
|
||||||
|
IsolatedSymbol: record.IsolatedSymbol,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (e *Exchange) QueryRepayHistory(ctx context.Context, asset string, startTime, endTime *time.Time) ([]types.MarginRepayRecord, error) {
|
func (e *Exchange) QueryRepayHistory(ctx context.Context, asset string, startTime, endTime *time.Time) ([]types.MarginRepayRecord, error) {
|
||||||
req := e.client2.NewGetMarginRepayHistoryRequest()
|
req := e.client2.NewGetMarginRepayHistoryRequest()
|
||||||
req.Asset(asset)
|
req.Asset(asset)
|
||||||
|
req.Size(100)
|
||||||
|
|
||||||
if startTime != nil {
|
if startTime != nil {
|
||||||
req.StartTime(*startTime)
|
req.StartTime(*startTime)
|
||||||
|
|
||||||
|
// 6 months
|
||||||
|
if time.Since(*startTime) > time.Hour*24*30*6 {
|
||||||
|
req.Archived(true)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if startTime != nil && endTime != nil {
|
||||||
|
duration := endTime.Sub(*startTime)
|
||||||
|
if duration > time.Hour*24*30 {
|
||||||
|
t := startTime.Add(time.Hour * 24 * 30)
|
||||||
|
endTime = &t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if endTime != nil {
|
if endTime != nil {
|
||||||
req.EndTime(*endTime)
|
req.EndTime(*endTime)
|
||||||
}
|
}
|
||||||
|
@ -42,8 +91,24 @@ func (e *Exchange) QueryRepayHistory(ctx context.Context, asset string, startTim
|
||||||
req.IsolatedSymbol(e.MarginSettings.IsolatedMarginSymbol)
|
req.IsolatedSymbol(e.MarginSettings.IsolatedMarginSymbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := req.Do(ctx)
|
records, err := req.Do(ctx)
|
||||||
return nil, err
|
|
||||||
|
var repays []types.MarginRepayRecord
|
||||||
|
for _, record := range records {
|
||||||
|
repays = append(repays, toGlobalRepay(record))
|
||||||
|
}
|
||||||
|
|
||||||
|
return repays, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func toGlobalRepay(record binanceapi.MarginRepayRecord) types.MarginRepayRecord {
|
||||||
|
return types.MarginRepayRecord{
|
||||||
|
TransactionID: record.TxId,
|
||||||
|
Asset: record.Asset,
|
||||||
|
Principle: record.Principal,
|
||||||
|
Time: types.Time(record.Timestamp),
|
||||||
|
IsolatedSymbol: record.IsolatedSymbol,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Exchange) QueryLiquidationHistory(ctx context.Context, startTime, endTime *time.Time) ([]types.MarginLiquidationRecord, error) {
|
func (e *Exchange) QueryLiquidationHistory(ctx context.Context, startTime, endTime *time.Time) ([]types.MarginLiquidationRecord, error) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user