Coin-M Futures kline endpoint 'startTime' parameter almost NEVER considered, possibly bugged.

I’m running into what seems to be a bug, and scoured the forum to find a similar issue about 1 year ago: COIN-M Futures. 'startTime' parameter doesn't apply for GET /klines endpoint

It seems ‘startTime’ parameter doesn’t apply for COIN-M futures, only ‘endTime’ works properly

To which the team was able to respond:

[aisling][Feb '21] Hello, at the moment it’s expected for dapi/v1/klines with startTime to return the data closest to endTime, although thanks for brining to our attention that the documentation is not in sync, we’ll update it.

I decided to investigate the updated documentation for klines on that endpoint and came across the current documentation:

  • The difference between startTime and endTime can only be up to 200 days
  • Between startTime and endTime, the most recent limit data from endTime will be returned:
    • If startTime and endTime are not sent, current timestamp will be set as endTime, and the most recent data will be returned.
    • If startTime is sent only, the timestamp of 200 days after startTime will be set as endTime(up to the current time)
    • If endTime is sent only, the timestamp of 200 days before endTime will be set as startTime

And it would seem that the first portion of…

Between startTime and endTime, the most recent limit data from endTime will be returned

Is potentially incorrectly implemented, as startTime is almost NEVER considered during API calls, even when it may be expected.

This makes historical requests almost ENTIRELY dependent on endTime and much more difficult, with startTime being nearly useless.

I will showcase this using the above documentation as a guide.

There are 4 Test Cases. The baseurl of https://testnet.binancefuture.com/dapi/v1/klines will be used.

Test Case 1

Between startTime and endTime, the most recent limit data from endTime will be returned

My variables here will be:

?symbol=BTCUSD_PERP&interval=1m&startTime=1667528549990&endTime=1668133349990&limit=499

Here we will see that the earliest data point we receive is at time 1668103440000, which DOES confirm what the documentation says (this data is the most recent when doing endTime - limit) , even though this response is not how the other APIs function.

Test Case 2

If startTime and endTime are not sent, current timestamp will be set as endTime, and the most recent data will be returned.

My variables here will be:

?symbol=BTCUSD_PERP&interval=1m&limit=499

At the time of this request, my epoch was roughly 1668152049000, and the first data response from my request was at 1668122160000, which is roughly endTime - limit. This DOES confirm the documentation.

Test Case 3

If startTime is sent only, the timestamp of 200 days after startTime will be set as endTime(up to the current time)

My epoch as of a few moments ago was 1668152366000, and subtracting 201 days in milliseconds (17366400000) from that yields 1650785966000. Therefore, my variables will be:

?symbol=BTCUSD_PERP&interval=1m&startTime=1650785966000&limit=499

Here, the earliest data point we receive is at time 1668036060000, roughly 1 day ago, which DOES confirm that 200 days were added to startTime to calculate endTime, HOWEVER, now startTime is completely ignored, and this request functions as both Test Case 1 and Test Case 2.

Test Case 4

If endTime is sent only, the timestamp of 200 days before endTime will be set as startTime

My epoch in milliseconds a few moments prior to this sentence was 1668153135000, and 200 days prior to this time would be 1650873135000. We are expecting response data to begin near startTime, since it isn’t mentioned that this case will return data the same way as Test Case 1, Test Case 2, or for some reason, Test Case 3 as well. My variables will be:

?symbol=BTCUSD_PERP&interval=1m&endTime=1668153135000&limit=499

To which, the earliest response received is around 1668123240000, which is only 8 hours prior to this request, and is, again, following similar logic of endTime - limit.

With this logic, even if we make the interval larger at, say, 1w, and set the endTime, the sole purpose of setting startTime is to get < 200 days worth of data.

To summarize:

There are only 2 situations where startTime is considered:

  • If endTime - limit < startTime, send first data point where endTime - data’s timestamp >= startTime
    or
  • To calculate endTime, and then ignore startTime (unless the above situation comes into play)

Overall, requesting historical data via kline endpoint on COIN-M Futures API is:

  • Quite literally, backwards in comparison to the SPOT API kline and the USD-M Futures API kline endpoints
  • Much more difficult, as the documentation doesn’t seem to clarify whether endTime - limit will always be the prioritized response format, or if startTime should be considered the start of your response during Test Case 3 + 4

Therefore, my question is, does the documentation really mean ALL responses will consider endTime - limit to be the standard? Or is this a bug, and startTime should be the start of the data during the above mentioned situations?

Hello, thank you ofr the detailed analysis feedback.

It’s not a bug, the endpoint’s response is following the technical requirements. It might be a bit confusing at first reading the conditions for the startTime and endTime, however for Test Case 3 it does follows what’s mentioned in the documentation, i.e:

For ?symbol=BTCUSD_PERP&interval=1m&startTime=1650785966000&limit=499,
the earliest data point we receive is at time 1668036060000, roughly 1 day ago, which DOES confirm that 200 days were added to startTime to calculate endTime .

Given the system has the startTime and endTime now, it will apply the general condition:

Between startTime and endTime , the most recent limit data from endTime will be returned: