Move _Delay local class in global scope (bfxapi.websocket.client.bfx_websocket_client).

Apply pylint's linting rules to bfxapi/rest/__init__.py, bfxapi/rest/enums.py, bfxapi/rest/exceptions.py, bfxapi/rest/serializers.py and bfxapi/rest/types.py."
Apply pylint's linting rules to bfxapi/rest/endpoints/__init__.py, bfxapi/rest/endpoints/bfx_rest_interface.py and bfxapi/rest/endpoints/rest_public_endpoints.py.
This commit is contained in:
Davide Casale
2023-03-07 15:42:27 +01:00
parent 9e566bbc5a
commit 9e1b336a67
16 changed files with 1236 additions and 921 deletions

View File

@@ -10,6 +10,7 @@ disable=
multiple-imports, multiple-imports,
missing-docstring, missing-docstring,
too-few-public-methods, too-few-public-methods,
too-many-public-methods,
too-many-instance-attributes, too-many-instance-attributes,
dangerous-default-value, dangerous-default-value,
inconsistent-return-statements, inconsistent-return-statements,
@@ -19,7 +20,7 @@ disable=
max-line-length=120 max-line-length=120
good-names=id,on,pl,t,A,B,C,D,E,F good-names=id,on,pl,t,ip,tf,A,B,C,D,E,F
[TYPECHECK] [TYPECHECK]

View File

@@ -1,16 +1,13 @@
from typing import Optional
from .rest_public_endpoints import RestPublicEndpoints from .rest_public_endpoints import RestPublicEndpoints
from .rest_authenticated_endpoints import RestAuthenticatedEndpoints from .rest_authenticated_endpoints import RestAuthenticatedEndpoints
from .rest_merchant_endpoints import RestMerchantEndpoints from .rest_merchant_endpoints import RestMerchantEndpoints
class BfxRestInterface(object): class BfxRestInterface:
VERSION = 2 VERSION = 2
def __init__(self, host, credentials = None): def __init__(self, host, credentials = None):
API_KEY, API_SECRET = credentials and \ api_key, api_secret = (credentials['api_key'], credentials['api_secret']) if credentials else (None, None)
(credentials["api_key"], credentials["api_secret"]) or (None, None)
self.public = RestPublicEndpoints(host=host) self.public = RestPublicEndpoints(host=host)
self.auth = RestAuthenticatedEndpoints(host=host, API_KEY=API_KEY, API_SECRET=API_SECRET) self.auth = RestAuthenticatedEndpoints(host=host, api_key=api_key, api_secret=api_secret)
self.merchant = RestMerchantEndpoints(host=host, API_KEY=API_KEY, API_SECRET=API_SECRET) self.merchant = RestMerchantEndpoints(host=host, api_key=api_key, api_secret=api_secret)

View File

@@ -10,19 +10,19 @@ from .. middleware import Middleware
class RestAuthenticatedEndpoints(Middleware): class RestAuthenticatedEndpoints(Middleware):
def get_user_info(self) -> UserInfo: def get_user_info(self) -> UserInfo:
return serializers.UserInfo.parse(*self._POST(f"auth/r/info/user")) return serializers.UserInfo.parse(*self._post(f"auth/r/info/user"))
def get_login_history(self) -> List[LoginHistory]: def get_login_history(self) -> List[LoginHistory]:
return [ serializers.LoginHistory.parse(*sub_data) for sub_data in self._POST("auth/r/logins/hist") ] return [ serializers.LoginHistory.parse(*sub_data) for sub_data in self._post("auth/r/logins/hist") ]
def get_balance_available_for_orders_or_offers(self, symbol: str, type: str, dir: Optional[int] = None, rate: Optional[str] = None, lev: Optional[str] = None) -> BalanceAvailable: def get_balance_available_for_orders_or_offers(self, symbol: str, type: str, dir: Optional[int] = None, rate: Optional[str] = None, lev: Optional[str] = None) -> BalanceAvailable:
return serializers.BalanceAvailable.parse(*self._POST("auth/calc/order/avail", body={ return serializers.BalanceAvailable.parse(*self._post("auth/calc/order/avail", body={
"symbol": symbol, "type": type, "dir": dir, "symbol": symbol, "type": type, "dir": dir,
"rate": rate, "lev": lev "rate": rate, "lev": lev
})) }))
def get_wallets(self) -> List[Wallet]: def get_wallets(self) -> List[Wallet]:
return [ serializers.Wallet.parse(*sub_data) for sub_data in self._POST("auth/r/wallets") ] return [ serializers.Wallet.parse(*sub_data) for sub_data in self._post("auth/r/wallets") ]
def get_orders(self, symbol: Optional[str] = None, ids: Optional[List[str]] = None) -> List[Order]: def get_orders(self, symbol: Optional[str] = None, ids: Optional[List[str]] = None) -> List[Order]:
endpoint = "auth/r/orders" endpoint = "auth/r/orders"
@@ -30,7 +30,7 @@ class RestAuthenticatedEndpoints(Middleware):
if symbol != None: if symbol != None:
endpoint += f"/{symbol}" endpoint += f"/{symbol}"
return [ serializers.Order.parse(*sub_data) for sub_data in self._POST(endpoint, body={ "id": ids }) ] return [ serializers.Order.parse(*sub_data) for sub_data in self._post(endpoint, body={ "id": ids }) ]
def submit_order(self, type: OrderType, symbol: str, amount: Union[Decimal, float, str], def submit_order(self, type: OrderType, symbol: str, amount: Union[Decimal, float, str],
price: Optional[Union[Decimal, float, str]] = None, lev: Optional[int] = None, price: Optional[Union[Decimal, float, str]] = None, lev: Optional[int] = None,
@@ -45,7 +45,7 @@ class RestAuthenticatedEndpoints(Middleware):
"flags": flags, "tif": tif, "meta": meta "flags": flags, "tif": tif, "meta": meta
} }
return serializers._Notification[Order](serializers.Order).parse(*self._POST("auth/w/order/submit", body=body)) return serializers._Notification[Order](serializers.Order).parse(*self._post("auth/w/order/submit", body=body))
def update_order(self, id: int, amount: Optional[Union[Decimal, float, str]] = None, price: Optional[Union[Decimal, float, str]] = None, def update_order(self, id: int, amount: Optional[Union[Decimal, float, str]] = None, price: Optional[Union[Decimal, float, str]] = None,
cid: Optional[int] = None, cid_date: Optional[str] = None, gid: Optional[int] = None, cid: Optional[int] = None, cid_date: Optional[str] = None, gid: Optional[int] = None,
@@ -58,7 +58,7 @@ class RestAuthenticatedEndpoints(Middleware):
"price_aux_limit": price_aux_limit, "price_trailing": price_trailing, "tif": tif "price_aux_limit": price_aux_limit, "price_trailing": price_trailing, "tif": tif
} }
return serializers._Notification[Order](serializers.Order).parse(*self._POST("auth/w/order/update", body=body)) return serializers._Notification[Order](serializers.Order).parse(*self._post("auth/w/order/update", body=body))
def cancel_order(self, id: Optional[int] = None, cid: Optional[int] = None, cid_date: Optional[str] = None) -> Notification[Order]: def cancel_order(self, id: Optional[int] = None, cid: Optional[int] = None, cid_date: Optional[str] = None) -> Notification[Order]:
body = { body = {
@@ -67,7 +67,7 @@ class RestAuthenticatedEndpoints(Middleware):
"cid_date": cid_date "cid_date": cid_date
} }
return serializers._Notification[Order](serializers.Order).parse(*self._POST("auth/w/order/cancel", body=body)) return serializers._Notification[Order](serializers.Order).parse(*self._post("auth/w/order/cancel", body=body))
def cancel_order_multi(self, ids: Optional[List[int]] = None, cids: Optional[List[Tuple[int, str]]] = None, gids: Optional[List[int]] = None, all: bool = False) -> Notification[List[Order]]: def cancel_order_multi(self, ids: Optional[List[int]] = None, cids: Optional[List[Tuple[int, str]]] = None, gids: Optional[List[int]] = None, all: bool = False) -> Notification[List[Order]]:
body = { body = {
@@ -78,7 +78,7 @@ class RestAuthenticatedEndpoints(Middleware):
"all": int(all) "all": int(all)
} }
return serializers._Notification[List[Order]](serializers.Order, is_iterable=True).parse(*self._POST("auth/w/order/cancel/multi", body=body)) return serializers._Notification[List[Order]](serializers.Order, is_iterable=True).parse(*self._post("auth/w/order/cancel/multi", body=body))
def get_orders_history(self, symbol: Optional[str] = None, ids: Optional[List[int]] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[Order]: def get_orders_history(self, symbol: Optional[str] = None, ids: Optional[List[int]] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[Order]:
if symbol == None: if symbol == None:
@@ -91,10 +91,10 @@ class RestAuthenticatedEndpoints(Middleware):
"limit": limit "limit": limit
} }
return [ serializers.Order.parse(*sub_data) for sub_data in self._POST(endpoint, body=body) ] return [ serializers.Order.parse(*sub_data) for sub_data in self._post(endpoint, body=body) ]
def get_order_trades(self, symbol: str, id: int) -> List[OrderTrade]: def get_order_trades(self, symbol: str, id: int) -> List[OrderTrade]:
return [ serializers.OrderTrade.parse(*sub_data) for sub_data in self._POST(f"auth/r/order/{symbol}:{id}/trades") ] return [ serializers.OrderTrade.parse(*sub_data) for sub_data in self._post(f"auth/r/order/{symbol}:{id}/trades") ]
def get_trades_history(self, symbol: Optional[str] = None, sort: Optional[Sort] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[Trade]: def get_trades_history(self, symbol: Optional[str] = None, sort: Optional[Sort] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[Trade]:
if symbol == None: if symbol == None:
@@ -107,7 +107,7 @@ class RestAuthenticatedEndpoints(Middleware):
"limit": limit "limit": limit
} }
return [ serializers.Trade.parse(*sub_data) for sub_data in self._POST(endpoint, body=body) ] return [ serializers.Trade.parse(*sub_data) for sub_data in self._post(endpoint, body=body) ]
def get_ledgers(self, currency: str, category: Optional[int] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[Ledger]: def get_ledgers(self, currency: str, category: Optional[int] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[Ledger]:
body = { body = {
@@ -116,51 +116,51 @@ class RestAuthenticatedEndpoints(Middleware):
"limit": limit "limit": limit
} }
return [ serializers.Ledger.parse(*sub_data) for sub_data in self._POST(f"auth/r/ledgers/{currency}/hist", body=body) ] return [ serializers.Ledger.parse(*sub_data) for sub_data in self._post(f"auth/r/ledgers/{currency}/hist", body=body) ]
def get_base_margin_info(self) -> BaseMarginInfo: def get_base_margin_info(self) -> BaseMarginInfo:
return serializers.BaseMarginInfo.parse(*(self._POST(f"auth/r/info/margin/base")[1])) return serializers.BaseMarginInfo.parse(*(self._post(f"auth/r/info/margin/base")[1]))
def get_symbol_margin_info(self, symbol: str) -> SymbolMarginInfo: def get_symbol_margin_info(self, symbol: str) -> SymbolMarginInfo:
response = self._POST(f"auth/r/info/margin/{symbol}") response = self._post(f"auth/r/info/margin/{symbol}")
data = [response[1]] + response[2] data = [response[1]] + response[2]
return serializers.SymbolMarginInfo.parse(*data) return serializers.SymbolMarginInfo.parse(*data)
def get_all_symbols_margin_info(self) -> List[SymbolMarginInfo]: def get_all_symbols_margin_info(self) -> List[SymbolMarginInfo]:
return [ serializers.SymbolMarginInfo.parse(*([sub_data[1]] + sub_data[2])) for sub_data in self._POST(f"auth/r/info/margin/sym_all") ] return [ serializers.SymbolMarginInfo.parse(*([sub_data[1]] + sub_data[2])) for sub_data in self._post(f"auth/r/info/margin/sym_all") ]
def get_positions(self) -> List[Position]: def get_positions(self) -> List[Position]:
return [ serializers.Position.parse(*sub_data) for sub_data in self._POST("auth/r/positions") ] return [ serializers.Position.parse(*sub_data) for sub_data in self._post("auth/r/positions") ]
def claim_position(self, id: int, amount: Optional[Union[Decimal, float, str]] = None) -> Notification[PositionClaim]: def claim_position(self, id: int, amount: Optional[Union[Decimal, float, str]] = None) -> Notification[PositionClaim]:
return serializers._Notification[PositionClaim](serializers.PositionClaim).parse( return serializers._Notification[PositionClaim](serializers.PositionClaim).parse(
*self._POST("auth/w/position/claim", body={ "id": id, "amount": amount }) *self._post("auth/w/position/claim", body={ "id": id, "amount": amount })
) )
def increase_position(self, symbol: str, amount: Union[Decimal, float, str]) -> Notification[PositionIncrease]: def increase_position(self, symbol: str, amount: Union[Decimal, float, str]) -> Notification[PositionIncrease]:
return serializers._Notification[PositionIncrease](serializers.PositionIncrease).parse( return serializers._Notification[PositionIncrease](serializers.PositionIncrease).parse(
*self._POST("auth/w/position/increase", body={ "symbol": symbol, "amount": amount }) *self._post("auth/w/position/increase", body={ "symbol": symbol, "amount": amount })
) )
def get_increase_position_info(self, symbol: str, amount: Union[Decimal, float, str]) -> PositionIncreaseInfo: def get_increase_position_info(self, symbol: str, amount: Union[Decimal, float, str]) -> PositionIncreaseInfo:
response = self._POST(f"auth/r/position/increase/info", body={ "symbol": symbol, "amount": amount }) response = self._post(f"auth/r/position/increase/info", body={ "symbol": symbol, "amount": amount })
data = response[0] + [response[1][0]] + response[1][1] + [response[1][2]] + response[4] + response[5] data = response[0] + [response[1][0]] + response[1][1] + [response[1][2]] + response[4] + response[5]
return serializers.PositionIncreaseInfo.parse(*data) return serializers.PositionIncreaseInfo.parse(*data)
def get_positions_history(self, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[PositionHistory]: def get_positions_history(self, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[PositionHistory]:
return [ serializers.PositionHistory.parse(*sub_data) for sub_data in self._POST("auth/r/positions/hist", body={ "start": start, "end": end, "limit": limit }) ] return [ serializers.PositionHistory.parse(*sub_data) for sub_data in self._post("auth/r/positions/hist", body={ "start": start, "end": end, "limit": limit }) ]
def get_positions_snapshot(self, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[PositionSnapshot]: def get_positions_snapshot(self, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[PositionSnapshot]:
return [ serializers.PositionSnapshot.parse(*sub_data) for sub_data in self._POST("auth/r/positions/snap", body={ "start": start, "end": end, "limit": limit }) ] return [ serializers.PositionSnapshot.parse(*sub_data) for sub_data in self._post("auth/r/positions/snap", body={ "start": start, "end": end, "limit": limit }) ]
def get_positions_audit(self, ids: Optional[List[int]] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[PositionAudit]: def get_positions_audit(self, ids: Optional[List[int]] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[PositionAudit]:
return [ serializers.PositionAudit.parse(*sub_data) for sub_data in self._POST("auth/r/positions/audit", body={ "ids": ids, "start": start, "end": end, "limit": limit }) ] return [ serializers.PositionAudit.parse(*sub_data) for sub_data in self._post("auth/r/positions/audit", body={ "ids": ids, "start": start, "end": end, "limit": limit }) ]
def set_derivative_position_collateral(self, symbol: str, collateral: Union[Decimal, float, str]) -> DerivativePositionCollateral: def set_derivative_position_collateral(self, symbol: str, collateral: Union[Decimal, float, str]) -> DerivativePositionCollateral:
return serializers.DerivativePositionCollateral.parse(*(self._POST("auth/w/deriv/collateral/set", body={ "symbol": symbol, "collateral": collateral })[0])) return serializers.DerivativePositionCollateral.parse(*(self._post("auth/w/deriv/collateral/set", body={ "symbol": symbol, "collateral": collateral })[0]))
def get_derivative_position_collateral_limits(self, symbol: str) -> DerivativePositionCollateralLimits: def get_derivative_position_collateral_limits(self, symbol: str) -> DerivativePositionCollateralLimits:
return serializers.DerivativePositionCollateralLimits.parse(*self._POST("auth/calc/deriv/collateral/limits", body={ "symbol": symbol })) return serializers.DerivativePositionCollateralLimits.parse(*self._post("auth/calc/deriv/collateral/limits", body={ "symbol": symbol }))
def get_funding_offers(self, symbol: Optional[str] = None) -> List[FundingOffer]: def get_funding_offers(self, symbol: Optional[str] = None) -> List[FundingOffer]:
endpoint = "auth/r/funding/offers" endpoint = "auth/r/funding/offers"
@@ -168,7 +168,7 @@ class RestAuthenticatedEndpoints(Middleware):
if symbol != None: if symbol != None:
endpoint += f"/{symbol}" endpoint += f"/{symbol}"
return [ serializers.FundingOffer.parse(*sub_data) for sub_data in self._POST(endpoint) ] return [ serializers.FundingOffer.parse(*sub_data) for sub_data in self._post(endpoint) ]
def submit_funding_offer(self, type: FundingOfferType, symbol: str, amount: Union[Decimal, float, str], def submit_funding_offer(self, type: FundingOfferType, symbol: str, amount: Union[Decimal, float, str],
rate: Union[Decimal, float, str], period: int, rate: Union[Decimal, float, str], period: int,
@@ -179,30 +179,30 @@ class RestAuthenticatedEndpoints(Middleware):
"flags": flags "flags": flags
} }
return serializers._Notification[FundingOffer](serializers.FundingOffer).parse(*self._POST("auth/w/funding/offer/submit", body=body)) return serializers._Notification[FundingOffer](serializers.FundingOffer).parse(*self._post("auth/w/funding/offer/submit", body=body))
def cancel_funding_offer(self, id: int) -> Notification[FundingOffer]: def cancel_funding_offer(self, id: int) -> Notification[FundingOffer]:
return serializers._Notification[FundingOffer](serializers.FundingOffer).parse(*self._POST("auth/w/funding/offer/cancel", body={ "id": id })) return serializers._Notification[FundingOffer](serializers.FundingOffer).parse(*self._post("auth/w/funding/offer/cancel", body={ "id": id }))
def cancel_all_funding_offers(self, currency: str) -> Notification[Literal[None]]: def cancel_all_funding_offers(self, currency: str) -> Notification[Literal[None]]:
return serializers._Notification[Literal[None]](None).parse( return serializers._Notification[Literal[None]](None).parse(
*self._POST("auth/w/funding/offer/cancel/all", body={ "currency": currency }) *self._post("auth/w/funding/offer/cancel/all", body={ "currency": currency })
) )
def submit_funding_close(self, id: int) -> Notification[Literal[None]]: def submit_funding_close(self, id: int) -> Notification[Literal[None]]:
return serializers._Notification[Literal[None]](None).parse( return serializers._Notification[Literal[None]](None).parse(
*self._POST("auth/w/funding/close", body={ "id": id }) *self._post("auth/w/funding/close", body={ "id": id })
) )
def toggle_auto_renew(self, status: bool, currency: str, amount: Optional[str] = None, rate: Optional[int] = None, period: Optional[int] = None) -> Notification[FundingAutoRenew]: def toggle_auto_renew(self, status: bool, currency: str, amount: Optional[str] = None, rate: Optional[int] = None, period: Optional[int] = None) -> Notification[FundingAutoRenew]:
return serializers._Notification[FundingAutoRenew](serializers.FundingAutoRenew).parse(*self._POST("auth/w/funding/auto", body={ return serializers._Notification[FundingAutoRenew](serializers.FundingAutoRenew).parse(*self._post("auth/w/funding/auto", body={
"status": int(status), "status": int(status),
"currency": currency, "amount": amount, "currency": currency, "amount": amount,
"rate": rate, "period": period "rate": rate, "period": period
})) }))
def toggle_keep_funding(self, type: Literal["credit", "loan"], ids: Optional[List[int]] = None, changes: Optional[Dict[int, Literal[1, 2]]] = None) -> Notification[Literal[None]]: def toggle_keep_funding(self, type: Literal["credit", "loan"], ids: Optional[List[int]] = None, changes: Optional[Dict[int, Literal[1, 2]]] = None) -> Notification[Literal[None]]:
return serializers._Notification[Literal[None]](None).parse(*self._POST("auth/w/funding/keep", body={ return serializers._Notification[Literal[None]](None).parse(*self._post("auth/w/funding/keep", body={
"type": type, "type": type,
"id": ids, "id": ids,
"changes": changes "changes": changes
@@ -218,14 +218,14 @@ class RestAuthenticatedEndpoints(Middleware):
"limit": limit "limit": limit
} }
return [ serializers.FundingOffer.parse(*sub_data) for sub_data in self._POST(endpoint, body=body) ] return [ serializers.FundingOffer.parse(*sub_data) for sub_data in self._post(endpoint, body=body) ]
def get_funding_loans(self, symbol: Optional[str] = None) -> List[FundingLoan]: def get_funding_loans(self, symbol: Optional[str] = None) -> List[FundingLoan]:
if symbol == None: if symbol == None:
endpoint = "auth/r/funding/loans" endpoint = "auth/r/funding/loans"
else: endpoint = f"auth/r/funding/loans/{symbol}" else: endpoint = f"auth/r/funding/loans/{symbol}"
return [ serializers.FundingLoan.parse(*sub_data) for sub_data in self._POST(endpoint) ] return [ serializers.FundingLoan.parse(*sub_data) for sub_data in self._post(endpoint) ]
def get_funding_loans_history(self, symbol: Optional[str] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[FundingLoan]: def get_funding_loans_history(self, symbol: Optional[str] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[FundingLoan]:
if symbol == None: if symbol == None:
@@ -237,14 +237,14 @@ class RestAuthenticatedEndpoints(Middleware):
"limit": limit "limit": limit
} }
return [ serializers.FundingLoan.parse(*sub_data) for sub_data in self._POST(endpoint, body=body) ] return [ serializers.FundingLoan.parse(*sub_data) for sub_data in self._post(endpoint, body=body) ]
def get_funding_credits(self, symbol: Optional[str] = None) -> List[FundingCredit]: def get_funding_credits(self, symbol: Optional[str] = None) -> List[FundingCredit]:
if symbol == None: if symbol == None:
endpoint = "auth/r/funding/credits" endpoint = "auth/r/funding/credits"
else: endpoint = f"auth/r/funding/credits/{symbol}" else: endpoint = f"auth/r/funding/credits/{symbol}"
return [ serializers.FundingCredit.parse(*sub_data) for sub_data in self._POST(endpoint) ] return [ serializers.FundingCredit.parse(*sub_data) for sub_data in self._post(endpoint) ]
def get_funding_credits_history(self, symbol: Optional[str] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[FundingCredit]: def get_funding_credits_history(self, symbol: Optional[str] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[FundingCredit]:
if symbol == None: if symbol == None:
@@ -256,7 +256,7 @@ class RestAuthenticatedEndpoints(Middleware):
"limit": limit "limit": limit
} }
return [ serializers.FundingCredit.parse(*sub_data) for sub_data in self._POST(endpoint, body=body) ] return [ serializers.FundingCredit.parse(*sub_data) for sub_data in self._post(endpoint, body=body) ]
def get_funding_trades_history(self, symbol: Optional[str] = None, sort: Optional[Sort] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[FundingTrade]: def get_funding_trades_history(self, symbol: Optional[str] = None, sort: Optional[Sort] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[FundingTrade]:
if symbol == None: if symbol == None:
@@ -269,10 +269,10 @@ class RestAuthenticatedEndpoints(Middleware):
"limit": limit "limit": limit
} }
return [ serializers.FundingTrade.parse(*sub_data) for sub_data in self._POST(endpoint, body=body) ] return [ serializers.FundingTrade.parse(*sub_data) for sub_data in self._post(endpoint, body=body) ]
def get_funding_info(self, key: str) -> FundingInfo: def get_funding_info(self, key: str) -> FundingInfo:
response = self._POST(f"auth/r/info/funding/{key}") response = self._post(f"auth/r/info/funding/{key}")
data = [response[1]] + response[2] data = [response[1]] + response[2]
return serializers.FundingInfo.parse(*data) return serializers.FundingInfo.parse(*data)
@@ -283,10 +283,10 @@ class RestAuthenticatedEndpoints(Middleware):
"amount": amount "amount": amount
} }
return serializers._Notification[Transfer](serializers.Transfer).parse(*self._POST("auth/w/transfer", body=body)) return serializers._Notification[Transfer](serializers.Transfer).parse(*self._post("auth/w/transfer", body=body))
def submit_wallet_withdrawal(self, wallet: str, method: str, address: str, amount: Union[Decimal, float, str]) -> Notification[Withdrawal]: def submit_wallet_withdrawal(self, wallet: str, method: str, address: str, amount: Union[Decimal, float, str]) -> Notification[Withdrawal]:
return serializers._Notification[Withdrawal](serializers.Withdrawal).parse(*self._POST("auth/w/withdraw", body={ return serializers._Notification[Withdrawal](serializers.Withdrawal).parse(*self._post("auth/w/withdraw", body={
"wallet": wallet, "method": method, "wallet": wallet, "method": method,
"address": address, "amount": amount, "address": address, "amount": amount,
})) }))
@@ -298,7 +298,7 @@ class RestAuthenticatedEndpoints(Middleware):
"renew": int(renew) "renew": int(renew)
} }
return serializers._Notification[DepositAddress](serializers.DepositAddress).parse(*self._POST("auth/w/deposit/address", body=body)) return serializers._Notification[DepositAddress](serializers.DepositAddress).parse(*self._post("auth/w/deposit/address", body=body))
def generate_deposit_invoice(self, wallet: str, currency: str, amount: Union[Decimal, float, str]) -> LightningNetworkInvoice: def generate_deposit_invoice(self, wallet: str, currency: str, amount: Union[Decimal, float, str]) -> LightningNetworkInvoice:
body = { body = {
@@ -306,7 +306,7 @@ class RestAuthenticatedEndpoints(Middleware):
"amount": amount "amount": amount
} }
return serializers.LightningNetworkInvoice.parse(*self._POST("auth/w/deposit/invoice", body=body)) return serializers.LightningNetworkInvoice.parse(*self._post("auth/w/deposit/invoice", body=body))
def get_movements(self, currency: Optional[str] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[Movement]: def get_movements(self, currency: Optional[str] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[Movement]:
if currency == None: if currency == None:
@@ -318,4 +318,4 @@ class RestAuthenticatedEndpoints(Middleware):
"limit": limit "limit": limit
} }
return [ serializers.Movement.parse(*sub_data) for sub_data in self._POST(endpoint, body=body) ] return [ serializers.Movement.parse(*sub_data) for sub_data in self._post(endpoint, body=body) ]

View File

@@ -24,12 +24,12 @@ class RestMerchantEndpoints(Middleware):
"webhook": webhook, "redirect_url": redirect_url "webhook": webhook, "redirect_url": redirect_url
}) })
data = to_snake_case_keys(self._POST("auth/w/ext/pay/invoice/create", body=body)) data = to_snake_case_keys(self._post("auth/w/ext/pay/invoice/create", body=body))
return InvoiceSubmission.parse(data) return InvoiceSubmission.parse(data)
def get_invoices(self, id: Optional[str] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[InvoiceSubmission]: def get_invoices(self, id: Optional[str] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[InvoiceSubmission]:
return [ InvoiceSubmission.parse(sub_data) for sub_data in to_snake_case_keys(self._POST("auth/r/ext/pay/invoices", body={ return [ InvoiceSubmission.parse(sub_data) for sub_data in to_snake_case_keys(self._post("auth/r/ext/pay/invoices", body={
"id": id, "start": start, "end": end, "id": id, "start": start, "end": end,
"limit": limit "limit": limit
})) ] })) ]
@@ -43,24 +43,24 @@ class RestMerchantEndpoints(Middleware):
"crypto": crypto, "id": id, "order_id": order_id "crypto": crypto, "id": id, "order_id": order_id
}) })
data = to_snake_case_keys(self._POST("auth/r/ext/pay/invoices/paginated", body=body)) data = to_snake_case_keys(self._post("auth/r/ext/pay/invoices/paginated", body=body))
return InvoicePage.parse(data) return InvoicePage.parse(data)
def get_invoice_count_stats(self, status: Literal["CREATED", "PENDING", "COMPLETED", "EXPIRED"], format: str) -> List[InvoiceStats]: def get_invoice_count_stats(self, status: Literal["CREATED", "PENDING", "COMPLETED", "EXPIRED"], format: str) -> List[InvoiceStats]:
return [ InvoiceStats(**sub_data) for sub_data in self._POST("auth/r/ext/pay/invoice/stats/count", body={ "status": status, "format": format }) ] return [ InvoiceStats(**sub_data) for sub_data in self._post("auth/r/ext/pay/invoice/stats/count", body={ "status": status, "format": format }) ]
def get_invoice_earning_stats(self, currency: str, format: str) -> List[InvoiceStats]: def get_invoice_earning_stats(self, currency: str, format: str) -> List[InvoiceStats]:
return [ InvoiceStats(**sub_data) for sub_data in self._POST("auth/r/ext/pay/invoice/stats/earning", body={ "currency": currency, "format": format }) ] return [ InvoiceStats(**sub_data) for sub_data in self._post("auth/r/ext/pay/invoice/stats/earning", body={ "currency": currency, "format": format }) ]
def complete_invoice(self, id: str, pay_currency: str, deposit_id: Optional[int] = None, ledger_id: Optional[int] = None) -> InvoiceSubmission: def complete_invoice(self, id: str, pay_currency: str, deposit_id: Optional[int] = None, ledger_id: Optional[int] = None) -> InvoiceSubmission:
return InvoiceSubmission.parse(to_snake_case_keys(self._POST("auth/w/ext/pay/invoice/complete", body={ return InvoiceSubmission.parse(to_snake_case_keys(self._post("auth/w/ext/pay/invoice/complete", body={
"id": id, "payCcy": pay_currency, "depositId": deposit_id, "id": id, "payCcy": pay_currency, "depositId": deposit_id,
"ledgerId": ledger_id "ledgerId": ledger_id
}))) })))
def expire_invoice(self, id: str) -> InvoiceSubmission: def expire_invoice(self, id: str) -> InvoiceSubmission:
return InvoiceSubmission.parse(to_snake_case_keys(self._POST("auth/w/ext/pay/invoice/expire", body={ "id": id }))) return InvoiceSubmission.parse(to_snake_case_keys(self._post("auth/w/ext/pay/invoice/expire", body={ "id": id })))
def get_currency_conversion_list(self) -> List[CurrencyConversion]: def get_currency_conversion_list(self) -> List[CurrencyConversion]:
return [ return [
@@ -68,36 +68,36 @@ class RestMerchantEndpoints(Middleware):
base_currency=sub_data["baseCcy"], base_currency=sub_data["baseCcy"],
convert_currency=sub_data["convertCcy"], convert_currency=sub_data["convertCcy"],
created=sub_data["created"] created=sub_data["created"]
) for sub_data in self._POST("auth/r/ext/pay/settings/convert/list") ) for sub_data in self._post("auth/r/ext/pay/settings/convert/list")
] ]
def add_currency_conversion(self, base_currency: str, convert_currency: str) -> bool: def add_currency_conversion(self, base_currency: str, convert_currency: str) -> bool:
return bool(self._POST("auth/w/ext/pay/settings/convert/create", body={ return bool(self._post("auth/w/ext/pay/settings/convert/create", body={
"baseCcy": base_currency, "baseCcy": base_currency,
"convertCcy": convert_currency "convertCcy": convert_currency
})) }))
def remove_currency_conversion(self, base_currency: str, convert_currency: str) -> bool: def remove_currency_conversion(self, base_currency: str, convert_currency: str) -> bool:
return bool(self._POST("auth/w/ext/pay/settings/convert/remove", body={ return bool(self._post("auth/w/ext/pay/settings/convert/remove", body={
"baseCcy": base_currency, "baseCcy": base_currency,
"convertCcy": convert_currency "convertCcy": convert_currency
})) }))
def set_merchant_settings(self, key: MerchantSettingsKey, val: Any) -> bool: def set_merchant_settings(self, key: MerchantSettingsKey, val: Any) -> bool:
return bool(self._POST("auth/w/ext/pay/settings/set", body={ "key": key, "val": val })) return bool(self._post("auth/w/ext/pay/settings/set", body={ "key": key, "val": val }))
def get_merchant_settings(self, key: MerchantSettingsKey) -> Any: def get_merchant_settings(self, key: MerchantSettingsKey) -> Any:
return self._POST("auth/r/ext/pay/settings/get", body={ "key": key }) return self._post("auth/r/ext/pay/settings/get", body={ "key": key })
def list_merchant_settings(self, keys: List[MerchantSettingsKey] = list()) -> Dict[MerchantSettingsKey, Any]: def list_merchant_settings(self, keys: List[MerchantSettingsKey] = list()) -> Dict[MerchantSettingsKey, Any]:
return self._POST("auth/r/ext/pay/settings/list", body={ "keys": keys }) return self._post("auth/r/ext/pay/settings/list", body={ "keys": keys })
def get_deposits(self, start: int, end: int, ccy: Optional[str] = None, unlinked: Optional[bool] = None) -> List[MerchantDeposit]: def get_deposits(self, start: int, end: int, ccy: Optional[str] = None, unlinked: Optional[bool] = None) -> List[MerchantDeposit]:
return [ MerchantDeposit(**sub_data) for sub_data in to_snake_case_keys(self._POST("auth/r/ext/pay/deposits", body={ return [ MerchantDeposit(**sub_data) for sub_data in to_snake_case_keys(self._post("auth/r/ext/pay/deposits", body={
"from": start, "to": end, "ccy": ccy, "unlinked": unlinked "from": start, "to": end, "ccy": ccy, "unlinked": unlinked
})) ] })) ]
def get_unlinked_deposits(self, ccy: str, start: Optional[int] = None, end: Optional[int] = None) -> List[MerchantUnlinkedDeposit]: def get_unlinked_deposits(self, ccy: str, start: Optional[int] = None, end: Optional[int] = None) -> List[MerchantUnlinkedDeposit]:
return [ MerchantUnlinkedDeposit(**sub_data) for sub_data in to_snake_case_keys(self._POST("/auth/r/ext/pay/deposits/unlinked", body={ return [ MerchantUnlinkedDeposit(**sub_data) for sub_data in to_snake_case_keys(self._post("/auth/r/ext/pay/deposits/unlinked", body={
"ccy": ccy, "start": start, "end": end "ccy": ccy, "start": start, "end": end
})) ] })) ]

View File

@@ -1,7 +1,17 @@
#pylint: disable=redefined-builtin
from typing import List, Union, Literal, Optional, Any, cast from typing import List, Union, Literal, Optional, Any, cast
from decimal import Decimal from decimal import Decimal
from .. types import * from .. types import \
PlatformStatus, TradingPairTicker, FundingCurrencyTicker, \
TickersHistory, TradingPairTrade, FundingCurrencyTrade, \
TradingPairBook, FundingCurrencyBook, TradingPairRawBook, \
FundingCurrencyRawBook, Statistic, Candle, \
DerivativesStatus, Liquidation, Leaderboard, \
FundingStatistic, PulseProfile, PulseMessage, \
TradingMarketAveragePrice, FundingMarketAveragePrice, FxRate
from .. import serializers from .. import serializers
from .. enums import Config, Sort from .. enums import Config, Sort
@@ -9,103 +19,151 @@ from .. middleware import Middleware
class RestPublicEndpoints(Middleware): class RestPublicEndpoints(Middleware):
def conf(self, config: Config) -> Any: def conf(self, config: Config) -> Any:
return self._GET(f"conf/{config}")[0] return self._get(f"conf/{config}")[0]
def get_platform_status(self) -> PlatformStatus: def get_platform_status(self) -> PlatformStatus:
return serializers.PlatformStatus.parse(*self._GET("platform/status")) return serializers.PlatformStatus.parse(*self._get("platform/status"))
def get_tickers(self, symbols: List[str]) -> List[Union[TradingPairTicker, FundingCurrencyTicker]]: def get_tickers(self, symbols: List[str]) -> List[Union[TradingPairTicker, FundingCurrencyTicker]]:
data = self._GET("tickers", params={ "symbols": ",".join(symbols) }) data = self._get("tickers", params={ "symbols": ",".join(symbols) })
parsers = { "t": serializers.TradingPairTicker.parse, "f": serializers.FundingCurrencyTicker.parse } parsers = { "t": serializers.TradingPairTicker.parse, "f": serializers.FundingCurrencyTicker.parse }
return [ cast(Union[TradingPairTicker, FundingCurrencyTicker], parsers[sub_data[0][0]](*sub_data)) for sub_data in data ] return [ cast(Union[TradingPairTicker, FundingCurrencyTicker], \
parsers[sub_data[0][0]](*sub_data)) for sub_data in data ]
def get_t_tickers(self, pairs: Union[List[str], Literal["ALL"]]) -> List[TradingPairTicker]: def get_t_tickers(self, pairs: Union[List[str], Literal["ALL"]]) -> List[TradingPairTicker]:
if isinstance(pairs, str) and pairs == "ALL": if isinstance(pairs, str) and pairs == "ALL":
return [ cast(TradingPairTicker, sub_data) for sub_data in self.get_tickers([ "ALL" ]) if cast(str, sub_data.symbol).startswith("t") ] return [ cast(TradingPairTicker, sub_data) for sub_data in self.get_tickers([ "ALL" ]) \
if cast(str, sub_data.symbol).startswith("t") ]
data = self.get_tickers([ pair for pair in pairs ]) data = self.get_tickers(list(pairs))
return cast(List[TradingPairTicker], data) return cast(List[TradingPairTicker], data)
def get_f_tickers(self, currencies: Union[List[str], Literal["ALL"]]) -> List[FundingCurrencyTicker]: def get_f_tickers(self, currencies: Union[List[str], Literal["ALL"]]) -> List[FundingCurrencyTicker]:
if isinstance(currencies, str) and currencies == "ALL": if isinstance(currencies, str) and currencies == "ALL":
return [ cast(FundingCurrencyTicker, sub_data) for sub_data in self.get_tickers([ "ALL" ]) if cast(str, sub_data.symbol).startswith("f") ] return [ cast(FundingCurrencyTicker, sub_data) for sub_data in self.get_tickers([ "ALL" ]) \
if cast(str, sub_data.symbol).startswith("f") ]
data = self.get_tickers([ currency for currency in currencies ]) data = self.get_tickers(list(currencies))
return cast(List[FundingCurrencyTicker], data) return cast(List[FundingCurrencyTicker], data)
def get_t_ticker(self, pair: str) -> TradingPairTicker: def get_t_ticker(self, pair: str) -> TradingPairTicker:
return serializers.TradingPairTicker.parse(*self._GET(f"ticker/t{pair}"), skip=["SYMBOL"]) return serializers.TradingPairTicker.parse(*self._get(f"ticker/t{pair}"), skip=["SYMBOL"])
def get_f_ticker(self, currency: str) -> FundingCurrencyTicker: def get_f_ticker(self, currency: str) -> FundingCurrencyTicker:
return serializers.FundingCurrencyTicker.parse(*self._GET(f"ticker/f{currency}"), skip=["SYMBOL"]) return serializers.FundingCurrencyTicker.parse(*self._get(f"ticker/f{currency}"), skip=["SYMBOL"])
def get_tickers_history(self, symbols: List[str], start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[TickersHistory]: def get_tickers_history(self,
return [ serializers.TickersHistory.parse(*sub_data) for sub_data in self._GET("tickers/hist", params={ symbols: List[str],
*,
start: Optional[str] = None,
end: Optional[str] = None,
limit: Optional[int] = None) -> List[TickersHistory]:
return [ serializers.TickersHistory.parse(*sub_data) for sub_data in self._get("tickers/hist", params={
"symbols": ",".join(symbols), "symbols": ",".join(symbols),
"start": start, "end": end, "start": start, "end": end,
"limit": limit "limit": limit
}) ] }) ]
def get_t_trades(self, pair: str, limit: Optional[int] = None, start: Optional[str] = None, end: Optional[str] = None, sort: Optional[Sort] = None) -> List[TradingPairTrade]: def get_t_trades(self,
pair: str,
*,
limit: Optional[int] = None,
start: Optional[str] = None,
end: Optional[str] = None,
sort: Optional[Sort] = None) -> List[TradingPairTrade]:
params = { "limit": limit, "start": start, "end": end, "sort": sort } params = { "limit": limit, "start": start, "end": end, "sort": sort }
data = self._GET(f"trades/{pair}/hist", params=params) data = self._get(f"trades/{pair}/hist", params=params)
return [ serializers.TradingPairTrade.parse(*sub_data) for sub_data in data ] return [ serializers.TradingPairTrade.parse(*sub_data) for sub_data in data ]
def get_f_trades(self, currency: str, limit: Optional[int] = None, start: Optional[str] = None, end: Optional[str] = None, sort: Optional[Sort] = None) -> List[FundingCurrencyTrade]: def get_f_trades(self,
currency: str,
*,
limit: Optional[int] = None,
start: Optional[str] = None,
end: Optional[str] = None,
sort: Optional[Sort] = None) -> List[FundingCurrencyTrade]:
params = { "limit": limit, "start": start, "end": end, "sort": sort } params = { "limit": limit, "start": start, "end": end, "sort": sort }
data = self._GET(f"trades/{currency}/hist", params=params) data = self._get(f"trades/{currency}/hist", params=params)
return [ serializers.FundingCurrencyTrade.parse(*sub_data) for sub_data in data ] return [ serializers.FundingCurrencyTrade.parse(*sub_data) for sub_data in data ]
def get_t_book(self, pair: str, precision: Literal["P0", "P1", "P2", "P3", "P4"], len: Optional[Literal[1, 25, 100]] = None) -> List[TradingPairBook]: def get_t_book(self,
return [ serializers.TradingPairBook.parse(*sub_data) for sub_data in self._GET(f"book/{pair}/{precision}", params={ "len": len }) ] pair: str,
precision: Literal["P0", "P1", "P2", "P3", "P4"],
*,
len: Optional[Literal[1, 25, 100]] = None) -> List[TradingPairBook]:
return [ serializers.TradingPairBook.parse(*sub_data) \
for sub_data in self._get(f"book/{pair}/{precision}", params={ "len": len }) ]
def get_f_book(self, currency: str, precision: Literal["P0", "P1", "P2", "P3", "P4"], len: Optional[Literal[1, 25, 100]] = None) -> List[FundingCurrencyBook]: def get_f_book(self,
return [ serializers.FundingCurrencyBook.parse(*sub_data) for sub_data in self._GET(f"book/{currency}/{precision}", params={ "len": len }) ] currency: str,
precision: Literal["P0", "P1", "P2", "P3", "P4"],
*,
len: Optional[Literal[1, 25, 100]] = None) -> List[FundingCurrencyBook]:
return [ serializers.FundingCurrencyBook.parse(*sub_data) \
for sub_data in self._get(f"book/{currency}/{precision}", params={ "len": len }) ]
def get_t_raw_book(self, pair: str, len: Optional[Literal[1, 25, 100]] = None) -> List[TradingPairRawBook]: def get_t_raw_book(self,
return [ serializers.TradingPairRawBook.parse(*sub_data) for sub_data in self._GET(f"book/{pair}/R0", params={ "len": len }) ] pair: str,
*,
len: Optional[Literal[1, 25, 100]] = None) -> List[TradingPairRawBook]:
return [ serializers.TradingPairRawBook.parse(*sub_data) \
for sub_data in self._get(f"book/{pair}/R0", params={ "len": len }) ]
def get_f_raw_book(self, currency: str, len: Optional[Literal[1, 25, 100]] = None) -> List[FundingCurrencyRawBook]: def get_f_raw_book(self,
return [ serializers.FundingCurrencyRawBook.parse(*sub_data) for sub_data in self._GET(f"book/{currency}/R0", params={ "len": len }) ] currency: str,
*,
len: Optional[Literal[1, 25, 100]] = None) -> List[FundingCurrencyRawBook]:
return [ serializers.FundingCurrencyRawBook.parse(*sub_data) \
for sub_data in self._get(f"book/{currency}/R0", params={ "len": len }) ]
def get_stats_hist( def get_stats_hist(self,
self,
resource: str, resource: str,
sort: Optional[Sort] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None *,
) -> List[Statistic]: sort: Optional[Sort] = None,
start: Optional[str] = None,
end: Optional[str] = None,
limit: Optional[int] = None) -> List[Statistic]:
params = { "sort": sort, "start": start, "end": end, "limit": limit } params = { "sort": sort, "start": start, "end": end, "limit": limit }
data = self._GET(f"stats1/{resource}/hist", params=params) data = self._get(f"stats1/{resource}/hist", params=params)
return [ serializers.Statistic.parse(*sub_data) for sub_data in data ] return [ serializers.Statistic.parse(*sub_data) for sub_data in data ]
def get_stats_last( def get_stats_last(self,
self,
resource: str, resource: str,
sort: Optional[Sort] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None *,
) -> Statistic: sort: Optional[Sort] = None,
start: Optional[str] = None,
end: Optional[str] = None,
limit: Optional[int] = None) -> Statistic:
params = { "sort": sort, "start": start, "end": end, "limit": limit } params = { "sort": sort, "start": start, "end": end, "limit": limit }
data = self._GET(f"stats1/{resource}/last", params=params) data = self._get(f"stats1/{resource}/last", params=params)
return serializers.Statistic.parse(*data) return serializers.Statistic.parse(*data)
def get_candles_hist( def get_candles_hist(self,
self, symbol: str,
symbol: str, tf: str = "1m", tf: str = "1m",
sort: Optional[Sort] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None *,
) -> List[Candle]: sort: Optional[Sort] = None,
start: Optional[str] = None,
end: Optional[str] = None,
limit: Optional[int] = None) -> List[Candle]:
params = { "sort": sort, "start": start, "end": end, "limit": limit } params = { "sort": sort, "start": start, "end": end, "limit": limit }
data = self._GET(f"candles/trade:{tf}:{symbol}/hist", params=params) data = self._get(f"candles/trade:{tf}:{symbol}/hist", params=params)
return [ serializers.Candle.parse(*sub_data) for sub_data in data ] return [ serializers.Candle.parse(*sub_data) for sub_data in data ]
def get_candles_last( def get_candles_last(self,
self, symbol: str,
symbol: str, tf: str = "1m", tf: str = "1m",
sort: Optional[Sort] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None *,
) -> Candle: sort: Optional[Sort] = None,
start: Optional[str] = None,
end: Optional[str] = None,
limit: Optional[int] = None) -> Candle:
params = { "sort": sort, "start": start, "end": end, "limit": limit } params = { "sort": sort, "start": start, "end": end, "limit": limit }
data = self._GET(f"candles/trade:{tf}:{symbol}/last", params=params) data = self._get(f"candles/trade:{tf}:{symbol}/last", params=params)
return serializers.Candle.parse(*data) return serializers.Candle.parse(*data)
def get_derivatives_status(self, keys: Union[List[str], Literal["ALL"]]) -> List[DerivativesStatus]: def get_derivatives_status(self, keys: Union[List[str], Literal["ALL"]]) -> List[DerivativesStatus]:
@@ -113,74 +171,109 @@ class RestPublicEndpoints(Middleware):
params = { "keys": "ALL" } params = { "keys": "ALL" }
else: params = { "keys": ",".join(keys) } else: params = { "keys": ",".join(keys) }
data = self._GET(f"status/deriv", params=params) data = self._get("status/deriv", params=params)
return [ serializers.DerivativesStatus.parse(*sub_data) for sub_data in data ] return [ serializers.DerivativesStatus.parse(*sub_data) for sub_data in data ]
def get_derivatives_status_history( def get_derivatives_status_history(self,
self, type: str,
type: str, symbol: str, symbol: str,
sort: Optional[Sort] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None *,
) -> List[DerivativesStatus]: sort: Optional[Sort] = None,
start: Optional[str] = None,
end: Optional[str] = None,
limit: Optional[int] = None) -> List[DerivativesStatus]:
params = { "sort": sort, "start": start, "end": end, "limit": limit } params = { "sort": sort, "start": start, "end": end, "limit": limit }
data = self._GET(f"status/{type}/{symbol}/hist", params=params) data = self._get(f"status/{type}/{symbol}/hist", params=params)
return [ serializers.DerivativesStatus.parse(*sub_data, skip=[ "KEY" ]) for sub_data in data ] return [ serializers.DerivativesStatus.parse(*sub_data, skip=[ "KEY" ]) for sub_data in data ]
def get_liquidations(self, sort: Optional[Sort] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[Liquidation]: def get_liquidations(self,
*,
sort: Optional[Sort] = None,
start: Optional[str] = None,
end: Optional[str] = None,
limit: Optional[int] = None) -> List[Liquidation]:
params = { "sort": sort, "start": start, "end": end, "limit": limit } params = { "sort": sort, "start": start, "end": end, "limit": limit }
data = self._GET("liquidations/hist", params=params) data = self._get("liquidations/hist", params=params)
return [ serializers.Liquidation.parse(*sub_data[0]) for sub_data in data ] return [ serializers.Liquidation.parse(*sub_data[0]) for sub_data in data ]
def get_seed_candles(self, symbol: str, tf: str = '1m', sort: Optional[Sort] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[Candle]: def get_seed_candles(self,
symbol: str,
tf: str = "1m",
*,
sort: Optional[Sort] = None,
start: Optional[str] = None,
end: Optional[str] = None,
limit: Optional[int] = None) -> List[Candle]:
params = {"sort": sort, "start": start, "end": end, "limit": limit} params = {"sort": sort, "start": start, "end": end, "limit": limit}
data = self._GET(f"candles/trade:{tf}:{symbol}/hist?limit={limit}&start={start}&end={end}&sort={sort}", params=params) data = self._get(f"candles/trade:{tf}:{symbol}/hist", params=params)
return [ serializers.Candle.parse(*sub_data) for sub_data in data ] return [ serializers.Candle.parse(*sub_data) for sub_data in data ]
def get_leaderboards_hist( def get_leaderboards_hist(self,
self,
resource: str, resource: str,
sort: Optional[Sort] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None *,
) -> List[Leaderboard]: sort: Optional[Sort] = None,
start: Optional[str] = None,
end: Optional[str] = None,
limit: Optional[int] = None) -> List[Leaderboard]:
params = { "sort": sort, "start": start, "end": end, "limit": limit } params = { "sort": sort, "start": start, "end": end, "limit": limit }
data = self._GET(f"rankings/{resource}/hist", params=params) data = self._get(f"rankings/{resource}/hist", params=params)
return [ serializers.Leaderboard.parse(*sub_data) for sub_data in data ] return [ serializers.Leaderboard.parse(*sub_data) for sub_data in data ]
def get_leaderboards_last( def get_leaderboards_last(self,
self,
resource: str, resource: str,
sort: Optional[Sort] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None *,
) -> Leaderboard: sort: Optional[Sort] = None,
start: Optional[str] = None,
end: Optional[str] = None,
limit: Optional[int] = None) -> Leaderboard:
params = { "sort": sort, "start": start, "end": end, "limit": limit } params = { "sort": sort, "start": start, "end": end, "limit": limit }
data = self._GET(f"rankings/{resource}/last", params=params) data = self._get(f"rankings/{resource}/last", params=params)
return serializers.Leaderboard.parse(*data) return serializers.Leaderboard.parse(*data)
def get_funding_stats(self, symbol: str, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[FundingStatistic]: def get_funding_stats(self,
symbol: str,
*,
start: Optional[str] = None,
end: Optional[str] = None,
limit: Optional[int] = None) -> List[FundingStatistic]:
params = { "start": start, "end": end, "limit": limit } params = { "start": start, "end": end, "limit": limit }
data = self._GET(f"funding/stats/{symbol}/hist", params=params) data = self._get(f"funding/stats/{symbol}/hist", params=params)
return [ serializers.FundingStatistic.parse(*sub_data) for sub_data in data ] return [ serializers.FundingStatistic.parse(*sub_data) for sub_data in data ]
def get_pulse_profile(self, nickname: str) -> PulseProfile: def get_pulse_profile(self, nickname: str) -> PulseProfile:
return serializers.PulseProfile.parse(*self._GET(f"pulse/profile/{nickname}")) return serializers.PulseProfile.parse(*self._get(f"pulse/profile/{nickname}"))
def get_pulse_history(self, end: Optional[str] = None, limit: Optional[int] = None) -> List[PulseMessage]: def get_pulse_history(self, *, end: Optional[str] = None, limit: Optional[int] = None) -> List[PulseMessage]:
messages = list() messages = []
for subdata in self._GET("pulse/hist", params={ "end": end, "limit": limit }): for subdata in self._get("pulse/hist", params={ "end": end, "limit": limit }):
subdata[18] = subdata[18][0] subdata[18] = subdata[18][0]
message = serializers.PulseMessage.parse(*subdata) message = serializers.PulseMessage.parse(*subdata)
messages.append(message) messages.append(message)
return messages return messages
def get_trading_market_average_price(self, symbol: str, amount: Union[Decimal, float, str], price_limit: Optional[Union[Decimal, float, str]] = None) -> TradingMarketAveragePrice: def get_trading_market_average_price(self,
return serializers.TradingMarketAveragePrice.parse(*self._POST("calc/trade/avg", body={ symbol: str,
amount: Union[Decimal, float, str],
*,
price_limit: Optional[Union[Decimal, float, str]] = None
) -> TradingMarketAveragePrice:
return serializers.TradingMarketAveragePrice.parse(*self._post("calc/trade/avg", body={
"symbol": symbol, "amount": amount, "price_limit": price_limit "symbol": symbol, "amount": amount, "price_limit": price_limit
})) }))
def get_funding_market_average_price(self, symbol: str, amount: Union[Decimal, float, str], period: int, rate_limit: Optional[Union[Decimal, float, str]] = None) -> FundingMarketAveragePrice: def get_funding_market_average_price(self,
return serializers.FundingMarketAveragePrice.parse(*self._POST("calc/trade/avg", body={ symbol: str,
amount: Union[Decimal, float, str],
period: int,
*,
rate_limit: Optional[Union[Decimal, float, str]] = None
) -> FundingMarketAveragePrice:
return serializers.FundingMarketAveragePrice.parse(*self._post("calc/trade/avg", body={
"symbol": symbol, "amount": amount, "period": period, "rate_limit": rate_limit "symbol": symbol, "amount": amount, "period": period, "rate_limit": rate_limit
})) }))
def get_fx_rate(self, ccy1: str, ccy2: str) -> FxRate: def get_fx_rate(self, ccy1: str, ccy2: str) -> FxRate:
return serializers.FxRate.parse(*self._POST("calc/fx", body={ "ccy1": ccy1, "ccy2": ccy2 })) return serializers.FxRate.parse(*self._post("calc/fx", body={ "ccy1": ccy1, "ccy2": ccy2 }))

View File

@@ -1,3 +1,4 @@
#pylint: disable-next=wildcard-import,unused-wildcard-import
from ..enums import * from ..enums import *
class Config(str, Enum): class Config(str, Enum):

View File

@@ -14,32 +14,22 @@ class BfxRestException(BfxBaseException):
Base class for all custom exceptions in bfxapi/rest/exceptions.py. Base class for all custom exceptions in bfxapi/rest/exceptions.py.
""" """
pass
class ResourceNotFound(BfxRestException): class ResourceNotFound(BfxRestException):
""" """
This error indicates a failed HTTP request to a non-existent resource. This error indicates a failed HTTP request to a non-existent resource.
""" """
pass
class RequestParametersError(BfxRestException): class RequestParametersError(BfxRestException):
""" """
This error indicates that there are some invalid parameters sent along with an HTTP request. This error indicates that there are some invalid parameters sent along with an HTTP request.
""" """
pass
class InvalidAuthenticationCredentials(BfxRestException): class InvalidAuthenticationCredentials(BfxRestException):
""" """
This error indicates that the user has provided incorrect credentials (API-KEY and API-SECRET) for authentication. This error indicates that the user has provided incorrect credentials (API-KEY and API-SECRET) for authentication.
""" """
pass
class UnknownGenericError(BfxRestException): class UnknownGenericError(BfxRestException):
""" """
This error indicates an undefined problem processing an HTTP request sent to the APIs. This error indicates an undefined problem processing an HTTP request sent to the APIs.
""" """
pass

View File

@@ -1,32 +1,34 @@
import time, hmac, hashlib, json, requests from typing import TYPE_CHECKING, Optional, Any
from typing import TYPE_CHECKING, Optional, Any, cast
from http import HTTPStatus from http import HTTPStatus
import time, hmac, hashlib, json, requests
from ..enums import Error from ..enums import Error
from ..exceptions import ResourceNotFound, RequestParametersError, InvalidAuthenticationCredentials, UnknownGenericError from ..exceptions import ResourceNotFound, RequestParametersError, InvalidAuthenticationCredentials, UnknownGenericError
from ...utils.json_encoder import JSONEncoder from ...utils.json_encoder import JSONEncoder
if TYPE_CHECKING: if TYPE_CHECKING:
from requests.sessions import _Params from requests.sessions import _Params
class Middleware(object): class Middleware:
def __init__(self, host: str, API_KEY: Optional[str] = None, API_SECRET: Optional[str] = None): TIMEOUT = 30
self.host, self.API_KEY, self.API_SECRET = host, API_KEY, API_SECRET
def __init__(self, host: str, api_key: Optional[str] = None, api_secret: Optional[str] = None):
self.host, self.api_key, self.api_secret = host, api_key, api_secret
def __build_authentication_headers(self, endpoint: str, data: Optional[str] = None): def __build_authentication_headers(self, endpoint: str, data: Optional[str] = None):
assert isinstance(self.API_KEY, str) and isinstance(self.API_SECRET, str), \ assert isinstance(self.api_key, str) and isinstance(self.api_secret, str), \
"API_KEY and API_SECRET must be both str to call __build_authentication_headers" "API_KEY and API_SECRET must be both str to call __build_authentication_headers"
nonce = str(round(time.time() * 1_000_000)) nonce = str(round(time.time() * 1_000_000))
if data == None: if data is None:
path = f"/api/v2/{endpoint}{nonce}" path = f"/api/v2/{endpoint}{nonce}"
else: path = f"/api/v2/{endpoint}{nonce}{data}" else: path = f"/api/v2/{endpoint}{nonce}{data}"
signature = hmac.new( signature = hmac.new(
self.API_SECRET.encode("utf8"), self.api_secret.encode("utf8"),
path.encode("utf8"), path.encode("utf8"),
hashlib.sha384 hashlib.sha384
).hexdigest() ).hexdigest()
@@ -34,11 +36,15 @@ class Middleware(object):
return { return {
"bfx-nonce": nonce, "bfx-nonce": nonce,
"bfx-signature": signature, "bfx-signature": signature,
"bfx-apikey": self.API_KEY "bfx-apikey": self.api_key
} }
def _GET(self, endpoint: str, params: Optional["_Params"] = None) -> Any: def _get(self, endpoint: str, params: Optional["_Params"] = None) -> Any:
response = requests.get(f"{self.host}/{endpoint}", params=params) response = requests.get(
url=f"{self.host}/{endpoint}",
params=params,
timeout=Middleware.TIMEOUT
)
if response.status_code == HTTPStatus.NOT_FOUND: if response.status_code == HTTPStatus.NOT_FOUND:
raise ResourceNotFound(f"No resources found at endpoint <{endpoint}>.") raise ResourceNotFound(f"No resources found at endpoint <{endpoint}>.")
@@ -47,22 +53,31 @@ class Middleware(object):
if len(data) and data[0] == "error": if len(data) and data[0] == "error":
if data[1] == Error.ERR_PARAMS: if data[1] == Error.ERR_PARAMS:
raise RequestParametersError(f"The request was rejected with the following parameter error: <{data[2]}>") raise RequestParametersError("The request was rejected with the "
+ f"following parameter error: <{data[2]}>")
if data[1] == None or data[1] == Error.ERR_UNK or data[1] == Error.ERR_GENERIC: if data[1] is None or data[1] == Error.ERR_UNK or data[1] == Error.ERR_GENERIC:
raise UnknownGenericError(f"The server replied to the request with a generic error with message: <{data[2]}>.") raise UnknownGenericError("The server replied to the request with "
+ f"a generic error with message: <{data[2]}>.")
return data return data
def _POST(self, endpoint: str, params: Optional["_Params"] = None, body: Optional[Any] = None, _ignore_authentication_headers: bool = False) -> Any: def _post(self, endpoint: str, params: Optional["_Params"] = None,
body: Optional[Any] = None, _ignore_authentication_headers: bool = False) -> Any:
data = body and json.dumps(body, cls=JSONEncoder) or None data = body and json.dumps(body, cls=JSONEncoder) or None
headers = { "Content-Type": "application/json" } headers = { "Content-Type": "application/json" }
if self.API_KEY and self.API_SECRET and _ignore_authentication_headers == False: if self.api_key and self.api_secret and not _ignore_authentication_headers:
headers = { **headers, **self.__build_authentication_headers(endpoint, data) } headers = { **headers, **self.__build_authentication_headers(endpoint, data) }
response = requests.post(f"{self.host}/{endpoint}", params=params, data=data, headers=headers) response = requests.post(
url=f"{self.host}/{endpoint}",
params=params,
data=data,
headers=headers,
timeout=Middleware.TIMEOUT
)
if response.status_code == HTTPStatus.NOT_FOUND: if response.status_code == HTTPStatus.NOT_FOUND:
raise ResourceNotFound(f"No resources found at endpoint <{endpoint}>.") raise ResourceNotFound(f"No resources found at endpoint <{endpoint}>.")
@@ -71,12 +86,14 @@ class Middleware(object):
if isinstance(data, list) and len(data) and data[0] == "error": if isinstance(data, list) and len(data) and data[0] == "error":
if data[1] == Error.ERR_PARAMS: if data[1] == Error.ERR_PARAMS:
raise RequestParametersError(f"The request was rejected with the following parameter error: <{data[2]}>") raise RequestParametersError("The request was rejected with the "
+ f"following parameter error: <{data[2]}>")
if data[1] == Error.ERR_AUTH_FAIL: if data[1] == Error.ERR_AUTH_FAIL:
raise InvalidAuthenticationCredentials("Cannot authenticate with given API-KEY and API-SECRET.") raise InvalidAuthenticationCredentials("Cannot authenticate with given API-KEY and API-SECRET.")
if data[1] == None or data[1] == Error.ERR_UNK or data[1] == Error.ERR_GENERIC: if data[1] is None or data[1] == Error.ERR_UNK or data[1] == Error.ERR_GENERIC:
raise UnknownGenericError(f"The server replied to the request with a generic error with message: <{data[2]}>.") raise UnknownGenericError("The server replied to the request with "
+ f"a generic error with message: <{data[2]}>.")
return data return data

View File

@@ -2,6 +2,7 @@ from . import types
from .. labeler import generate_labeler_serializer, generate_recursive_serializer from .. labeler import generate_labeler_serializer, generate_recursive_serializer
#pylint: disable-next=unused-import
from .. notification import _Notification from .. notification import _Notification
__serializers__ = [ __serializers__ = [
@@ -27,11 +28,18 @@ __serializers__ = [
#region Serializers definition for Rest Public Endpoints #region Serializers definition for Rest Public Endpoints
PlatformStatus = generate_labeler_serializer("PlatformStatus", klass=types.PlatformStatus, labels=[ PlatformStatus = generate_labeler_serializer(
name="PlatformStatus",
klass=types.PlatformStatus,
labels=[
"status" "status"
]) ]
)
TradingPairTicker = generate_labeler_serializer("TradingPairTicker", klass=types.TradingPairTicker, labels=[ TradingPairTicker = generate_labeler_serializer(
name="TradingPairTicker",
klass=types.TradingPairTicker,
labels=[
"symbol", "symbol",
"bid", "bid",
"bid_size", "bid_size",
@@ -43,9 +51,13 @@ TradingPairTicker = generate_labeler_serializer("TradingPairTicker", klass=types
"volume", "volume",
"high", "high",
"low" "low"
]) ]
)
FundingCurrencyTicker = generate_labeler_serializer("FundingCurrencyTicker", klass=types.FundingCurrencyTicker, labels=[ FundingCurrencyTicker = generate_labeler_serializer(
name="FundingCurrencyTicker",
klass=types.FundingCurrencyTicker,
labels=[
"symbol", "symbol",
"frr", "frr",
"bid", "bid",
@@ -63,9 +75,13 @@ FundingCurrencyTicker = generate_labeler_serializer("FundingCurrencyTicker", kla
"_PLACEHOLDER", "_PLACEHOLDER",
"_PLACEHOLDER", "_PLACEHOLDER",
"frr_amount_available" "frr_amount_available"
]) ]
)
TickersHistory = generate_labeler_serializer("TickersHistory", klass=types.TickersHistory, labels=[ TickersHistory = generate_labeler_serializer(
name="TickersHistory",
klass=types.TickersHistory,
labels=[
"symbol", "symbol",
"bid", "bid",
"_PLACEHOLDER", "_PLACEHOLDER",
@@ -79,64 +95,100 @@ TickersHistory = generate_labeler_serializer("TickersHistory", klass=types.Ticke
"_PLACEHOLDER", "_PLACEHOLDER",
"_PLACEHOLDER", "_PLACEHOLDER",
"mts" "mts"
]) ]
)
TradingPairTrade = generate_labeler_serializer("TradingPairTrade", klass=types.TradingPairTrade, labels=[ TradingPairTrade = generate_labeler_serializer(
name="TradingPairTrade",
klass=types.TradingPairTrade,
labels=[
"id", "id",
"mts", "mts",
"amount", "amount",
"price" "price"
]) ]
)
FundingCurrencyTrade = generate_labeler_serializer("FundingCurrencyTrade", klass=types.FundingCurrencyTrade, labels=[ FundingCurrencyTrade = generate_labeler_serializer(
name="FundingCurrencyTrade",
klass=types.FundingCurrencyTrade,
labels=[
"id", "id",
"mts", "mts",
"amount", "amount",
"rate", "rate",
"period" "period"
]) ]
)
TradingPairBook = generate_labeler_serializer("TradingPairBook", klass=types.TradingPairBook, labels=[ TradingPairBook = generate_labeler_serializer(
name="TradingPairBook",
klass=types.TradingPairBook,
labels=[
"price", "price",
"count", "count",
"amount" "amount"
]) ]
)
FundingCurrencyBook = generate_labeler_serializer("FundingCurrencyBook", klass=types.FundingCurrencyBook, labels=[ FundingCurrencyBook = generate_labeler_serializer(
name="FundingCurrencyBook",
klass=types.FundingCurrencyBook,
labels=[
"rate", "rate",
"period", "period",
"count", "count",
"amount" "amount"
]) ]
)
TradingPairRawBook = generate_labeler_serializer("TradingPairRawBook", klass=types.TradingPairRawBook, labels=[ TradingPairRawBook = generate_labeler_serializer(
name="TradingPairRawBook",
klass=types.TradingPairRawBook,
labels=[
"order_id", "order_id",
"price", "price",
"amount" "amount"
]) ]
)
FundingCurrencyRawBook = generate_labeler_serializer("FundingCurrencyRawBook", klass=types.FundingCurrencyRawBook, labels=[ FundingCurrencyRawBook = generate_labeler_serializer(
name="FundingCurrencyRawBook",
klass=types.FundingCurrencyRawBook,
labels=[
"offer_id", "offer_id",
"period", "period",
"rate", "rate",
"amount" "amount"
]) ]
)
Statistic = generate_labeler_serializer("Statistic", klass=types.Statistic, labels=[ Statistic = generate_labeler_serializer(
name="Statistic",
klass=types.Statistic,
labels=[
"mts", "mts",
"value" "value"
]) ]
)
Candle = generate_labeler_serializer("Candle", klass=types.Candle, labels=[ Candle = generate_labeler_serializer(
name="Candle",
klass=types.Candle,
labels=[
"mts", "mts",
"open", "open",
"close", "close",
"high", "high",
"low", "low",
"volume" "volume"
]) ]
)
DerivativesStatus = generate_labeler_serializer("DerivativesStatus", klass=types.DerivativesStatus, labels=[ DerivativesStatus = generate_labeler_serializer(
name="DerivativesStatus",
klass=types.DerivativesStatus,
labels=[
"key", "key",
"mts", "mts",
"_PLACEHOLDER", "_PLACEHOLDER",
@@ -161,9 +213,13 @@ DerivativesStatus = generate_labeler_serializer("DerivativesStatus", klass=types
"_PLACEHOLDER", "_PLACEHOLDER",
"clamp_min", "clamp_min",
"clamp_max" "clamp_max"
]) ]
)
Liquidation = generate_labeler_serializer("Liquidation", klass=types.Liquidation, labels=[ Liquidation = generate_labeler_serializer(
name="Liquidation",
klass=types.Liquidation,
labels=[
"_PLACEHOLDER", "_PLACEHOLDER",
"pos_id", "pos_id",
"mts", "mts",
@@ -176,9 +232,13 @@ Liquidation = generate_labeler_serializer("Liquidation", klass=types.Liquidation
"is_market_sold", "is_market_sold",
"_PLACEHOLDER", "_PLACEHOLDER",
"price_acquired" "price_acquired"
]) ]
)
Leaderboard = generate_labeler_serializer("Leaderboard", klass=types.Leaderboard, labels=[ Leaderboard = generate_labeler_serializer(
name="Leaderboard",
klass=types.Leaderboard,
labels=[
"mts", "mts",
"_PLACEHOLDER", "_PLACEHOLDER",
"username", "username",
@@ -189,9 +249,13 @@ Leaderboard = generate_labeler_serializer("Leaderboard", klass=types.Leaderboard
"_PLACEHOLDER", "_PLACEHOLDER",
"_PLACEHOLDER", "_PLACEHOLDER",
"twitter_handle" "twitter_handle"
]) ]
)
FundingStatistic = generate_labeler_serializer("FundingStatistic", klass=types.FundingStatistic, labels=[ FundingStatistic = generate_labeler_serializer(
name="FundingStatistic",
klass=types.FundingStatistic,
labels=[
"timestamp", "timestamp",
"_PLACEHOLDER", "_PLACEHOLDER",
"_PLACEHOLDER", "_PLACEHOLDER",
@@ -204,9 +268,13 @@ FundingStatistic = generate_labeler_serializer("FundingStatistic", klass=types.F
"_PLACEHOLDER", "_PLACEHOLDER",
"_PLACEHOLDER", "_PLACEHOLDER",
"funding_below_threshold" "funding_below_threshold"
]) ]
)
PulseProfile = generate_labeler_serializer("PulseProfile", klass=types.PulseProfile, labels=[ PulseProfile = generate_labeler_serializer(
name="PulseProfile",
klass=types.PulseProfile,
labels=[
"puid", "puid",
"mts", "mts",
"_PLACEHOLDER", "_PLACEHOLDER",
@@ -224,9 +292,14 @@ PulseProfile = generate_labeler_serializer("PulseProfile", klass=types.PulseProf
"_PLACEHOLDER", "_PLACEHOLDER",
"_PLACEHOLDER", "_PLACEHOLDER",
"tipping_status" "tipping_status"
]) ]
)
PulseMessage = generate_recursive_serializer("PulseMessage", klass=types.PulseMessage, serializers={ "profile": PulseProfile }, labels=[ PulseMessage = generate_recursive_serializer(
name="PulseMessage",
klass=types.PulseMessage,
serializers={ "profile": PulseProfile },
labels=[
"pid", "pid",
"mts", "mts",
"_PLACEHOLDER", "_PLACEHOLDER",
@@ -249,27 +322,43 @@ PulseMessage = generate_recursive_serializer("PulseMessage", klass=types.PulseMe
"comments", "comments",
"_PLACEHOLDER", "_PLACEHOLDER",
"_PLACEHOLDER" "_PLACEHOLDER"
]) ]
)
TradingMarketAveragePrice = generate_labeler_serializer("TradingMarketAveragePrice", klass=types.TradingMarketAveragePrice, labels=[ TradingMarketAveragePrice = generate_labeler_serializer(
name="TradingMarketAveragePrice",
klass=types.TradingMarketAveragePrice,
labels=[
"price_avg", "price_avg",
"amount" "amount"
]) ]
)
FundingMarketAveragePrice = generate_labeler_serializer("FundingMarketAveragePrice", klass=types.FundingMarketAveragePrice, labels=[ FundingMarketAveragePrice = generate_labeler_serializer(
name="FundingMarketAveragePrice",
klass=types.FundingMarketAveragePrice,
labels=[
"rate_avg", "rate_avg",
"amount" "amount"
]) ]
)
FxRate = generate_labeler_serializer("FxRate", klass=types.FxRate, labels=[ FxRate = generate_labeler_serializer(
name="FxRate",
klass=types.FxRate,
labels=[
"current_rate" "current_rate"
]) ]
)
#endregion #endregion
#region Serializers definition for Rest Authenticated Endpoints #region Serializers definition for Rest Authenticated Endpoints
UserInfo = generate_labeler_serializer("UserInfo", klass=types.UserInfo, labels=[ UserInfo = generate_labeler_serializer(
name="UserInfo",
klass=types.UserInfo,
labels=[
"id", "id",
"email", "email",
"username", "username",
@@ -325,9 +414,13 @@ UserInfo = generate_labeler_serializer("UserInfo", klass=types.UserInfo, labels=
"_PLACEHOLDER", "_PLACEHOLDER",
"_PLACEHOLDER", "_PLACEHOLDER",
"is_merchant_enterprise" "is_merchant_enterprise"
]) ]
)
LoginHistory = generate_labeler_serializer("LoginHistory", klass=types.LoginHistory, labels=[ LoginHistory = generate_labeler_serializer(
name="LoginHistory",
klass=types.LoginHistory,
labels=[
"id", "id",
"_PLACEHOLDER", "_PLACEHOLDER",
"time", "time",
@@ -336,13 +429,21 @@ LoginHistory = generate_labeler_serializer("LoginHistory", klass=types.LoginHist
"_PLACEHOLDER", "_PLACEHOLDER",
"_PLACEHOLDER", "_PLACEHOLDER",
"extra_info" "extra_info"
]) ]
)
BalanceAvailable = generate_labeler_serializer("BalanceAvailable", klass=types.BalanceAvailable, labels=[ BalanceAvailable = generate_labeler_serializer(
name="BalanceAvailable",
klass=types.BalanceAvailable,
labels=[
"amount" "amount"
]) ]
)
Order = generate_labeler_serializer("Order", klass=types.Order, labels=[ Order = generate_labeler_serializer(
name="Order",
klass=types.Order,
labels=[
"id", "id",
"gid", "gid",
"cid", "cid",
@@ -375,9 +476,13 @@ Order = generate_labeler_serializer("Order", klass=types.Order, labels=[
"_PLACEHOLDER", "_PLACEHOLDER",
"_PLACEHOLDER", "_PLACEHOLDER",
"meta" "meta"
]) ]
)
Position = generate_labeler_serializer("Position", klass=types.Position, labels=[ Position = generate_labeler_serializer(
name="Position",
klass=types.Position,
labels=[
"symbol", "symbol",
"status", "status",
"amount", "amount",
@@ -398,9 +503,13 @@ Position = generate_labeler_serializer("Position", klass=types.Position, labels=
"collateral", "collateral",
"collateral_min", "collateral_min",
"meta" "meta"
]) ]
)
Trade = generate_labeler_serializer("Trade", klass=types.Trade, labels=[ Trade = generate_labeler_serializer(
name="Trade",
klass=types.Trade,
labels=[
"id", "id",
"symbol", "symbol",
"mts_create", "mts_create",
@@ -413,9 +522,13 @@ Trade = generate_labeler_serializer("Trade", klass=types.Trade, labels=[
"fee", "fee",
"fee_currency", "fee_currency",
"cid" "cid"
]) ]
)
FundingTrade = generate_labeler_serializer("FundingTrade", klass=types.FundingTrade, labels=[ FundingTrade = generate_labeler_serializer(
name="FundingTrade",
klass=types.FundingTrade,
labels=[
"id", "id",
"currency", "currency",
"mts_create", "mts_create",
@@ -423,9 +536,13 @@ FundingTrade = generate_labeler_serializer("FundingTrade", klass=types.FundingTr
"amount", "amount",
"rate", "rate",
"period" "period"
]) ]
)
OrderTrade = generate_labeler_serializer("OrderTrade", klass=types.OrderTrade, labels=[ OrderTrade = generate_labeler_serializer(
name="OrderTrade",
klass=types.OrderTrade,
labels=[
"id", "id",
"symbol", "symbol",
"mts_create", "mts_create",
@@ -438,9 +555,13 @@ OrderTrade = generate_labeler_serializer("OrderTrade", klass=types.OrderTrade, l
"fee", "fee",
"fee_currency", "fee_currency",
"cid" "cid"
]) ]
)
Ledger = generate_labeler_serializer("Ledger", klass=types.Ledger, labels=[ Ledger = generate_labeler_serializer(
name="Ledger",
klass=types.Ledger,
labels=[
"id", "id",
"currency", "currency",
"_PLACEHOLDER", "_PLACEHOLDER",
@@ -450,9 +571,13 @@ Ledger = generate_labeler_serializer("Ledger", klass=types.Ledger, labels=[
"balance", "balance",
"_PLACEHOLDER", "_PLACEHOLDER",
"description" "description"
]) ]
)
FundingOffer = generate_labeler_serializer("FundingOffer", klass=types.FundingOffer, labels=[ FundingOffer = generate_labeler_serializer(
name="FundingOffer",
klass=types.FundingOffer,
labels=[
"id", "id",
"symbol", "symbol",
"mts_create", "mts_create",
@@ -474,9 +599,13 @@ FundingOffer = generate_labeler_serializer("FundingOffer", klass=types.FundingOf
"_PLACEHOLDER", "_PLACEHOLDER",
"renew", "renew",
"_PLACEHOLDER" "_PLACEHOLDER"
]) ]
)
FundingCredit = generate_labeler_serializer("FundingCredit", klass=types.FundingCredit, labels=[ FundingCredit = generate_labeler_serializer(
name="FundingCredit",
klass=types.FundingCredit,
labels=[
"id", "id",
"symbol", "symbol",
"side", "side",
@@ -499,9 +628,13 @@ FundingCredit = generate_labeler_serializer("FundingCredit", klass=types.Funding
"_PLACEHOLDER", "_PLACEHOLDER",
"no_close", "no_close",
"position_pair" "position_pair"
]) ]
)
FundingLoan = generate_labeler_serializer("FundingLoan", klass=types.FundingLoan, labels=[ FundingLoan = generate_labeler_serializer(
name="FundingLoan",
klass=types.FundingLoan,
labels=[
"id", "id",
"symbol", "symbol",
"side", "side",
@@ -523,24 +656,36 @@ FundingLoan = generate_labeler_serializer("FundingLoan", klass=types.FundingLoan
"renew", "renew",
"_PLACEHOLDER", "_PLACEHOLDER",
"no_close" "no_close"
]) ]
)
FundingAutoRenew = generate_labeler_serializer("FundingAutoRenew", klass=types.FundingAutoRenew, labels=[ FundingAutoRenew = generate_labeler_serializer(
name="FundingAutoRenew",
klass=types.FundingAutoRenew,
labels=[
"currency", "currency",
"period", "period",
"rate", "rate",
"threshold" "threshold"
]) ]
)
FundingInfo = generate_labeler_serializer("FundingInfo", klass=types.FundingInfo, labels=[ FundingInfo = generate_labeler_serializer(
name="FundingInfo",
klass=types.FundingInfo,
labels=[
"symbol", "symbol",
"yield_loan", "yield_loan",
"yield_lend", "yield_lend",
"duration_loan", "duration_loan",
"duration_lend" "duration_lend"
]) ]
)
Wallet = generate_labeler_serializer("Wallet", klass=types.Wallet, labels=[ Wallet = generate_labeler_serializer(
name="Wallet",
klass=types.Wallet,
labels=[
"wallet_type", "wallet_type",
"currency", "currency",
"balance", "balance",
@@ -548,9 +693,13 @@ Wallet = generate_labeler_serializer("Wallet", klass=types.Wallet, labels=[
"available_balance", "available_balance",
"last_change", "last_change",
"trade_details" "trade_details"
]) ]
)
Transfer = generate_labeler_serializer("Transfer", klass=types.Transfer, labels=[ Transfer = generate_labeler_serializer(
name="Transfer",
klass=types.Transfer,
labels=[
"mts", "mts",
"wallet_from", "wallet_from",
"wallet_to", "wallet_to",
@@ -559,9 +708,13 @@ Transfer = generate_labeler_serializer("Transfer", klass=types.Transfer, labels=
"currency_to", "currency_to",
"_PLACEHOLDER", "_PLACEHOLDER",
"amount" "amount"
]) ]
)
Withdrawal = generate_labeler_serializer("Withdrawal", klass=types.Withdrawal, labels=[ Withdrawal = generate_labeler_serializer(
name="Withdrawal",
klass=types.Withdrawal,
labels=[
"withdrawal_id", "withdrawal_id",
"_PLACEHOLDER", "_PLACEHOLDER",
"method", "method",
@@ -571,26 +724,38 @@ Withdrawal = generate_labeler_serializer("Withdrawal", klass=types.Withdrawal, l
"_PLACEHOLDER", "_PLACEHOLDER",
"_PLACEHOLDER", "_PLACEHOLDER",
"withdrawal_fee" "withdrawal_fee"
]) ]
)
DepositAddress = generate_labeler_serializer("DepositAddress", klass=types.DepositAddress, labels=[ DepositAddress = generate_labeler_serializer(
name="DepositAddress",
klass=types.DepositAddress,
labels=[
"_PLACEHOLDER", "_PLACEHOLDER",
"method", "method",
"currency_code", "currency_code",
"_PLACEHOLDER", "_PLACEHOLDER",
"address", "address",
"pool_address" "pool_address"
]) ]
)
LightningNetworkInvoice = generate_labeler_serializer("LightningNetworkInvoice", klass=types.LightningNetworkInvoice, labels=[ LightningNetworkInvoice = generate_labeler_serializer(
name="LightningNetworkInvoice",
klass=types.LightningNetworkInvoice,
labels=[
"invoice_hash", "invoice_hash",
"invoice", "invoice",
"_PLACEHOLDER", "_PLACEHOLDER",
"_PLACEHOLDER", "_PLACEHOLDER",
"amount" "amount"
]) ]
)
Movement = generate_labeler_serializer("Movement", klass=types.Movement, labels=[ Movement = generate_labeler_serializer(
name="Movement",
klass=types.Movement,
labels=[
"id", "id",
"currency", "currency",
"currency_name", "currency_name",
@@ -613,25 +778,37 @@ Movement = generate_labeler_serializer("Movement", klass=types.Movement, labels=
"_PLACEHOLDER", "_PLACEHOLDER",
"transaction_id", "transaction_id",
"withdraw_transaction_note" "withdraw_transaction_note"
]) ]
)
SymbolMarginInfo = generate_labeler_serializer("SymbolMarginInfo", klass=types.SymbolMarginInfo, labels=[ SymbolMarginInfo = generate_labeler_serializer(
name="SymbolMarginInfo",
klass=types.SymbolMarginInfo,
labels=[
"symbol", "symbol",
"tradable_balance", "tradable_balance",
"gross_balance", "gross_balance",
"buy", "buy",
"sell" "sell"
]) ]
)
BaseMarginInfo = generate_labeler_serializer("BaseMarginInfo", klass=types.BaseMarginInfo, labels=[ BaseMarginInfo = generate_labeler_serializer(
name="BaseMarginInfo",
klass=types.BaseMarginInfo,
labels=[
"user_pl", "user_pl",
"user_swaps", "user_swaps",
"margin_balance", "margin_balance",
"margin_net", "margin_net",
"margin_min" "margin_min"
]) ]
)
PositionClaim = generate_labeler_serializer("PositionClaim", klass=types.PositionClaim, labels=[ PositionClaim = generate_labeler_serializer(
name="PositionClaim",
klass=types.PositionClaim,
labels=[
"symbol", "symbol",
"position_status", "position_status",
"amount", "amount",
@@ -652,9 +829,13 @@ PositionClaim = generate_labeler_serializer("PositionClaim", klass=types.Positio
"collateral", "collateral",
"min_collateral", "min_collateral",
"meta" "meta"
]) ]
)
PositionIncreaseInfo = generate_labeler_serializer("PositionIncreaseInfo", klass=types.PositionIncreaseInfo, labels=[ PositionIncreaseInfo = generate_labeler_serializer(
name="PositionIncreaseInfo",
klass=types.PositionIncreaseInfo,
labels=[
"max_pos", "max_pos",
"current_pos", "current_pos",
"base_currency_balance", "base_currency_balance",
@@ -671,16 +852,24 @@ PositionIncreaseInfo = generate_labeler_serializer("PositionIncreaseInfo", klass
"funding_required", "funding_required",
"funding_value_currency", "funding_value_currency",
"funding_required_currency" "funding_required_currency"
]) ]
)
PositionIncrease = generate_labeler_serializer("PositionIncrease", klass=types.PositionIncrease, labels=[ PositionIncrease = generate_labeler_serializer(
name="PositionIncrease",
klass=types.PositionIncrease,
labels=[
"symbol", "symbol",
"_PLACEHOLDER", "_PLACEHOLDER",
"amount", "amount",
"base_price" "base_price"
]) ]
)
PositionHistory = generate_labeler_serializer("PositionHistory", klass=types.PositionHistory, labels=[ PositionHistory = generate_labeler_serializer(
name="PositionHistory",
klass=types.PositionHistory,
labels=[
"symbol", "symbol",
"status", "status",
"amount", "amount",
@@ -695,9 +884,13 @@ PositionHistory = generate_labeler_serializer("PositionHistory", klass=types.Pos
"position_id", "position_id",
"mts_create", "mts_create",
"mts_update" "mts_update"
]) ]
)
PositionSnapshot = generate_labeler_serializer("PositionSnapshot", klass=types.PositionSnapshot, labels=[ PositionSnapshot = generate_labeler_serializer(
name="PositionSnapshot",
klass=types.PositionSnapshot,
labels=[
"symbol", "symbol",
"status", "status",
"amount", "amount",
@@ -712,9 +905,13 @@ PositionSnapshot = generate_labeler_serializer("PositionSnapshot", klass=types.P
"position_id", "position_id",
"mts_create", "mts_create",
"mts_update" "mts_update"
]) ]
)
PositionAudit = generate_labeler_serializer("PositionAudit", klass=types.PositionAudit, labels=[ PositionAudit = generate_labeler_serializer(
name="PositionAudit",
klass=types.PositionAudit,
labels=[
"symbol", "symbol",
"status", "status",
"amount", "amount",
@@ -735,15 +932,24 @@ PositionAudit = generate_labeler_serializer("PositionAudit", klass=types.Positio
"collateral", "collateral",
"collateral_min", "collateral_min",
"meta" "meta"
]) ]
)
DerivativePositionCollateral = generate_labeler_serializer("DerivativePositionCollateral", klass=types.DerivativePositionCollateral, labels=[ DerivativePositionCollateral = generate_labeler_serializer(
name="DerivativePositionCollateral",
klass=types.DerivativePositionCollateral,
labels=[
"status" "status"
]) ]
)
DerivativePositionCollateralLimits = generate_labeler_serializer("DerivativePositionCollateralLimits", klass=types.DerivativePositionCollateralLimits, labels=[ DerivativePositionCollateralLimits = generate_labeler_serializer(
name="DerivativePositionCollateralLimits",
klass=types.DerivativePositionCollateralLimits,
labels=[
"min_collateral", "min_collateral",
"max_collateral" "max_collateral"
]) ]
)
#endregion #endregion

View File

@@ -1,9 +1,13 @@
#pylint: disable-next=wildcard-import,unused-wildcard-import
from typing import * from typing import *
from dataclasses import dataclass from dataclasses import dataclass
from .. labeler import _Type, partial, compose from .. labeler import _Type, partial, compose
#pylint: disable-next=unused-import
from .. notification import Notification from .. notification import Notification
from ..utils.json_encoder import JSON from ..utils.json_encoder import JSON
#region Type hinting for Rest Public Endpoints #region Type hinting for Rest Public Endpoints
@@ -586,16 +590,16 @@ class InvoiceSubmission(_Type):
@classmethod @classmethod
def parse(cls, data: Dict[str, Any]) -> "InvoiceSubmission": def parse(cls, data: Dict[str, Any]) -> "InvoiceSubmission":
if "customer_info" in data and data["customer_info"] != None: if "customer_info" in data and data["customer_info"] is not None:
data["customer_info"] = InvoiceSubmission.CustomerInfo(**data["customer_info"]) data["customer_info"] = InvoiceSubmission.CustomerInfo(**data["customer_info"])
for index, invoice in enumerate(data["invoices"]): for index, invoice in enumerate(data["invoices"]):
data["invoices"][index] = InvoiceSubmission.Invoice(**invoice) data["invoices"][index] = InvoiceSubmission.Invoice(**invoice)
if "payment" in data and data["payment"] != None: if "payment" in data and data["payment"] is not None:
data["payment"] = InvoiceSubmission.Payment(**data["payment"]) data["payment"] = InvoiceSubmission.Payment(**data["payment"])
if "additional_payments" in data and data["additional_payments"] != None: if "additional_payments" in data and data["additional_payments"] is not None:
for index, additional_payment in enumerate(data["additional_payments"]): for index, additional_payment in enumerate(data["additional_payments"]):
data["additional_payments"][index] = InvoiceSubmission.Payment(**additional_payment) data["additional_payments"][index] = InvoiceSubmission.Payment(**additional_payment)

View File

@@ -29,6 +29,27 @@ def _require_websocket_authentication(function: F) -> F:
return cast(F, wrapper) return cast(F, wrapper)
class _Delay:
BACKOFF_MIN, BACKOFF_MAX = 1.92, 60.0
BACKOFF_INITIAL = 5.0
def __init__(self, backoff_factor):
self.__backoff_factor = backoff_factor
self.__backoff_delay = _Delay.BACKOFF_MIN
self.__initial_delay = random.random() * _Delay.BACKOFF_INITIAL
def next(self):
backoff_delay = self.peek()
__backoff_delay = self.__backoff_delay * self.__backoff_factor
self.__backoff_delay = min(__backoff_delay, _Delay.BACKOFF_MAX)
return backoff_delay
def peek(self):
return (self.__backoff_delay == _Delay.BACKOFF_MIN) \
and self.__initial_delay or self.__backoff_delay
class BfxWebsocketClient: class BfxWebsocketClient:
VERSION = BfxWebsocketBucket.VERSION VERSION = BfxWebsocketBucket.VERSION
@@ -135,27 +156,6 @@ class BfxWebsocketClient:
if message[0] == 0 and message[1] != _HEARTBEAT: if message[0] == 0 and message[1] != _HEARTBEAT:
self.handler.handle(message[1], message[2]) self.handler.handle(message[1], message[2])
class _Delay:
BACKOFF_MIN, BACKOFF_MAX = 1.92, 60.0
BACKOFF_INITIAL = 5.0
def __init__(self, backoff_factor):
self.__backoff_factor = backoff_factor
self.__backoff_delay = _Delay.BACKOFF_MIN
self.__initial_delay = random.random() * _Delay.BACKOFF_INITIAL
def next(self):
backoff_delay = self.peek()
__backoff_delay = self.__backoff_delay * self.__backoff_factor
self.__backoff_delay = min(__backoff_delay, _Delay.BACKOFF_MAX)
return backoff_delay
def peek(self):
return (self.__backoff_delay == _Delay.BACKOFF_MIN) \
and self.__initial_delay or self.__backoff_delay
while True: while True:
if reconnection.status: if reconnection.status:
await asyncio.sleep(delay.next()) await asyncio.sleep(delay.next())

View File

@@ -1,4 +1,4 @@
#pylint: disable=redefined-builtin,too-many-arguments #pylint: disable=redefined-builtin
from decimal import Decimal from decimal import Decimal
from datetime import datetime from datetime import datetime
@@ -15,6 +15,7 @@ class BfxWebsocketInputs:
type: OrderType, type: OrderType,
symbol: str, symbol: str,
amount: Union[Decimal, float, str], amount: Union[Decimal, float, str],
*,
price: Optional[Union[Decimal, float, str]] = None, price: Optional[Union[Decimal, float, str]] = None,
lev: Optional[int] = None, lev: Optional[int] = None,
price_trailing: Optional[Union[Decimal, float, str]] = None, price_trailing: Optional[Union[Decimal, float, str]] = None,
@@ -35,6 +36,7 @@ class BfxWebsocketInputs:
async def update_order(self, async def update_order(self,
id: int, id: int,
*,
amount: Optional[Union[Decimal, float, str]] = None, amount: Optional[Union[Decimal, float, str]] = None,
price: Optional[Union[Decimal, float, str]] = None, price: Optional[Union[Decimal, float, str]] = None,
cid: Optional[int] = None, cid: Optional[int] = None,
@@ -54,6 +56,7 @@ class BfxWebsocketInputs:
}) })
async def cancel_order(self, async def cancel_order(self,
*,
id: Optional[int] = None, id: Optional[int] = None,
cid: Optional[int] = None, cid: Optional[int] = None,
cid_date: Optional[str] = None): cid_date: Optional[str] = None):
@@ -62,6 +65,7 @@ class BfxWebsocketInputs:
}) })
async def cancel_order_multi(self, async def cancel_order_multi(self,
*,
ids: Optional[List[int]] = None, ids: Optional[List[int]] = None,
cids: Optional[List[Tuple[int, str]]] = None, cids: Optional[List[Tuple[int, str]]] = None,
gids: Optional[List[int]] = None, gids: Optional[List[int]] = None,
@@ -71,12 +75,14 @@ class BfxWebsocketInputs:
"all": int(all) "all": int(all)
}) })
#pylint: disable-next=too-many-arguments
async def submit_funding_offer(self, async def submit_funding_offer(self,
type: FundingOfferType, type: FundingOfferType,
symbol: str, symbol: str,
amount: Union[Decimal, float, str], amount: Union[Decimal, float, str],
rate: Union[Decimal, float, str], rate: Union[Decimal, float, str],
period: int, period: int,
*,
flags: Optional[int] = 0): flags: Optional[int] = 0):
await self.__handle_websocket_input("fon", { await self.__handle_websocket_input("fon", {
"type": type, "symbol": symbol, "amount": amount, "type": type, "symbol": symbol, "amount": amount,

View File

@@ -3,11 +3,11 @@ from typing import *
from dataclasses import dataclass from dataclasses import dataclass
from .. labeler import _Type
#pylint: disable-next=unused-import #pylint: disable-next=unused-import
from .. notification import Notification from .. notification import Notification
from .. labeler import _Type
from ..utils.json_encoder import JSON from ..utils.json_encoder import JSON
#region Type hinting for Websocket Public Channels #region Type hinting for Websocket Public Channels