bybit.go.api/bybit_api_client.go

387 lines
9.2 KiB
Go
Raw Permalink Normal View History

2023-11-03 16:29:17 +02:00
package bybit_connector
2023-10-30 20:26:54 +02:00
import (
"bytes"
"context"
"crypto/hmac"
"crypto/sha256"
2023-11-05 18:33:56 +02:00
"encoding/hex"
2023-10-30 20:26:54 +02:00
"fmt"
"io"
"log"
"net/http"
"os"
2023-11-05 18:33:56 +02:00
"strconv"
2023-10-30 20:26:54 +02:00
"time"
2024-01-04 15:20:40 +02:00
2024-06-03 23:07:14 +03:00
"gitea.computernetthings.ru/yash/bybit.go.api/handlers"
2024-01-04 15:20:40 +02:00
"github.com/bitly/go-simplejson"
jsoniter "github.com/json-iterator/go"
2023-10-30 20:26:54 +02:00
)
2024-01-04 15:20:40 +02:00
var json = jsoniter.ConfigCompatibleWithStandardLibrary
2023-11-05 18:33:56 +02:00
type ServerResponse struct {
RetCode int `json:"retCode"`
RetMsg string `json:"retMsg"`
Result interface{} `json:"result"`
RetExtInfo struct{} `json:"retExtInfo"`
Time int64 `json:"time"`
}
2023-10-30 20:26:54 +02:00
// Client define API client
type Client struct {
APIKey string
2023-11-05 18:33:56 +02:00
APISecret string
2023-10-30 20:26:54 +02:00
BaseURL string
HTTPClient *http.Client
Debug bool
Logger *log.Logger
do doFunc
}
type doFunc func(req *http.Request) (*http.Response, error)
2023-11-03 16:29:17 +02:00
type ClientOption func(*Client)
// WithDebug print more details in debug mode
2023-11-03 16:29:17 +02:00
func WithDebug(debug bool) ClientOption {
return func(c *Client) {
c.Debug = debug
}
}
2023-11-05 18:33:56 +02:00
// WithBaseURL is a client option to set the base URL of the Bybit HTTP client.
2023-11-03 16:29:17 +02:00
func WithBaseURL(baseURL string) ClientOption {
return func(c *Client) {
c.BaseURL = baseURL
}
}
2023-10-30 20:26:54 +02:00
func PrettyPrint(i interface{}) string {
2024-02-22 19:19:26 +02:00
s, _ := json.MarshalIndent(i, "", " ")
2023-10-30 20:26:54 +02:00
return string(s)
}
func (c *Client) debug(format string, v ...interface{}) {
if c.Debug {
c.Logger.Printf(format, v...)
}
}
2023-11-06 18:29:28 +02:00
// FormatTimestamp formats a time into Unix timestamp in milliseconds, as requested by Binance.
func FormatTimestamp(t time.Time) int64 {
return t.UnixNano() / int64(time.Millisecond)
}
2023-11-05 23:35:56 +02:00
func GetCurrentTime() int64 {
now := time.Now()
unixNano := now.UnixNano()
timeStamp := unixNano / int64(time.Millisecond)
return timeStamp
}
2024-01-04 15:20:40 +02:00
func newJSON(data []byte) (j *simplejson.Json, err error) {
j, err = simplejson.NewJson(data)
if err != nil {
return nil, err
}
return j, nil
}
2023-11-03 16:29:17 +02:00
// NewBybitHttpClient NewClient Create client function for initialising new Bybit client
2023-11-05 18:33:56 +02:00
func NewBybitHttpClient(apiKey string, APISecret string, options ...ClientOption) *Client {
2023-11-03 16:29:17 +02:00
c := &Client{
2023-10-30 20:26:54 +02:00
APIKey: apiKey,
2023-11-05 18:33:56 +02:00
APISecret: APISecret,
BaseURL: MAINNET,
2023-10-30 20:26:54 +02:00
HTTPClient: http.DefaultClient,
Logger: log.New(os.Stderr, Name, log.LstdFlags),
}
2023-11-03 16:29:17 +02:00
// Apply the provided options
for _, opt := range options {
opt(c)
}
return c
2023-10-30 20:26:54 +02:00
}
func (c *Client) parseRequest(r *request, opts ...RequestOption) (err error) {
// set request options from user
for _, opt := range opts {
opt(r)
}
err = r.validate()
if err != nil {
return err
}
fullURL := fmt.Sprintf("%s%s", c.BaseURL, r.endpoint)
queryString := r.query.Encode()
header := http.Header{}
2023-11-05 18:33:56 +02:00
body := &bytes.Buffer{}
if r.params != nil {
body = bytes.NewBuffer(r.params)
}
2023-10-30 20:26:54 +02:00
if r.header != nil {
header = r.header.Clone()
}
header.Set("User-Agent", fmt.Sprintf("%s/%s", Name, Version))
2023-11-05 18:33:56 +02:00
2023-10-30 20:26:54 +02:00
if r.secType == secTypeSigned {
2023-11-05 23:35:56 +02:00
timeStamp := GetCurrentTime()
2023-10-30 20:26:54 +02:00
header.Set(signTypeKey, "2")
header.Set(apiRequestKey, c.APIKey)
2023-11-05 18:33:56 +02:00
header.Set(timestampKey, strconv.FormatInt(timeStamp, 10))
2023-10-30 20:26:54 +02:00
if r.recvWindow == "" {
2023-11-05 18:33:56 +02:00
r.recvWindow = "5000"
2023-10-30 20:26:54 +02:00
}
2023-11-05 18:33:56 +02:00
header.Set(recvWindowKey, r.recvWindow)
2023-10-30 20:26:54 +02:00
2023-11-05 18:33:56 +02:00
var signatureBase []byte
if r.method == "POST" {
header.Set("Content-Type", "application/json")
signatureBase = []byte(strconv.FormatInt(timeStamp, 10) + c.APIKey + r.recvWindow + string(r.params[:]))
} else {
signatureBase = []byte(strconv.FormatInt(timeStamp, 10) + c.APIKey + r.recvWindow + queryString)
2023-10-30 20:26:54 +02:00
}
2023-11-05 18:33:56 +02:00
hmac256 := hmac.New(sha256.New, []byte(c.APISecret))
hmac256.Write(signatureBase)
signature := hex.EncodeToString(hmac256.Sum(nil))
header.Set(signatureKey, signature)
2023-10-30 20:26:54 +02:00
}
if queryString != "" {
fullURL = fmt.Sprintf("%s?%s", fullURL, queryString)
}
2023-11-05 18:33:56 +02:00
c.debug("full url: %s, body: %s", fullURL, body)
2023-10-30 20:26:54 +02:00
r.fullURL = fullURL
r.body = body
2023-11-05 18:33:56 +02:00
r.header = header
2023-10-30 20:26:54 +02:00
return nil
}
func (c *Client) callAPI(ctx context.Context, r *request, opts ...RequestOption) (data []byte, err error) {
err = c.parseRequest(r, opts...)
2024-01-04 15:20:40 +02:00
if err != nil {
return nil, err
}
2023-10-30 20:26:54 +02:00
req, err := http.NewRequest(r.method, r.fullURL, r.body)
if err != nil {
return []byte{}, err
}
req = req.WithContext(ctx)
req.Header = r.header
2023-11-03 16:29:17 +02:00
c.debug("request: %#v", req)
2023-10-30 20:26:54 +02:00
f := c.do
if f == nil {
f = c.HTTPClient.Do
}
res, err := f(req)
if err != nil {
return []byte{}, err
}
data, err = io.ReadAll(res.Body)
if err != nil {
return []byte{}, err
}
defer func() {
cerr := res.Body.Close()
// Only overwrite the returned error if the original error was nil and an
// error occurred while closing the body.
if err == nil && cerr != nil {
err = cerr
}
}()
2023-11-03 16:29:17 +02:00
c.debug("response: %#v", res)
2023-10-30 20:26:54 +02:00
c.debug("response body: %s", string(data))
2023-11-03 16:29:17 +02:00
c.debug("response status code: %d", res.StatusCode)
2023-10-30 20:26:54 +02:00
if res.StatusCode >= http.StatusBadRequest {
2024-06-03 23:07:14 +03:00
apiErr := new(handlers.APIError)
2023-10-30 20:26:54 +02:00
e := json.Unmarshal(data, apiErr)
if e != nil {
2023-11-03 16:29:17 +02:00
c.debug("failed to unmarshal json: %s", e)
2023-10-30 20:26:54 +02:00
}
return nil, apiErr
}
return data, nil
}
2024-01-04 15:20:40 +02:00
func (c *Client) NewInstrumentsInfoService() *InstrumentsInfoService {
return &InstrumentsInfoService{c: c}
2023-11-05 18:33:56 +02:00
}
2024-01-04 15:20:40 +02:00
// NewMarketKlineService Market Kline Endpoints
func (c *Client) NewMarketKlineService() *MarketKlinesService {
return &MarketKlinesService{c: c}
2023-11-05 23:35:56 +02:00
}
2024-01-04 15:20:40 +02:00
// NewMarketMarkPriceKlineService Market Mark Price Kline Endpoints
func (c *Client) NewMarketMarkPriceKlineService() *MarketMarkPriceKlineService {
return &MarketMarkPriceKlineService{c: c}
2023-11-05 23:35:56 +02:00
}
2024-01-04 15:20:40 +02:00
// NewMarketIndexPriceKlineService Market Index Price Kline Endpoints
func (c *Client) NewMarketIndexPriceKlineService() *MarketIndexPriceKlineService {
return &MarketIndexPriceKlineService{c: c}
}
// NewMarketPremiumIndexPriceKlineService Market Premium Index Price Kline Endpoints
func (c *Client) NewMarketPremiumIndexPriceKlineService() *MarketPremiumIndexPriceKlineService {
return &MarketPremiumIndexPriceKlineService{c: c}
}
func (c *Client) NewOrderBookService() *MarketOrderBookService {
return &MarketOrderBookService{c: c}
}
func (c *Client) NewTickersService() *MarketTickersService {
return &MarketTickersService{c: c}
}
func (c *Client) NewFundingTatesService() *MarketFundingRatesService {
return &MarketFundingRatesService{c: c}
}
func (c *Client) NewGetPublicRecentTradesService() *GetPublicRecentTradesService {
return &GetPublicRecentTradesService{c: c}
}
// GetOpenInterestsServicdde
func (c *Client) NewGetOpenInterestsService() *GetOpenInterestsService {
return &GetOpenInterestsService{c: c}
}
// GetHistoricalVolatilityService
func (c *Client) NewGetHistoricalVolatilityService() *GetHistoricalVolatilityService {
return &GetHistoricalVolatilityService{c: c}
}
// GetInsuranceInfoService
func (c *Client) NewGetInsuranceInfoService() *GetInsuranceInfoService {
return &GetInsuranceInfoService{c: c}
}
// GetRiskLimitService
func (c *Client) NewGetRiskLimitService() *GetRiskLimitService {
return &GetRiskLimitService{c: c}
}
// GetDeliveryPriceService
func (c *Client) NewGetDeliveryPriceService() *GetDeliveryPriceService {
return &GetDeliveryPriceService{c: c}
}
// GetMarketLSRatioService
func (c *Client) NewGetMarketLSRatioService() *GetMarketLSRatioService {
return &GetMarketLSRatioService{c: c}
}
// GetServerTimeService
func (c *Client) NewGetServerTimeService() *GetServerTimeService {
return &GetServerTimeService{c: c}
2023-11-05 23:35:56 +02:00
}
2023-11-05 18:33:56 +02:00
// NewPlaceOrderService Trade Endpoints
func (c *Client) NewPlaceOrderService(category, symbol, side, orderType, qty string) *Order {
return &Order{
c: c,
category: category,
symbol: symbol,
side: side,
orderType: orderType,
qty: qty,
}
}
2023-11-05 23:35:56 +02:00
2023-11-06 00:42:17 +02:00
func (c *Client) NewTradeService(params map[string]interface{}) *TradeClient {
return &TradeClient{
2023-11-05 23:35:56 +02:00
c: c,
params: params,
}
}
2023-11-06 00:42:17 +02:00
func (c *Client) NewPositionService(params map[string]interface{}) *PositionClient {
return &PositionClient{
c: c,
params: params,
}
}
2023-11-06 00:55:41 +02:00
func (c *Client) NewPreUpgradeService(params map[string]interface{}) *PreUpgradeClient {
return &PreUpgradeClient{
c: c,
params: params,
}
}
2023-11-06 01:16:08 +02:00
func (c *Client) NewAccountService(params map[string]interface{}) *AccountClient {
return &AccountClient{
c: c,
params: params,
}
}
func (c *Client) NewAccountServiceNoParams() *AccountClient {
return &AccountClient{
c: c,
}
}
2023-11-06 01:44:54 +02:00
func (c *Client) NewAssetService(params map[string]interface{}) *AssetClient {
return &AssetClient{
2023-11-06 02:15:59 +02:00
c: c,
params: params,
2023-11-06 01:44:54 +02:00
}
}
2023-11-06 02:08:54 +02:00
func (c *Client) NewUserService(params map[string]interface{}) *UserServiceClient {
return &UserServiceClient{
2023-11-06 02:15:59 +02:00
c: c,
params: params,
2023-11-06 02:08:54 +02:00
}
}
2023-12-10 16:25:04 +02:00
func (c *Client) NewUserServiceNoParams() *UserServiceClient {
return &UserServiceClient{
c: c,
}
}
2023-11-06 02:08:54 +02:00
func (c *Client) NewBrokerService(params map[string]interface{}) *BrokerServiceClient {
return &BrokerServiceClient{
2023-11-06 02:15:59 +02:00
c: c,
params: params,
2023-11-06 02:08:54 +02:00
}
}
func (c *Client) NewLendingService(params map[string]interface{}) *LendingServiceClient {
2023-11-06 02:15:59 +02:00
return &LendingServiceClient{
c: c,
params: params,
}
}
func (c *Client) NewLendingServiceNoParams() *LendingServiceClient {
2023-11-06 02:08:54 +02:00
return &LendingServiceClient{
c: c,
}
}
2023-11-06 13:40:09 +02:00
func (c *Client) NewSpotLeverageService(params map[string]interface{}) *SpotLeverageClient {
return &SpotLeverageClient{
c: c,
params: params,
}
}
func (c *Client) NewSpotMarginDataService(params map[string]interface{}, isUta bool) *SpotMarginClient {
return &SpotMarginClient{
c: c,
isUta: isUta,
params: params,
}
}