From d767e5dcfe8e805b74b9eb9a9d08a47e80309608 Mon Sep 17 00:00:00 2001 From: Davide Casale Date: Thu, 26 Jan 2023 18:59:01 +0100 Subject: [PATCH 1/5] Replace every snake case (uppercase) to snake case (lowercase) in serializers, types and notification. --- bfxapi/notification.py | 22 +- bfxapi/rest/serializers.py | 662 ++++++++++++++++---------------- bfxapi/rest/types.py | 658 +++++++++++++++---------------- bfxapi/websocket/serializers.py | 370 +++++++++--------- bfxapi/websocket/types.py | 368 +++++++++--------- 5 files changed, 1040 insertions(+), 1040 deletions(-) diff --git a/bfxapi/notification.py b/bfxapi/notification.py index b2f90b8..f4301b3 100644 --- a/bfxapi/notification.py +++ b/bfxapi/notification.py @@ -8,16 +8,16 @@ T = TypeVar("T") @dataclass class Notification(_Type, Generic[T]): - MTS: int - TYPE: str - MESSAGE_ID: Optional[int] - NOTIFY_INFO: T - CODE: Optional[int] - STATUS: str - TEXT: str + mts: int + type: str + message_id: Optional[int] + notify_info: T + code: Optional[int] + status: str + text: str class _Notification(_Serializer, Generic[T]): - __LABELS = [ "MTS", "TYPE", "MESSAGE_ID", "_PLACEHOLDER", "NOTIFY_INFO", "CODE", "STATUS", "TEXT" ] + __LABELS = [ "mts", "type", "message_id", "_PLACEHOLDER", "notify_info", "code", "status", "text" ] def __init__(self, serializer: Optional[_Serializer] = None, iterate: bool = False): super().__init__("Notification", Notification, _Notification.__LABELS, IGNORE = [ "_PLACEHOLDER" ]) @@ -28,13 +28,13 @@ class _Notification(_Serializer, Generic[T]): notification = cast(Notification[T], Notification(**dict(self._serialize(*values)))) if isinstance(self.serializer, _Serializer): - NOTIFY_INFO = cast(List[Any], notification.NOTIFY_INFO) + NOTIFY_INFO = cast(List[Any], notification.notify_info) if self.iterate == False: if len(NOTIFY_INFO) == 1 and isinstance(NOTIFY_INFO[0], list): NOTIFY_INFO = NOTIFY_INFO[0] - notification.NOTIFY_INFO = cast(T, self.serializer.klass(**dict(self.serializer._serialize(*NOTIFY_INFO, skip=skip)))) - else: notification.NOTIFY_INFO = cast(T, [ self.serializer.klass(**dict(self.serializer._serialize(*data, skip=skip))) for data in NOTIFY_INFO ]) + notification.notify_info = cast(T, self.serializer.klass(**dict(self.serializer._serialize(*NOTIFY_INFO, skip=skip)))) + else: notification.notify_info = cast(T, [ self.serializer.klass(**dict(self.serializer._serialize(*data, skip=skip))) for data in NOTIFY_INFO ]) return notification \ No newline at end of file diff --git a/bfxapi/rest/serializers.py b/bfxapi/rest/serializers.py index 32d2d44..a6cf582 100644 --- a/bfxapi/rest/serializers.py +++ b/bfxapi/rest/serializers.py @@ -7,48 +7,48 @@ from .. notification import _Notification #region Serializers definition for Rest Public Endpoints PlatformStatus = generate_labeler_serializer("PlatformStatus", klass=types.PlatformStatus, labels=[ - "STATUS" + "status" ]) TradingPairTicker = generate_labeler_serializer("TradingPairTicker", klass=types.TradingPairTicker, labels=[ - "SYMBOL", - "BID", - "BID_SIZE", - "ASK", - "ASK_SIZE", - "DAILY_CHANGE", - "DAILY_CHANGE_RELATIVE", - "LAST_PRICE", - "VOLUME", - "HIGH", - "LOW" + "symbol", + "bid", + "bid_size", + "ask", + "ask_size", + "daily_change", + "daily_change_relative", + "last_price", + "volume", + "high", + "low" ]) FundingCurrencyTicker = generate_labeler_serializer("FundingCurrencyTicker", klass=types.FundingCurrencyTicker, labels=[ - "SYMBOL", - "FRR", - "BID", - "BID_PERIOD", - "BID_SIZE", - "ASK", - "ASK_PERIOD", - "ASK_SIZE", - "DAILY_CHANGE", - "DAILY_CHANGE_RELATIVE", - "LAST_PRICE", - "VOLUME", - "HIGH", - "LOW", + "symbol", + "frr", + "bid", + "bid_period", + "bid_size", + "ask", + "ask_period", + "ask_size", + "daily_change", + "daily_change_relative", + "last_price", + "volume", + "high", + "low", "_PLACEHOLDER", "_PLACEHOLDER", - "FRR_AMOUNT_AVAILABLE" + "frr_amount_available" ]) TickersHistory = generate_labeler_serializer("TickersHistory", klass=types.TickersHistory, labels=[ - "SYMBOL", - "BID", + "symbol", + "bid", "_PLACEHOLDER", - "ASK", + "ask", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", @@ -57,191 +57,191 @@ TickersHistory = generate_labeler_serializer("TickersHistory", klass=types.Ticke "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", - "MTS" + "mts" ]) TradingPairTrade = generate_labeler_serializer("TradingPairTrade", klass=types.TradingPairTrade, labels=[ - "ID", - "MTS", - "AMOUNT", - "PRICE" + "id", + "mts", + "amount", + "price" ]) FundingCurrencyTrade = generate_labeler_serializer("FundingCurrencyTrade", klass=types.FundingCurrencyTrade, labels=[ - "ID", - "MTS", - "AMOUNT", - "RATE", - "PERIOD" + "id", + "mts", + "amount", + "rate", + "period" ]) TradingPairBook = generate_labeler_serializer("TradingPairBook", klass=types.TradingPairBook, labels=[ - "PRICE", - "COUNT", - "AMOUNT" + "price", + "count", + "amount" ]) FundingCurrencyBook = generate_labeler_serializer("FundingCurrencyBook", klass=types.FundingCurrencyBook, labels=[ - "RATE", - "PERIOD", - "COUNT", - "AMOUNT" + "rate", + "period", + "count", + "amount" ]) TradingPairRawBook = generate_labeler_serializer("TradingPairRawBook", klass=types.TradingPairRawBook, labels=[ - "ORDER_ID", - "PRICE", - "AMOUNT" + "order_id", + "price", + "amount" ]) FundingCurrencyRawBook = generate_labeler_serializer("FundingCurrencyRawBook", klass=types.FundingCurrencyRawBook, labels=[ - "OFFER_ID", - "PERIOD", - "RATE", - "AMOUNT" + "offer_id", + "period", + "rate", + "amount" ]) Statistic = generate_labeler_serializer("Statistic", klass=types.Statistic, labels=[ - "MTS", - "VALUE" + "mts", + "value" ]) Candle = generate_labeler_serializer("Candle", klass=types.Candle, labels=[ - "MTS", - "OPEN", - "CLOSE", - "HIGH", - "LOW", - "VOLUME" + "mts", + "open", + "close", + "high", + "low", + "volume" ]) DerivativesStatus = generate_labeler_serializer("DerivativesStatus", klass=types.DerivativesStatus, labels=[ - "KEY", - "MTS", + "key", + "mts", "_PLACEHOLDER", - "DERIV_PRICE", - "SPOT_PRICE", + "deriv_price", + "spot_price", "_PLACEHOLDER", - "INSURANCE_FUND_BALANCE", + "insurance_fund_balance", "_PLACEHOLDER", - "NEXT_FUNDING_EVT_TIMESTAMP_MS", - "NEXT_FUNDING_ACCRUED", - "NEXT_FUNDING_STEP", + "next_funding_evt_timestamp_ms", + "next_funding_accrued", + "next_funding_step", "_PLACEHOLDER", - "CURRENT_FUNDING", + "current_funding", "_PLACEHOLDER", "_PLACEHOLDER", - "MARK_PRICE", + "mark_price", "_PLACEHOLDER", "_PLACEHOLDER", - "OPEN_INTEREST", + "open_interest", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", - "CLAMP_MIN", - "CLAMP_MAX" + "clamp_min", + "clamp_max" ]) Liquidation = generate_labeler_serializer("Liquidation", klass=types.Liquidation, labels=[ "_PLACEHOLDER", - "POS_ID", - "MTS", + "pos_id", + "mts", "_PLACEHOLDER", - "SYMBOL", - "AMOUNT", - "BASE_PRICE", + "symbol", + "amount", + "base_price", "_PLACEHOLDER", - "IS_MATCH", - "IS_MARKET_SOLD", + "is_match", + "is_market_sold", "_PLACEHOLDER", - "PRICE_ACQUIRED" + "price_acquired" ]) Leaderboard = generate_labeler_serializer("Leaderboard", klass=types.Leaderboard, labels=[ - "MTS", + "mts", "_PLACEHOLDER", - "USERNAME", - "RANKING", + "username", + "ranking", "_PLACEHOLDER", "_PLACEHOLDER", - "VALUE", + "value", "_PLACEHOLDER", "_PLACEHOLDER", - "TWITTER_HANDLE" + "twitter_handle" ]) FundingStatistic = generate_labeler_serializer("FundingStatistic", klass=types.FundingStatistic, labels=[ - "TIMESTAMP", + "timestamp", "_PLACEHOLDER", "_PLACEHOLDER", - "FRR", - "AVG_PERIOD", + "frr", + "avg_period", "_PLACEHOLDER", "_PLACEHOLDER", - "FUNDING_AMOUNT", - "FUNDING_AMOUNT_USED", + "funding_amount", + "funding_amount_used", "_PLACEHOLDER", "_PLACEHOLDER", - "FUNDING_BELOW_THRESHOLD" + "funding_below_threshold" ]) PulseProfile = generate_labeler_serializer("PulseProfile", klass=types.PulseProfile, labels=[ - "PUID", - "MTS", + "puid", + "mts", "_PLACEHOLDER", - "NICKNAME", + "nickname", "_PLACEHOLDER", - "PICTURE", - "TEXT", + "picture", + "text", "_PLACEHOLDER", "_PLACEHOLDER", - "TWITTER_HANDLE", + "twitter_handle", "_PLACEHOLDER", - "FOLLOWERS", - "FOLLOWING", + "followers", + "following", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", - "TIPPING_STATUS" + "tipping_status" ]) -PulseMessage = generate_recursive_serializer("PulseMessage", klass=types.PulseMessage, serializers={ "PROFILE": PulseProfile }, labels=[ - "PID", - "MTS", +PulseMessage = generate_recursive_serializer("PulseMessage", klass=types.PulseMessage, serializers={ "profile": PulseProfile }, labels=[ + "pid", + "mts", "_PLACEHOLDER", - "PUID", + "puid", "_PLACEHOLDER", - "TITLE", - "CONTENT", + "title", + "content", "_PLACEHOLDER", "_PLACEHOLDER", - "IS_PIN", - "IS_PUBLIC", - "COMMENTS_DISABLED", - "TAGS", - "ATTACHMENTS", - "META", - "LIKES", + "is_pin", + "is_public", + "comments_disabled", + "tags", + "attachments", + "meta", + "likes", "_PLACEHOLDER", "_PLACEHOLDER", - "PROFILE", - "COMMENTS", + "profile", + "comments", "_PLACEHOLDER", "_PLACEHOLDER" ]) TradingMarketAveragePrice = generate_labeler_serializer("TradingMarketAveragePrice", klass=types.TradingMarketAveragePrice, labels=[ - "PRICE_AVG", - "AMOUNT" + "price_avg", + "amount" ]) FundingMarketAveragePrice = generate_labeler_serializer("FundingMarketAveragePrice", klass=types.FundingMarketAveragePrice, labels=[ - "RATE_AVG", - "AMOUNT" + "rate_avg", + "amount" ]) FxRate = generate_labeler_serializer("FxRate", klass=types.FxRate, labels=[ - "CURRENT_RATE" + "current_rate" ]) #endregion @@ -249,358 +249,358 @@ FxRate = generate_labeler_serializer("FxRate", klass=types.FxRate, labels=[ #region Serializers definition for Rest Authenticated Endpoints Wallet = generate_labeler_serializer("Wallet", klass=types.Wallet, labels=[ - "WALLET_TYPE", - "CURRENCY", - "BALANCE", - "UNSETTLED_INTEREST", - "AVAILABLE_BALANCE", - "LAST_CHANGE", - "TRADE_DETAILS" + "wallet_type", + "currency", + "balance", + "unsettled_interest", + "available_balance", + "last_change", + "trade_details" ]) Order = generate_labeler_serializer("Order", klass=types.Order, labels=[ - "ID", - "GID", - "CID", - "SYMBOL", - "MTS_CREATE", - "MTS_UPDATE", - "AMOUNT", - "AMOUNT_ORIG", - "ORDER_TYPE", - "TYPE_PREV", - "MTS_TIF", + "id", + "gid", + "cid", + "symbol", + "mts_create", + "mts_update", + "amount", + "amount_orig", + "order_type", + "type_prev", + "mts_tif", "_PLACEHOLDER", - "FLAGS", - "ORDER_STATUS", + "flags", + "order_status", "_PLACEHOLDER", "_PLACEHOLDER", - "PRICE", - "PRICE_AVG", - "PRICE_TRAILING", - "PRICE_AUX_LIMIT", + "price", + "price_avg", + "price_trailing", + "price_aux_limit", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", - "NOTIFY", - "HIDDEN", - "PLACED_ID", + "notify", + "hidden", + "placed_id", "_PLACEHOLDER", "_PLACEHOLDER", - "ROUTING", + "routing", "_PLACEHOLDER", "_PLACEHOLDER", - "META" + "meta" ]) Position = generate_labeler_serializer("Position", klass=types.Position, labels=[ - "SYMBOL", - "STATUS", - "AMOUNT", - "BASE_PRICE", - "MARGIN_FUNDING", - "MARGIN_FUNDING_TYPE", - "PL", - "PL_PERC", - "PRICE_LIQ", - "LEVERAGE", + "symbol", + "status", + "amount", + "base_price", + "margin_funding", + "margin_funding_type", + "pl", + "pl_perc", + "price_liq", + "leverage", "_PLACEHOLDER", - "POSITION_ID", - "MTS_CREATE", - "MTS_UPDATE", + "position_id", + "mts_create", + "mts_update", "_PLACEHOLDER", - "TYPE", + "type", "_PLACEHOLDER", - "COLLATERAL", - "COLLATERAL_MIN", - "META" + "collateral", + "collateral_min", + "meta" ]) FundingOffer = generate_labeler_serializer("FundingOffer", klass=types.FundingOffer, labels=[ - "ID", - "SYMBOL", - "MTS_CREATED", - "MTS_UPDATED", - "AMOUNT", - "AMOUNT_ORIG", - "OFFER_TYPE", + "id", + "symbol", + "mts_created", + "mts_updated", + "amount", + "amount_orig", + "offer_type", "_PLACEHOLDER", "_PLACEHOLDER", - "FLAGS", - "OFFER_STATUS", + "flags", + "offer_status", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", - "RATE", - "PERIOD", - "NOTIFY", - "HIDDEN", + "rate", + "period", + "notify", + "hidden", "_PLACEHOLDER", - "RENEW", + "renew", "_PLACEHOLDER" ]) Trade = generate_labeler_serializer("Trade", klass=types.Trade, labels=[ - "ID", - "PAIR", - "MTS_CREATE", - "ORDER_ID", - "EXEC_AMOUNT", - "EXEC_PRICE", - "ORDER_TYPE", - "ORDER_PRICE", - "MAKER", - "FEE", - "FEE_CURRENCY", - "CID" + "id", + "pair", + "mts_create", + "order_id", + "exec_amount", + "exec_price", + "order_type", + "order_price", + "maker", + "fee", + "fee_currency", + "cid" ]) OrderTrade = generate_labeler_serializer("OrderTrade", klass=types.OrderTrade, labels=[ - "ID", - "PAIR", - "MTS_CREATE", - "ORDER_ID", - "EXEC_AMOUNT", - "EXEC_PRICE", + "id", + "pair", + "mts_create", + "order_id", + "exec_amount", + "exec_price", "_PLACEHOLDER", "_PLACEHOLDER", - "MAKER", - "FEE", - "FEE_CURRENCY", - "CID" + "maker", + "fee", + "fee_currency", + "cid" ]) Ledger = generate_labeler_serializer("Ledger", klass=types.Ledger, labels=[ - "ID", - "CURRENCY", + "id", + "currency", "_PLACEHOLDER", - "MTS", + "mts", "_PLACEHOLDER", - "AMOUNT", - "BALANCE", + "amount", + "balance", "_PLACEHOLDER", - "DESCRIPTION" + "description" ]) FundingCredit = generate_labeler_serializer("FundingCredit", klass=types.FundingCredit, labels=[ - "ID", - "SYMBOL", - "SIDE", - "MTS_CREATE", - "MTS_UPDATE", - "AMOUNT", - "FLAGS", - "STATUS", - "RATE_TYPE", + "id", + "symbol", + "side", + "mts_create", + "mts_update", + "amount", + "flags", + "status", + "rate_type", "_PLACEHOLDER", "_PLACEHOLDER", - "RATE", - "PERIOD", - "MTS_OPENING", - "MTS_LAST_PAYOUT", - "NOTIFY", - "HIDDEN", + "rate", + "period", + "mts_opening", + "mts_last_payout", + "notify", + "hidden", "_PLACEHOLDER", - "RENEW", + "renew", "_PLACEHOLDER", - "NO_CLOSE", - "POSITION_PAIR" + "no_close", + "position_pair" ]) Transfer = generate_labeler_serializer("Transfer", klass=types.Transfer, labels=[ - "MTS", - "WALLET_FROM", - "WALLET_TO", + "mts", + "wallet_from", + "wallet_to", "_PLACEHOLDER", - "CURRENCY", - "CURRENCY_TO", + "currency", + "currency_to", "_PLACEHOLDER", - "AMOUNT" + "amount" ]) Withdrawal = generate_labeler_serializer("Withdrawal", klass=types.Withdrawal, labels=[ - "WITHDRAWAL_ID", + "withdrawal_id", "_PLACEHOLDER", - "METHOD", - "PAYMENT_ID", - "WALLET", - "AMOUNT", + "method", + "payment_id", + "wallet", + "amount", "_PLACEHOLDER", "_PLACEHOLDER", - "WITHDRAWAL_FEE" + "withdrawal_fee" ]) DepositAddress = generate_labeler_serializer("DepositAddress", klass=types.DepositAddress, labels=[ "_PLACEHOLDER", - "METHOD", - "CURRENCY_CODE", + "method", + "currency_code", "_PLACEHOLDER", - "ADDRESS", - "POOL_ADDRESS" + "address", + "pool_address" ]) Invoice = generate_labeler_serializer("Invoice", klass=types.Invoice, labels=[ - "INVOICE_HASH", - "INVOICE", + "invoice_hash", + "invoice", "_PLACEHOLDER", "_PLACEHOLDER", - "AMOUNT" + "amount" ]) Movement = generate_labeler_serializer("Movement", klass=types.Movement, labels=[ - "ID", - "CURRENCY", - "CURRENCY_NAME", + "id", + "currency", + "currency_name", "_PLACEHOLDER", "_PLACEHOLDER", - "MTS_STARTED", - "MTS_UPDATED", + "mts_started", + "mts_updated", "_PLACEHOLDER", "_PLACEHOLDER", - "STATUS", + "status", "_PLACEHOLDER", "_PLACEHOLDER", - "AMOUNT", - "FEES", + "amount", + "fees", "_PLACEHOLDER", "_PLACEHOLDER", - "DESTINATION_ADDRESS", + "destination_address", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", - "TRANSACTION_ID", - "WITHDRAW_TRANSACTION_NOTE" + "transaction_id", + "withdraw_transaction_note" ]) SymbolMarginInfo = generate_labeler_serializer("SymbolMarginInfo", klass=types.SymbolMarginInfo, labels=[ - "SYMBOL", - "TRADABLE_BALANCE", - "GROSS_BALANCE", - "BUY", - "SELL" + "symbol", + "tradable_balance", + "gross_balance", + "buy", + "sell" ]) BaseMarginInfo = generate_labeler_serializer("BaseMarginInfo", klass=types.BaseMarginInfo, labels=[ - "USER_PL", - "USER_SWAPS", - "MARGIN_BALANCE", - "MARGIN_NET", - "MARGIN_MIN" + "user_pl", + "user_swaps", + "margin_balance", + "margin_net", + "margin_min" ]) Claim = generate_labeler_serializer("Claim", klass=types.Claim, labels=[ - "SYMBOL", - "POSITION_STATUS", - "AMOUNT", - "BASE_PRICE", - "MARGIN_FUNDING", - "MARGIN_FUNDING_TYPE", + "symbol", + "position_status", + "amount", + "base_price", + "margin_funding", + "margin_funding_type", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", - "POSITION_ID", - "MTS_CREATE", - "MTS_UPDATE", + "position_id", + "mts_create", + "mts_update", "_PLACEHOLDER", - "POS_TYPE", + "pos_type", "_PLACEHOLDER", - "COLLATERAL", - "MIN_COLLATERAL", - "META" + "collateral", + "min_collateral", + "meta" ]) IncreaseInfo = generate_labeler_serializer("IncreaseInfo", klass=types.IncreaseInfo, labels=[ - "MAX_POS", - "CURRENT_POS", - "BASE_CURRENCY_BALANCE", - "TRADABLE_BALANCE_QUOTE_CURRENCY", - "TRADABLE_BALANCE_QUOTE_TOTAL", - "TRADABLE_BALANCE_BASE_CURRENCY", - "TRADABLE_BALANCE_BASE_TOTAL", + "max_pos", + "current_pos", + "base_currency_balance", + "tradable_balance_quote_currency", + "tradable_balance_quote_total", + "tradable_balance_base_currency", + "tradable_balance_base_total", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", - "FUNDING_AVAIL", - "FUNDING_VALUE", - "FUNDING_REQUIRED", - "FUNDING_VALUE_CURRENCY", - "FUNDING_REQUIRED_CURRENCY" + "funding_avail", + "funding_value", + "funding_required", + "funding_value_currency", + "funding_required_currency" ]) Increase = generate_labeler_serializer("Increase", klass=types.Increase, labels=[ - "SYMBOL", + "symbol", "_PLACEHOLDER", - "AMOUNT", - "BASE_PRICE" + "amount", + "base_price" ]) PositionHistory = generate_labeler_serializer("PositionHistory", klass=types.PositionHistory, labels=[ - "SYMBOL", - "STATUS", - "AMOUNT", - "BASE_PRICE", - "FUNDING", - "FUNDING_TYPE", + "symbol", + "status", + "amount", + "base_price", + "funding", + "funding_type", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", - "POSITION_ID", - "MTS_CREATE", - "MTS_UPDATE" + "position_id", + "mts_create", + "mts_update" ]) PositionSnapshot = generate_labeler_serializer("PositionSnapshot", klass=types.PositionSnapshot, labels=[ - "SYMBOL", - "STATUS", - "AMOUNT", - "BASE_PRICE", - "FUNDING", - "FUNDING_TYPE", + "symbol", + "status", + "amount", + "base_price", + "funding", + "funding_type", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", - "POSITION_ID", - "MTS_CREATE", - "MTS_UPDATE" + "position_id", + "mts_create", + "mts_update" ]) PositionAudit = generate_labeler_serializer("PositionAudit", klass=types.PositionAudit, labels=[ - "SYMBOL", - "STATUS", - "AMOUNT", - "BASE_PRICE", - "FUNDING", - "FUNDING_TYPE", + "symbol", + "status", + "amount", + "base_price", + "funding", + "funding_type", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", - "POSITION_ID", - "MTS_CREATE", - "MTS_UPDATE", + "position_id", + "mts_create", + "mts_update", "_PLACEHOLDER", - "TYPE", + "type", "_PLACEHOLDER", - "COLLATERAL", - "COLLATERAL_MIN", - "META" + "collateral", + "collateral_min", + "meta" ]) DerivativePositionCollateral = generate_labeler_serializer("DerivativePositionCollateral", klass=types.DerivativePositionCollateral, labels=[ - "STATUS" + "status" ]) DerivativePositionCollateralLimits = generate_labeler_serializer("DerivativePositionCollateralLimits", klass=types.DerivativePositionCollateralLimits, labels=[ - "MIN_COLLATERAL", - "MAX_COLLATERAL" + "min_collateral", + "max_collateral" ]) #endregion \ No newline at end of file diff --git a/bfxapi/rest/types.py b/bfxapi/rest/types.py index 4f2647f..4850404 100644 --- a/bfxapi/rest/types.py +++ b/bfxapi/rest/types.py @@ -10,188 +10,188 @@ from .. utils.encoder import JSON @dataclass class PlatformStatus(_Type): - STATUS: int + status: int @dataclass class TradingPairTicker(_Type): - SYMBOL: Optional[str] - 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 + symbol: Optional[str] + 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 @dataclass class FundingCurrencyTicker(_Type): - SYMBOL: Optional[str] - 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 + symbol: Optional[str] + 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 @dataclass class TickersHistory(_Type): - SYMBOL: str - BID: float - ASK: float - MTS: int + symbol: str + bid: float + ask: float + mts: int @dataclass class TradingPairTrade(_Type): - ID: int - MTS: int - AMOUNT: float - PRICE: float + id: int + mts: int + amount: float + price: float @dataclass class FundingCurrencyTrade(_Type): - ID: int - MTS: int - AMOUNT: float - RATE: float - PERIOD: int + id: int + mts: int + amount: float + rate: float + period: int @dataclass class TradingPairBook(_Type): - PRICE: float - COUNT: int - AMOUNT: float + price: float + count: int + amount: float @dataclass class FundingCurrencyBook(_Type): - RATE: float - PERIOD: int - COUNT: int - AMOUNT: float + rate: float + period: int + count: int + amount: float @dataclass class TradingPairRawBook(_Type): - ORDER_ID: int - PRICE: float - AMOUNT: float + order_id: int + price: float + amount: float @dataclass class FundingCurrencyRawBook(_Type): - OFFER_ID: int - PERIOD: int - RATE: float - AMOUNT: float + offer_id: int + period: int + rate: float + amount: float @dataclass class Statistic(_Type): - MTS: int - VALUE: float + mts: int + value: float @dataclass class Candle(_Type): - MTS: int - OPEN: float - CLOSE: float - HIGH: float - LOW: float - VOLUME: float + mts: int + open: float + close: float + high: float + low: float + volume: float @dataclass class DerivativesStatus(_Type): - KEY: Optional[str] - MTS: 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 + key: Optional[str] + mts: 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 @dataclass class Liquidation(_Type): - POS_ID: int - MTS: int - SYMBOL: str - AMOUNT: float - BASE_PRICE: float - IS_MATCH: int - IS_MARKET_SOLD: int - PRICE_ACQUIRED: float + pos_id: int + mts: int + symbol: str + amount: float + base_price: float + is_match: int + is_market_sold: int + price_acquired: float @dataclass class Leaderboard(_Type): - MTS: int - USERNAME: str - RANKING: int - VALUE: float - TWITTER_HANDLE: Optional[str] + mts: int + username: str + ranking: int + value: float + twitter_handle: Optional[str] @dataclass class FundingStatistic(_Type): - TIMESTAMP: int - FRR: float - AVG_PERIOD: float - FUNDING_AMOUNT: float - FUNDING_AMOUNT_USED: float - FUNDING_BELOW_THRESHOLD: float + timestamp: int + frr: float + avg_period: float + funding_amount: float + funding_amount_used: float + funding_below_threshold: float @dataclass class PulseProfile(_Type): - PUID: str - MTS: int - NICKNAME: str - PICTURE: str - TEXT: str - TWITTER_HANDLE: str - FOLLOWERS: int - FOLLOWING: int - TIPPING_STATUS: int + puid: str + mts: int + nickname: str + picture: str + text: str + twitter_handle: str + followers: int + following: int + tipping_status: int @dataclass class PulseMessage(_Type): - PID: str - MTS: int - PUID: str - TITLE: str - CONTENT: str - IS_PIN: int - IS_PUBLIC: int - COMMENTS_DISABLED: int - TAGS: List[str] - ATTACHMENTS: List[str] - META: List[JSON] - LIKES: int - PROFILE: PulseProfile - COMMENTS: int + pid: str + mts: int + puid: str + title: str + content: str + is_pin: int + is_public: int + comments_disabled: int + tags: List[str] + attachments: List[str] + meta: List[JSON] + likes: int + profile: PulseProfile + comments: int @dataclass class TradingMarketAveragePrice(_Type): - PRICE_AVG: float - AMOUNT: float + price_avg: float + amount: float @dataclass class FundingMarketAveragePrice(_Type): - RATE_AVG: float - AMOUNT: float + rate_avg: float + amount: float @dataclass class FxRate(_Type): - CURRENT_RATE: float + current_rate: float #endregion @@ -199,279 +199,279 @@ class FxRate(_Type): @dataclass class Wallet(_Type): - WALLET_TYPE: str - CURRENCY: str - BALANCE: float - UNSETTLED_INTEREST: float - AVAILABLE_BALANCE: float - LAST_CHANGE: str - TRADE_DETAILS: JSON + wallet_type: str + currency: str + balance: float + unsettled_interest: float + available_balance: float + last_change: str + trade_details: JSON @dataclass class Order(_Type): - 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 + 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 @dataclass class Position(_Type): - 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 + 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 @dataclass class FundingOffer(_Type): - ID: int - SYMBOL: str - MTS_CREATE: int - MTS_UPDATE: int - AMOUNT: float - AMOUNT_ORIG: float - OFFER_TYPE: str - FLAGS: int - OFFER_STATUS: str - RATE: float - PERIOD: int - NOTIFY: bool - HIDDEN: int - RENEW: bool + id: int + symbol: str + mts_create: int + mts_update: int + amount: float + amount_orig: float + offer_type: str + flags: int + offer_status: str + rate: float + period: int + notify: bool + hidden: int + renew: bool @dataclass class Trade(_Type): - 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 + 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 @dataclass class OrderTrade(_Type): - ID: int - SYMBOL: str - MTS_CREATE: int - ORDER_ID: int - EXEC_AMOUNT: float - EXEC_PRICE: float - MAKER:int - FEE: float - FEE_CURRENCY: str - CID: int + id: int + symbol: str + mts_create: int + order_id: int + exec_amount: float + exec_price: float + maker:int + fee: float + fee_currency: str + cid: int @dataclass class Ledger(_Type): - ID: int - CURRENCY: str - MTS: int - AMOUNT: float - BALANCE: float + id: int + currency: str + mts: int + amount: float + balance: float description: str @dataclass class FundingCredit(_Type): - 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 + 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 @dataclass class Transfer(_Type): - MTS: int - WALLET_FROM: str - WALLET_TO: str - CURRENCY: str - CURRENCY_TO: str - AMOUNT: int + mts: int + wallet_from: str + wallet_to: str + currency: str + currency_to: str + amount: int @dataclass class Withdrawal(_Type): - WITHDRAWAL_ID: int - METHOD: str - PAYMENT_ID: str - WALLET: str - AMOUNT: float - WITHDRAWAL_FEE: float + withdrawal_id: int + method: str + payment_id: str + wallet: str + amount: float + withdrawal_fee: float @dataclass class DepositAddress(_Type): - METHOD: str - CURRENCY_CODE: str - ADDRESS: str - POOL_ADDRESS: str + method: str + currency_code: str + address: str + pool_address: str @dataclass class Invoice(_Type): - INVOICE_HASH: str - INVOICE: str - AMOUNT: str + invoice_hash: str + invoice: str + amount: str @dataclass class Movement(_Type): - ID: str - CURRENCY: str - CURRENCY_NAME: str - MTS_STARTED: int - MTS_UPDATED: int - STATUS: str - AMOUNT: int - FEES: int - DESTINATION_ADDRESS: str - TRANSACTION_ID: str - WITHDRAW_TRANSACTION_NOTE: str + id: str + currency: str + currency_name: str + mts_started: int + mts_updated: int + status: str + amount: int + fees: int + destination_address: str + transaction_id: str + withdraw_transaction_note: str @dataclass class SymbolMarginInfo(_Type): - SYMBOL: str - TRADABLE_BALANCE: float - GROSS_BALANCE: float - BUY: float - SELL: float + symbol: str + tradable_balance: float + gross_balance: float + buy: float + sell: float @dataclass class BaseMarginInfo(_Type): - USER_PL: float - USER_SWAPS: float - MARGIN_BALANCE: float - MARGIN_NET: float - MARGIN_MIN: float + user_pl: float + user_swaps: float + margin_balance: float + margin_net: float + margin_min: float @dataclass class Claim(_Type): - SYMBOL: str - POSITION_STATUS: str - AMOUNT: float - BASE_PRICE: float - MARGIN_FUNDING: float - MARGIN_FUNDING_TYPE: int - POSITION_ID: int - MTS_CREATE: int - MTS_UPDATE: int - POS_TYPE: int - COLLATERAL: str - MIN_COLLATERAL: str - META: JSON + symbol: str + position_status: str + amount: float + base_price: float + margin_funding: float + margin_funding_type: int + position_id: int + mts_create: int + mts_update: int + pos_type: int + collateral: str + min_collateral: str + meta: JSON @dataclass class IncreaseInfo(_Type): - MAX_POS: int - CURRENT_POS: float - BASE_CURRENCY_BALANCE: float - TRADABLE_BALANCE_QUOTE_CURRENCY: float - TRADABLE_BALANCE_QUOTE_TOTAL: float - TRADABLE_BALANCE_BASE_CURRENCY: float - TRADABLE_BALANCE_BASE_TOTAL: float - FUNDING_AVAIL: float - FUNDING_VALUE: float - FUNDING_REQUIRED: float - FUNDING_VALUE_CURRENCY: str - FUNDING_REQUIRED_CURRENCY: str + max_pos: int + current_pos: float + base_currency_balance: float + tradable_balance_quote_currency: float + tradable_balance_quote_total: float + tradable_balance_base_currency: float + tradable_balance_base_total: float + funding_avail: float + funding_value: float + funding_required: float + funding_value_currency: str + funding_required_currency: str @dataclass class Increase(_Type): - SYMBOL: str - AMOUNT: float - BASE_PRICE: float + symbol: str + amount: float + base_price: float @dataclass class PositionHistory(_Type): - SYMBOL: str - STATUS: str - AMOUNT: float - BASE_PRICE: float - FUNDING: float - FUNDING_TYPE: int - POSITION_ID: int - MTS_CREATE: int - MTS_UPDATE: int + symbol: str + status: str + amount: float + base_price: float + funding: float + funding_type: int + position_id: int + mts_create: int + mts_update: int @dataclass class PositionSnapshot(_Type): - SYMBOL: str - STATUS: str - AMOUNT: float - BASE_PRICE: float - FUNDING: float - FUNDING_TYPE: int - POSITION_ID: int - MTS_CREATE: int - MTS_UPDATE: int + symbol: str + status: str + amount: float + base_price: float + funding: float + funding_type: int + position_id: int + mts_create: int + mts_update: int @dataclass class PositionAudit(_Type): - SYMBOL: str - STATUS: str - AMOUNT: float - BASE_PRICE: float - FUNDING: float - FUNDING_TYPE: int - POSITION_ID: int - MTS_CREATE: int - MTS_UPDATE: int - TYPE: int - COLLATERAL: float - COLLATERAL_MIN: float - META: JSON + symbol: str + status: str + amount: float + base_price: float + funding: float + funding_type: int + position_id: int + mts_create: int + mts_update: int + type: int + collateral: float + collateral_min: float + meta: JSON @dataclass class DerivativePositionCollateral(_Type): - STATUS: int + status: int @dataclass class DerivativePositionCollateralLimits(_Type): - MIN_COLLATERAL: float - MAX_COLLATERAL: float + min_collateral: float + max_collateral: float #endregion \ No newline at end of file diff --git a/bfxapi/websocket/serializers.py b/bfxapi/websocket/serializers.py index 1e14dbc..5991cc9 100644 --- a/bfxapi/websocket/serializers.py +++ b/bfxapi/websocket/serializers.py @@ -7,111 +7,111 @@ from .. notification import _Notification #region Serializers definition for Websocket Public Channels TradingPairTicker = generate_labeler_serializer("TradingPairTicker", klass=types.TradingPairTicker, labels=[ - "BID", - "BID_SIZE", - "ASK", - "ASK_SIZE", - "DAILY_CHANGE", - "DAILY_CHANGE_RELATIVE", - "LAST_PRICE", - "VOLUME", - "HIGH", - "LOW" + "bid", + "bid_size", + "ask", + "ask_size", + "daily_change", + "daily_change_relative", + "last_price", + "volume", + "high", + "low" ]) FundingCurrencyTicker = generate_labeler_serializer("FundingCurrencyTicker", klass=types.FundingCurrencyTicker, labels=[ - "FRR", - "BID", - "BID_PERIOD", - "BID_SIZE", - "ASK", - "ASK_PERIOD", - "ASK_SIZE", - "DAILY_CHANGE", - "DAILY_CHANGE_RELATIVE", - "LAST_PRICE", - "VOLUME", - "HIGH", - "LOW" + "frr", + "bid", + "bid_period", + "bid_size", + "ask", + "ask_period", + "ask_size", + "daily_change", + "daily_change_relative", + "last_price", + "volume", + "high", + "low" "_PLACEHOLDER", "_PLACEHOLDER", - "FRR_AMOUNT_AVAILABLE" + "frr_amount_available" ]) TradingPairTrade = generate_labeler_serializer("TradingPairTrade", klass=types.TradingPairTrade, labels=[ - "ID", - "MTS", - "AMOUNT", - "PRICE" + "id", + "mts", + "amount", + "price" ]) FundingCurrencyTrade = generate_labeler_serializer("FundingCurrencyTrade", klass=types.FundingCurrencyTrade, labels=[ - "ID", - "MTS", - "AMOUNT", - "RATE", - "PERIOD" + "id", + "mts", + "amount", + "rate", + "period" ]) TradingPairBook = generate_labeler_serializer("TradingPairBook", klass=types.TradingPairBook, labels=[ - "PRICE", - "COUNT", - "AMOUNT" + "price", + "count", + "amount" ]) FundingCurrencyBook = generate_labeler_serializer("FundingCurrencyBook", klass=types.FundingCurrencyBook, labels=[ - "RATE", - "PERIOD", - "COUNT", - "AMOUNT" + "rate", + "period", + "count", + "amount" ]) TradingPairRawBook = generate_labeler_serializer("TradingPairRawBook", klass=types.TradingPairRawBook, labels=[ - "ORDER_ID", - "PRICE", - "AMOUNT" + "order_id", + "price", + "amount" ]) FundingCurrencyRawBook = generate_labeler_serializer("FundingCurrencyRawBook", klass=types.FundingCurrencyRawBook, labels=[ - "OFFER_ID", - "PERIOD", - "RATE", - "AMOUNT" + "offer_id", + "period", + "rate", + "amount" ]) Candle = generate_labeler_serializer("Candle", klass=types.Candle, labels=[ - "MTS", - "OPEN", - "CLOSE", - "HIGH", - "LOW", - "VOLUME" + "mts", + "open", + "close", + "high", + "low", + "volume" ]) DerivativesStatus = generate_labeler_serializer("DerivativesStatus", klass=types.DerivativesStatus, labels=[ - "TIME_MS", + "time_ms", "_PLACEHOLDER", - "DERIV_PRICE", - "SPOT_PRICE", + "deriv_price", + "spot_price", "_PLACEHOLDER", - "INSURANCE_FUND_BALANCE", + "insurance_fund_balance", "_PLACEHOLDER", - "NEXT_FUNDING_EVT_TIMESTAMP_MS", - "NEXT_FUNDING_ACCRUED", - "NEXT_FUNDING_STEP", + "next_funding_evt_timestamp_ms", + "next_funding_accrued", + "next_funding_step", "_PLACEHOLDER", - "CURRENT_FUNDING" + "current_funding" "_PLACEHOLDER", "_PLACEHOLDER", - "MARK_PRICE", + "mark_price", "_PLACEHOLDER", "_PLACEHOLDER", - "OPEN_INTEREST", + "open_interest", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", - "CLAMP_MIN", - "CLAMP_MAX" + "clamp_min", + "clamp_max" ]) #endregion @@ -119,179 +119,179 @@ DerivativesStatus = generate_labeler_serializer("DerivativesStatus", klass=types #region Serializers definition for Websocket Authenticated Channels Order = generate_labeler_serializer("Order", klass=types.Order, labels=[ - "ID", - "GID", - "CID", - "SYMBOL", - "MTS_CREATE", - "MTS_UPDATE", - "AMOUNT", - "AMOUNT_ORIG", - "ORDER_TYPE", - "TYPE_PREV", - "MTS_TIF", + "id", + "gid", + "cid", + "symbol", + "mts_create", + "mts_update", + "amount", + "amount_orig", + "order_type", + "type_prev", + "mts_tif", "_PLACEHOLDER", - "FLAGS", - "ORDER_STATUS", + "flags", + "order_status", "_PLACEHOLDER", "_PLACEHOLDER", - "PRICE", - "PRICE_AVG", - "PRICE_TRAILING", - "PRICE_AUX_LIMIT", + "price", + "price_avg", + "price_trailing", + "price_aux_limit", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", - "NOTIFY", - "HIDDEN", - "PLACED_ID", + "notify", + "hidden", + "placed_id", "_PLACEHOLDER", "_PLACEHOLDER", - "ROUTING", + "routing", "_PLACEHOLDER", "_PLACEHOLDER", - "META" + "meta" ]) Position = generate_labeler_serializer("Position", klass=types.Position, labels=[ - "SYMBOL", - "STATUS", - "AMOUNT", - "BASE_PRICE", - "MARGIN_FUNDING", - "MARGIN_FUNDING_TYPE", - "PL", - "PL_PERC", - "PRICE_LIQ", - "LEVERAGE", - "FLAG", - "POSITION_ID", - "MTS_CREATE", - "MTS_UPDATE", + "symbol", + "status", + "amount", + "base_price", + "margin_funding", + "margin_funding_type", + "pl", + "pl_perc", + "price_liq", + "leverage", + "flag", + "position_id", + "mts_create", + "mts_update", "_PLACEHOLDER", - "TYPE", + "type", "_PLACEHOLDER", - "COLLATERAL", - "COLLATERAL_MIN", - "META" + "collateral", + "collateral_min", + "meta" ]) TradeExecuted = generate_labeler_serializer("TradeExecuted", klass=types.TradeExecuted, labels=[ - "ID", - "SYMBOL", - "MTS_CREATE", - "ORDER_ID", - "EXEC_AMOUNT", - "EXEC_PRICE", - "ORDER_TYPE", - "ORDER_PRICE", - "MAKER", + "id", + "symbol", + "mts_create", + "order_id", + "exec_amount", + "exec_price", + "order_type", + "order_price", + "maker", "_PLACEHOLDER", "_PLACEHOLDER", - "CID" + "cid" ]) TradeExecutionUpdate = generate_labeler_serializer("TradeExecutionUpdate", klass=types.TradeExecutionUpdate, labels=[ - "ID", - "SYMBOL", - "MTS_CREATE", - "ORDER_ID", - "EXEC_AMOUNT", - "EXEC_PRICE", - "ORDER_TYPE", - "ORDER_PRICE", - "MAKER", - "FEE", - "FEE_CURRENCY", - "CID" + "id", + "symbol", + "mts_create", + "order_id", + "exec_amount", + "exec_price", + "order_type", + "order_price", + "maker", + "fee", + "fee_currency", + "cid" ]) FundingOffer = generate_labeler_serializer("FundingOffer", klass=types.FundingOffer, labels=[ - "ID", - "SYMBOL", - "MTS_CREATED", - "MTS_UPDATED", - "AMOUNT", - "AMOUNT_ORIG", - "OFFER_TYPE", + "id", + "symbol", + "mts_created", + "mts_updated", + "amount", + "amount_orig", + "offer_type", "_PLACEHOLDER", "_PLACEHOLDER", - "FLAGS", - "STATUS", + "flags", + "status", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", - "RATE", - "PERIOD", - "NOTIFY", - "HIDDEN", + "rate", + "period", + "notify", + "hidden", "_PLACEHOLDER", - "RENEW", + "renew", "_PLACEHOLDER" ]) FundingCredit = generate_labeler_serializer("FundingCredit", klass=types.FundingCredit, labels=[ - "ID", - "SYMBOL", - "SIDE", - "MTS_CREATE", - "MTS_UPDATE", - "AMOUNT", - "FLAGS", - "STATUS", + "id", + "symbol", + "side", + "mts_create", + "mts_update", + "amount", + "flags", + "status", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", - "RATE", - "PERIOD", - "MTS_OPENING", - "MTS_LAST_PAYOUT", - "NOTIFY", - "HIDDEN", + "rate", + "period", + "mts_opening", + "mts_last_payout", + "notify", + "hidden", "_PLACEHOLDER", - "RENEW", - "RATE_REAL", - "NO_CLOSE", - "POSITION_PAIR" + "renew", + "rate_real", + "no_close", + "position_pair" ]) FundingLoan = generate_labeler_serializer("FundingLoan", klass=types.FundingLoan, labels=[ - "ID", - "SYMBOL", - "SIDE", - "MTS_CREATE", - "MTS_UPDATE", - "AMOUNT", - "FLAGS", - "STATUS", + "id", + "symbol", + "side", + "mts_create", + "mts_update", + "amount", + "flags", + "status", "_PLACEHOLDER", "_PLACEHOLDER", "_PLACEHOLDER", - "RATE", - "PERIOD", - "MTS_OPENING", - "MTS_LAST_PAYOUT", - "NOTIFY", - "HIDDEN", + "rate", + "period", + "mts_opening", + "mts_last_payout", + "notify", + "hidden", "_PLACEHOLDER", - "RENEW", - "RATE_REAL", - "NO_CLOSE" + "renew", + "rate_real", + "no_close" ]) Wallet = generate_labeler_serializer("Wallet", klass=types.Wallet, labels=[ - "WALLET_TYPE", - "CURRENCY", - "BALANCE", - "UNSETTLED_INTEREST", - "BALANCE_AVAILABLE", - "DESCRIPTION", - "META" + "wallet_type", + "currency", + "balance", + "unsettled_interest", + "balance_available", + "description", + "meta" ]) BalanceInfo = generate_labeler_serializer("BalanceInfo", klass=types.BalanceInfo, labels=[ - "AUM", - "AUM_NET", + "aum", + "aum_net", ]) #endregion \ No newline at end of file diff --git a/bfxapi/websocket/types.py b/bfxapi/websocket/types.py index 19ed3ef..91bac2a 100644 --- a/bfxapi/websocket/types.py +++ b/bfxapi/websocket/types.py @@ -10,246 +10,246 @@ from .. utils.encoder import JSON @dataclass class TradingPairTicker(_Type): - 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 + 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 @dataclass class FundingCurrencyTicker(_Type): - 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 + 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 @dataclass class TradingPairTrade(_Type): - ID: int - MTS: int - AMOUNT: float - PRICE: float + id: int + mts: int + amount: float + price: float @dataclass class FundingCurrencyTrade(_Type): - ID: int - MTS: int - AMOUNT: float - RATE: float - PERIOD: int + id: int + mts: int + amount: float + rate: float + period: int @dataclass class TradingPairBook(_Type): - PRICE: float - COUNT: int - AMOUNT: float + price: float + count: int + amount: float @dataclass class FundingCurrencyBook(_Type): - RATE: float - PERIOD: int - COUNT: int - AMOUNT: float + rate: float + period: int + count: int + amount: float @dataclass class TradingPairRawBook(_Type): - ORDER_ID: int - PRICE: float - AMOUNT: float + order_id: int + price: float + amount: float @dataclass class FundingCurrencyRawBook(_Type): - OFFER_ID: int - PERIOD: int - RATE: float - AMOUNT: float + offer_id: int + period: int + rate: float + amount: float @dataclass class Candle(_Type): - MTS: int - OPEN: float - CLOSE: float - HIGH: float - LOW: float - VOLUME: float + mts: int + open: float + close: float + high: float + low: float + volume: float @dataclass class DerivativesStatus(_Type): - 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 + 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 @dataclass class Order(_Type): - 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 + 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 @dataclass class Position(_Type): - 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 + 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 @dataclass class TradeExecuted(_Type): - 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 + 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 @dataclass class TradeExecutionUpdate(_Type): - 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 + 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 @dataclass class FundingOffer(_Type): - 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 + 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 @dataclass class FundingCredit(_Type): - 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 + 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 @dataclass class FundingLoan(_Type): - 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 + 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 @dataclass class Wallet(_Type): - WALLET_TYPE: str - CURRENCY: str - BALANCE: float - UNSETTLED_INTEREST: float - BALANCE_AVAILABLE: float - DESCRIPTION: str - META: JSON + wallet_type: str + currency: str + balance: float + unsettled_interest: float + balance_available: float + description: str + meta: JSON @dataclass class BalanceInfo(_Type): - AUM: float - AUM_NET: float + aum: float + aum_net: float #endregion \ No newline at end of file From 6e96cda584ba69d1dfc53297e6352038bf95301a Mon Sep 17 00:00:00 2001 From: Davide Casale Date: Fri, 27 Jan 2023 15:57:36 +0100 Subject: [PATCH 2/5] Edit demos in examples/ folder to use lowercase property identifiers. --- bfxapi/rest/BfxRestInterface.py | 5 ++--- examples/rest/claim_position.py | 4 ++-- examples/rest/create_order.py | 4 ++-- examples/rest/derivatives.py | 2 +- examples/rest/extra_calcs.py | 6 +++--- examples/rest/get_pulse_data.py | 6 +++--- examples/rest/increase_position.py | 2 +- examples/rest/transfer_wallet.py | 8 ++++---- examples/websocket/order_book.py | 2 +- examples/websocket/raw_order_book.py | 2 +- 10 files changed, 20 insertions(+), 21 deletions(-) diff --git a/bfxapi/rest/BfxRestInterface.py b/bfxapi/rest/BfxRestInterface.py index bf4e1cf..d50799c 100644 --- a/bfxapi/rest/BfxRestInterface.py +++ b/bfxapi/rest/BfxRestInterface.py @@ -101,7 +101,7 @@ class _RestPublicEndpoints(_Requests): def get_t_tickers(self, pairs: Union[List[str], Literal["ALL"]]) -> List[TradingPairTicker]: 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([ "t" + pair for pair in pairs ]) @@ -109,7 +109,7 @@ class _RestPublicEndpoints(_Requests): def get_f_tickers(self, currencies: Union[List[str], Literal["ALL"]]) -> List[FundingCurrencyTicker]: 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([ "f" + currency for currency in currencies ]) @@ -218,7 +218,6 @@ class _RestPublicEndpoints(_Requests): 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]: - 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) diff --git a/examples/rest/claim_position.py b/examples/rest/claim_position.py index de3b5f2..caf5e23 100644 --- a/examples/rest/claim_position.py +++ b/examples/rest/claim_position.py @@ -15,5 +15,5 @@ open_margin_positions = bfx.rest.auth.get_positions() # claim all positions for position in open_margin_positions: print(f"Position {position}") - claim = bfx.rest.auth.claim_position(position.POSITION_ID, amount=0.000001) - print(f"Claim {claim.NOTIFY_INFO}") \ No newline at end of file + claim = bfx.rest.auth.claim_position(position.position_id, amount=0.000001) + print(f"Claim {claim.notify_info}") \ No newline at end of file diff --git a/examples/rest/create_order.py b/examples/rest/create_order.py index 1f63e46..2c13ae2 100644 --- a/examples/rest/create_order.py +++ b/examples/rest/create_order.py @@ -25,7 +25,7 @@ print("Submit Order Notification:", submitted_order) # Update it updated_order = bfx.rest.auth.update_order( - id=submitted_order.NOTIFY_INFO.ID, + id=submitted_order.notify_info.id, amount="0.020", price="10100" ) @@ -33,6 +33,6 @@ updated_order = bfx.rest.auth.update_order( print("Update Order Notification:", updated_order) # Delete it -canceled_order = bfx.rest.auth.cancel_order(id=submitted_order.NOTIFY_INFO.ID) +canceled_order = bfx.rest.auth.cancel_order(id=submitted_order.notify_info.id) print("Cancel Order Notification:", canceled_order) diff --git a/examples/rest/derivatives.py b/examples/rest/derivatives.py index 89865a5..4aedd00 100644 --- a/examples/rest/derivatives.py +++ b/examples/rest/derivatives.py @@ -27,5 +27,5 @@ print(f"Limits {limits}") # Update position collateral response = bfx.rest.auth.set_derivative_position_collateral(symbol="tBTCF0:USTF0", collateral=50) -print(response.STATUS) +print(response.status) diff --git a/examples/rest/extra_calcs.py b/examples/rest/extra_calcs.py index 0e6fb1e..e380aef 100644 --- a/examples/rest/extra_calcs.py +++ b/examples/rest/extra_calcs.py @@ -12,7 +12,7 @@ t_symbol_response = bfx.rest.public.get_trading_market_average_price( price_limit="20000.5" ) -print(t_symbol_response.PRICE_AVG) +print(t_symbol_response.price_avg) f_symbol_response = bfx.rest.public.get_funding_market_average_price( symbol="fUSD", @@ -21,8 +21,8 @@ f_symbol_response = bfx.rest.public.get_funding_market_average_price( rate_limit="0.00015" ) -print(f_symbol_response.RATE_AVG) +print(f_symbol_response.rate_avg) fx_rate = bfx.rest.public.get_fx_rate(ccy1="USD", ccy2="EUR") -print(fx_rate.CURRENT_RATE) \ No newline at end of file +print(fx_rate.current_rate) \ No newline at end of file diff --git a/examples/rest/get_pulse_data.py b/examples/rest/get_pulse_data.py index 9fb8832..75b55ae 100644 --- a/examples/rest/get_pulse_data.py +++ b/examples/rest/get_pulse_data.py @@ -14,9 +14,9 @@ messages = bfx.rest.public.get_pulse_history(end=now, limit=100) for message in messages: print(f"Message: {message}") - print(message.CONTENT) - print(message.PROFILE.PICTURE) + print(message.content) + print(message.profile.picture) profile = bfx.rest.public.get_pulse_profile("News") print(f"Profile: {profile}") -print(f"Profile picture: {profile.PICTURE}") \ No newline at end of file +print(f"Profile picture: {profile.picture}") \ No newline at end of file diff --git a/examples/rest/increase_position.py b/examples/rest/increase_position.py index 440f9c8..65595c8 100644 --- a/examples/rest/increase_position.py +++ b/examples/rest/increase_position.py @@ -15,4 +15,4 @@ print(increase_info) # increase a margin position notification = bfx.rest.auth.increase_position(symbol="tBTCUSD", amount=0.0001) -print(notification.NOTIFY_INFO) +print(notification.notify_info) diff --git a/examples/rest/transfer_wallet.py b/examples/rest/transfer_wallet.py index b1d9fd3..e986bfd 100644 --- a/examples/rest/transfer_wallet.py +++ b/examples/rest/transfer_wallet.py @@ -12,20 +12,20 @@ bfx = Client( def transfer_wallet(): response = bfx.rest.auth.submit_wallet_transfer(from_wallet="exchange", to_wallet="funding", from_currency="ETH", to_currency="ETH", amount=0.001) - print("Transfer:", response.NOTIFY_INFO) + print("Transfer:", response.notify_info) def get_existing_deposit_address(): response = bfx.rest.auth.get_deposit_address(wallet="exchange", method="bitcoin", renew=False) - print("Address:", response.NOTIFY_INFO) + print("Address:", response.notify_info) def create_new_deposit_address(): response = bfx.rest.auth.get_deposit_address(wallet="exchange", method="bitcoin", renew=True) - print("Address:", response.NOTIFY_INFO) + print("Address:", response.notify_info) def withdraw(): # tetheruse = Tether (ERC20) response = bfx.rest.auth.submit_wallet_withdraw(wallet="exchange", method="tetheruse", amount=1, address="0x742d35Cc6634C0532925a3b844Bc454e4438f44e") - print("Address:", response.NOTIFY_INFO) + print("Address:", response.notify_info) def create_lighting_network_deposit_address(): invoice = bfx.rest.auth.get_deposit_invoice(wallet="funding", currency="LNX", amount=0.001) diff --git a/examples/websocket/order_book.py b/examples/websocket/order_book.py index 8774b8a..82bd105 100644 --- a/examples/websocket/order_book.py +++ b/examples/websocket/order_book.py @@ -19,7 +19,7 @@ class OrderBook(object): } def update(self, symbol: str, data: TradingPairBook) -> None: - price, count, amount = data.PRICE, data.COUNT, data.AMOUNT + price, count, amount = data.price, data.count, data.amount kind = (amount > 0) and "bids" or "asks" diff --git a/examples/websocket/raw_order_book.py b/examples/websocket/raw_order_book.py index 172873e..896e351 100644 --- a/examples/websocket/raw_order_book.py +++ b/examples/websocket/raw_order_book.py @@ -19,7 +19,7 @@ class RawOrderBook(object): } def update(self, symbol: str, data: TradingPairRawBook) -> None: - order_id, price, amount = data.ORDER_ID, data.PRICE, data.AMOUNT + order_id, price, amount = data.order_id, data.price, data.amount kind = (amount > 0) and "bids" or "asks" From f12981b841b6403bbbfde742ee4ef28812eabae0 Mon Sep 17 00:00:00 2001 From: Davide Casale Date: Fri, 27 Jan 2023 16:10:11 +0100 Subject: [PATCH 3/5] Refactor some _RestPublicEndpoints's methods. --- bfxapi/rest/BfxRestInterface.py | 39 ++++++++++----------------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/bfxapi/rest/BfxRestInterface.py b/bfxapi/rest/BfxRestInterface.py index d50799c..2555eae 100644 --- a/bfxapi/rest/BfxRestInterface.py +++ b/bfxapi/rest/BfxRestInterface.py @@ -89,6 +89,9 @@ class _Requests(object): return data class _RestPublicEndpoints(_Requests): + def conf(self, config: Config) -> Any: + return self._GET(f"conf/{config}")[0] + def get_platform_status(self) -> PlatformStatus: return serializers.PlatformStatus.parse(*self._GET("platform/status")) @@ -121,16 +124,12 @@ class _RestPublicEndpoints(_Requests): def get_f_ticker(self, currency: str) -> FundingCurrencyTicker: 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]: - params = { + def get_tickers_history(self, 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), "start": start, "end": end, "limit": limit - } - - data = self._GET("tickers/hist", params=params) - - return [ serializers.TickersHistory.parse(*sub_data) for sub_data in data ] + }) ] 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 } @@ -205,23 +204,17 @@ class _RestPublicEndpoints(_Requests): 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 } - data = self._GET(f"status/{type}/{symbol}/hist", params=params) - 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]: params = { "sort": sort, "start": start, "end": end, "limit": limit } - data = self._GET("liquidations/hist", params=params) - 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]: 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) - return [ serializers.Candle.parse(*sub_data) for sub_data in data ] def get_leaderboards_hist( @@ -244,14 +237,9 @@ class _RestPublicEndpoints(_Requests): 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 } - data = self._GET(f"funding/stats/{symbol}/hist", params=params) - return [ serializers.FundingStatistic.parse(*sub_data) for sub_data in data ] - def conf(self, config: Config) -> Any: - return self._GET(f"conf/{config}")[0] - def get_pulse_profile(self, nickname: str) -> PulseProfile: return serializers.PulseProfile.parse(*self._GET(f"pulse/profile/{nickname}")) @@ -266,19 +254,14 @@ class _RestPublicEndpoints(_Requests): 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: - data = { + return serializers.TradingMarketAveragePrice.parse(*self._POST("calc/trade/avg", data={ "symbol": symbol, "amount": amount, "price_limit": price_limit - } - - return serializers.TradingMarketAveragePrice.parse(*self._POST("calc/trade/avg", data=data)) + })) 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: - data = { - "symbol": symbol, "amount": amount, "period": period, - "rate_limit": rate_limit - } - - return serializers.FundingMarketAveragePrice.parse(*self._POST("calc/trade/avg", data=data)) + return serializers.FundingMarketAveragePrice.parse(*self._POST("calc/trade/avg", data={ + "symbol": symbol, "amount": amount, "period": period, "rate_limit": rate_limit + })) def get_fx_rate(self, ccy1: str, ccy2: str) -> FxRate: return serializers.FxRate.parse(*self._POST("calc/fx", data={ "ccy1": ccy1, "ccy2": ccy2 })) From 17fc29d4fa37b404b0e81ff209529b7318eb64dc Mon Sep 17 00:00:00 2001 From: Davide Casale Date: Fri, 27 Jan 2023 16:38:58 +0100 Subject: [PATCH 4/5] Separate in different classes the content of BfxRestInterface.py script. --- bfxapi/rest/BfxRestInterface.py | 510 +-------------------- bfxapi/rest/_Requests.py | 75 +++ bfxapi/rest/_RestAuthenticatedEndpoints.py | 253 ++++++++++ bfxapi/rest/_RestPublicEndpoints.py | 188 ++++++++ 4 files changed, 523 insertions(+), 503 deletions(-) create mode 100644 bfxapi/rest/_Requests.py create mode 100644 bfxapi/rest/_RestAuthenticatedEndpoints.py create mode 100644 bfxapi/rest/_RestPublicEndpoints.py diff --git a/bfxapi/rest/BfxRestInterface.py b/bfxapi/rest/BfxRestInterface.py index 2555eae..91d31a2 100644 --- a/bfxapi/rest/BfxRestInterface.py +++ b/bfxapi/rest/BfxRestInterface.py @@ -1,509 +1,13 @@ -import time, hmac, hashlib, json, requests +from typing import Optional -from decimal import Decimal -from datetime import datetime -from http import HTTPStatus +from ._RestPublicEndpoints import _RestPublicEndpoints -from typing import List, Union, Literal, Optional, Any, cast - -from . import serializers - -from .types import * -from .enums import Config, Sort, OrderType, FundingOfferType, Error -from .exceptions import ResourceNotFound, RequestParametersError, InvalidAuthenticationCredentials, UnknownGenericError - -from .. utils.encoder import JSONEncoder +from ._RestAuthenticatedEndpoints import _RestAuthenticatedEndpoints class BfxRestInterface(object): - def __init__(self, host, API_KEY = None, API_SECRET = None): + VERSION = 2 + + def __init__(self, host: str, API_KEY: Optional[str] = None, API_SECRET: Optional[str] = None): self.public = _RestPublicEndpoints(host=host) - self.auth = _RestAuthenticatedEndpoints(host=host, API_KEY=API_KEY, API_SECRET=API_SECRET) - -class _Requests(object): - def __init__(self, host, API_KEY = None, API_SECRET = None): - self.host, self.API_KEY, self.API_SECRET = host, API_KEY, API_SECRET - - def __build_authentication_headers(self, endpoint, data): - nonce = str(int(time.time()) * 1000) - - path = f"/api/v2/{endpoint}{nonce}" - - if data != None: path += data - - signature = hmac.new( - self.API_SECRET.encode("utf8"), - path.encode("utf8"), - hashlib.sha384 - ).hexdigest() - - return { - "bfx-nonce": nonce, - "bfx-signature": signature, - "bfx-apikey": self.API_KEY - } - - def _GET(self, endpoint, params = None): - response = requests.get(f"{self.host}/{endpoint}", params=params) - - if response.status_code == HTTPStatus.NOT_FOUND: - raise ResourceNotFound(f"No resources found at endpoint <{endpoint}>.") - - data = response.json() - - if len(data) and data[0] == "error": - if data[1] == Error.ERR_PARAMS: - raise RequestParametersError(f"The request was rejected with the following parameter error: <{data[2]}>") - - if data[1] == 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]}>.") - - return data - - def _POST(self, endpoint, params = None, data = None): - headers = { "Content-Type": "application/json" } - - if isinstance(data, dict): - data = json.dumps({ key: value for key, value in data.items() if value != None}, cls=JSONEncoder) - - if self.API_KEY and self.API_SECRET: - headers = { **headers, **self.__build_authentication_headers(endpoint, data) } - - response = requests.post(f"{self.host}/{endpoint}", params=params, data=data, headers=headers) - - if response.status_code == HTTPStatus.NOT_FOUND: - raise ResourceNotFound(f"No resources found at endpoint <{endpoint}>.") - - data = response.json() - - if len(data) and data[0] == "error": - if data[1] == Error.ERR_PARAMS: - raise RequestParametersError(f"The request was rejected with the following parameter error: <{data[2]}>") - - if data[1] == Error.ERR_AUTH_FAIL: - 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: - raise UnknownGenericError(f"The server replied to the request with a generic error with message: <{data[2]}>.") - - return data - -class _RestPublicEndpoints(_Requests): - def conf(self, config: Config) -> Any: - return self._GET(f"conf/{config}")[0] - - def get_platform_status(self) -> PlatformStatus: - return serializers.PlatformStatus.parse(*self._GET("platform/status")) - - def get_tickers(self, symbols: List[str]) -> List[Union[TradingPairTicker, FundingCurrencyTicker]]: - data = self._GET("tickers", params={ "symbols": ",".join(symbols) }) - - 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 ] - - def get_t_tickers(self, pairs: Union[List[str], Literal["ALL"]]) -> List[TradingPairTicker]: - 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") ] - - data = self.get_tickers([ "t" + pair for pair in pairs ]) - - return cast(List[TradingPairTicker], data) - - def get_f_tickers(self, currencies: Union[List[str], Literal["ALL"]]) -> List[FundingCurrencyTicker]: - 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") ] - - data = self.get_tickers([ "f" + currency for currency in currencies ]) - - return cast(List[FundingCurrencyTicker], data) - - def get_t_ticker(self, pair: str) -> TradingPairTicker: - return serializers.TradingPairTicker.parse(*self._GET(f"ticker/t{pair}"), skip=["SYMBOL"]) - - def get_f_ticker(self, currency: str) -> FundingCurrencyTicker: - 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]: - return [ serializers.TickersHistory.parse(*sub_data) for sub_data in self._GET("tickers/hist", params={ - "symbols": ",".join(symbols), - "start": start, "end": end, - "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]: - params = { "limit": limit, "start": start, "end": end, "sort": sort } - data = self._GET(f"trades/{'t' + pair}/hist", params=params) - 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]: - params = { "limit": limit, "start": start, "end": end, "sort": sort } - data = self._GET(f"trades/{'f' + currency}/hist", params=params) - 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]: - return [ serializers.TradingPairBook.parse(*sub_data) for sub_data in self._GET(f"book/{'t' + 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]: - return [ serializers.FundingCurrencyBook.parse(*sub_data) for sub_data in self._GET(f"book/{'f' + currency}/{precision}", params={ "len": len }) ] - - def get_t_raw_book(self, 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/{'t' + pair}/R0", params={ "len": len }) ] - - def get_f_raw_book(self, 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/{'f' + currency}/R0", params={ "len": len }) ] - - def get_stats_hist( - self, - resource: str, - 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 } - data = self._GET(f"stats1/{resource}/hist", params=params) - return [ serializers.Statistic.parse(*sub_data) for sub_data in data ] - - def get_stats_last( - self, - resource: str, - 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 } - data = self._GET(f"stats1/{resource}/last", params=params) - return serializers.Statistic.parse(*data) - - def get_candles_hist( - 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 } - data = self._GET(f"candles/trade:{tf}:{symbol}/hist", params=params) - return [ serializers.Candle.parse(*sub_data) for sub_data in data ] - - def get_candles_last( - self, - symbol: str, tf: str = "1m", - 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 } - data = self._GET(f"candles/trade:{tf}:{symbol}/last", params=params) - return serializers.Candle.parse(*data) - - def get_derivatives_status(self, keys: Union[List[str], Literal["ALL"]]) -> List[DerivativesStatus]: - if keys == "ALL": - params = { "keys": "ALL" } - else: params = { "keys": ",".join(keys) } - - data = self._GET(f"status/deriv", params=params) - - return [ serializers.DerivativesStatus.parse(*sub_data) for sub_data in data ] - - def get_derivatives_status_history( - self, - type: str, symbol: str, - 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 } - data = self._GET(f"status/{type}/{symbol}/hist", params=params) - 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]: - params = { "sort": sort, "start": start, "end": end, "limit": limit } - data = self._GET("liquidations/hist", params=params) - 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]: - 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) - return [ serializers.Candle.parse(*sub_data) for sub_data in data ] - - def get_leaderboards_hist( - self, - resource: str, - 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 } - data = self._GET(f"rankings/{resource}/hist", params=params) - return [ serializers.Leaderboard.parse(*sub_data) for sub_data in data ] - - def get_leaderboards_last( - self, - resource: str, - 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 } - data = self._GET(f"rankings/{resource}/last", params=params) - 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]: - params = { "start": start, "end": end, "limit": limit } - data = self._GET(f"funding/stats/{symbol}/hist", params=params) - return [ serializers.FundingStatistic.parse(*sub_data) for sub_data in data ] - - def get_pulse_profile(self, nickname: str) -> PulseProfile: - 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]: - messages = list() - - for subdata in self._GET("pulse/hist", params={ "end": end, "limit": limit }): - subdata[18] = subdata[18][0] - message = serializers.PulseMessage.parse(*subdata) - messages.append(message) - - 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: - return serializers.TradingMarketAveragePrice.parse(*self._POST("calc/trade/avg", data={ - "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: - return serializers.FundingMarketAveragePrice.parse(*self._POST("calc/trade/avg", data={ - "symbol": symbol, "amount": amount, "period": period, "rate_limit": rate_limit - })) - - def get_fx_rate(self, ccy1: str, ccy2: str) -> FxRate: - return serializers.FxRate.parse(*self._POST("calc/fx", data={ "ccy1": ccy1, "ccy2": ccy2 })) - -class _RestAuthenticatedEndpoints(_Requests): - def get_wallets(self) -> List[Wallet]: - 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]: - endpoint = "auth/r/orders" - - if symbol != None: - endpoint += f"/{symbol}" - - return [ serializers.Order.parse(*sub_data) for sub_data in self._POST(endpoint, data={ "id": ids }) ] - - def get_positions(self) -> List[Position]: - return [ serializers.Position.parse(*sub_data) for sub_data in self._POST("auth/r/positions") ] - - 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_trailing: Optional[Union[Decimal, float, str]] = None, price_aux_limit: Optional[Union[Decimal, float, str]] = None, price_oco_stop: Optional[Union[Decimal, float, str]] = None, - gid: Optional[int] = None, cid: Optional[int] = None, - flags: Optional[int] = 0, tif: Optional[Union[datetime, str]] = None, meta: Optional[JSON] = None) -> Notification[Order]: - data = { - "type": type, "symbol": symbol, "amount": amount, - "price": price, "lev": lev, - "price_trailing": price_trailing, "price_aux_limit": price_aux_limit, "price_oco_stop": price_oco_stop, - "gid": gid, "cid": cid, - "flags": flags, "tif": tif, "meta": meta - } - - return serializers._Notification[Order](serializer=serializers.Order).parse(*self._POST("auth/w/order/submit", data=data)) - - 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, - flags: Optional[int] = 0, lev: Optional[int] = None, delta: Optional[Union[Decimal, float, str]] = None, - price_aux_limit: Optional[Union[Decimal, float, str]] = None, price_trailing: Optional[Union[Decimal, float, str]] = None, tif: Optional[Union[datetime, str]] = None) -> Notification[Order]: - data = { - "id": id, "amount": amount, "price": price, - "cid": cid, "cid_date": cid_date, "gid": gid, - "flags": flags, "lev": lev, "delta": delta, - "price_aux_limit": price_aux_limit, "price_trailing": price_trailing, "tif": tif - } - - return serializers._Notification[Order](serializer=serializers.Order).parse(*self._POST("auth/w/order/update", data=data)) - - def cancel_order(self, id: Optional[int] = None, cid: Optional[int] = None, cid_date: Optional[str] = None) -> Notification[Order]: - data = { - "id": id, - "cid": cid, - "cid_date": cid_date - } - - return serializers._Notification[Order](serializer=serializers.Order).parse(*self._POST("auth/w/order/cancel", data=data)) - - 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]]: - data = { - "ids": ids, - "cids": cids, - "gids": gids, - - "all": int(all) - } - - return serializers._Notification[List[Order]](serializer=serializers.Order, iterate=True).parse(*self._POST("auth/w/order/cancel/multi", data=data)) - - 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: - endpoint = "auth/r/orders/hist" - else: endpoint = f"auth/r/orders/{symbol}/hist" - - data = { - "id": ids, - "start": start, "end": end, - "limit": limit - } - - return [ serializers.Order.parse(*sub_data) for sub_data in self._POST(endpoint, data=data) ] - - 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: - endpoint = "auth/r/trades/hist" - else: endpoint = f"auth/r/trades/{symbol}/hist" - - data = { - "sort": sort, - "start": start, "end": end, - "limit": limit - } - - return [ serializers.Trade.parse(*sub_data) for sub_data in self._POST(endpoint, data=data) ] - - 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") ] - - def get_ledgers(self, currency: str, category: Optional[int] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[Ledger]: - data = { - "category": category, - "start": start, "end": end, - "limit": limit - } - - return [ serializers.Ledger.parse(*sub_data) for sub_data in self._POST(f"auth/r/ledgers/{currency}/hist", data=data) ] - - def get_funding_offers(self, symbol: Optional[str] = None) -> List[FundingOffer]: - endpoint = "auth/r/funding/offers" - - if symbol != None: - endpoint += f"/{symbol}" - - 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], - rate: Union[Decimal, float, str], period: int, - flags: Optional[int] = 0) -> Notification[FundingOffer]: - data = { - "type": type, "symbol": symbol, "amount": amount, - "rate": rate, "period": period, - "flags": flags - } - - return serializers._Notification[FundingOffer](serializer=serializers.FundingOffer).parse(*self._POST("auth/w/funding/offer/submit", data=data)) - - def cancel_funding_offer(self, id: int) -> Notification[FundingOffer]: - return serializers._Notification[FundingOffer](serializer=serializers.FundingOffer).parse(*self._POST("auth/w/funding/offer/cancel", data={ "id": id })) - - def cancel_all_funding_offers(self, currency: str) -> Notification: - return serializers._Notification().parse(*self._POST("auth/w/funding/offer/cancel/all", data={ "currency": currency })) - - def get_funding_offers_history(self, symbol: Optional[str] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[FundingOffer]: - if symbol == None: - endpoint = "auth/r/funding/offers/hist" - else: endpoint = f"auth/r/funding/offers/{symbol}/hist" - - data = { - "start": start, "end": end, - "limit": limit - } - - return [ serializers.FundingOffer.parse(*sub_data) for sub_data in self._POST(endpoint, data=data) ] - - def get_funding_credits(self, symbol: Optional[str] = None) -> List[FundingCredit]: - if symbol == None: - endpoint = "auth/r/funding/credits" - else: endpoint = f"auth/r/funding/credits/{symbol}" - - 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]: - if symbol == None: - endpoint = "auth/r/funding/credits/hist" - else: endpoint = f"auth/r/funding/credits/{symbol}/hist" - - data = { - "start": start, "end": end, - "limit": limit - } - - return [ serializers.FundingCredit.parse(*sub_data) for sub_data in self._POST(endpoint, data=data) ] - - def submit_wallet_transfer(self, from_wallet: str, to_wallet: str, currency: str, currency_to: str, amount: Union[Decimal, float, str]) -> Notification[Transfer]: - data = { - "from": from_wallet, "to": to_wallet, - "currency": currency, "currency_to": currency_to, - "amount": amount - } - - return serializers._Notification[Transfer](serializer=serializers.Transfer).parse(*self._POST("auth/w/transfer", data=data)) - - def submit_wallet_withdraw(self, wallet: str, method: str, address: str, amount: Union[Decimal, float, str]) -> Notification[Withdrawal]: - data = { - "wallet": wallet, "method": method, - "address": address, "amount": amount, - } - - return serializers._Notification[Withdrawal](serializer=serializers.Withdrawal).parse(*self._POST("auth/w/withdraw", data=data)) - - def get_deposit_address(self, wallet: str, method: str, renew: bool = False) -> Notification[DepositAddress]: - data = { - "wallet": wallet, - "method": method, - "renew": int(renew) - } - - return serializers._Notification[DepositAddress](serializer=serializers.DepositAddress).parse(*self._POST("auth/w/deposit/address", data=data)) - - def get_deposit_invoice(self, wallet: str, currency: str, amount: Union[Decimal, float, str]) -> Invoice: - data = { - "wallet": wallet, "currency": currency, - "amount": amount - } - - return serializers.Invoice.parse(*self._POST("auth/w/deposit/invoice", data=data)) - - 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: - endpoint = "auth/r/movements/hist" - else: endpoint = f"auth/r/movements/{currency}/hist" - - data = { - "start": start, "end": end, - "limit": limit - } - - return [ serializers.Movement.parse(*sub_data) for sub_data in self._POST(endpoint, data=data) ] - - def get_symbol_margin_info(self, symbol: str) -> SymbolMarginInfo: - response = self._POST(f"auth/r/info/margin/{symbol}") - - return serializers.SymbolMarginInfo.parse(*([response[1]] + response[2])) - - 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") ] - - def get_base_margin_info(self) -> BaseMarginInfo: - return serializers.BaseMarginInfo.parse(*(self._POST(f"auth/r/info/margin/base")[1])) - - def claim_position(self, id: int, amount: Optional[Union[Decimal, float, str]] = None) -> Notification[Claim]: - return serializers._Notification[Claim](serializer=serializers.Claim).parse(*self._POST("auth/w/position/claim", data={ "id": id, "amount": amount })) - - def get_increase_position_info(self, symbol: str, amount: Union[Decimal, float, str]) -> IncreaseInfo: - response = self._POST(f"auth/r/position/increase/info", data={ "symbol": symbol, "amount": amount }) - - return serializers.IncreaseInfo.parse(*( - response[0] + [response[1][0]] + response[1][1] + [response[1][2]] + response[4] + response[5] - )) - - def increase_position(self, symbol: str, amount: Union[Decimal, float, str]) -> Notification[Increase]: - return serializers._Notification[Increase](serializer=serializers.Increase).parse(*self._POST("auth/w/position/increase", data={ "symbol": symbol, "amount": amount })) - - 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", data={ "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]: - return [ serializers.PositionSnapshot.parse(*sub_data) for sub_data in self._POST("auth/r/positions/snap", data={ "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]: - return [ serializers.PositionAudit.parse(*sub_data) for sub_data in self._POST("auth/r/positions/audit", data={ "ids": ids, "start": start, "end": end, "limit": limit }) ] - - 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", data={ "symbol": symbol, "collateral": collateral })[0])) - - def get_derivative_position_collateral_limits(self, symbol: str) -> DerivativePositionCollateralLimits: - return serializers.DerivativePositionCollateralLimits.parse(*self._POST("auth/calc/deriv/collateral/limits", data={ "symbol": symbol })) + self.auth = _RestAuthenticatedEndpoints(host=host, API_KEY=API_KEY, API_SECRET=API_SECRET) \ No newline at end of file diff --git a/bfxapi/rest/_Requests.py b/bfxapi/rest/_Requests.py new file mode 100644 index 0000000..6e4383a --- /dev/null +++ b/bfxapi/rest/_Requests.py @@ -0,0 +1,75 @@ +import time, hmac, hashlib, json, requests + +from http import HTTPStatus +from .enums import Error +from .exceptions import ResourceNotFound, RequestParametersError, InvalidAuthenticationCredentials, UnknownGenericError + +from .. utils.encoder import JSONEncoder + +class _Requests(object): + def __init__(self, host, API_KEY = None, API_SECRET = None): + self.host, self.API_KEY, self.API_SECRET = host, API_KEY, API_SECRET + + def __build_authentication_headers(self, endpoint, data): + nonce = str(int(time.time()) * 1000) + + path = f"/api/v2/{endpoint}{nonce}" + + if data != None: path += data + + signature = hmac.new( + self.API_SECRET.encode("utf8"), + path.encode("utf8"), + hashlib.sha384 + ).hexdigest() + + return { + "bfx-nonce": nonce, + "bfx-signature": signature, + "bfx-apikey": self.API_KEY + } + + def _GET(self, endpoint, params = None): + response = requests.get(f"{self.host}/{endpoint}", params=params) + + if response.status_code == HTTPStatus.NOT_FOUND: + raise ResourceNotFound(f"No resources found at endpoint <{endpoint}>.") + + data = response.json() + + if len(data) and data[0] == "error": + if data[1] == Error.ERR_PARAMS: + raise RequestParametersError(f"The request was rejected with the following parameter error: <{data[2]}>") + + if data[1] == 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]}>.") + + return data + + def _POST(self, endpoint, params = None, data = None, _ignore_authentication_headers = False): + headers = { "Content-Type": "application/json" } + + if isinstance(data, dict): + data = json.dumps({ key: value for key, value in data.items() if value != None}, cls=JSONEncoder) + + if self.API_KEY and self.API_SECRET and _ignore_authentication_headers == False: + headers = { **headers, **self.__build_authentication_headers(endpoint, data) } + + response = requests.post(f"{self.host}/{endpoint}", params=params, data=data, headers=headers) + + if response.status_code == HTTPStatus.NOT_FOUND: + raise ResourceNotFound(f"No resources found at endpoint <{endpoint}>.") + + data = response.json() + + if len(data) and data[0] == "error": + if data[1] == Error.ERR_PARAMS: + raise RequestParametersError(f"The request was rejected with the following parameter error: <{data[2]}>") + + if data[1] == Error.ERR_AUTH_FAIL: + 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: + raise UnknownGenericError(f"The server replied to the request with a generic error with message: <{data[2]}>.") + + return data \ No newline at end of file diff --git a/bfxapi/rest/_RestAuthenticatedEndpoints.py b/bfxapi/rest/_RestAuthenticatedEndpoints.py new file mode 100644 index 0000000..a464b8e --- /dev/null +++ b/bfxapi/rest/_RestAuthenticatedEndpoints.py @@ -0,0 +1,253 @@ +from typing import List, Union, Literal, Optional, Any, cast + +from .types import * + +from . import serializers + +from .enums import Config, Sort, OrderType, FundingOfferType +from decimal import Decimal +from datetime import datetime + +from ._Requests import _Requests + +class _RestAuthenticatedEndpoints(_Requests): + def get_wallets(self) -> List[Wallet]: + 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]: + endpoint = "auth/r/orders" + + if symbol != None: + endpoint += f"/{symbol}" + + return [ serializers.Order.parse(*sub_data) for sub_data in self._POST(endpoint, data={ "id": ids }) ] + + def get_positions(self) -> List[Position]: + return [ serializers.Position.parse(*sub_data) for sub_data in self._POST("auth/r/positions") ] + + 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_trailing: Optional[Union[Decimal, float, str]] = None, price_aux_limit: Optional[Union[Decimal, float, str]] = None, price_oco_stop: Optional[Union[Decimal, float, str]] = None, + gid: Optional[int] = None, cid: Optional[int] = None, + flags: Optional[int] = 0, tif: Optional[Union[datetime, str]] = None, meta: Optional[JSON] = None) -> Notification[Order]: + data = { + "type": type, "symbol": symbol, "amount": amount, + "price": price, "lev": lev, + "price_trailing": price_trailing, "price_aux_limit": price_aux_limit, "price_oco_stop": price_oco_stop, + "gid": gid, "cid": cid, + "flags": flags, "tif": tif, "meta": meta + } + + return serializers._Notification[Order](serializer=serializers.Order).parse(*self._POST("auth/w/order/submit", data=data)) + + 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, + flags: Optional[int] = 0, lev: Optional[int] = None, delta: Optional[Union[Decimal, float, str]] = None, + price_aux_limit: Optional[Union[Decimal, float, str]] = None, price_trailing: Optional[Union[Decimal, float, str]] = None, tif: Optional[Union[datetime, str]] = None) -> Notification[Order]: + data = { + "id": id, "amount": amount, "price": price, + "cid": cid, "cid_date": cid_date, "gid": gid, + "flags": flags, "lev": lev, "delta": delta, + "price_aux_limit": price_aux_limit, "price_trailing": price_trailing, "tif": tif + } + + return serializers._Notification[Order](serializer=serializers.Order).parse(*self._POST("auth/w/order/update", data=data)) + + def cancel_order(self, id: Optional[int] = None, cid: Optional[int] = None, cid_date: Optional[str] = None) -> Notification[Order]: + data = { + "id": id, + "cid": cid, + "cid_date": cid_date + } + + return serializers._Notification[Order](serializer=serializers.Order).parse(*self._POST("auth/w/order/cancel", data=data)) + + 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]]: + data = { + "ids": ids, + "cids": cids, + "gids": gids, + + "all": int(all) + } + + return serializers._Notification[List[Order]](serializer=serializers.Order, iterate=True).parse(*self._POST("auth/w/order/cancel/multi", data=data)) + + 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: + endpoint = "auth/r/orders/hist" + else: endpoint = f"auth/r/orders/{symbol}/hist" + + data = { + "id": ids, + "start": start, "end": end, + "limit": limit + } + + return [ serializers.Order.parse(*sub_data) for sub_data in self._POST(endpoint, data=data) ] + + 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: + endpoint = "auth/r/trades/hist" + else: endpoint = f"auth/r/trades/{symbol}/hist" + + data = { + "sort": sort, + "start": start, "end": end, + "limit": limit + } + + return [ serializers.Trade.parse(*sub_data) for sub_data in self._POST(endpoint, data=data) ] + + 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") ] + + def get_ledgers(self, currency: str, category: Optional[int] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[Ledger]: + data = { + "category": category, + "start": start, "end": end, + "limit": limit + } + + return [ serializers.Ledger.parse(*sub_data) for sub_data in self._POST(f"auth/r/ledgers/{currency}/hist", data=data) ] + + def get_funding_offers(self, symbol: Optional[str] = None) -> List[FundingOffer]: + endpoint = "auth/r/funding/offers" + + if symbol != None: + endpoint += f"/{symbol}" + + 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], + rate: Union[Decimal, float, str], period: int, + flags: Optional[int] = 0) -> Notification[FundingOffer]: + data = { + "type": type, "symbol": symbol, "amount": amount, + "rate": rate, "period": period, + "flags": flags + } + + return serializers._Notification[FundingOffer](serializer=serializers.FundingOffer).parse(*self._POST("auth/w/funding/offer/submit", data=data)) + + def cancel_funding_offer(self, id: int) -> Notification[FundingOffer]: + return serializers._Notification[FundingOffer](serializer=serializers.FundingOffer).parse(*self._POST("auth/w/funding/offer/cancel", data={ "id": id })) + + def cancel_all_funding_offers(self, currency: str) -> Notification: + return serializers._Notification().parse(*self._POST("auth/w/funding/offer/cancel/all", data={ "currency": currency })) + + def get_funding_offers_history(self, symbol: Optional[str] = None, start: Optional[str] = None, end: Optional[str] = None, limit: Optional[int] = None) -> List[FundingOffer]: + if symbol == None: + endpoint = "auth/r/funding/offers/hist" + else: endpoint = f"auth/r/funding/offers/{symbol}/hist" + + data = { + "start": start, "end": end, + "limit": limit + } + + return [ serializers.FundingOffer.parse(*sub_data) for sub_data in self._POST(endpoint, data=data) ] + + def get_funding_credits(self, symbol: Optional[str] = None) -> List[FundingCredit]: + if symbol == None: + endpoint = "auth/r/funding/credits" + else: endpoint = f"auth/r/funding/credits/{symbol}" + + 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]: + if symbol == None: + endpoint = "auth/r/funding/credits/hist" + else: endpoint = f"auth/r/funding/credits/{symbol}/hist" + + data = { + "start": start, "end": end, + "limit": limit + } + + return [ serializers.FundingCredit.parse(*sub_data) for sub_data in self._POST(endpoint, data=data) ] + + def submit_wallet_transfer(self, from_wallet: str, to_wallet: str, currency: str, currency_to: str, amount: Union[Decimal, float, str]) -> Notification[Transfer]: + data = { + "from": from_wallet, "to": to_wallet, + "currency": currency, "currency_to": currency_to, + "amount": amount + } + + return serializers._Notification[Transfer](serializer=serializers.Transfer).parse(*self._POST("auth/w/transfer", data=data)) + + def submit_wallet_withdraw(self, wallet: str, method: str, address: str, amount: Union[Decimal, float, str]) -> Notification[Withdrawal]: + data = { + "wallet": wallet, "method": method, + "address": address, "amount": amount, + } + + return serializers._Notification[Withdrawal](serializer=serializers.Withdrawal).parse(*self._POST("auth/w/withdraw", data=data)) + + def get_deposit_address(self, wallet: str, method: str, renew: bool = False) -> Notification[DepositAddress]: + data = { + "wallet": wallet, + "method": method, + "renew": int(renew) + } + + return serializers._Notification[DepositAddress](serializer=serializers.DepositAddress).parse(*self._POST("auth/w/deposit/address", data=data)) + + def get_deposit_invoice(self, wallet: str, currency: str, amount: Union[Decimal, float, str]) -> Invoice: + data = { + "wallet": wallet, "currency": currency, + "amount": amount + } + + return serializers.Invoice.parse(*self._POST("auth/w/deposit/invoice", data=data)) + + 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: + endpoint = "auth/r/movements/hist" + else: endpoint = f"auth/r/movements/{currency}/hist" + + data = { + "start": start, "end": end, + "limit": limit + } + + return [ serializers.Movement.parse(*sub_data) for sub_data in self._POST(endpoint, data=data) ] + + def get_symbol_margin_info(self, symbol: str) -> SymbolMarginInfo: + response = self._POST(f"auth/r/info/margin/{symbol}") + + return serializers.SymbolMarginInfo.parse(*([response[1]] + response[2])) + + 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") ] + + def get_base_margin_info(self) -> BaseMarginInfo: + return serializers.BaseMarginInfo.parse(*(self._POST(f"auth/r/info/margin/base")[1])) + + def claim_position(self, id: int, amount: Optional[Union[Decimal, float, str]] = None) -> Notification[Claim]: + return serializers._Notification[Claim](serializer=serializers.Claim).parse(*self._POST("auth/w/position/claim", data={ "id": id, "amount": amount })) + + def get_increase_position_info(self, symbol: str, amount: Union[Decimal, float, str]) -> IncreaseInfo: + response = self._POST(f"auth/r/position/increase/info", data={ "symbol": symbol, "amount": amount }) + + return serializers.IncreaseInfo.parse(*( + response[0] + [response[1][0]] + response[1][1] + [response[1][2]] + response[4] + response[5] + )) + + def increase_position(self, symbol: str, amount: Union[Decimal, float, str]) -> Notification[Increase]: + return serializers._Notification[Increase](serializer=serializers.Increase).parse(*self._POST("auth/w/position/increase", data={ "symbol": symbol, "amount": amount })) + + 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", data={ "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]: + return [ serializers.PositionSnapshot.parse(*sub_data) for sub_data in self._POST("auth/r/positions/snap", data={ "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]: + return [ serializers.PositionAudit.parse(*sub_data) for sub_data in self._POST("auth/r/positions/audit", data={ "ids": ids, "start": start, "end": end, "limit": limit }) ] + + 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", data={ "symbol": symbol, "collateral": collateral })[0])) + + def get_derivative_position_collateral_limits(self, symbol: str) -> DerivativePositionCollateralLimits: + return serializers.DerivativePositionCollateralLimits.parse(*self._POST("auth/calc/deriv/collateral/limits", data={ "symbol": symbol })) \ No newline at end of file diff --git a/bfxapi/rest/_RestPublicEndpoints.py b/bfxapi/rest/_RestPublicEndpoints.py new file mode 100644 index 0000000..5157256 --- /dev/null +++ b/bfxapi/rest/_RestPublicEndpoints.py @@ -0,0 +1,188 @@ +from typing import List, Union, Literal, Optional, Any, cast + +from .types import * + +from . import serializers + +from .enums import Config, Sort +from decimal import Decimal + +from ._Requests import _Requests + +class _RestPublicEndpoints(_Requests): + def conf(self, config: Config) -> Any: + return self._GET(f"conf/{config}")[0] + + def get_platform_status(self) -> PlatformStatus: + return serializers.PlatformStatus.parse(*self._GET("platform/status")) + + def get_tickers(self, symbols: List[str]) -> List[Union[TradingPairTicker, FundingCurrencyTicker]]: + data = self._GET("tickers", params={ "symbols": ",".join(symbols) }) + + 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 ] + + def get_t_tickers(self, pairs: Union[List[str], Literal["ALL"]]) -> List[TradingPairTicker]: + 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") ] + + data = self.get_tickers([ "t" + pair for pair in pairs ]) + + return cast(List[TradingPairTicker], data) + + def get_f_tickers(self, currencies: Union[List[str], Literal["ALL"]]) -> List[FundingCurrencyTicker]: + 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") ] + + data = self.get_tickers([ "f" + currency for currency in currencies ]) + + return cast(List[FundingCurrencyTicker], data) + + def get_t_ticker(self, pair: str) -> TradingPairTicker: + return serializers.TradingPairTicker.parse(*self._GET(f"ticker/t{pair}"), skip=["SYMBOL"]) + + def get_f_ticker(self, currency: str) -> FundingCurrencyTicker: + 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]: + return [ serializers.TickersHistory.parse(*sub_data) for sub_data in self._GET("tickers/hist", params={ + "symbols": ",".join(symbols), + "start": start, "end": end, + "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]: + params = { "limit": limit, "start": start, "end": end, "sort": sort } + data = self._GET(f"trades/{'t' + pair}/hist", params=params) + 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]: + params = { "limit": limit, "start": start, "end": end, "sort": sort } + data = self._GET(f"trades/{'f' + currency}/hist", params=params) + 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]: + return [ serializers.TradingPairBook.parse(*sub_data) for sub_data in self._GET(f"book/{'t' + 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]: + return [ serializers.FundingCurrencyBook.parse(*sub_data) for sub_data in self._GET(f"book/{'f' + currency}/{precision}", params={ "len": len }) ] + + def get_t_raw_book(self, 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/{'t' + pair}/R0", params={ "len": len }) ] + + def get_f_raw_book(self, 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/{'f' + currency}/R0", params={ "len": len }) ] + + def get_stats_hist( + self, + resource: str, + 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 } + data = self._GET(f"stats1/{resource}/hist", params=params) + return [ serializers.Statistic.parse(*sub_data) for sub_data in data ] + + def get_stats_last( + self, + resource: str, + 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 } + data = self._GET(f"stats1/{resource}/last", params=params) + return serializers.Statistic.parse(*data) + + def get_candles_hist( + 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 } + data = self._GET(f"candles/trade:{tf}:{symbol}/hist", params=params) + return [ serializers.Candle.parse(*sub_data) for sub_data in data ] + + def get_candles_last( + self, + symbol: str, tf: str = "1m", + 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 } + data = self._GET(f"candles/trade:{tf}:{symbol}/last", params=params) + return serializers.Candle.parse(*data) + + def get_derivatives_status(self, keys: Union[List[str], Literal["ALL"]]) -> List[DerivativesStatus]: + if keys == "ALL": + params = { "keys": "ALL" } + else: params = { "keys": ",".join(keys) } + + data = self._GET(f"status/deriv", params=params) + + return [ serializers.DerivativesStatus.parse(*sub_data) for sub_data in data ] + + def get_derivatives_status_history( + self, + type: str, symbol: str, + 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 } + data = self._GET(f"status/{type}/{symbol}/hist", params=params) + 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]: + params = { "sort": sort, "start": start, "end": end, "limit": limit } + data = self._GET("liquidations/hist", params=params) + 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]: + 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) + return [ serializers.Candle.parse(*sub_data) for sub_data in data ] + + def get_leaderboards_hist( + self, + resource: str, + 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 } + data = self._GET(f"rankings/{resource}/hist", params=params) + return [ serializers.Leaderboard.parse(*sub_data) for sub_data in data ] + + def get_leaderboards_last( + self, + resource: str, + 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 } + data = self._GET(f"rankings/{resource}/last", params=params) + 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]: + params = { "start": start, "end": end, "limit": limit } + data = self._GET(f"funding/stats/{symbol}/hist", params=params) + return [ serializers.FundingStatistic.parse(*sub_data) for sub_data in data ] + + def get_pulse_profile(self, nickname: str) -> PulseProfile: + 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]: + messages = list() + + for subdata in self._GET("pulse/hist", params={ "end": end, "limit": limit }): + subdata[18] = subdata[18][0] + message = serializers.PulseMessage.parse(*subdata) + messages.append(message) + + 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: + return serializers.TradingMarketAveragePrice.parse(*self._POST("calc/trade/avg", data={ + "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: + return serializers.FundingMarketAveragePrice.parse(*self._POST("calc/trade/avg", data={ + "symbol": symbol, "amount": amount, "period": period, "rate_limit": rate_limit + })) + + def get_fx_rate(self, ccy1: str, ccy2: str) -> FxRate: + return serializers.FxRate.parse(*self._POST("calc/fx", data={ "ccy1": ccy1, "ccy2": ccy2 })) \ No newline at end of file From 2fc31db7a36ac2ec880487907d5a001791b99cd6 Mon Sep 17 00:00:00 2001 From: Davide Casale Date: Fri, 27 Jan 2023 17:23:41 +0100 Subject: [PATCH 5/5] Add get_funding_loans and get_funding_loans_history endpoints to _RestAuthenticatedEndpoints.py. --- bfxapi/rest/_RestAuthenticatedEndpoints.py | 19 ++++++++++++++++ bfxapi/rest/serializers.py | 25 ++++++++++++++++++++++ bfxapi/rest/types.py | 20 +++++++++++++++++ examples/rest/get_authenticated_data.py | 2 +- 4 files changed, 65 insertions(+), 1 deletion(-) diff --git a/bfxapi/rest/_RestAuthenticatedEndpoints.py b/bfxapi/rest/_RestAuthenticatedEndpoints.py index a464b8e..61ee64d 100644 --- a/bfxapi/rest/_RestAuthenticatedEndpoints.py +++ b/bfxapi/rest/_RestAuthenticatedEndpoints.py @@ -148,6 +148,25 @@ class _RestAuthenticatedEndpoints(_Requests): return [ serializers.FundingOffer.parse(*sub_data) for sub_data in self._POST(endpoint, data=data) ] + def get_funding_loans(self, symbol: Optional[str] = None) -> List[FundingLoan]: + if symbol == None: + endpoint = "auth/r/funding/loans" + else: endpoint = f"auth/r/funding/loans/{symbol}" + + 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]: + if symbol == None: + endpoint = "auth/r/funding/loans/hist" + else: endpoint = f"auth/r/funding/loans/{symbol}/hist" + + data = { + "start": start, "end": end, + "limit": limit + } + + return [ serializers.FundingLoan.parse(*sub_data) for sub_data in self._POST(endpoint, data=data) ] + def get_funding_credits(self, symbol: Optional[str] = None) -> List[FundingCredit]: if symbol == None: endpoint = "auth/r/funding/credits" diff --git a/bfxapi/rest/serializers.py b/bfxapi/rest/serializers.py index a6cf582..44296d9 100644 --- a/bfxapi/rest/serializers.py +++ b/bfxapi/rest/serializers.py @@ -382,6 +382,31 @@ Ledger = generate_labeler_serializer("Ledger", klass=types.Ledger, labels=[ "description" ]) +FundingLoan = generate_labeler_serializer("FundingLoan", klass=types.FundingLoan, labels=[ + "id", + "symbol", + "side", + "mts_create", + "mts_update", + "amount", + "flags", + "status", + "_PLACEHOLDER", + "_PLACEHOLDER", + "_PLACEHOLDER", + "rate", + "period", + "mts_opening", + "mts_last_payout", + "notify", + "hidden", + "_PLACEHOLDER", + "renew", + "rate_real", + "no_close" +]) + + FundingCredit = generate_labeler_serializer("FundingCredit", klass=types.FundingCredit, labels=[ "id", "symbol", diff --git a/bfxapi/rest/types.py b/bfxapi/rest/types.py index 4850404..58ce507 100644 --- a/bfxapi/rest/types.py +++ b/bfxapi/rest/types.py @@ -306,6 +306,26 @@ class Ledger(_Type): balance: float description: str +@dataclass +class FundingLoan(_Type): + 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 + @dataclass class FundingCredit(_Type): id: int diff --git a/examples/rest/get_authenticated_data.py b/examples/rest/get_authenticated_data.py index 4af5165..2ff1de6 100644 --- a/examples/rest/get_authenticated_data.py +++ b/examples/rest/get_authenticated_data.py @@ -69,7 +69,7 @@ def log_funding_loans(): def log_funding_loans_history(): - loans = bfx.rest.auth.get_funding_loan_history(symbol='fUSD', start=0, end=now) + loans = bfx.rest.auth.get_funding_loans_history(symbol='fUSD', start=0, end=now) print("Funding loan history:") [print(l) for l in loans]