Throttle OKX amp-stats candle pagination and retry on 429.

Add page pauses, exponential backoff, and cooldown before swap fallback to avoid rate limits.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-23 02:57:24 +08:00
parent 0a9e3aa95c
commit 910c938d0a
5 changed files with 142 additions and 35 deletions
+61 -7
View File
@@ -14,6 +14,8 @@ from lib.hub.amp_stats_lib import (
window_bounds_for_settlement,
)
import httpx
TZ = ZoneInfo("Asia/Shanghai")
@@ -198,11 +200,17 @@ class AmpStatsLibTests(unittest.TestCase):
calls: list[str] = []
class FakeResp:
def __init__(self, data):
def __init__(self, data, url="https://x", status_code=200):
self._data = data
self.status_code = status_code
self.url = url
self.request = httpx.Request("GET", url)
def raise_for_status(self):
return None
if self.status_code >= 400:
raise httpx.HTTPStatusError(
"err", request=self.request, response=self
)
def json(self):
return {"code": "0", "data": self._data}
@@ -214,14 +222,14 @@ class AmpStatsLibTests(unittest.TestCase):
# recent: only 2 pages then empty; history continues
if "history" not in url:
if after is None:
return FakeResp([["2000", "1", "2", "0.5", "1.5"], ["1900", "1", "2", "0.5", "1.5"]])
return FakeResp([["2000", "1", "2", "0.5", "1.5"], ["1900", "1", "2", "0.5", "1.5"]], url=url)
if after == "1900":
return FakeResp([]) # recent exhausted
return FakeResp([])
return FakeResp([], url=url) # recent exhausted
return FakeResp([], url=url)
# history
if after == "1900":
return FakeResp([["1800", "1", "2", "0.5", "1.5"], ["1000", "1", "2", "0.5", "1.5"]])
return FakeResp([])
return FakeResp([["1800", "1", "2", "0.5", "1.5"], ["1000", "1", "2", "0.5", "1.5"]], url=url)
return FakeResp([], url=url)
def close(self):
return None
@@ -234,11 +242,57 @@ class AmpStatsLibTests(unittest.TestCase):
until_ms=3000,
client=FakeClient(),
max_pages=10,
page_pause_sec=0,
history_page_pause_sec=0,
)
self.assertTrue(any("history-index-candles" in u for u in calls))
self.assertGreaterEqual(len(bars), 3)
self.assertEqual(bars[0]["ts"], 1000)
def test_fetch_retries_on_429(self):
from lib.hub.amp_stats_lib import fetch_okx_candles
import httpx as _httpx
hits = {"n": 0}
class FakeResp:
def __init__(self, status_code, data=None):
self.status_code = status_code
self.url = "https://www.okx.com/api/v5/market/history-candles"
self.request = _httpx.Request("GET", self.url)
self._data = data or []
def raise_for_status(self):
if self.status_code >= 400:
raise _httpx.HTTPStatusError("429", request=self.request, response=self)
def json(self):
return {"code": "0", "data": self._data}
class FakeClient:
def get(self, url, params=None):
hits["n"] += 1
if hits["n"] < 3:
return FakeResp(429)
return FakeResp(200, [["1000", "1", "2", "0.5", "1.5"]])
def close(self):
return None
bars = fetch_okx_candles(
url="https://www.okx.com/api/v5/market/candles",
history_url=None,
inst_id="ETH-USDT-SWAP",
since_ms=1000,
until_ms=2000,
client=FakeClient(),
max_pages=3,
page_pause_sec=0,
history_page_pause_sec=0,
)
self.assertGreaterEqual(hits["n"], 3)
self.assertEqual(len(bars), 1)
def test_compute_with_mock_fetch(self):
now = datetime(2026, 7, 22, 18, 0, tzinfo=TZ)