diff --git a/client.go b/client.go index 972f8bc8..43b67970 100644 --- a/client.go +++ b/client.go @@ -578,24 +578,23 @@ func (c *Client) getTimestamp() int64 { func (c *Client) updateSyncTimeDelta( remoteServerTimeRaw string, localTimestampNanoseconds int64, -) error { +) (int64, error) { remoteServerTimeNS, err := strconv.ParseInt(remoteServerTimeRaw, 10, 64) if err != nil { - return fmt.Errorf("parse server time: %w", err) + return 0, fmt.Errorf("parse server time: %w", err) } - c.syncTimeDeltaNanoSeconds = localTimestampNanoseconds - remoteServerTimeNS - return nil + return c.syncTimeDeltaNanoSeconds, nil } -func (c *Client) SyncServerTime() error { +func (c *Client) SyncServerTime() (int64, error) { r, err := c.NewTimeService().GetServerTime() if err != nil { - return fmt.Errorf("get server time: %w", err) + return 0, fmt.Errorf("get server time: %w", err) } if r.Result.TimeNano == "" { - return errors.New("server time is empty") + return 0, errors.New("server time is empty") } return c.updateSyncTimeDelta(r.Result.TimeNano, time.Now().UnixNano()) diff --git a/client_web_socket.go b/client_web_socket.go index 37ac60bb..7f0c3d5f 100644 --- a/client_web_socket.go +++ b/client_web_socket.go @@ -36,12 +36,14 @@ type WebSocketClient struct { baseURL string key string secret string - + // RSA signing support useRSA bool privateKey *rsa.PrivateKey - - dialer *websocket.Dialer + + dialer *websocket.Dialer + + syncTimeDeltaNanoSeconds int64 } func (c *WebSocketClient) debugf(format string, v ...interface{}) { @@ -87,13 +89,13 @@ func (c *WebSocketClient) WithAuth(key string, secret string) *WebSocketClient { func (c *WebSocketClient) WithAuthRSA(key string, privateKeyPEM string) *WebSocketClient { c.key = key c.useRSA = true - + // Parse the private key block, _ := pem.Decode([]byte(privateKeyPEM)) if block == nil { panic("failed to parse PEM block containing the private key") } - + privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { // Try PKCS8 format if PKCS1 fails @@ -107,9 +109,9 @@ func (c *WebSocketClient) WithAuthRSA(key string, privateKeyPEM string) *WebSock panic("not an RSA private key") } } - + c.privateKey = privateKey - + return c } @@ -132,14 +134,24 @@ func (c *WebSocketClient) hasAuth() bool { return c.key != "" && c.secret != "" } +// getTimestamp returns the current timestamp in milliseconds +func (c *WebSocketClient) getTimestamp() int64 { + return (time.Now().UnixNano() - c.syncTimeDeltaNanoSeconds) / 1000000 +} + +// UpdateTimeDelta : +func (c *WebSocketClient) UpdateTimeDelta(timeDelta int64) { + c.syncTimeDeltaNanoSeconds = timeDelta +} + func (c *WebSocketClient) buildAuthParam() ([]byte, error) { if !c.hasAuth() { return nil, fmt.Errorf("this is private endpoint, please set api key and secret") } - expires := time.Now().Unix()*1000 + 10000 + expires := c.getTimestamp() + 10000 req := fmt.Sprintf("GET/realtime%d", expires) - + var signature string if c.useRSA { // For RSA signatures @@ -157,7 +169,7 @@ func (c *WebSocketClient) buildAuthParam() ([]byte, error) { } signature = hex.EncodeToString(s.Sum(nil)) } - + param := struct { Op string `json:"op"` Args []interface{} `json:"args"` diff --git a/time_service_test.go b/time_service_test.go index 65bd0983..f1aa9a14 100644 --- a/time_service_test.go +++ b/time_service_test.go @@ -19,7 +19,7 @@ func TestUpdateSyncTimeDelta(t *testing.T) { nowTimestampMs := time.Now().UnixMilli() // when - err := c.updateSyncTimeDelta(remoteServerTimeRaw, localTimestampNanoseconds) + _, err := c.updateSyncTimeDelta(remoteServerTimeRaw, localTimestampNanoseconds) // then require.NoError(t, err) diff --git a/v5_ws_trade_order.go b/v5_ws_trade_order.go index 432f1d28..39dc16fb 100644 --- a/v5_ws_trade_order.go +++ b/v5_ws_trade_order.go @@ -3,7 +3,6 @@ package bybit import ( "encoding/json" "strconv" - "time" "github.com/google/uuid" "github.com/gorilla/websocket" @@ -11,7 +10,7 @@ import ( // CreateOrder : func (s *V5WebsocketTradeService) CreateOrder(orders []*V5CreateOrderParam) error { - timestamp := strconv.FormatInt(time.Now().UnixMilli(), 10) + timestamp := strconv.FormatInt(s.client.getTimestamp(), 10) headers := make(map[string]string) headers["X-BAPI-TIMESTAMP"] = timestamp headers["X-BAPI-RECV-WINDOW"] = "8000" @@ -39,7 +38,7 @@ func (s *V5WebsocketTradeService) CreateOrder(orders []*V5CreateOrderParam) erro } func (s *V5WebsocketTradeService) CancelOrder(orders []*V5CancelOrderParam) error { - timestamp := strconv.FormatInt(time.Now().UnixMilli(), 10) + timestamp := strconv.FormatInt(s.client.getTimestamp(), 10) headers := make(map[string]string) headers["X-BAPI-TIMESTAMP"] = timestamp headers["X-BAPI-RECV-WINDOW"] = "8000"