Rate Limits
Understand API rate limits, quota management, and best practices for optimizing your API usage across different subscription tiers.
Overview
The arrow Trading API implements rate limiting to ensure fair usage, maintain system stability, and provide consistent performance for all users. Rate limits vary by subscription tier and are applied on a per-endpoint basis with additional burst capacity for temporary traffic spikes.
Rate Limit Tiers
Basic Tier
The Basic tier is ideal for individual traders and small-scale applications with moderate API usage.
| Endpoint Category | Requests per Minute | Burst Limit | Daily Quota |
|---|---|---|---|
| Orders | 30 | 5 | 10,000 |
| Positions | 60 | 10 | 20,000 |
| Holdings | 60 | 10 | 20,000 |
| Funds | 60 | 10 | 20,000 |
| Margin Calculation | 60 | 10 | 20,000 |
| Historical Data | 30 | 5 | 5,000 |
| Realtime Market Data | 120 | 20 | 50,000 |
| Realtime Order Data | 120 | 20 | 50,000 |
Basic Tier Features
- Monthly Cost: Free or Low-cost entry tier
- Concurrent Connections: Up to 2
- WebSocket Connections: 1 active connection
- Best For: Individual traders, hobby projects, testing
Premium Tier
The Premium tier is designed for active traders, professional applications, and growing businesses requiring higher throughput.
| Endpoint Category | Requests per Minute | Burst Limit | Daily Quota |
|---|---|---|---|
| Orders | 150 | 25 | 100,000 |
| Positions | 300 | 50 | 200,000 |
| Holdings | 300 | 50 | 200,000 |
| Funds | 300 | 50 | 200,000 |
| Margin Calculation | 300 | 50 | 200,000 |
| Historical Data | 150 | 25 | 50,000 |
| Realtime Market Data | 600 | 100 | 500,000 |
| Realtime Order Data | 600 | 100 | 500,000 |
Premium Tier Features
- Monthly Cost: Mid-tier pricing
- Concurrent Connections: Up to 10
- WebSocket Connections: 3 active connections
- Priority Support: Email support with 24-hour response time
- Best For: Active traders, algorithmic trading, small trading firms
Enterprise Tier
The Enterprise tier offers the highest limits for institutional traders, brokerages, and large-scale applications requiring maximum performance.
| Endpoint Category | Requests per Minute | Burst Limit | Daily Quota |
|---|---|---|---|
| Orders | 500 | 100 | 1,000,000 |
| Positions | 1000 | 100 | 2,000,000 |
| Holdings | 1000 | 100 | 2,000,000 |
| Funds | 1000 | 100 | 2,000,000 |
| Margin Calculation | 1000 | 100 | 2,000,000 |
| Historical Data | 500 | 100 | 500,000 |
| Realtime Market Data | 2000 | 200 | Unlimited |
| Realtime Order Data | 2000 | 200 | Unlimited |
Enterprise Tier Features
- Monthly Cost: Custom pricing
- Concurrent Connections: Unlimited
- WebSocket Connections: 10+ active connections
- Dedicated Support: Phone and email support with 2-hour response time
- Custom Solutions: Dedicated infrastructure, custom rate limits available
- Best For: Institutional traders, brokerages, fintech platforms, high-frequency trading
Rate Limit Details
Understanding Rate Limits
Rate limits are applied using a sliding window algorithm that tracks requests over a rolling time period.
Requests per Minute
The primary rate limit specifies the maximum number of requests allowed within any 60-second window.
Example: With a 60 requests/minute limit: - You can make 60 requests at 10:00:00 - At 10:00:30, you can make additional requests if fewer than 60 were made in the previous 60 seconds - The limit resets continuously as the time window slides forward
Burst Limit
Burst limits allow temporary spikes in traffic beyond the per-minute rate, useful for handling sudden data requirements.
Example: With a 60 requests/minute limit and 10 burst capacity: - You can make up to 10 requests simultaneously - But still cannot exceed 60 requests total within any 60-second window - Burst capacity is ideal for initial data loads or periodic batch operations
Daily Quota
Daily quotas reset at 00:00 IST (Indian Standard Time) and provide an upper bound on total daily usage.
Quota Management
Monitor your daily quota usage carefully. Once exhausted, API requests will be rejected until the quota resets at midnight IST.
Rate Limit Headers
Every API response includes headers indicating your current rate limit status:
HTTP/1.1 200 OK
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1678901234
X-RateLimit-Burst-Limit: 10
X-RateLimit-Burst-Remaining: 8
X-DailyQuota-Limit: 20000
X-DailyQuota-Remaining: 15847
X-DailyQuota-Reset: 1678924800
Response Headers Explained
| Header | Description |
|---|---|
X-RateLimit-Limit |
Maximum requests allowed per minute |
X-RateLimit-Remaining |
Remaining requests in current window |
X-RateLimit-Reset |
Unix timestamp when the rate limit resets |
X-RateLimit-Burst-Limit |
Maximum burst capacity |
X-RateLimit-Burst-Remaining |
Remaining burst capacity |
X-DailyQuota-Limit |
Maximum daily requests allowed |
X-DailyQuota-Remaining |
Remaining requests in daily quota |
X-DailyQuota-Reset |
Unix timestamp when daily quota resets (midnight IST) |
Rate Limit Exceeded Response
When you exceed rate limits, the API returns a 429 Too Many Requests status code:
{
"status": "error",
"message": "Rate limit exceeded",
"code": "RATE_LIMIT_EXCEEDED",
"details": {
"limit": 60,
"remaining": 0,
"resetAt": "2024-03-15T10:15:30+0530",
"retryAfter": 45
}
}
Error Response Fields
| Field | Description |
|---|---|
status |
Always "error" for rate limit errors |
message |
Human-readable error description |
code |
Error code (RATE_LIMIT_EXCEEDED or DAILY_QUOTA_EXCEEDED) |
details.limit |
The rate limit that was exceeded |
details.remaining |
Requests remaining (0 when exceeded) |
details.resetAt |
Timestamp when the limit resets |
details.retryAfter |
Seconds to wait before retrying |
Best Practices
1. Monitor Rate Limit Headers
Always check rate limit headers in responses to track your usage and avoid hitting limits:
const response = await fetch('https://api.arrow.trading/user/holdings', {
headers: {
'appID': APP_ID,
'token': TOKEN
}
});
// Check rate limit headers
const remaining = response.headers.get('X-RateLimit-Remaining');
const resetTime = response.headers.get('X-RateLimit-Reset');
console.log(`Requests remaining: ${remaining}`);
console.log(`Resets at: ${new Date(resetTime * 1000)}`);
if (remaining < 10) {
console.warn('Approaching rate limit!');
}
response = requests.get(
'https://api.arrow.trading/user/holdings',
headers={'appID': APP_ID, 'token': TOKEN}
)
# Check rate limit headers
remaining = int(response.headers.get('X-RateLimit-Remaining', 0))
reset_time = int(response.headers.get('X-RateLimit-Reset', 0))
print(f'Requests remaining: {remaining}')
print(f'Resets at: {datetime.fromtimestamp(reset_time)}')
if remaining < 10:
print('Warning: Approaching rate limit!')
2. Implement Exponential Backoff
When you receive a 429 error, implement exponential backoff with jitter:
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || Math.pow(2, i);
const jitter = Math.random() * 1000;
const delay = (retryAfter * 1000) + jitter;
console.log(`Rate limited. Retrying after ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
return response;
}
throw new Error('Max retries exceeded');
}
import time
import random
def fetch_with_retry(url, headers, max_retries=3):
for i in range(max_retries):
response = requests.get(url, headers=headers)
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 2 ** i))
jitter = random.uniform(0, 1)
delay = retry_after + jitter
print(f'Rate limited. Retrying after {delay}s')
time.sleep(delay)
continue
return response
raise Exception('Max retries exceeded')
3. Cache Responses
Cache data that doesn't change frequently to reduce API calls:
// Simple in-memory cache with TTL
class APICache {
constructor(ttl = 60000) { // 60 seconds default
this.cache = new Map();
this.ttl = ttl;
}
get(key) {
const item = this.cache.get(key);
if (!item) return null;
if (Date.now() > item.expiry) {
this.cache.delete(key);
return null;
}
return item.data;
}
set(key, data) {
this.cache.set(key, {
data,
expiry: Date.now() + this.ttl
});
}
}
// Usage
const cache = new APICache(60000); // Cache for 60 seconds
async function getHoldings() {
const cached = cache.get('holdings');
if (cached) return cached;
const response = await fetch('https://api.arrow.trading/user/holdings', {
headers: { 'appID': APP_ID, 'token': TOKEN }
});
const holdings = await response.json();
cache.set('holdings', holdings);
return holdings;
}
4. Batch Requests When Possible
Use batch endpoints to reduce the number of API calls:
// Instead of individual margin calls
const margins = [];
for (const order of orders) {
const margin = await calculateOrderMargin(order); // Multiple API calls
margins.push(margin);
}
// Use basket margin endpoint
const basketMargin = await calculateBasketMargin(orders); // Single API call
5. Use WebSockets for Real-time Data
For real-time market data and order updates, use WebSocket connections instead of polling:
// ❌ Avoid polling (wastes rate limits)
setInterval(async () => {
const positions = await fetchPositions();
updateUI(positions);
}, 1000);
// ✅ Use WebSocket for real-time updates
const ws = new WebSocket('wss://api.arrow.trading/stream');
ws.onmessage = (event) => {
const update = JSON.parse(event.data);
updateUI(update);
};
6. Implement Request Queuing
Queue requests to stay within rate limits:
class RateLimiter {
constructor(requestsPerMinute) {
this.requestsPerMinute = requestsPerMinute;
this.queue = [];
this.timestamps = [];
}
async execute(fn) {
return new Promise((resolve, reject) => {
this.queue.push({ fn, resolve, reject });
this.processQueue();
});
}
async processQueue() {
if (this.queue.length === 0) return;
// Remove timestamps older than 1 minute
const now = Date.now();
this.timestamps = this.timestamps.filter(t => now - t < 60000);
// Check if we can make a request
if (this.timestamps.length < this.requestsPerMinute) {
const { fn, resolve, reject } = this.queue.shift();
this.timestamps.push(now);
try {
const result = await fn();
resolve(result);
} catch (error) {
reject(error);
}
// Process next item
setTimeout(() => this.processQueue(), 0);
} else {
// Wait until we can make the next request
const oldestTimestamp = this.timestamps[0];
const delay = 60000 - (now - oldestTimestamp);
setTimeout(() => this.processQueue(), delay);
}
}
}
// Usage
const limiter = new RateLimiter(60);
async function safeFetch(url, options) {
return limiter.execute(() => fetch(url, options));
}
Upgrading Your Tier
When to Upgrade
Consider upgrading to a higher tier when you:
- Consistently hit rate limits during trading hours
- Need higher burst capacity for algorithmic strategies
- Require more daily quota for historical data analysis
- Need priority support for production applications
- Want to scale your trading operations
How to Upgrade
Tier Upgrades
To upgrade your subscription tier:
- Visit the arrow Trading Dashboard
- Navigate to Account Settings > Subscription
- Select your desired tier
- Complete the payment process
- Your new limits are applied immediately
Custom Enterprise Plans
For custom requirements beyond Enterprise tier limits, contact our sales team:
- Email: enterprise@arrow.trading
- Phone: +91-XXXX-XXXXXX
- Custom Features: Dedicated infrastructure, SLA guarantees, custom endpoints
Rate Limit FAQs
Do rate limits apply per API key or per account?
Rate limits are applied per API key (appID + token combination). If you have multiple API keys, each has its own independent rate limit.
Are WebSocket connections counted against rate limits?
WebSocket connections have separate connection limits but do not count against REST API rate limits. However, initial connection requests are counted.
What happens if I exceed my daily quota?
Once your daily quota is exhausted, all API requests will return 429 errors with code DAILY_QUOTA_EXCEEDED until midnight IST when the quota resets.
Can I request a temporary rate limit increase?
Enterprise customers can request temporary rate limit increases for specific events (e.g., earnings season, IPOs). Contact support at least 48 hours in advance.
Do failed requests count against rate limits?
Yes, all requests count against rate limits regardless of success or failure, including requests that return 4xx or 5xx errors.
Are there separate limits for market hours vs. non-market hours?
No, rate limits are consistent throughout the day. However, market data endpoints may have reduced data availability outside trading hours.
Monitoring Your Usage
Usage Dashboard
Track your API usage in real-time through the arrow Trading Dashboard:
- View current rate limit consumption
- Monitor daily quota usage
- Analyze usage patterns by endpoint
- Set up alerts for approaching limits
- Download usage reports
Usage Alerts
Configure alerts to notify you when:
- Rate limit consumption exceeds 80%
- Daily quota usage exceeds 80%
- Multiple 429 errors occur
- Unusual usage patterns detected
Alert Configuration
Set up usage alerts in Dashboard > Settings > API Alerts
Contact Support
If you have questions about rate limits or need assistance:
- Basic Tier: Email support@arrow.trading
- Premium Tier: Email premium@arrow.trading (24-hour response)
- Enterprise Tier: Call dedicated support line or email enterprise@arrow.trading (2-hour response)
For urgent production issues, Enterprise customers can contact the 24/7 emergency support line.