|
@@ -29,13 +29,31 @@ class AccountInfo:
|
|
|
_AUTH_BREAKER_LOCK = threading.Lock()
|
|
_AUTH_BREAKER_LOCK = threading.Lock()
|
|
|
_AUTH_BREAKER_NEXT_ALLOWED: dict[str, float] = {}
|
|
_AUTH_BREAKER_NEXT_ALLOWED: dict[str, float] = {}
|
|
|
_AUTH_BREAKER_SECONDS = 5.0
|
|
_AUTH_BREAKER_SECONDS = 5.0
|
|
|
|
|
+_NONCE_LOCK = threading.Lock()
|
|
|
|
|
+_LAST_NONCE_BY_SCOPE: dict[str, int] = {}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def _nonce_now_ms() -> int:
|
|
|
|
|
+ return time.time_ns() // 1_000_000
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def _next_nonce(scope: str) -> int:
|
|
|
|
|
+ with _NONCE_LOCK:
|
|
|
|
|
+ last_nonce = _LAST_NONCE_BY_SCOPE.get(scope, 0)
|
|
|
|
|
+ nonce = max(_nonce_now_ms(), last_nonce + 1)
|
|
|
|
|
+ _LAST_NONCE_BY_SCOPE[scope] = nonce
|
|
|
|
|
+ return nonce
|
|
|
|
|
|
|
|
|
|
|
|
|
class LG_Trading(Trading):
|
|
class LG_Trading(Trading):
|
|
|
def __init__(self, username, key, secret, *args, **kwargs):
|
|
def __init__(self, username, key, secret, *args, **kwargs):
|
|
|
self._username = str(username)
|
|
self._username = str(username)
|
|
|
|
|
+ self._nonce_scope = f"{username}:{key}"
|
|
|
super(LG_Trading, self).__init__(username=username, key=key, secret=secret, *args, **kwargs)
|
|
super(LG_Trading, self).__init__(username=username, key=key, secret=secret, *args, **kwargs)
|
|
|
|
|
|
|
|
|
|
+ def get_nonce(self):
|
|
|
|
|
+ return _next_nonce(self._nonce_scope)
|
|
|
|
|
+
|
|
|
def _breaker_is_open(self) -> bool:
|
|
def _breaker_is_open(self) -> bool:
|
|
|
with _AUTH_BREAKER_LOCK:
|
|
with _AUTH_BREAKER_LOCK:
|
|
|
return _AUTH_BREAKER_NEXT_ALLOWED.get(self._username, 0.0) > time.monotonic()
|
|
return _AUTH_BREAKER_NEXT_ALLOWED.get(self._username, 0.0) > time.monotonic()
|