mirror of
https://github.com/aljazceru/bitfinex-api-py.git
synced 2026-01-30 10:54:32 +01:00
Apply black to all python files (bfxapi/**/*.py).
This commit is contained in:
@@ -13,9 +13,10 @@ from bfxapi.websocket.subscriptions import Subscription
|
||||
|
||||
_CHECKSUM_FLAG_VALUE = 131_072
|
||||
|
||||
|
||||
def _strip(message: Dict[str, Any], keys: List[str]) -> Dict[str, Any]:
|
||||
return { key: value for key, value in message.items() \
|
||||
if not key in keys }
|
||||
return {key: value for key, value in message.items() if not key in keys}
|
||||
|
||||
|
||||
class BfxWebSocketBucket(Connection):
|
||||
__MAXIMUM_SUBSCRIPTIONS_AMOUNT = 25
|
||||
@@ -24,28 +25,26 @@ class BfxWebSocketBucket(Connection):
|
||||
super().__init__(host)
|
||||
|
||||
self.__event_emitter = event_emitter
|
||||
self.__pendings: List[Dict[str, Any]] = [ ]
|
||||
self.__subscriptions: Dict[int, Subscription] = { }
|
||||
self.__pendings: List[Dict[str, Any]] = []
|
||||
self.__subscriptions: Dict[int, Subscription] = {}
|
||||
|
||||
self.__condition = asyncio.locks.Condition()
|
||||
|
||||
self.__handler = PublicChannelsHandler( \
|
||||
event_emitter=self.__event_emitter)
|
||||
self.__handler = PublicChannelsHandler(event_emitter=self.__event_emitter)
|
||||
|
||||
@property
|
||||
def count(self) -> int:
|
||||
return len(self.__pendings) + \
|
||||
len(self.__subscriptions)
|
||||
return len(self.__pendings) + len(self.__subscriptions)
|
||||
|
||||
@property
|
||||
def is_full(self) -> bool:
|
||||
return self.count == \
|
||||
BfxWebSocketBucket.__MAXIMUM_SUBSCRIPTIONS_AMOUNT
|
||||
return self.count == BfxWebSocketBucket.__MAXIMUM_SUBSCRIPTIONS_AMOUNT
|
||||
|
||||
@property
|
||||
def ids(self) -> List[str]:
|
||||
return [ pending["subId"] for pending in self.__pendings ] + \
|
||||
[ subscription["sub_id"] for subscription in self.__subscriptions.values() ]
|
||||
return [pending["subId"] for pending in self.__pendings] + [
|
||||
subscription["sub_id"] for subscription in self.__subscriptions.values()
|
||||
]
|
||||
|
||||
async def start(self) -> None:
|
||||
async with websockets.client.connect(self._host) as websocket:
|
||||
@@ -64,20 +63,25 @@ class BfxWebSocketBucket(Connection):
|
||||
self.__on_subscribed(message)
|
||||
|
||||
if isinstance(message, list):
|
||||
if (chan_id := cast(int, message[0])) and \
|
||||
(subscription := self.__subscriptions.get(chan_id)) and \
|
||||
(message[1] != Connection._HEARTBEAT):
|
||||
if (
|
||||
(chan_id := cast(int, message[0]))
|
||||
and (subscription := self.__subscriptions.get(chan_id))
|
||||
and (message[1] != Connection._HEARTBEAT)
|
||||
):
|
||||
self.__handler.handle(subscription, message[1:])
|
||||
|
||||
def __on_subscribed(self, message: Dict[str, Any]) -> None:
|
||||
chan_id = cast(int, message["chan_id"])
|
||||
|
||||
subscription = cast(Subscription, _strip(message, \
|
||||
keys=["chan_id", "event", "pair", "currency"]))
|
||||
subscription = cast(
|
||||
Subscription, _strip(message, keys=["chan_id", "event", "pair", "currency"])
|
||||
)
|
||||
|
||||
self.__pendings = [ pending \
|
||||
for pending in self.__pendings \
|
||||
if pending["subId"] != message["sub_id"] ]
|
||||
self.__pendings = [
|
||||
pending
|
||||
for pending in self.__pendings
|
||||
if pending["subId"] != message["sub_id"]
|
||||
]
|
||||
|
||||
self.__subscriptions[chan_id] = subscription
|
||||
|
||||
@@ -85,47 +89,43 @@ class BfxWebSocketBucket(Connection):
|
||||
|
||||
async def __recover_state(self) -> None:
|
||||
for pending in self.__pendings:
|
||||
await self._websocket.send(message = \
|
||||
json.dumps(pending))
|
||||
await self._websocket.send(message=json.dumps(pending))
|
||||
|
||||
for chan_id in list(self.__subscriptions.keys()):
|
||||
subscription = self.__subscriptions.pop(chan_id)
|
||||
|
||||
await self.subscribe(**subscription)
|
||||
|
||||
await self.__set_config([ _CHECKSUM_FLAG_VALUE ])
|
||||
await self.__set_config([_CHECKSUM_FLAG_VALUE])
|
||||
|
||||
async def __set_config(self, flags: List[int]) -> None:
|
||||
await self._websocket.send(json.dumps( \
|
||||
{ "event": "conf", "flags": sum(flags) }))
|
||||
await self._websocket.send(json.dumps({"event": "conf", "flags": sum(flags)}))
|
||||
|
||||
@Connection._require_websocket_connection
|
||||
async def subscribe(self,
|
||||
channel: str,
|
||||
sub_id: Optional[str] = None,
|
||||
**kwargs: Any) -> None:
|
||||
subscription: Dict[str, Any] = \
|
||||
{ **kwargs, "event": "subscribe", "channel": channel }
|
||||
async def subscribe(
|
||||
self, channel: str, sub_id: Optional[str] = None, **kwargs: Any
|
||||
) -> None:
|
||||
subscription: Dict[str, Any] = {
|
||||
**kwargs,
|
||||
"event": "subscribe",
|
||||
"channel": channel,
|
||||
}
|
||||
|
||||
subscription["subId"] = sub_id or str(uuid.uuid4())
|
||||
|
||||
self.__pendings.append(subscription)
|
||||
|
||||
await self._websocket.send(message = \
|
||||
json.dumps(subscription))
|
||||
await self._websocket.send(message=json.dumps(subscription))
|
||||
|
||||
@Connection._require_websocket_connection
|
||||
async def unsubscribe(self, sub_id: str) -> None:
|
||||
for chan_id, subscription in list(self.__subscriptions.items()):
|
||||
if subscription["sub_id"] == sub_id:
|
||||
unsubscription = {
|
||||
"event": "unsubscribe",
|
||||
"chanId": chan_id }
|
||||
unsubscription = {"event": "unsubscribe", "chanId": chan_id}
|
||||
|
||||
del self.__subscriptions[chan_id]
|
||||
|
||||
await self._websocket.send(message = \
|
||||
json.dumps(unsubscription))
|
||||
await self._websocket.send(message=json.dumps(unsubscription))
|
||||
|
||||
@Connection._require_websocket_connection
|
||||
async def resubscribe(self, sub_id: str) -> None:
|
||||
@@ -148,5 +148,4 @@ class BfxWebSocketBucket(Connection):
|
||||
|
||||
async def wait(self) -> None:
|
||||
async with self.__condition:
|
||||
await self.__condition \
|
||||
.wait_for(lambda: self.open)
|
||||
await self.__condition.wait_for(lambda: self.open)
|
||||
|
||||
@@ -28,14 +28,17 @@ from bfxapi.websocket.exceptions import (
|
||||
from .bfx_websocket_bucket import BfxWebSocketBucket
|
||||
from .bfx_websocket_inputs import BfxWebSocketInputs
|
||||
|
||||
_Credentials = TypedDict("_Credentials", \
|
||||
{ "api_key": str, "api_secret": str, "filters": Optional[List[str]] })
|
||||
_Credentials = TypedDict(
|
||||
"_Credentials", {"api_key": str, "api_secret": str, "filters": Optional[List[str]]}
|
||||
)
|
||||
|
||||
_Reconnection = TypedDict("_Reconnection",
|
||||
{ "attempts": int, "reason": str, "timestamp": datetime })
|
||||
_Reconnection = TypedDict(
|
||||
"_Reconnection", {"attempts": int, "reason": str, "timestamp": datetime}
|
||||
)
|
||||
|
||||
_DEFAULT_LOGGER = Logger("bfxapi.websocket._client", level=0)
|
||||
|
||||
|
||||
class _Delay:
|
||||
__BACKOFF_MIN = 1.92
|
||||
|
||||
@@ -54,59 +57,61 @@ class _Delay:
|
||||
return _backoff_delay
|
||||
|
||||
def peek(self) -> float:
|
||||
return (self.__backoff_delay == _Delay.__BACKOFF_MIN) \
|
||||
and self.__initial_delay or self.__backoff_delay
|
||||
return (
|
||||
(self.__backoff_delay == _Delay.__BACKOFF_MIN)
|
||||
and self.__initial_delay
|
||||
or self.__backoff_delay
|
||||
)
|
||||
|
||||
def reset(self) -> None:
|
||||
self.__backoff_delay = _Delay.__BACKOFF_MIN
|
||||
|
||||
#pylint: disable-next=too-many-instance-attributes
|
||||
|
||||
# pylint: disable-next=too-many-instance-attributes
|
||||
class BfxWebSocketClient(Connection):
|
||||
def __init__(self,
|
||||
host: str,
|
||||
*,
|
||||
credentials: Optional[_Credentials] = None,
|
||||
timeout: Optional[int] = 60 * 15,
|
||||
logger: Logger = _DEFAULT_LOGGER) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
host: str,
|
||||
*,
|
||||
credentials: Optional[_Credentials] = None,
|
||||
timeout: Optional[int] = 60 * 15,
|
||||
logger: Logger = _DEFAULT_LOGGER,
|
||||
) -> None:
|
||||
super().__init__(host)
|
||||
|
||||
self.__credentials, self.__timeout, self.__logger = \
|
||||
credentials, \
|
||||
timeout, \
|
||||
logger
|
||||
self.__credentials, self.__timeout, self.__logger = credentials, timeout, logger
|
||||
|
||||
self.__buckets: Dict[BfxWebSocketBucket, Optional[Task]] = { }
|
||||
self.__buckets: Dict[BfxWebSocketBucket, Optional[Task]] = {}
|
||||
|
||||
self.__reconnection: Optional[_Reconnection] = None
|
||||
|
||||
self.__event_emitter = BfxEventEmitter(loop=None)
|
||||
|
||||
self.__handler = AuthEventsHandler( \
|
||||
event_emitter=self.__event_emitter)
|
||||
self.__handler = AuthEventsHandler(event_emitter=self.__event_emitter)
|
||||
|
||||
self.__inputs = BfxWebSocketInputs( \
|
||||
handle_websocket_input=self.__handle_websocket_input)
|
||||
self.__inputs = BfxWebSocketInputs(
|
||||
handle_websocket_input=self.__handle_websocket_input
|
||||
)
|
||||
|
||||
@self.__event_emitter.listens_to("error")
|
||||
def error(exception: Exception) -> None:
|
||||
header = f"{type(exception).__name__}: {str(exception)}"
|
||||
|
||||
stack_trace = traceback.format_exception( \
|
||||
type(exception), exception, exception.__traceback__)
|
||||
stack_trace = traceback.format_exception(
|
||||
type(exception), exception, exception.__traceback__
|
||||
)
|
||||
|
||||
#pylint: disable-next=logging-not-lazy
|
||||
self.__logger.critical(header + "\n" + \
|
||||
str().join(stack_trace)[:-1])
|
||||
# pylint: disable-next=logging-not-lazy
|
||||
self.__logger.critical(header + "\n" + str().join(stack_trace)[:-1])
|
||||
|
||||
@property
|
||||
def inputs(self) -> BfxWebSocketInputs:
|
||||
return self.__inputs
|
||||
|
||||
def run(self) -> None:
|
||||
return asyncio.get_event_loop() \
|
||||
.run_until_complete(self.start())
|
||||
return asyncio.get_event_loop().run_until_complete(self.start())
|
||||
|
||||
#pylint: disable-next=too-many-branches
|
||||
# pylint: disable-next=too-many-branches
|
||||
async def start(self) -> None:
|
||||
_delay = _Delay(backoff_factor=1.618)
|
||||
|
||||
@@ -119,19 +124,20 @@ class BfxWebSocketClient(Connection):
|
||||
|
||||
while True:
|
||||
if self.__reconnection:
|
||||
_sleep = asyncio.create_task( \
|
||||
asyncio.sleep(int(_delay.next())))
|
||||
_sleep = asyncio.create_task(asyncio.sleep(int(_delay.next())))
|
||||
|
||||
try:
|
||||
await _sleep
|
||||
except asyncio.CancelledError:
|
||||
raise ReconnectionTimeoutError("Connection has been offline for too long " \
|
||||
f"without being able to reconnect (timeout: {self.__timeout}s).") \
|
||||
from None
|
||||
raise ReconnectionTimeoutError(
|
||||
"Connection has been offline for too long "
|
||||
f"without being able to reconnect (timeout: {self.__timeout}s)."
|
||||
) from None
|
||||
|
||||
try:
|
||||
await self.__connect()
|
||||
except (ConnectionClosedError, InvalidStatusCode, gaierror) as error:
|
||||
|
||||
async def _cancel(task: Task) -> None:
|
||||
task.cancel()
|
||||
|
||||
@@ -150,69 +156,87 @@ class BfxWebSocketClient(Connection):
|
||||
|
||||
await _cancel(task)
|
||||
|
||||
if isinstance(error, ConnectionClosedError) and error.code in (1006, 1012):
|
||||
if isinstance(error, ConnectionClosedError) and error.code in (
|
||||
1006,
|
||||
1012,
|
||||
):
|
||||
if error.code == 1006:
|
||||
self.__logger.error("Connection lost: trying to reconnect...")
|
||||
|
||||
if error.code == 1012:
|
||||
self.__logger.warning("WSS server is restarting: all " \
|
||||
"clients need to reconnect (server sent 20051).")
|
||||
self.__logger.warning(
|
||||
"WSS server is restarting: all "
|
||||
"clients need to reconnect (server sent 20051)."
|
||||
)
|
||||
|
||||
if self.__timeout:
|
||||
asyncio.get_event_loop().call_later(
|
||||
self.__timeout, _on_timeout)
|
||||
asyncio.get_event_loop().call_later(self.__timeout, _on_timeout)
|
||||
|
||||
self.__reconnection = \
|
||||
{ "attempts": 1, "reason": error.reason, "timestamp": datetime.now() }
|
||||
self.__reconnection = {
|
||||
"attempts": 1,
|
||||
"reason": error.reason,
|
||||
"timestamp": datetime.now(),
|
||||
}
|
||||
|
||||
self._authentication = False
|
||||
|
||||
_delay.reset()
|
||||
elif ((isinstance(error, InvalidStatusCode) and error.status_code == 408) or \
|
||||
isinstance(error, gaierror)) and self.__reconnection:
|
||||
#pylint: disable-next=logging-fstring-interpolation
|
||||
self.__logger.warning("Reconnection attempt unsuccessful (no." \
|
||||
f"{self.__reconnection['attempts']}): next attempt in " \
|
||||
f"~{int(_delay.peek())}.0s.")
|
||||
elif (
|
||||
(isinstance(error, InvalidStatusCode) and error.status_code == 408)
|
||||
or isinstance(error, gaierror)
|
||||
) and self.__reconnection:
|
||||
# pylint: disable-next=logging-fstring-interpolation
|
||||
self.__logger.warning(
|
||||
"Reconnection attempt unsuccessful (no."
|
||||
f"{self.__reconnection['attempts']}): next attempt in "
|
||||
f"~{int(_delay.peek())}.0s."
|
||||
)
|
||||
|
||||
#pylint: disable-next=logging-fstring-interpolation
|
||||
self.__logger.info(f"The client has been offline for " \
|
||||
f"{datetime.now() - self.__reconnection['timestamp']}.")
|
||||
# pylint: disable-next=logging-fstring-interpolation
|
||||
self.__logger.info(
|
||||
f"The client has been offline for "
|
||||
f"{datetime.now() - self.__reconnection['timestamp']}."
|
||||
)
|
||||
|
||||
self.__reconnection["attempts"] += 1
|
||||
else:
|
||||
raise error
|
||||
|
||||
if not self.__reconnection:
|
||||
self.__event_emitter.emit("disconnected",
|
||||
self._websocket.close_code, \
|
||||
self._websocket.close_reason)
|
||||
self.__event_emitter.emit(
|
||||
"disconnected",
|
||||
self._websocket.close_code,
|
||||
self._websocket.close_reason,
|
||||
)
|
||||
|
||||
break
|
||||
|
||||
async def __connect(self) -> None:
|
||||
async with websockets.client.connect(self._host) as websocket:
|
||||
if self.__reconnection:
|
||||
#pylint: disable-next=logging-fstring-interpolation
|
||||
self.__logger.warning("Reconnection attempt successful (no." \
|
||||
f"{self.__reconnection['attempts']}): recovering " \
|
||||
"connection state...")
|
||||
# pylint: disable-next=logging-fstring-interpolation
|
||||
self.__logger.warning(
|
||||
"Reconnection attempt successful (no."
|
||||
f"{self.__reconnection['attempts']}): recovering "
|
||||
"connection state..."
|
||||
)
|
||||
|
||||
self.__reconnection = None
|
||||
|
||||
self._websocket = websocket
|
||||
|
||||
for bucket in self.__buckets:
|
||||
self.__buckets[bucket] = \
|
||||
asyncio.create_task(bucket.start())
|
||||
self.__buckets[bucket] = asyncio.create_task(bucket.start())
|
||||
|
||||
if len(self.__buckets) == 0 or \
|
||||
(await asyncio.gather(*[bucket.wait() for bucket in self.__buckets])):
|
||||
if len(self.__buckets) == 0 or (
|
||||
await asyncio.gather(*[bucket.wait() for bucket in self.__buckets])
|
||||
):
|
||||
self.__event_emitter.emit("open")
|
||||
|
||||
if self.__credentials:
|
||||
authentication = Connection. \
|
||||
_get_authentication_message(**self.__credentials)
|
||||
authentication = Connection._get_authentication_message(
|
||||
**self.__credentials
|
||||
)
|
||||
|
||||
await self._websocket.send(authentication)
|
||||
|
||||
@@ -222,61 +246,64 @@ class BfxWebSocketClient(Connection):
|
||||
if isinstance(message, dict):
|
||||
if message["event"] == "info" and "version" in message:
|
||||
if message["version"] != 2:
|
||||
raise VersionMismatchError("Mismatch between the client and the server version: " + \
|
||||
"please update bitfinex-api-py to the latest version to resolve this error " + \
|
||||
f"(client version: 2, server version: {message['version']}).")
|
||||
raise VersionMismatchError(
|
||||
"Mismatch between the client and the server version: "
|
||||
+ "please update bitfinex-api-py to the latest version to resolve this error "
|
||||
+ f"(client version: 2, server version: {message['version']})."
|
||||
)
|
||||
elif message["event"] == "info" and message["code"] == 20051:
|
||||
rcvd = websockets.frames.Close( \
|
||||
1012, "Stop/Restart WebSocket Server (please reconnect).")
|
||||
rcvd = websockets.frames.Close(
|
||||
1012, "Stop/Restart WebSocket Server (please reconnect)."
|
||||
)
|
||||
|
||||
raise ConnectionClosedError(rcvd=rcvd, sent=None)
|
||||
elif message["event"] == "auth":
|
||||
if message["status"] != "OK":
|
||||
raise InvalidCredentialError("Can't authenticate " + \
|
||||
"with given API-KEY and API-SECRET.")
|
||||
raise InvalidCredentialError(
|
||||
"Can't authenticate "
|
||||
+ "with given API-KEY and API-SECRET."
|
||||
)
|
||||
|
||||
self.__event_emitter.emit("authenticated", message)
|
||||
|
||||
self._authentication = True
|
||||
|
||||
if isinstance(message, list) and \
|
||||
message[0] == 0 and message[1] != Connection._HEARTBEAT:
|
||||
if (
|
||||
isinstance(message, list)
|
||||
and message[0] == 0
|
||||
and message[1] != Connection._HEARTBEAT
|
||||
):
|
||||
self.__handler.handle(message[1], message[2])
|
||||
|
||||
async def __new_bucket(self) -> BfxWebSocketBucket:
|
||||
bucket = BfxWebSocketBucket( \
|
||||
self._host, self.__event_emitter)
|
||||
bucket = BfxWebSocketBucket(self._host, self.__event_emitter)
|
||||
|
||||
self.__buckets[bucket] = asyncio \
|
||||
.create_task(bucket.start())
|
||||
self.__buckets[bucket] = asyncio.create_task(bucket.start())
|
||||
|
||||
await bucket.wait()
|
||||
|
||||
return bucket
|
||||
|
||||
@Connection._require_websocket_connection
|
||||
async def subscribe(self,
|
||||
channel: str,
|
||||
sub_id: Optional[str] = None,
|
||||
**kwargs: Any) -> None:
|
||||
async def subscribe(
|
||||
self, channel: str, sub_id: Optional[str] = None, **kwargs: Any
|
||||
) -> None:
|
||||
if not channel in ["ticker", "trades", "book", "candles", "status"]:
|
||||
raise UnknownChannelError("Available channels are: " + \
|
||||
"ticker, trades, book, candles and status.")
|
||||
raise UnknownChannelError(
|
||||
"Available channels are: " + "ticker, trades, book, candles and status."
|
||||
)
|
||||
|
||||
for bucket in self.__buckets:
|
||||
if sub_id in bucket.ids:
|
||||
raise SubIdError("sub_id must be " + \
|
||||
"unique for all subscriptions.")
|
||||
raise SubIdError("sub_id must be " + "unique for all subscriptions.")
|
||||
|
||||
for bucket in self.__buckets:
|
||||
if not bucket.is_full:
|
||||
return await bucket.subscribe( \
|
||||
channel, sub_id, **kwargs)
|
||||
return await bucket.subscribe(channel, sub_id, **kwargs)
|
||||
|
||||
bucket = await self.__new_bucket()
|
||||
|
||||
return await bucket.subscribe( \
|
||||
channel, sub_id, **kwargs)
|
||||
return await bucket.subscribe(channel, sub_id, **kwargs)
|
||||
|
||||
@Connection._require_websocket_connection
|
||||
async def unsubscribe(self, sub_id: str) -> None:
|
||||
@@ -286,13 +313,13 @@ class BfxWebSocketClient(Connection):
|
||||
if bucket.count == 1:
|
||||
del self.__buckets[bucket]
|
||||
|
||||
return await bucket.close( \
|
||||
code=1001, reason="Going Away")
|
||||
return await bucket.close(code=1001, reason="Going Away")
|
||||
|
||||
return await bucket.unsubscribe(sub_id)
|
||||
|
||||
raise UnknownSubscriptionError("Unable to find " + \
|
||||
f"a subscription with sub_id <{sub_id}>.")
|
||||
raise UnknownSubscriptionError(
|
||||
"Unable to find " + f"a subscription with sub_id <{sub_id}>."
|
||||
)
|
||||
|
||||
@Connection._require_websocket_connection
|
||||
async def resubscribe(self, sub_id: str) -> None:
|
||||
@@ -300,8 +327,9 @@ class BfxWebSocketClient(Connection):
|
||||
if bucket.has(sub_id):
|
||||
return await bucket.resubscribe(sub_id)
|
||||
|
||||
raise UnknownSubscriptionError("Unable to find " + \
|
||||
f"a subscription with sub_id <{sub_id}>.")
|
||||
raise UnknownSubscriptionError(
|
||||
"Unable to find " + f"a subscription with sub_id <{sub_id}>."
|
||||
)
|
||||
|
||||
@Connection._require_websocket_connection
|
||||
async def close(self, code: int = 1000, reason: str = str()) -> None:
|
||||
@@ -309,22 +337,21 @@ class BfxWebSocketClient(Connection):
|
||||
await bucket.close(code=code, reason=reason)
|
||||
|
||||
if self._websocket.open:
|
||||
await self._websocket.close( \
|
||||
code=code, reason=reason)
|
||||
await self._websocket.close(code=code, reason=reason)
|
||||
|
||||
@Connection._require_websocket_authentication
|
||||
async def notify(self,
|
||||
info: Any,
|
||||
message_id: Optional[int] = None,
|
||||
**kwargs: Any) -> None:
|
||||
async def notify(
|
||||
self, info: Any, message_id: Optional[int] = None, **kwargs: Any
|
||||
) -> None:
|
||||
await self._websocket.send(
|
||||
json.dumps([ 0, "n", message_id,
|
||||
{ "type": "ucm-test", "info": info, **kwargs } ]))
|
||||
json.dumps(
|
||||
[0, "n", message_id, {"type": "ucm-test", "info": info, **kwargs}]
|
||||
)
|
||||
)
|
||||
|
||||
@Connection._require_websocket_authentication
|
||||
async def __handle_websocket_input(self, event: str, data: Any) -> None:
|
||||
await self._websocket.send(json.dumps( \
|
||||
[ 0, event, None, data], cls=JSONEncoder))
|
||||
await self._websocket.send(json.dumps([0, event, None, data], cls=JSONEncoder))
|
||||
|
||||
def on(self, event, callback = None):
|
||||
def on(self, event, callback=None):
|
||||
return self.__event_emitter.on(event, callback)
|
||||
|
||||
@@ -3,89 +3,127 @@ from typing import Any, Awaitable, Callable, List, Optional, Tuple, Union
|
||||
|
||||
_Handler = Callable[[str, Any], Awaitable[None]]
|
||||
|
||||
|
||||
class BfxWebSocketInputs:
|
||||
def __init__(self, handle_websocket_input: _Handler) -> None:
|
||||
self.__handle_websocket_input = handle_websocket_input
|
||||
|
||||
async def submit_order(self,
|
||||
type: str,
|
||||
symbol: str,
|
||||
amount: Union[str, float, Decimal],
|
||||
price: Union[str, float, Decimal],
|
||||
*,
|
||||
lev: Optional[int] = None,
|
||||
price_trailing: Optional[Union[str, float, Decimal]] = None,
|
||||
price_aux_limit: Optional[Union[str, float, Decimal]] = None,
|
||||
price_oco_stop: Optional[Union[str, float, Decimal]] = None,
|
||||
gid: Optional[int] = None,
|
||||
cid: Optional[int] = None,
|
||||
flags: Optional[int] = None,
|
||||
tif: Optional[str] = None) -> None:
|
||||
await self.__handle_websocket_input("on", {
|
||||
"type": type, "symbol": symbol, "amount": amount,
|
||||
"price": price, "lev": lev, "price_trailing": price_trailing,
|
||||
"price_aux_limit": price_aux_limit, "price_oco_stop": price_oco_stop, "gid": gid,
|
||||
"cid": cid, "flags": flags, "tif": tif
|
||||
})
|
||||
async def submit_order(
|
||||
self,
|
||||
type: str,
|
||||
symbol: str,
|
||||
amount: Union[str, float, Decimal],
|
||||
price: Union[str, float, Decimal],
|
||||
*,
|
||||
lev: Optional[int] = None,
|
||||
price_trailing: Optional[Union[str, float, Decimal]] = None,
|
||||
price_aux_limit: Optional[Union[str, float, Decimal]] = None,
|
||||
price_oco_stop: Optional[Union[str, float, Decimal]] = None,
|
||||
gid: Optional[int] = None,
|
||||
cid: Optional[int] = None,
|
||||
flags: Optional[int] = None,
|
||||
tif: Optional[str] = None,
|
||||
) -> None:
|
||||
await self.__handle_websocket_input(
|
||||
"on",
|
||||
{
|
||||
"type": type,
|
||||
"symbol": symbol,
|
||||
"amount": amount,
|
||||
"price": price,
|
||||
"lev": lev,
|
||||
"price_trailing": price_trailing,
|
||||
"price_aux_limit": price_aux_limit,
|
||||
"price_oco_stop": price_oco_stop,
|
||||
"gid": gid,
|
||||
"cid": cid,
|
||||
"flags": flags,
|
||||
"tif": tif,
|
||||
},
|
||||
)
|
||||
|
||||
async def update_order(self,
|
||||
id: int,
|
||||
*,
|
||||
amount: Optional[Union[str, float, Decimal]] = None,
|
||||
price: Optional[Union[str, float, Decimal]] = None,
|
||||
cid: Optional[int] = None,
|
||||
cid_date: Optional[str] = None,
|
||||
gid: Optional[int] = None,
|
||||
flags: Optional[int] = None,
|
||||
lev: Optional[int] = None,
|
||||
delta: Optional[Union[str, float, Decimal]] = None,
|
||||
price_aux_limit: Optional[Union[str, float, Decimal]] = None,
|
||||
price_trailing: Optional[Union[str, float, Decimal]] = None,
|
||||
tif: Optional[str] = None) -> None:
|
||||
await self.__handle_websocket_input("ou", {
|
||||
"id": id, "amount": amount, "price": price,
|
||||
"cid": cid, "cid_date": cid_date, "gid": gid,
|
||||
"flags": flags, "lev": lev, "delta": delta,
|
||||
"price_aux_limit": price_aux_limit, "price_trailing": price_trailing, "tif": tif
|
||||
})
|
||||
async def update_order(
|
||||
self,
|
||||
id: int,
|
||||
*,
|
||||
amount: Optional[Union[str, float, Decimal]] = None,
|
||||
price: Optional[Union[str, float, Decimal]] = None,
|
||||
cid: Optional[int] = None,
|
||||
cid_date: Optional[str] = None,
|
||||
gid: Optional[int] = None,
|
||||
flags: Optional[int] = None,
|
||||
lev: Optional[int] = None,
|
||||
delta: Optional[Union[str, float, Decimal]] = None,
|
||||
price_aux_limit: Optional[Union[str, float, Decimal]] = None,
|
||||
price_trailing: Optional[Union[str, float, Decimal]] = None,
|
||||
tif: Optional[str] = None,
|
||||
) -> None:
|
||||
await self.__handle_websocket_input(
|
||||
"ou",
|
||||
{
|
||||
"id": id,
|
||||
"amount": amount,
|
||||
"price": price,
|
||||
"cid": cid,
|
||||
"cid_date": cid_date,
|
||||
"gid": gid,
|
||||
"flags": flags,
|
||||
"lev": lev,
|
||||
"delta": delta,
|
||||
"price_aux_limit": price_aux_limit,
|
||||
"price_trailing": price_trailing,
|
||||
"tif": tif,
|
||||
},
|
||||
)
|
||||
|
||||
async def cancel_order(self,
|
||||
*,
|
||||
id: Optional[int] = None,
|
||||
cid: Optional[int] = None,
|
||||
cid_date: Optional[str] = None) -> None:
|
||||
await self.__handle_websocket_input("oc", {
|
||||
"id": id, "cid": cid, "cid_date": cid_date
|
||||
})
|
||||
async def cancel_order(
|
||||
self,
|
||||
*,
|
||||
id: Optional[int] = None,
|
||||
cid: Optional[int] = None,
|
||||
cid_date: Optional[str] = None,
|
||||
) -> None:
|
||||
await self.__handle_websocket_input(
|
||||
"oc", {"id": id, "cid": cid, "cid_date": cid_date}
|
||||
)
|
||||
|
||||
async def cancel_order_multi(self,
|
||||
*,
|
||||
id: Optional[List[int]] = None,
|
||||
cid: Optional[List[Tuple[int, str]]] = None,
|
||||
gid: Optional[List[int]] = None,
|
||||
all: Optional[bool] = None) -> None:
|
||||
await self.__handle_websocket_input("oc_multi", {
|
||||
"id": id, "cid": cid, "gid": gid,
|
||||
"all": all
|
||||
})
|
||||
async def cancel_order_multi(
|
||||
self,
|
||||
*,
|
||||
id: Optional[List[int]] = None,
|
||||
cid: Optional[List[Tuple[int, str]]] = None,
|
||||
gid: Optional[List[int]] = None,
|
||||
all: Optional[bool] = None,
|
||||
) -> None:
|
||||
await self.__handle_websocket_input(
|
||||
"oc_multi", {"id": id, "cid": cid, "gid": gid, "all": all}
|
||||
)
|
||||
|
||||
#pylint: disable-next=too-many-arguments
|
||||
async def submit_funding_offer(self,
|
||||
type: str,
|
||||
symbol: str,
|
||||
amount: Union[str, float, Decimal],
|
||||
rate: Union[str, float, Decimal],
|
||||
period: int,
|
||||
*,
|
||||
flags: Optional[int] = None) -> None:
|
||||
await self.__handle_websocket_input("fon", {
|
||||
"type": type, "symbol": symbol, "amount": amount,
|
||||
"rate": rate, "period": period, "flags": flags
|
||||
})
|
||||
# pylint: disable-next=too-many-arguments
|
||||
async def submit_funding_offer(
|
||||
self,
|
||||
type: str,
|
||||
symbol: str,
|
||||
amount: Union[str, float, Decimal],
|
||||
rate: Union[str, float, Decimal],
|
||||
period: int,
|
||||
*,
|
||||
flags: Optional[int] = None,
|
||||
) -> None:
|
||||
await self.__handle_websocket_input(
|
||||
"fon",
|
||||
{
|
||||
"type": type,
|
||||
"symbol": symbol,
|
||||
"amount": amount,
|
||||
"rate": rate,
|
||||
"period": period,
|
||||
"flags": flags,
|
||||
},
|
||||
)
|
||||
|
||||
async def cancel_funding_offer(self, id: int) -> None:
|
||||
await self.__handle_websocket_input("foc", { "id": id })
|
||||
await self.__handle_websocket_input("foc", {"id": id})
|
||||
|
||||
async def calc(self, *args: str) -> None:
|
||||
await self.__handle_websocket_input("calc",
|
||||
list(map(lambda arg: [arg], args)))
|
||||
await self.__handle_websocket_input("calc", list(map(lambda arg: [arg], args)))
|
||||
|
||||
Reference in New Issue
Block a user