diff --git a/cmd/exchange_wrapper_issues/main.go b/cmd/exchange_wrapper_issues/main.go index ab1e5089..64ea0c9b 100644 --- a/cmd/exchange_wrapper_issues/main.go +++ b/cmd/exchange_wrapper_issues/main.go @@ -480,6 +480,20 @@ func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config) SentParams: jsonifyInterface([]interface{}{p, assetTypes[i], startTime, endTime, kline.OneDay}), }) + var getServerTimeResponse time.Time + getServerTimeResponse, err = e.GetServerTime(context.TODO(), assetTypes[i]) + msg = "" + if err != nil { + msg = err.Error() + responseContainer.ErrorCount++ + } + responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{ + Function: "GetServerTime", + Error: msg, + Response: getServerTimeResponse, + SentParams: jsonifyInterface([]interface{}{assetTypes[i]}), + }) + err = e.UpdateOrderExecutionLimits(context.TODO(), assetTypes[i]) msg = "" if err != nil { diff --git a/exchanges/binance/binance_test.go b/exchanges/binance/binance_test.go index f6b18f44..ee0585d2 100644 --- a/exchanges/binance/binance_test.go +++ b/exchanges/binance/binance_test.go @@ -70,6 +70,41 @@ func TestUServerTime(t *testing.T) { } } +func TestWrapperGetServerTime(t *testing.T) { + t.Parallel() + _, err := b.GetServerTime(context.Background(), asset.Empty) + if !errors.Is(err, asset.ErrNotSupported) { + t.Fatalf("received: '%v' but expected: '%v'", err, asset.ErrNotSupported) + } + + st, err := b.GetServerTime(context.Background(), asset.Spot) + if !errors.Is(err, nil) { + t.Fatalf("received: '%v' but expected: '%v'", err, nil) + } + + if st.IsZero() { + t.Fatal("expected a time") + } + + st, err = b.GetServerTime(context.Background(), asset.USDTMarginedFutures) + if !errors.Is(err, nil) { + t.Fatalf("received: '%v' but expected: '%v'", err, nil) + } + + if st.IsZero() { + t.Fatal("expected a time") + } + + st, err = b.GetServerTime(context.Background(), asset.CoinMarginedFutures) + if !errors.Is(err, nil) { + t.Fatalf("received: '%v' but expected: '%v'", err, nil) + } + + if st.IsZero() { + t.Fatal("expected a time") + } +} + func TestParseSAPITime(t *testing.T) { t.Parallel() tm, err := time.Parse(binanceSAPITimeLayout, "2021-05-27 03:56:46") diff --git a/exchanges/binance/binance_ufutures.go b/exchanges/binance/binance_ufutures.go index e812f974..963f2dbe 100644 --- a/exchanges/binance/binance_ufutures.go +++ b/exchanges/binance/binance_ufutures.go @@ -74,7 +74,7 @@ func (b *Binance) UServerTime(ctx context.Context) (time.Time, error) { if err != nil { return time.Time{}, err } - return time.Unix(0, data.ServerTime*1000000), nil + return time.UnixMilli(data.ServerTime), nil } // UExchangeInfo stores usdt margined futures data diff --git a/exchanges/binance/binance_wrapper.go b/exchanges/binance/binance_wrapper.go index 6fbc4e6b..9eee7eeb 100644 --- a/exchanges/binance/binance_wrapper.go +++ b/exchanges/binance/binance_wrapper.go @@ -1882,3 +1882,24 @@ func (b *Binance) formatUSDTMarginedFuturesPair(p currency.Pair, pairFmt currenc } return p.Format(currency.UnderscoreDelimiter, pairFmt.Uppercase) } + +// GetServerTime returns the current exchange server time. +func (b *Binance) GetServerTime(ctx context.Context, ai asset.Item) (time.Time, error) { + switch ai { + case asset.USDTMarginedFutures: + return b.UServerTime(ctx) + case asset.Spot: + info, err := b.GetExchangeInfo(ctx) + if err != nil { + return time.Time{}, err + } + return info.Servertime, nil + case asset.CoinMarginedFutures: + info, err := b.FuturesExchangeInfo(ctx) + if err != nil { + return time.Time{}, err + } + return time.UnixMilli(info.ServerTime), nil + } + return time.Time{}, fmt.Errorf("%s %w", ai, asset.ErrNotSupported) +} diff --git a/exchanges/btcmarkets/btcmarkets.go b/exchanges/btcmarkets/btcmarkets.go index c6d2031b..036b8ee9 100644 --- a/exchanges/btcmarkets/btcmarkets.go +++ b/exchanges/btcmarkets/btcmarkets.go @@ -270,8 +270,8 @@ func (b *BTCMarkets) GetMultipleOrderbooks(ctx context.Context, marketIDs []stri return orderbooks, nil } -// GetServerTime gets time from btcmarkets -func (b *BTCMarkets) GetServerTime(ctx context.Context) (time.Time, error) { +// GetCurrentServerTime gets time from btcmarkets +func (b *BTCMarkets) GetCurrentServerTime(ctx context.Context) (time.Time, error) { var resp TimeResp return resp.Time, b.SendHTTPRequest(ctx, btcMarketsAPIURL+btcMarketsAPIVersion+btcMarketsGetTime, &resp) diff --git a/exchanges/btcmarkets/btcmarkets_test.go b/exchanges/btcmarkets/btcmarkets_test.go index 7a476d47..603f8e65 100644 --- a/exchanges/btcmarkets/btcmarkets_test.go +++ b/exchanges/btcmarkets/btcmarkets_test.go @@ -142,14 +142,26 @@ func TestGetMultipleOrderbooks(t *testing.T) { } } -func TestGetServerTime(t *testing.T) { +func TestGetCurrentServerTime(t *testing.T) { t.Parallel() - _, err := b.GetServerTime(context.Background()) + _, err := b.GetCurrentServerTime(context.Background()) if err != nil { t.Error(err) } } +func TestWrapperGetServerTime(t *testing.T) { + t.Parallel() + st, err := b.GetServerTime(context.Background(), asset.Spot) + if !errors.Is(err, nil) { + t.Fatalf("received: '%v' but expected: '%v'", err, nil) + } + + if st.IsZero() { + t.Fatal("expected a time") + } +} + func TestGetAccountBalance(t *testing.T) { t.Parallel() if !areTestAPIKeysSet() { diff --git a/exchanges/btcmarkets/btcmarkets_wrapper.go b/exchanges/btcmarkets/btcmarkets_wrapper.go index 45167eb9..a98aff34 100644 --- a/exchanges/btcmarkets/btcmarkets_wrapper.go +++ b/exchanges/btcmarkets/btcmarkets_wrapper.go @@ -1086,3 +1086,8 @@ func (b *BTCMarkets) GetHistoricCandlesExtended(ctx context.Context, p currency. ret.SortCandlesByTimestamp(false) return ret, nil } + +// GetServerTime returns the current exchange server time. +func (b *BTCMarkets) GetServerTime(ctx context.Context, _ asset.Item) (time.Time, error) { + return b.GetCurrentServerTime(ctx) +} diff --git a/exchanges/btse/btse.go b/exchanges/btse/btse.go index 915fc679..80480844 100644 --- a/exchanges/btse/btse.go +++ b/exchanges/btse/btse.go @@ -162,8 +162,8 @@ func (b *BTSE) GetPrice(ctx context.Context, symbol string) (Price, error) { return p, b.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, path, &p, true, queryFunc) } -// GetServerTime returns the exchanges server time -func (b *BTSE) GetServerTime(ctx context.Context) (*ServerTime, error) { +// GetCurrentServerTime returns the exchanges server time +func (b *BTSE) GetCurrentServerTime(ctx context.Context) (*ServerTime, error) { var s ServerTime return &s, b.SendHTTPRequest(ctx, exchange.RestSpot, http.MethodGet, btseTime, &s, true, queryFunc) } diff --git a/exchanges/btse/btse_test.go b/exchanges/btse/btse_test.go index da6f4fbc..6fcc803d 100644 --- a/exchanges/btse/btse_test.go +++ b/exchanges/btse/btse_test.go @@ -291,14 +291,26 @@ func TestUpdateTickers(t *testing.T) { } } -func TestGetServerTime(t *testing.T) { +func TestGetCurrentServerTime(t *testing.T) { t.Parallel() - _, err := b.GetServerTime(context.Background()) + _, err := b.GetCurrentServerTime(context.Background()) if err != nil { t.Error(err) } } +func TestWrapperGetServerTime(t *testing.T) { + t.Parallel() + st, err := b.GetServerTime(context.Background(), asset.Spot) + if !errors.Is(err, nil) { + t.Fatalf("received: '%v' but expected: '%v'", err, nil) + } + + if st.IsZero() { + t.Fatal("expected a time") + } +} + func TestGetWalletInformation(t *testing.T) { t.Parallel() if !areTestAPIKeysSet() { diff --git a/exchanges/btse/btse_wrapper.go b/exchanges/btse/btse_wrapper.go index 3d8b8eb4..08393923 100644 --- a/exchanges/btse/btse_wrapper.go +++ b/exchanges/btse/btse_wrapper.go @@ -1106,3 +1106,12 @@ func OrderSizeLimits(pair string) (limits OrderSizeLimit, found bool) { val, ok := resp.(OrderSizeLimit) return val, ok } + +// GetServerTime returns the current exchange server time. +func (b *BTSE) GetServerTime(ctx context.Context, _ asset.Item) (time.Time, error) { + st, err := b.GetCurrentServerTime(ctx) + if err != nil { + return time.Time{}, err + } + return st.ISO, nil +} diff --git a/exchanges/coinbasepro/coinbasepro.go b/exchanges/coinbasepro/coinbasepro.go index fa9befb7..9bdf976b 100644 --- a/exchanges/coinbasepro/coinbasepro.go +++ b/exchanges/coinbasepro/coinbasepro.go @@ -273,10 +273,9 @@ func (c *CoinbasePro) GetCurrencies(ctx context.Context) ([]Currency, error) { return currencies, c.SendHTTPRequest(ctx, exchange.RestSpot, coinbaseproCurrencies, ¤cies) } -// GetServerTime returns the API server time -func (c *CoinbasePro) GetServerTime(ctx context.Context) (ServerTime, error) { +// GetCurrentServerTime returns the API server time +func (c *CoinbasePro) GetCurrentServerTime(ctx context.Context) (ServerTime, error) { serverTime := ServerTime{} - return serverTime, c.SendHTTPRequest(ctx, exchange.RestSpot, coinbaseproTime, &serverTime) } diff --git a/exchanges/coinbasepro/coinbasepro_test.go b/exchanges/coinbasepro/coinbasepro_test.go index 35d7de8c..d1efd4a9 100644 --- a/exchanges/coinbasepro/coinbasepro_test.go +++ b/exchanges/coinbasepro/coinbasepro_test.go @@ -144,13 +144,25 @@ func TestGetCurrencies(t *testing.T) { } } -func TestGetServerTime(t *testing.T) { - _, err := c.GetServerTime(context.Background()) +func TestGetCurrentServerTime(t *testing.T) { + _, err := c.GetCurrentServerTime(context.Background()) if err != nil { t.Error("GetServerTime() error", err) } } +func TestWrapperGetServerTime(t *testing.T) { + t.Parallel() + st, err := c.GetServerTime(context.Background(), asset.Spot) + if !errors.Is(err, nil) { + t.Fatalf("received: '%v' but expected: '%v'", err, nil) + } + + if st.IsZero() { + t.Fatal("expected a time") + } +} + func TestAuthRequests(t *testing.T) { if !areTestAPIKeysSet() { t.Skip("API keys not set, skipping test") diff --git a/exchanges/coinbasepro/coinbasepro_wrapper.go b/exchanges/coinbasepro/coinbasepro_wrapper.go index e93b407f..6b705f84 100644 --- a/exchanges/coinbasepro/coinbasepro_wrapper.go +++ b/exchanges/coinbasepro/coinbasepro_wrapper.go @@ -1019,3 +1019,12 @@ func (c *CoinbasePro) ValidateCredentials(ctx context.Context, assetType asset.I _, err := c.UpdateAccountInfo(ctx, assetType) return c.CheckTransientError(err) } + +// GetServerTime returns the current exchange server time. +func (c *CoinbasePro) GetServerTime(ctx context.Context, _ asset.Item) (time.Time, error) { + st, err := c.GetCurrentServerTime(ctx) + if err != nil { + return time.Time{}, err + } + return st.ISO, nil +} diff --git a/exchanges/exchange.go b/exchanges/exchange.go index 79c15608..0cda9628 100644 --- a/exchanges/exchange.go +++ b/exchanges/exchange.go @@ -1306,3 +1306,8 @@ func (b *Base) GetFuturesPositions(context.Context, asset.Item, currency.Pair, t func (b *Base) HasAssetTypeAccountSegregation() bool { return b.Features.Supports.RESTCapabilities.HasAssetTypeAccountSegregation } + +// GetServerTime returns the current exchange server time. +func (b *Base) GetServerTime(_ context.Context, _ asset.Item) (time.Time, error) { + return time.Time{}, common.ErrNotYetImplemented +} diff --git a/exchanges/exchange_test.go b/exchanges/exchange_test.go index bf9fab49..1081b7f3 100644 --- a/exchanges/exchange_test.go +++ b/exchanges/exchange_test.go @@ -2320,3 +2320,11 @@ func TestSetFillsFeedStatus(t *testing.T) { t.Error("expected false") } } + +func TestGetServerTime(t *testing.T) { + t.Parallel() + var b Base + if _, err := b.GetServerTime(context.Background(), asset.Spot); !errors.Is(err, common.ErrNotYetImplemented) { + t.Errorf("received: %v, expected: %v", err, common.ErrNotYetImplemented) + } +} diff --git a/exchanges/huobi/huobi.go b/exchanges/huobi/huobi.go index ff305b22..c2a6c7cd 100644 --- a/exchanges/huobi/huobi.go +++ b/exchanges/huobi/huobi.go @@ -324,20 +324,17 @@ func (h *HUOBI) GetCurrenciesIncludingChains(ctx context.Context, curr currency. return resp.Data, nil } -// GetTimestamp returns the Huobi server time -func (h *HUOBI) GetTimestamp(ctx context.Context) (int64, error) { - type response struct { +// GetCurrentServerTime returns the Huobi server time +func (h *HUOBI) GetCurrentServerTime(ctx context.Context) (time.Time, error) { + var result struct { Response Timestamp int64 `json:"data"` } - - var result response - err := h.SendHTTPRequest(ctx, exchange.RestSpot, "/v"+huobiAPIVersion+"/"+huobiTimestamp, &result) if result.ErrorMessage != "" { - return 0, errors.New(result.ErrorMessage) + return time.Time{}, errors.New(result.ErrorMessage) } - return result.Timestamp, err + return time.UnixMilli(result.Timestamp), err } // GetAccounts returns the Huobi user accounts diff --git a/exchanges/huobi/huobi_test.go b/exchanges/huobi/huobi_test.go index b8a65c35..a78ae3ec 100644 --- a/exchanges/huobi/huobi_test.go +++ b/exchanges/huobi/huobi_test.go @@ -1754,10 +1754,26 @@ func TestGetTicker(t *testing.T) { func TestGetTimestamp(t *testing.T) { t.Parallel() - _, err := h.GetTimestamp(context.Background()) + st, err := h.GetCurrentServerTime(context.Background()) if err != nil { t.Errorf("Huobi TestGetTimestamp: %s", err) } + + if st.IsZero() { + t.Fatal("expected a time") + } +} + +func TestWrapperGetServerTime(t *testing.T) { + t.Parallel() + st, err := h.GetServerTime(context.Background(), asset.Spot) + if !errors.Is(err, nil) { + t.Fatalf("received: '%v' but expected: '%v'", err, nil) + } + + if st.IsZero() { + t.Fatal("expected a time") + } } func TestGetAccounts(t *testing.T) { diff --git a/exchanges/huobi/huobi_wrapper.go b/exchanges/huobi/huobi_wrapper.go index 8267272c..7ebe733d 100644 --- a/exchanges/huobi/huobi_wrapper.go +++ b/exchanges/huobi/huobi_wrapper.go @@ -1844,3 +1844,8 @@ func (h *HUOBI) GetAvailableTransferChains(ctx context.Context, cryptocurrency c } return availableChains, nil } + +// GetServerTime returns the current exchange server time. +func (h *HUOBI) GetServerTime(ctx context.Context, _ asset.Item) (time.Time, error) { + return h.GetCurrentServerTime(ctx) +} diff --git a/exchanges/interfaces.go b/exchanges/interfaces.go index c2b2ca33..c8c23bb1 100644 --- a/exchanges/interfaces.go +++ b/exchanges/interfaces.go @@ -78,6 +78,7 @@ type IBotExchange interface { GetHistoricCandlesExtended(ctx context.Context, p currency.Pair, a asset.Item, timeStart, timeEnd time.Time, interval kline.Interval) (kline.Item, error) DisableRateLimiter() error EnableRateLimiter() error + GetServerTime(ctx context.Context, ai asset.Item) (time.Time, error) CurrencyStateManagement order.PNLCalculation diff --git a/exchanges/kraken/kraken.go b/exchanges/kraken/kraken.go index ba495013..504ed557 100644 --- a/exchanges/kraken/kraken.go +++ b/exchanges/kraken/kraken.go @@ -37,8 +37,8 @@ type Kraken struct { wsRequestMtx sync.Mutex } -// GetServerTime returns current server time -func (k *Kraken) GetServerTime(ctx context.Context) (TimeResponse, error) { +// GetCurrentServerTime returns current server time +func (k *Kraken) GetCurrentServerTime(ctx context.Context) (TimeResponse, error) { path := fmt.Sprintf("/%s/public/%s", krakenAPIVersion, krakenServerTime) var response struct { diff --git a/exchanges/kraken/kraken_test.go b/exchanges/kraken/kraken_test.go index fb3dc0b7..43140648 100644 --- a/exchanges/kraken/kraken_test.go +++ b/exchanges/kraken/kraken_test.go @@ -75,11 +75,23 @@ func TestStart(t *testing.T) { testWg.Wait() } -func TestGetServerTime(t *testing.T) { +func TestGetCurrentServerTime(t *testing.T) { t.Parallel() - _, err := k.GetServerTime(context.Background()) + _, err := k.GetCurrentServerTime(context.Background()) if err != nil { - t.Error("GetServerTime() error", err) + t.Error("GetCurrentServerTime() error", err) + } +} + +func TestWrapperGetServerTime(t *testing.T) { + t.Parallel() + st, err := k.GetServerTime(context.Background(), asset.Spot) + if !errors.Is(err, nil) { + t.Fatalf("received: '%v' but expected: '%v'", err, nil) + } + + if st.IsZero() { + t.Fatal("expected a time") } } diff --git a/exchanges/kraken/kraken_wrapper.go b/exchanges/kraken/kraken_wrapper.go index 08e520f3..70fc9817 100644 --- a/exchanges/kraken/kraken_wrapper.go +++ b/exchanges/kraken/kraken_wrapper.go @@ -1565,3 +1565,12 @@ func (k *Kraken) GetAvailableTransferChains(ctx context.Context, cryptocurrency } return availableChains, nil } + +// GetServerTime returns the current exchange server time. +func (k *Kraken) GetServerTime(ctx context.Context, _ asset.Item) (time.Time, error) { + st, err := k.GetCurrentServerTime(ctx) + if err != nil { + return time.Time{}, err + } + return time.Parse("Mon, 02 Jan 06 15:04:05 -0700", st.Rfc1123) +} diff --git a/exchanges/yobit/yobit_test.go b/exchanges/yobit/yobit_test.go index 231ed88e..c7cfeb6e 100644 --- a/exchanges/yobit/yobit_test.go +++ b/exchanges/yobit/yobit_test.go @@ -570,3 +570,15 @@ func TestUpdateTickers(t *testing.T) { t.Error(err) } } + +func TestWrapperGetServerTime(t *testing.T) { + t.Parallel() + st, err := y.GetServerTime(context.Background(), asset.Spot) + if !errors.Is(err, nil) { + t.Fatalf("received: '%v' but expected: '%v'", err, nil) + } + + if st.IsZero() { + t.Fatal("expected a time") + } +} diff --git a/exchanges/yobit/yobit_wrapper.go b/exchanges/yobit/yobit_wrapper.go index 5f5f4953..25ade3a5 100644 --- a/exchanges/yobit/yobit_wrapper.go +++ b/exchanges/yobit/yobit_wrapper.go @@ -698,3 +698,12 @@ func (y *Yobit) GetHistoricCandles(ctx context.Context, pair currency.Pair, a as func (y *Yobit) GetHistoricCandlesExtended(ctx context.Context, pair currency.Pair, a asset.Item, start, end time.Time, interval kline.Interval) (kline.Item, error) { return kline.Item{}, common.ErrFunctionNotSupported } + +// GetServerTime returns the current exchange server time. +func (y *Yobit) GetServerTime(ctx context.Context, _ asset.Item) (time.Time, error) { + info, err := y.GetInfo(ctx) + if err != nil { + return time.Time{}, err + } + return time.Unix(info.ServerTime, 0), nil +}