/** * Simulation of too many requests, HTTP 429 error, when <10 orders are placed despite being spread 1s+ apart. * Make sure API_KEY and ACCESS_TOKEN are replaced before running following nodejs script. * * 4-5 of 20 orders are rejected with following configuration even if batches of 10 orders * are separated by 1.5 seconds. */ const API_KEY = ''; const ACCESS_TOKEN = '' const ORDER_WINDOW_MS = 1550; // Size of window measured in milliseconds. This is used to separate order batches. const ORDERS_PER_WINDOW = 10; // Batch size const TOTAL_ORDERS_TO_PLACE = 20; // Total number of orders to be placed function placeOrder(i) { // Places GTT order for IDBI const data = new URLSearchParams({ 'variety': 'gtt', 'exchange': 'NSE', 'tradingsymbol': 'IDBI', 'transaction_type': 'BUY', 'order_type': 'LIMIT', 'quantity': i, 'price': '85', 'product': 'CNC', 'validity': 'DAY', 'disclosed_quantity': '0', 'trigger_price': '0', 'squareoff': '0', 'stoploss': '0', 'trailing_stoploss': '0' }); console.log(getTimestamp(), `sending request number`, i); fetch('https://api.kite.trade/orders/amo', { method: 'post', headers: { 'X-Kite-Version': '3', 'Authorization': `token ${API_KEY}:${ACCESS_TOKEN}`, 'Content-Type': 'application/x-www-form-urlencoded' }, body: data.toString() }) .then((response) => { if (!response.ok) { throw new Error(`HTTP ${response.status} ${response.statusText}`); } console.error(getTimestamp(), `request number ${i} placed successfully`); }) .catch((error) => { console.error(getTimestamp(), `request number ${i} failed due to error: ${error.message}`); }); } function getTimestamp() { const now = new Date(); return `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}.${now.getMilliseconds()}`; } /* * delay = batchIndex * ORDER_WINDOW_MS, where batchIndex = (i - 1) / ORDERS_PER_WINDOW (floored). * Orders 1..ORDERS_PER_WINDOW get batchIndex 0 -> delay 0ms, the next ORDERS_PER_WINDOW get * batchIndex 1 -> delay ORDER_WINDOW_MS, and so on. Each batch is therefore placed exactly * one window after the previous batch. */ for (let i = 1; i <= TOTAL_ORDERS_TO_PLACE; i++) { const delay = Math.floor((i - 1) / ORDERS_PER_WINDOW) * ORDER_WINDOW_MS; setTimeout(() => { placeOrder(i); }, delay); }