diff --git a/bfxapi/exceptions.py b/bfxapi/exceptions.py index 8e9b6e5..1033837 100644 --- a/bfxapi/exceptions.py +++ b/bfxapi/exceptions.py @@ -1,6 +1,9 @@ __all__ = [ "BfxBaseException", - "LabelerSerializerException" + + "LabelerSerializerException", + "IntegerUnderflowError", + "IntegerOverflowflowError" ] class BfxBaseException(Exception): @@ -15,4 +18,18 @@ class LabelerSerializerException(BfxBaseException): This exception indicates an error thrown by the _Serializer class in bfxapi/labeler.py. """ + pass + +class IntegerUnderflowError(BfxBaseException): + """ + This error indicates an underflow in one of the integer types defined in bfxapi/utils/integers.py. + """ + + pass + +class IntegerOverflowflowError(BfxBaseException): + """ + This error indicates an overflow in one of the integer types defined in bfxapi/utils/integers.py. + """ + pass \ No newline at end of file diff --git a/bfxapi/rest/exceptions.py b/bfxapi/rest/exceptions.py index 0fc6de8..81bcb8f 100644 --- a/bfxapi/rest/exceptions.py +++ b/bfxapi/rest/exceptions.py @@ -1,4 +1,4 @@ -from ..exceptions import BfxBaseException +from .. exceptions import BfxBaseException __all__ = [ "BfxRestException", diff --git a/bfxapi/utils/decimal.py b/bfxapi/utils/decimal.py new file mode 100644 index 0000000..5a7af71 --- /dev/null +++ b/bfxapi/utils/decimal.py @@ -0,0 +1,9 @@ +import json + +from decimal import Decimal + +class DecimalEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, Decimal): + return str(obj) + return json.JSONEncoder.default(self, obj) \ No newline at end of file diff --git a/bfxapi/utils/integers.py b/bfxapi/utils/integers.py new file mode 100644 index 0000000..e38f107 --- /dev/null +++ b/bfxapi/utils/integers.py @@ -0,0 +1,35 @@ +from typing import cast, TypeVar + +from .. exceptions import IntegerUnderflowError, IntegerOverflowflowError + +__all__ = [ "Int16", "Int32", "Int45", "Int64" ] + +T = TypeVar("T") + +class _Int(int): + def __new__(cls: T, integer: int) -> T: + assert hasattr(cls, "_BITS"), "_Int must be extended by a class that has a static member _BITS (indicating the number of bits with which to represent the integers)." + + bits = cls._BITS - 1 + + min, max = -(2 ** bits), (2 ** bits) - 1 + + if integer < min: + raise IntegerUnderflowError(f"Underflow. Cannot store <{integer}> in {cls._BITS} bits integer. The min and max bounds are {min} and {max}.") + + if integer > max: + raise IntegerOverflowflowError(f"Overflow. Cannot store <{integer}> in {cls._BITS} bits integer. The min and max bounds are {min} and {max}.") + + return cast(T, super().__new__(int, integer)) + +class Int16(_Int): + _BITS = 16 + +class Int32(_Int): + _BITS = 32 + +class Int45(_Int): + _BITS = 45 + +class Int64(_Int): + _BITS = 64 \ No newline at end of file diff --git a/bfxapi/websocket/BfxWebsocketClient.py b/bfxapi/websocket/BfxWebsocketClient.py index e8bb4d0..775fa10 100644 --- a/bfxapi/websocket/BfxWebsocketClient.py +++ b/bfxapi/websocket/BfxWebsocketClient.py @@ -1,25 +1,40 @@ import traceback, json, asyncio, hmac, hashlib, time, uuid, websockets +from typing import Tuple, Union, Literal, TypeVar, Callable, cast + from enum import Enum from pyee.asyncio import AsyncIOEventEmitter -from .typings import Inputs, Tuple, Union +from .typings import Inputs from .handlers import Channels, PublicChannelsHandler, AuthenticatedChannelsHandler from .exceptions import ConnectionNotOpen, TooManySubscriptions, WebsocketAuthenticationRequired, InvalidAuthenticationCredentials, EventNotSupported, OutdatedClientVersion +from ..utils.decimal import DecimalEncoder + from ..utils.logger import Formatter, CustomLogger _HEARTBEAT = "hb" -def _require_websocket_connection(function): +F = TypeVar("F", bound=Callable[..., Literal[None]]) + +def _require_websocket_connection(function: F) -> F: async def wrapper(self, *args, **kwargs): if self.websocket == None or self.websocket.open == False: raise ConnectionNotOpen("No open connection with the server.") await function(self, *args, **kwargs) - return wrapper + return cast(F, wrapper) + +def _require_websocket_authentication(function: F) -> F: + async def wrapper(self, *args, **kwargs): + if self.authentication == False: + raise WebsocketAuthenticationRequired("To perform this action you need to authenticate using your API_KEY and API_SECRET.") + + await _require_websocket_connection(function)(self, *args, **kwargs) + + return cast(F, wrapper) class BfxWebsocketClient(object): VERSION = 2 @@ -118,22 +133,13 @@ class BfxWebsocketClient(object): for bucket in self.buckets: await bucket._close(code=code, reason=reason) - def __require_websocket_authentication(function): - async def wrapper(self, *args, **kwargs): - if self.authentication == False: - raise WebsocketAuthenticationRequired("To perform this action you need to authenticate using your API_KEY and API_SECRET.") - - await _require_websocket_connection(function)(self, *args, **kwargs) - - return wrapper - - @__require_websocket_authentication + @_require_websocket_authentication async def notify(self, info, MESSAGE_ID=None, **kwargs): await self.websocket.send(json.dumps([ 0, "n", MESSAGE_ID, { "type": "ucm-test", "info": info, **kwargs } ])) - @__require_websocket_authentication + @_require_websocket_authentication async def __handle_websocket_input(self, input, data): - await self.websocket.send(json.dumps([ 0, input, None, data])) + await self.websocket.send(json.dumps([ 0, input, None, data], cls=DecimalEncoder)) def __bucket_open_signal(self, index): if all(bucket.websocket != None and bucket.websocket.open == True for bucket in self.buckets): diff --git a/bfxapi/websocket/exceptions.py b/bfxapi/websocket/exceptions.py index c55b767..5691af8 100644 --- a/bfxapi/websocket/exceptions.py +++ b/bfxapi/websocket/exceptions.py @@ -1,4 +1,8 @@ +from .. exceptions import BfxBaseException + __all__ = [ + "BfxWebsocketException", + "ConnectionNotOpen", "TooManySubscriptions", "WebsocketAuthenticationRequired", @@ -7,9 +11,9 @@ __all__ = [ "OutdatedClientVersion" ] -class BfxWebsocketException(Exception): +class BfxWebsocketException(BfxBaseException): """ - Base class for all exceptions defined in bfxapi/websocket/exceptions.py. + Base class for all custom exceptions in bfxapi/websocket/exceptions.py. """ pass @@ -35,13 +39,6 @@ class WebsocketAuthenticationRequired(BfxWebsocketException): pass -class InvalidAuthenticationCredentials(BfxWebsocketException): - """ - This error indicates that the user has provided incorrect credentials (API-KEY and API-SECRET) for authentication. - """ - - pass - class EventNotSupported(BfxWebsocketException): """ This error indicates a failed attempt to subscribe to an event not supported by the BfxWebsocketClient. @@ -54,4 +51,11 @@ class OutdatedClientVersion(BfxWebsocketException): This error indicates a mismatch between the client version and the server WSS version. """ + pass + +class InvalidAuthenticationCredentials(BfxWebsocketException): + """ + This error indicates that the user has provided incorrect credentials (API-KEY and API-SECRET) for authentication. + """ + pass \ No newline at end of file diff --git a/bfxapi/websocket/serializers.py b/bfxapi/websocket/serializers.py index 64573cc..00f43d2 100644 --- a/bfxapi/websocket/serializers.py +++ b/bfxapi/websocket/serializers.py @@ -1,25 +1,6 @@ -from typing import Generic, TypeVar, Iterable, List, Any - from . import typings -from .exceptions import BfxWebsocketException - -T = TypeVar("T") - -class _Serializer(Generic[T]): - def __init__(self, name: str, labels: List[str]): - self.name, self.__labels = name, labels - - def __serialize(self, *args: Any, IGNORE: List[str] = [ "_PLACEHOLDER" ]) -> Iterable[T]: - if len(self.__labels) != len(args): - raise BfxWebsocketException(" and <*args> arguments should contain the same amount of elements.") - - for index, label in enumerate(self.__labels): - if label not in IGNORE: - yield label, args[index] - - def parse(self, *values: Any) -> T: - return dict(self.__serialize(*values)) +from .. labeler import _Serializer #region Serializers definition for Websocket Public Channels @@ -315,7 +296,7 @@ BalanceInfo = _Serializer[typings.BalanceInfo]("BalanceInfo", labels=[ #region Serializers definition for Notifications channel -Notification = _Serializer("Notification", labels=[ +Notification = _Serializer[typings.Notification]("Notification", labels=[ "MTS", "TYPE", "MESSAGE_ID", diff --git a/bfxapi/websocket/typings.py b/bfxapi/websocket/typings.py index 4a3b918..9966d99 100644 --- a/bfxapi/websocket/typings.py +++ b/bfxapi/websocket/typings.py @@ -2,301 +2,294 @@ from decimal import Decimal from datetime import datetime -from typing import Type, Tuple, List, Dict, TypedDict, Union, Optional, Any +from typing import Type, NewType, Tuple, List, Dict, TypedDict, Union, Optional, Any -int16 = int32 = int45 = int64 = int +from ..utils.integers import Int16, Int32, Int45, Int64 JSON = Union[Dict[str, "JSON"], List["JSON"], bool, int, float, str, Type[None]] #region Type hinting for subscription objects class Subscriptions: - TradingPairsTicker = TypedDict("Subscriptions.TradingPairsTicker", { - "chanId": int, - "symbol": str, - "pair": str - }) + class TradingPairsTicker(TypedDict): + chanId: int + symbol: str + pair: str - FundingCurrenciesTicker = TypedDict("Subscriptions.FundingCurrenciesTicker", { - "chanId": int, - "symbol": str, - "currency": str - }) + class FundingCurrenciesTicker(TypedDict): + chanId: int + symbol: str + currency: str - TradingPairsTrades = TypedDict("Subscriptions.TradingPairsTrades", { - "chanId": int, - "symbol": str, - "pair": str - }) + class TradingPairsTrades(TypedDict): + chanId: int + symbol: str + pair: str - FundingCurrenciesTrades = TypedDict("Subscriptions.FundingCurrenciesTrades", { - "chanId": int, - "symbol": str, - "currency": str - }) + class FundingCurrenciesTrades(TypedDict): + chanId: int + symbol: str + currency: str - Book = TypedDict("Subscriptions.Book", { - "chanId": int, - "symbol": str, - "prec": str, - "freq": str, - "len": str, - "subId": int, - "pair": str - }) + class Book(TypedDict): + chanId: int + symbol: str + prec: str + freq: str + len: str + subId: int + pair: str - Candles = TypedDict("Subscriptions.Candles", { - "chanId": int, - "key": str - }) + class Candles(TypedDict): + chanId: int + key: str - DerivativesStatus = TypedDict("Subscriptions.DerivativesStatus", { - "chanId": int, - "key": str - }) + class DerivativesStatus(TypedDict): + chanId: int + key: str #endregion #region Type hinting for Websocket Public Channels -TradingPairTicker = TypedDict("TradingPairTicker", { - "BID": float, - "BID_SIZE": float, - "ASK": float, - "ASK_SIZE": float, - "DAILY_CHANGE": float, - "DAILY_CHANGE_RELATIVE": float, - "LAST_PRICE": float, - "VOLUME": float, - "HIGH": float, - "LOW": float -}) +class TradingPairTicker(TypedDict): + BID: float + BID_SIZE: float + ASK: float + ASK_SIZE: float + DAILY_CHANGE: float + DAILY_CHANGE_RELATIVE: float + LAST_PRICE: float + VOLUME: float + HIGH: float + LOW: float -FundingCurrencyTicker = TypedDict("FundingCurrencyTicker", { - "FRR": float, - "BID": float, - "BID_PERIOD": int, - "BID_SIZE": float, - "ASK": float, - "ASK_PERIOD": int, - "ASK_SIZE": float, - "DAILY_CHANGE": float, - "DAILY_CHANGE_RELATIVE": float, - "LAST_PRICE": float, - "VOLUME": float, - "HIGH": float, - "LOW": float, - "FRR_AMOUNT_AVAILABLE": float -}) +class FundingCurrencyTicker(TypedDict): + FRR: float + BID: float + BID_PERIOD: int + BID_SIZE: float + ASK: float + ASK_PERIOD: int + ASK_SIZE: float + DAILY_CHANGE: float + DAILY_CHANGE_RELATIVE: float + LAST_PRICE: float + VOLUME: float + HIGH: float + LOW: float + FRR_AMOUNT_AVAILABLE: float -(TradingPairTrade, FundingCurrencyTrade) = ( - TypedDict("TradingPairTrade", { "ID": int, "MTS": int, "AMOUNT": float, "PRICE": float }), - TypedDict("FundingCurrencyTrade", { "ID": int, "MTS": int, "AMOUNT": float, "RATE": float, "PERIOD": int }) -) +class TradingPairTrade(TypedDict): + ID: int + MTS: int + AMOUNT: float + PRICE: float -(TradingPairTrades, FundingCurrencyTrades) = (List[TradingPairTrade], List[FundingCurrencyTrade]) +class FundingCurrencyTrade(TypedDict): + ID: int + MTS: int + AMOUNT: float + RATE: float + PERIOD: int -(TradingPairBook, FundingCurrencyBook) = ( - TypedDict("TradingPairBook", { "PRICE": float, "COUNT": int, "AMOUNT": float }), - TypedDict("FundingCurrencyBook", { "RATE": float, "PERIOD": int, "COUNT": int, "AMOUNT": float }) -) +class TradingPairBook(TypedDict): + PRICE: float + COUNT: int + AMOUNT: float + +class FundingCurrencyBook(TypedDict): + RATE: float + PERIOD: int + COUNT: int + AMOUNT: float + +class TradingPairRawBook(TypedDict): + ORDER_ID: int + PRICE: float + AMOUNT: float + +class FundingCurrencyRawBook(TypedDict): + OFFER_ID: int + PERIOD: int + RATE: float + AMOUNT: float -(TradingPairBooks, FundingCurrencyBooks) = (List[TradingPairBook], List[FundingCurrencyBook]) +class Candle(TypedDict): + MTS: int + OPEN: float + CLOSE: float + HIGH: float + LOW: float + VOLUME: float -(TradingPairRawBook, FundingCurrencyRawBook) = ( - TypedDict("TradingPairRawBook", { "ORDER_ID": int, "PRICE": float, "AMOUNT": float }), - TypedDict("FundingCurrencyRawBook", { "OFFER_ID": int, "PERIOD": int, "RATE": float, "AMOUNT": float }), -) - -(TradingPairRawBooks, FundingCurrencyRawBooks) = (List[TradingPairRawBook], List[FundingCurrencyRawBook]) - -Candle = TypedDict("Candle", { - "MTS": int, - "OPEN": float, - "CLOSE": float, - "HIGH": float, - "LOW": float, - "VOLUME": float -}) - -Candles = List[Candle] - -DerivativesStatus = TypedDict("DerivativesStatus", { - "TIME_MS": int, - "DERIV_PRICE": float, - "SPOT_PRICE": float, - "INSURANCE_FUND_BALANCE": float, - "NEXT_FUNDING_EVT_TIMESTAMP_MS": int, - "NEXT_FUNDING_ACCRUED": float, - "NEXT_FUNDING_STEP": int, - "CURRENT_FUNDING": float, - "MARK_PRICE": float, - "OPEN_INTEREST": float, - "CLAMP_MIN": float, - "CLAMP_MAX": float -}) +class DerivativesStatus(TypedDict): + TIME_MS: int + DERIV_PRICE: float + SPOT_PRICE: float + INSURANCE_FUND_BALANCE: float + NEXT_FUNDING_EVT_TIMESTAMP_MS: int + NEXT_FUNDING_ACCRUED: float + NEXT_FUNDING_STEP: int + CURRENT_FUNDING: float + MARK_PRICE: float + OPEN_INTEREST: float + CLAMP_MIN: float + CLAMP_MAX: float #endregion #region Type hinting for Websocket Authenticated Channels -Order = TypedDict("Order", { - "ID": int, - "GID": int, - "CID": int, - "SYMBOL": str, - "MTS_CREATE": int, - "MTS_UPDATE": int, - "AMOUNT": float, - "AMOUNT_ORIG": float, - "ORDER_TYPE": str, - "TYPE_PREV": str, - "MTS_TIF": int, - "FLAGS": int, - "ORDER_STATUS": str, - "PRICE": float, - "PRICE_AVG": float, - "PRICE_TRAILING": float, - "PRICE_AUX_LIMIT": float, - "NOTIFY": int, - "HIDDEN": int, - "PLACED_ID": int, - "ROUTING": str, - "META": JSON -}) +class Order(TypedDict): + ID: int + GID: int + CID: int + SYMBOL: str + MTS_CREATE: int + MTS_UPDATE: int + AMOUNT: float + AMOUNT_ORIG: float + ORDER_TYPE: str + TYPE_PREV: str + MTS_TIF: int + FLAGS: int + ORDER_STATUS: str + PRICE: float + PRICE_AVG: float + PRICE_TRAILING: float + PRICE_AUX_LIMIT: float + NOTIFY: int + HIDDEN: int + PLACED_ID: int + ROUTING: str + META: JSON -Orders = List[Order] +class Position(TypedDict): + SYMBOL: str + STATUS: str + AMOUNT: float + BASE_PRICE: float + MARGIN_FUNDING: float + MARGIN_FUNDING_TYPE: int + PL: float + PL_PERC: float + PRICE_LIQ: float + LEVERAGE: float + POSITION_ID: int + MTS_CREATE: int + MTS_UPDATE: int + TYPE: int + COLLATERAL: float + COLLATERAL_MIN: float + META: JSON -Position = TypedDict("Position", { - "SYMBOL": str, - "STATUS": str, - "AMOUNT": float, - "BASE_PRICE": float, - "MARGIN_FUNDING": float, - "MARGIN_FUNDING_TYPE": int, - "PL": float, - "PL_PERC": float, - "PRICE_LIQ": float, - "LEVERAGE": float, - "POSITION_ID": int, - "MTS_CREATE": int, - "MTS_UPDATE": int, - "TYPE": int, - "COLLATERAL": float, - "COLLATERAL_MIN": float, - "META": JSON, -}) +class TradeExecuted(TypedDict): + ID: int + SYMBOL: str + MTS_CREATE: int + ORDER_ID: int + EXEC_AMOUNT: float + EXEC_PRICE: float + ORDER_TYPE: str + ORDER_PRICE: float + MAKER:int + CID: int -Positions = List[Position] +class TradeExecutionUpdate(TypedDict): + ID: int + SYMBOL: str + MTS_CREATE: int + ORDER_ID: int + EXEC_AMOUNT: float + EXEC_PRICE: float + ORDER_TYPE: str + ORDER_PRICE: float + MAKER:int + FEE: float + FEE_CURRENCY: str + CID: int -TradeExecuted = TypedDict("TradeExecuted", { - "ID": int, - "SYMBOL": str, - "MTS_CREATE": int, - "ORDER_ID": int, - "EXEC_AMOUNT": float, - "EXEC_PRICE": float, - "ORDER_TYPE": str, - "ORDER_PRICE": float, - "MAKER":int, - "CID": int -}) +class FundingOffer(TypedDict): + ID: int + SYMBOL: str + MTS_CREATED: int + MTS_UPDATED: int + AMOUNT: float + AMOUNT_ORIG: float + OFFER_TYPE: str + FLAGS: int + STATUS: str + RATE: float + PERIOD: int + NOTIFY: int + HIDDEN: int + RENEW: int -TradeExecutionUpdate = TypedDict("TradeExecutionUpdate", { - "ID": int, - "SYMBOL": str, - "MTS_CREATE": int, - "ORDER_ID": int, - "EXEC_AMOUNT": float, - "EXEC_PRICE": float, - "ORDER_TYPE": str, - "ORDER_PRICE": float, - "MAKER":int, - "FEE": float, - "FEE_CURRENCY": str, - "CID": int -}) +class FundingCredit(TypedDict): + ID: int + SYMBOL: str + SIDE: int + MTS_CREATE: int + MTS_UPDATE: int + AMOUNT: float + FLAGS: int + STATUS: str + RATE: float + PERIOD: int + MTS_OPENING: int + MTS_LAST_PAYOUT: int + NOTIFY: int + HIDDEN: int + RENEW: int + RATE_REAL: float + NO_CLOSE: int + POSITION_PAIR: str -FundingOffer = TypedDict("FundingOffer", { - "ID": int, - "SYMBOL": str, - "MTS_CREATED": int, - "MTS_UPDATED": int, - "AMOUNT": float, - "AMOUNT_ORIG": float, - "OFFER_TYPE": str, - "FLAGS": int, - "STATUS": str, - "RATE": float, - "PERIOD": int, - "NOTIFY": int, - "HIDDEN": int, - "RENEW": int, -}) +class FundingLoan(TypedDict): + ID: int + SYMBOL: str + SIDE: int + MTS_CREATE: int + MTS_UPDATE: int + AMOUNT: float + FLAGS: int + STATUS: str + RATE: float + PERIOD: int + MTS_OPENING: int + MTS_LAST_PAYOUT: int + NOTIFY: int + HIDDEN: int + RENEW: int + RATE_REAL: float + NO_CLOSE: int -FundingOffers = List[FundingOffer] +class Wallet(TypedDict): + WALLET_TYPE: str + CURRENCY: str + BALANCE: float + UNSETTLED_INTEREST: float + BALANCE_AVAILABLE: float + DESCRIPTION: str + META: JSON -FundingCredit = TypedDict("FundingCredit", { - "ID": int, - "SYMBOL": str, - "SIDE": int, - "MTS_CREATE": int, - "MTS_UPDATE": int, - "AMOUNT": float, - "FLAGS": int, - "STATUS": str, - "RATE": float, - "PERIOD": int, - "MTS_OPENING": int, - "MTS_LAST_PAYOUT": int, - "NOTIFY": int, - "HIDDEN": int, - "RENEW": int, - "RATE_REAL": float, - "NO_CLOSE": int, - "POSITION_PAIR": str -}) +class BalanceInfo(TypedDict): + AUM: float + AUM_NET: float -FundingCredits = List[FundingCredit] +#endregion -FundingLoan = TypedDict("FundingLoan", { - "ID": int, - "SYMBOL": str, - "SIDE": int, - "MTS_CREATE": int, - "MTS_UPDATE": int, - "AMOUNT": float, - "FLAGS": int, - "STATUS": str, - "RATE": float, - "PERIOD": int, - "MTS_OPENING": int, - "MTS_LAST_PAYOUT": int, - "NOTIFY": int, - "HIDDEN": int, - "RENEW": int, - "RATE_REAL": float, - "NO_CLOSE": int -}) +#region Serializers definition for Notifications channel -FundingLoans = List[FundingLoan] - -Wallet = TypedDict("Wallet", { - "WALLET_TYPE": str, - "CURRENCY": str, - "BALANCE": float, - "UNSETTLED_INTEREST": float, - "BALANCE_AVAILABLE": float, - "DESCRIPTION": str, - "META": JSON -}) - -Wallets = List[Wallet] - -BalanceInfo = TypedDict("BalanceInfo", { - "AUM": float, - "AUM_NET": float -}) +class Notification(TypedDict): + MTS: int + TYPE: str + MESSAGE_ID: int + NOTIFY_INFO: JSON + CODE: int + STATUS: str + TEXT: str #endregion @@ -304,55 +297,50 @@ BalanceInfo = TypedDict("BalanceInfo", { class Inputs: class Order: - New = TypedDict("Inputs.Order.New", { - "gid": Optional[int32], - "cid": int45, - "type": str, - "symbol": str, - "amount": Union[Decimal, str], - "price": Union[Decimal, str], - "lev": int, - "price_trailing": Union[Decimal, str], - "price_aux_limit": Union[Decimal, str], - "price_oco_stop": Union[Decimal, str], - "flags": int16, - "tif": Union[datetime, str], - "meta": JSON - }) + class New(TypedDict, total=False): + gid: Union[Int32, int] + cid: Union[Int45, int] + type: str + symbol: str + amount: Union[Decimal, str] + price: Union[Decimal, str] + lev: Union[Int32, int] + price_trailing: Union[Decimal, str] + price_aux_limit: Union[Decimal, str] + price_oco_stop: Union[Decimal, str] + flags: Union[Int16, int] + tif: Union[datetime, str] + meta: JSON - Update = TypedDict("Inputs.Order.Update", { - "id": int64, - "cid": int45, - "cid_date": str, - "gid": int32, - "price": Union[Decimal, str], - "amount": Union[Decimal, str], - "lev": int, - "delta": Union[Decimal, str], - "price_aux_limit": Union[Decimal, str], - "price_trailing": Union[Decimal, str], - "flags": int16, - "tif": Union[datetime, str] - }) + class Update(TypedDict, total=False): + id: Union[Int64, int] + cid: Union[Int45, int] + cid_date: str + gid: Union[Int32, int] + price: Union[Decimal, str] + amount: Union[Decimal, str] + lev: Union[Int32, int] + delta: Union[Decimal, str] + price_aux_limit: Union[Decimal, str] + price_trailing: Union[Decimal, str] + flags: Union[Int16, int] + tif: Union[datetime, str] - Cancel = TypedDict("Inputs.Order.Cancel", { - "id": int64, - "cid": int45, - "cid_date": str - }) + class Cancel(TypedDict, total=False): + id: Union[Int64, int] + cid: Union[Int45, int] + cid_date: Union[datetime, str] class Offer: - New = TypedDict("Inputs.Offer.New", { - "type": str, - "symbol": str, - "amount": Union[Decimal, str], - "rate": Union[Decimal, str], - "period": int, - "flags": int16 - }) + class New(TypedDict, total=False): + type: str + symbol: str + amount: Union[Decimal, str] + rate: Union[Decimal, str] + period: Union[Int32, int] + flags: Union[Int16, int] - Cancel = TypedDict("Inputs.Offer.Cancel", { - "id": int - }) + class Cancel(TypedDict, total=False): + id: Union[Int32, int] #endregion \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 549f7a6..71a2708 100644 Binary files a/requirements.txt and b/requirements.txt differ diff --git a/setup.py b/setup.py index a4c8397..963f30a 100644 --- a/setup.py +++ b/setup.py @@ -11,11 +11,16 @@ setup( description="Official Bitfinex Python API", keywords="bitfinex,api,trading", install_requires=[ - "certifi~=2022.9.24", + "certifi~=2022.12.7", "charset-normalizer~=2.1.1", "idna~=3.4", + "mypy~=0.991", + "mypy-extensions~=0.4.3", "pyee~=9.0.4", "requests~=2.28.1", + "tomli~=2.0.1", + "types-requests~=2.28.11.5", + "types-urllib3~=1.26.25.4", "typing_extensions~=4.4.0", "urllib3~=1.26.13", "websockets~=10.4",