简体   繁体   中英

GDAX API - Rate limit exceeded

I get an error message saying "Rate limit exceeded" when I try to request historical data from GDAX. I use promises and setInterval to request historical price data from GDAX like this:

let promiseArray = //Array with promises
let j = 0;
let grabPrices = setInterval(() => {
    if (j === promiseArray.length) {
        //Do something when all promises have been resolved
    } 
    else {
        promiseArray[j].then(
            data => {
                //Work with data
            }
        ).catch(error => console.log('An error occurred: ' + error));
        j++;
    }
}, 1000) //I have even tried to use 10 seconds (10000) as a second argument to setInterval, but it doesn't make any difference.

FROM the official API documentation

Rate Limits When a rate limit is exceeded, a status of 429 Too Many Requests will be returned.

REST API PUBLIC ENDPOINTS We throttle public endpoints by IP: 3 requests per second, up to 6 requests per second in bursts.

When you have a promise then the request is already made so your promiseArray is an array of ongoing requests.

Let's say I have an array of urls and use fetch to get the content. Using map to map the url to a promise and give the array of promises to Promise.all :

Promise.all(
  urls.map(fetch)
).then(
  resulst=>...
);

If urls has 10 items this program will make 10 requests immediately.

You can pass the fetch function to a throttle function that will schedule fetch in such a way that it will only be called 3 times a second. The throttle function will return a promise but will not call fetch immediately.

The throttlePeriod function can be found here . If you're only going to copy paste code from that module and not import the whole module then you need the later function as well because throttlePeriod depends on it.

const fetchMaxThreePerSecond = throttlePeriod(3,1100)/*give it an extra 100*/(fetch)
Promise.all(
  urls.map(fetchMaxThreePerSecond)
).then(
  resulst=>...
);

That takes care of the throttling but if you know how Promise.all works you know that all promises reject if only one rejects. So if you have a hundred urls and 99 resolve but one rejects your .then never gets called. You will loose the 99 successful requests.

You could pass a promise to Promise.all that will not reject, you can do so by catching a rejected promise and in the catch return a special value that you can filter out when processing results:

const fetchMaxThreePerSecond = throttlePeriod(3,1100)/*give it an extra 100*/(fetch);
const Fail = function(reason){this.reason = reason;};
const isFail = x=>(x&&x.constructor)===Fail;
const isNotFail = x=>!isFail(x);
Promise.all(
  urls.map(
    url=>
      fetchMaxThreePerSecond(url)
      .catch(e=>new Fail([url,e]))//save url and error in Fail object
  )
)
.then(//even if a request fails, it will not reject
  results=>{
    const successes = results.filter(isNotFail);
    const failed = results.filter(isFail);
    if(failed.length!==0){
      console.log("some requests failed:");
      failed.forEach(
        (fail)=>{
          const [url,error] = fail.reason;
          console.log(`Url: ${url}`);
          console.log(JSON.stringify(error,undefined,2));
        }
      )
    }
  }
); 

I have no problem with GDAX history calls when I set my rate limiter to 3 API calls every 2.1 seconds.

I have some occasional problems when I set my rate limiter to 3 API calls every 1.8 seconds.

I have tested these values with automated tests.

Important: all my calls to GDAX share the same rate limiter(!)

To be save, use the code from @HMR's answer together with my tested parameters.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM