Refactored RPS

api-breakage
Irishery 4 years ago
parent ef10e26229
commit f29a2ccc7d
  1. 89
      src/cryptocom/exchange/api.py
  2. 27
      tests/test_api.py

@ -1,6 +1,6 @@
import os
import json
from re import S
import re
import time
import hmac
import random
@ -34,19 +34,18 @@ class ApiProvider:
self.ws_root_url = ws_root_url
self.timeout = timeout
self.retries = retries
self.limiter = AsyncLimiter(1, 1)
self.last_request = ''
self.last_request_path = ''
self.limits = {
# method: (req_limit, period)
'private/create-order': (15, 0.1),
'private/cancel-order': (15, 0.1),
'private/cancel-all-orders': (15, 0.1),
'private/margin/create-order': (15, 0.1),
'private/margin/cancel-order': (15, 0.1),
'private/margin/cancel-all-orders': (15, 0.1),
'private/create-order': (14, 0.1),
'private/cancel-order': (14, 0.1),
'private/cancel-all-orders': (14, 0.1),
'private/margin/create-order': (14, 0.1),
'private/margin/cancel-order': (14, 0.1),
'private/margin/cancel-all-orders': (14, 0.1),
'private/get-order-detail': (30, 0.1),
'private/margin/get-order-detail': (30, 0.1),
'private/get-order-detail': (29, 0.1),
'private/margin/get-order-detail': (29, 0.1),
'private/get-trades': (1, 1),
'private/margin/get-trades': (1, 1),
@ -54,6 +53,38 @@ class ApiProvider:
'private/margin/get-order-history': (1, 1)
}
# lists for methods - aiolimiter metching
self.order_methods = [
'private/create-order',
'private/cancel-order',
'private/cancel-all-orders',
'private/margin/create-order',
'private/margin/cancel-order',
'private/margin/cancel-all-orders',
]
self.order_methods_limit = AsyncLimiter(14, 0.1)
self.detail_methods = [
'private/get-order-detail',
'private/margin/get-order-detail',
]
self.detail_methods_limit = AsyncLimiter(29, 0.1)
self.general_trade_methods = [
'private/get-trades',
'private/margin/get-trades',
'private/get-order-history',
'private/margin/get-order-history'
]
self.general_trade_methods_limit = AsyncLimiter(1, 1)
# limits for not matched methods
self.general_private_limit = AsyncLimiter(3, 0.1)
self.general_public_limit = AsyncLimiter(100, 1)
if not auth_required:
return
@ -95,38 +126,34 @@ class ApiProvider:
).hexdigest()
return data
def set_limit(self, url):
if not(url in self.limits.keys()):
if url.startswith('private'):
rate_limit, period = 3, 0.1
elif url.startswith('public'):
rate_limit, period = 100, 1
else:
raise ApiError(f'Wrong path: {url}')
else:
rate_limit, period = self.limits[url]
def set_limit(self, path):
if path in self.order_methods:
return self.order_methods_limit
elif path in self.detail_methods:
return self.detail_methods_limit
elif path in self.general_trade_methods:
return self.general_trade_methods_limit
self.limiter.max_rate = rate_limit
self.limiter.time_period = period
else:
if path.startswith('private'):
return self.general_private_limit
elif path.startswith('public'):
return self.general_public_limit
else:
raise ApiError(f'Wrong path: {path}')
async def request(self, method, path, params=None, data=None, sign=False):
original_data = data
timeout = aiohttp.ClientTimeout(total=self.timeout)
if not (path == self.last_request):
self.set_limit(path)
self.last_request = path
limiter = self.set_limit(path)
for count in range(self.retries + 1):
if sign:
data = self._sign(path, original_data)
try:
async with aiohttp.ClientSession(timeout=timeout) as session:
async with self.limiter:
async with limiter:
resp = await session.request(
method, urljoin(self.root_url, path),
params=params, json=data,

@ -1,3 +1,5 @@
import asyncio
from asyncio.events import get_running_loop
import os
import time
import pytest
@ -71,34 +73,29 @@ async def test_api_rate_limits():
params['instrument_name'] = pair.name
start_time = time.time()
await api.post('private/get-order-history', {'params': params})
await api.post('private/get-order-history', {'params': params})
finish_time = (time.time() - start_time)
tasks = [api.post('private/get-order-history', {'params': params}) for i in range(2)]
await asyncio.gather(*tasks)
finish_time = (time.time() - start_time)
assert finish_time > 1
start_time = time.time()
await api.post('private/get-order-history', {'params': params})
await api.post('private/get-order-history', {'params': params})
await api.post('private/get-order-history', {'params': params})
await api.post('private/get-order-history', {'params': params})
tasks = [api.post('private/get-order-history', {'params': params}) for _ in range(5)]
await asyncio.gather(*tasks)
finish_time = time.time() - start_time
assert finish_time > 4
start_time = time.time()
await api.get('public/get-instruments')
await api.get('public/get-instruments')
await api.get('public/get-instruments')
await api.get('public/get-instruments')
tasks = [api.get('public/get-instruments') for _ in range(200)]
await asyncio.gather(*tasks)
finish_time = time.time() - start_time
assert finish_time < 4
assert finish_time > 1
start_time = time.time()
await api.post('private/get-order-history', {'params': params})
await api.post('private/get-order-history', {'params': params})
await api.post('private/get-order-history', {'params': params})
tasks = [api.post('private/get-order-history', {'params': params}) for _ in range(4)]
await asyncio.gather(*tasks)
finish_time = time.time() - start_time
assert finish_time > 3

Loading…
Cancel
Save