diff --git a/pkg/exchange/binance/binanceapi/client.go b/pkg/exchange/binance/binanceapi/client.go index f239735742..45c39e6f11 100644 --- a/pkg/exchange/binance/binanceapi/client.go +++ b/pkg/exchange/binance/binanceapi/client.go @@ -24,7 +24,7 @@ const RestBaseURL = "https://api.binance.com" const SandboxRestBaseURL = "https://testnet.binance.vision" const DebugRequestResponse = false -var defaultHttpClient = &http.Client{ +var DefaultHttpClient = &http.Client{ Timeout: defaultHTTPTimeout, } @@ -37,8 +37,12 @@ type RestClient struct { timeOffset int64 } -func NewClient() *RestClient { - u, err := url.Parse(RestBaseURL) +func NewClient(baseURL string) *RestClient { + if len(baseURL) == 0 { + baseURL = RestBaseURL + } + + u, err := url.Parse(baseURL) if err != nil { panic(err) } @@ -46,7 +50,7 @@ func NewClient() *RestClient { client := &RestClient{ BaseAPIClient: requestgen.BaseAPIClient{ BaseURL: u, - HttpClient: defaultHttpClient, + HttpClient: DefaultHttpClient, }, } diff --git a/pkg/exchange/binance/binanceapi/client_test.go b/pkg/exchange/binance/binanceapi/client_test.go index 51c6d07df0..84a6542f89 100644 --- a/pkg/exchange/binance/binanceapi/client_test.go +++ b/pkg/exchange/binance/binanceapi/client_test.go @@ -35,7 +35,7 @@ func getTestClientOrSkip(t *testing.T) *RestClient { return nil } - client := NewClient() + client := NewClient("") client.Auth(key, secret) return client } @@ -124,7 +124,7 @@ func TestClient_privateCall(t *testing.T) { t.SkipNow() } - client := NewClient() + client := NewClient("") client.Auth(key, secret) ctx := context.Background() @@ -154,7 +154,7 @@ func TestClient_privateCall(t *testing.T) { } func TestClient_setTimeOffsetFromServer(t *testing.T) { - client := NewClient() + client := NewClient("") err := client.SetTimeOffsetFromServer(context.Background()) assert.NoError(t, err) } diff --git a/pkg/exchange/binance/binanceapi/get_spot_rebate_history_request.go b/pkg/exchange/binance/binanceapi/get_spot_rebate_history_request.go index eb3db5ab84..7fff74ffbe 100644 --- a/pkg/exchange/binance/binanceapi/get_spot_rebate_history_request.go +++ b/pkg/exchange/binance/binanceapi/get_spot_rebate_history_request.go @@ -24,7 +24,6 @@ type SpotRebate struct { UpdateTime types.MillisecondTimestamp `json:"updateTime"` } - // GetSpotRebateHistoryRequest // The max interval between startTime and endTime is 30 days. // If startTime and endTime are not sent, the recent 7 days' data will be returned. diff --git a/pkg/exchange/binance/exchange.go b/pkg/exchange/binance/exchange.go index 87fc672808..5a1db26fa3 100644 --- a/pkg/exchange/binance/exchange.go +++ b/pkg/exchange/binance/exchange.go @@ -3,7 +3,6 @@ package binance import ( "context" "fmt" - "net/http" "os" "strconv" "strings" @@ -22,6 +21,7 @@ import ( "github.com/pkg/errors" "github.com/sirupsen/logrus" + "github.com/c9s/bbgo/pkg/exchange/binance/binanceapi" "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/types" "github.com/c9s/bbgo/pkg/util" @@ -77,17 +77,21 @@ type Exchange struct { // futuresClient is used for usdt-m futures futuresClient *futures.Client // USDT-M Futures // deliveryClient *delivery.Client // Coin-M Futures + + // client2 is a newer version of the binance api client implemented by ourselves. + client2 *binanceapi.RestClient } var timeSetter sync.Once func New(key, secret string) *Exchange { var client = binance.NewClient(key, secret) - client.HTTPClient = &http.Client{Timeout: 15 * time.Second} + client.HTTPClient = binanceapi.DefaultHttpClient client.Debug = viper.GetBool("debug-binance-client") var futuresClient = binance.NewFuturesClient(key, secret) - futuresClient.HTTPClient = &http.Client{Timeout: 15 * time.Second} + futuresClient.HTTPClient = binanceapi.DefaultHttpClient + futuresClient.Debug = viper.GetBool("debug-binance-futures-client") if isBinanceUs() { client.BaseURL = BinanceUSBaseURL @@ -98,6 +102,8 @@ func New(key, secret string) *Exchange { futuresClient.BaseURL = FutureTestBaseURL } + client2 := binanceapi.NewClient(client.BaseURL) + var err error if len(key) > 0 && len(secret) > 0 { timeSetter.Do(func() { @@ -118,7 +124,7 @@ func New(key, secret string) *Exchange { secret: secret, client: client, futuresClient: futuresClient, - // deliveryClient: deliveryClient, + client2: client2, } } diff --git a/pkg/exchange/binance/margin_history.go b/pkg/exchange/binance/margin_history.go new file mode 100644 index 0000000000..6eb6793693 --- /dev/null +++ b/pkg/exchange/binance/margin_history.go @@ -0,0 +1,85 @@ +package binance + +import ( + "context" + "time" + + "github.com/c9s/bbgo/pkg/types" +) + +func (e *Exchange) QueryLoanHistory(ctx context.Context, asset string, startTime, endTime *time.Time) ([]types.MarginLoanRecord, error) { + req := e.client2.NewGetMarginLoanHistoryRequest() + req.Asset(asset) + + if startTime != nil { + req.StartTime(*startTime) + } + if endTime != nil { + req.EndTime(*endTime) + } + + if e.MarginSettings.IsIsolatedMargin { + req.IsolatedSymbol(e.MarginSettings.IsolatedMarginSymbol) + } + + loans, err := req.Do(ctx) + _ = loans + return nil, err +} + +func (e *Exchange) QueryRepayHistory(ctx context.Context, asset string, startTime, endTime *time.Time) ([]types.MarginRepayRecord, error) { + req := e.client2.NewGetMarginRepayHistoryRequest() + req.Asset(asset) + + if startTime != nil { + req.StartTime(*startTime) + } + if endTime != nil { + req.EndTime(*endTime) + } + + if e.MarginSettings.IsIsolatedMargin { + req.IsolatedSymbol(e.MarginSettings.IsolatedMarginSymbol) + } + + _, err := req.Do(ctx) + return nil, err +} + +func (e *Exchange) QueryLiquidationHistory(ctx context.Context, startTime, endTime *time.Time) ([]types.MarginLiquidationRecord, error) { + req := e.client2.NewGetMarginLiquidationHistoryRequest() + + if startTime != nil { + req.StartTime(*startTime) + } + if endTime != nil { + req.EndTime(*endTime) + } + + if e.MarginSettings.IsIsolatedMargin { + req.IsolatedSymbol(e.MarginSettings.IsolatedMarginSymbol) + } + + _, err := req.Do(ctx) + return nil, err +} + +func (e *Exchange) QueryInterestHistory(ctx context.Context, asset string, startTime, endTime *time.Time) ([]types.MarginInterest, error) { + req := e.client2.NewGetMarginInterestHistoryRequest() + req.Asset(asset) + + if startTime != nil { + req.StartTime(*startTime) + } + + if endTime != nil { + req.EndTime(*endTime) + } + + if e.MarginSettings.IsIsolatedMargin { + req.IsolatedSymbol(e.MarginSettings.IsolatedMarginSymbol) + } + + _, err := req.Do(ctx) + return nil, err +} diff --git a/pkg/types/margin.go b/pkg/types/margin.go index dde7705148..3739ad2c80 100644 --- a/pkg/types/margin.go +++ b/pkg/types/margin.go @@ -2,6 +2,7 @@ package types import ( "context" + "time" "github.com/c9s/bbgo/pkg/fixedpoint" ) @@ -98,10 +99,10 @@ type MarginLiquidationRecord struct { // MarginHistory provides the service of querying loan history and repay history type MarginHistory interface { - QueryLoanHistory() ([]MarginLoanRecord, error) - QueryRepayHistory() ([]MarginRepayRecord, error) - QueryLiquidationHistory() ([]MarginLiquidationRecord, error) - QueryInterestHistory() ([]MarginInterest, error) + QueryLoanHistory(ctx context.Context, asset string, startTime, endTime *time.Time) ([]MarginLoanRecord, error) + QueryRepayHistory(ctx context.Context, asset string, startTime, endTime *time.Time) ([]MarginRepayRecord, error) + QueryLiquidationHistory(ctx context.Context, startTime, endTime *time.Time) ([]MarginLiquidationRecord, error) + QueryInterestHistory(ctx context.Context, asset string, startTime, endTime *time.Time) ([]MarginInterest, error) } type MarginSettings struct {