From d884441b640a59f94a1158705df5afdf5b026085 Mon Sep 17 00:00:00 2001 From: akpav Date: Thu, 12 Jun 2025 19:07:25 -0400 Subject: [PATCH 1/2] Added activeAssetCtx websocket subscription --- examples/basic_ws.py | 2 ++ hyperliquid/info.py | 1 + hyperliquid/utils/types.py | 36 +++++++++++++++++++++++++++++++- hyperliquid/websocket_manager.py | 7 +++++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/examples/basic_ws.py b/examples/basic_ws.py index eb7f7f3e..e01eea57 100644 --- a/examples/basic_ws.py +++ b/examples/basic_ws.py @@ -18,6 +18,8 @@ def main(): info.subscribe({"type": "userNonFundingLedgerUpdates", "user": address}, print) info.subscribe({"type": "webData2", "user": address}, print) info.subscribe({"type": "bbo", "coin": "ETH"}, print) + info.subscribe({"type": "activeAssetCtx", "coin": "BTC"}, print) # Perp + info.subscribe({"type": "activeAssetCtx", "coin": "@1"}, print) # Spot if __name__ == "__main__": diff --git a/hyperliquid/info.py b/hyperliquid/info.py index ee3eabe0..485779ab 100644 --- a/hyperliquid/info.py +++ b/hyperliquid/info.py @@ -604,6 +604,7 @@ def _remap_coin_subscription(self, subscription: Subscription) -> None: or subscription["type"] == "trades" or subscription["type"] == "candle" or subscription["type"] == "bbo" + or subscription["type"] == "activeAssetCtx" ): subscription["coin"] = self.name_to_coin[subscription["coin"]] diff --git a/hyperliquid/utils/types.py b/hyperliquid/utils/types.py index a045abd3..ed39abeb 100644 --- a/hyperliquid/utils/types.py +++ b/hyperliquid/utils/types.py @@ -49,6 +49,7 @@ "UserNonFundingLedgerUpdatesSubscription", {"type": Literal["userNonFundingLedgerUpdates"], "user": str} ) WebData2Subscription = TypedDict("WebData2Subscription", {"type": Literal["webData2"], "user": str}) +ActiveAssetCtxSubscription = TypedDict("ActiveAssetCtxSubscription", {"type": Literal["activeAssetCtx"], "coin": str}) # If adding new subscription types that contain coin's don't forget to handle automatically rewrite name to coin in info.subscribe Subscription = Union[ AllMidsSubscription, @@ -62,6 +63,7 @@ UserFundingsSubscription, UserNonFundingLedgerUpdatesSubscription, WebData2Subscription, + ActiveAssetCtxSubscription, ] AllMidsData = TypedDict("AllMidsData", {"mids": Dict[str, str]}) @@ -74,6 +76,27 @@ PongMsg = TypedDict("PongMsg", {"channel": Literal["pong"]}) Trade = TypedDict("Trade", {"coin": str, "side": Side, "px": str, "sz": int, "hash": str, "time": int}) TradesMsg = TypedDict("TradesMsg", {"channel": Literal["trades"], "data": List[Trade]}) +PerpAssetCtx = TypedDict( + "PerpAssetCtx", + { + "funding": str, + "openInterest": str, + "prevDayPx": str, + "dayNtlVlm": str, + "premium": str, + "oraclePx": str, + "markPx": str, + "midPx": str, + "impactPxs": Tuple[str, str], + "dayBaseVlm": str, + }, +) +ActiveAssetCtx = TypedDict("ActiveAssetCtx", {"coin": str, "ctx": PerpAssetCtx}) +ActiveAssetSpotCtx = TypedDict("ActiveAssetSpotCtx", {"coin": str, "ctx": SpotAssetCtx}) +ActiveAssetCtxMsg = TypedDict("ActiveAssetCtxMsg", {"channel": Literal["activeAssetCtx"], "data": ActiveAssetCtx}) +ActiveSpotAssetCtxMsg = TypedDict( + "ActiveSpotAssetCtxMsg", {"channel": Literal["activeSpotAssetCtx"], "data": ActiveAssetSpotCtx} +) Fill = TypedDict( "Fill", { @@ -112,7 +135,18 @@ }, total=False, ) -WsMsg = Union[AllMidsMsg, BboMsg, L2BookMsg, TradesMsg, UserEventsMsg, PongMsg, UserFillsMsg, OtherWsMsg] +WsMsg = Union[ + AllMidsMsg, + BboMsg, + L2BookMsg, + TradesMsg, + UserEventsMsg, + PongMsg, + UserFillsMsg, + OtherWsMsg, + ActiveAssetCtxMsg, + ActiveSpotAssetCtxMsg, +] # b is the public address of the builder, f is the amount of the fee in tenths of basis points. e.g. 10 means 1 basis point BuilderInfo = TypedDict("BuilderInfo", {"b": str, "f": int}) diff --git a/hyperliquid/websocket_manager.py b/hyperliquid/websocket_manager.py index 8c7ca7ac..9d64443f 100644 --- a/hyperliquid/websocket_manager.py +++ b/hyperliquid/websocket_manager.py @@ -33,6 +33,8 @@ def subscription_to_identifier(subscription: Subscription) -> str: return f'webData2:{subscription["user"].lower()}' elif subscription["type"] == "bbo": return f'bbo:{subscription["coin"].lower()}' + elif subscription["type"] == "activeAssetCtx": + return f'activeAssetCtx:{subscription["coin"].lower()}' def ws_msg_to_identifier(ws_msg: WsMsg) -> Optional[str]: @@ -64,6 +66,11 @@ def ws_msg_to_identifier(ws_msg: WsMsg) -> Optional[str]: return f'webData2:{ws_msg["data"]["user"].lower()}' elif ws_msg["channel"] == "bbo": return f'bbo:{ws_msg["data"]["coin"].lower()}' + elif ws_msg["channel"] == "activeAssetCtx": + return f'activeAssetCtx:{ws_msg["data"]["coin"].lower()}' + elif ws_msg["channel"] == "activeSpotAssetCtx": + return f'activeAssetCtx:{ws_msg["data"]["coin"].lower()}' + pass class WebsocketManager(threading.Thread): From ce1273e9e3eb5ff6bbdcaf0b04b4a637c48db68c Mon Sep 17 00:00:00 2001 From: akpav Date: Fri, 13 Jun 2025 08:06:53 -0400 Subject: [PATCH 2/2] resolved requested changes --- hyperliquid/utils/types.py | 8 ++++---- hyperliquid/websocket_manager.py | 5 +---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/hyperliquid/utils/types.py b/hyperliquid/utils/types.py index ed39abeb..00c58c7a 100644 --- a/hyperliquid/utils/types.py +++ b/hyperliquid/utils/types.py @@ -86,16 +86,16 @@ "premium": str, "oraclePx": str, "markPx": str, - "midPx": str, - "impactPxs": Tuple[str, str], + "midPx": Optional[str], + "impactPxs": Optional[Tuple[str, str]], "dayBaseVlm": str, }, ) ActiveAssetCtx = TypedDict("ActiveAssetCtx", {"coin": str, "ctx": PerpAssetCtx}) -ActiveAssetSpotCtx = TypedDict("ActiveAssetSpotCtx", {"coin": str, "ctx": SpotAssetCtx}) +ActiveSpotAssetCtx = TypedDict("ActiveSpotAssetCtx", {"coin": str, "ctx": SpotAssetCtx}) ActiveAssetCtxMsg = TypedDict("ActiveAssetCtxMsg", {"channel": Literal["activeAssetCtx"], "data": ActiveAssetCtx}) ActiveSpotAssetCtxMsg = TypedDict( - "ActiveSpotAssetCtxMsg", {"channel": Literal["activeSpotAssetCtx"], "data": ActiveAssetSpotCtx} + "ActiveSpotAssetCtxMsg", {"channel": Literal["activeSpotAssetCtx"], "data": ActiveSpotAssetCtx} ) Fill = TypedDict( "Fill", diff --git a/hyperliquid/websocket_manager.py b/hyperliquid/websocket_manager.py index 9d64443f..7875dac5 100644 --- a/hyperliquid/websocket_manager.py +++ b/hyperliquid/websocket_manager.py @@ -66,11 +66,8 @@ def ws_msg_to_identifier(ws_msg: WsMsg) -> Optional[str]: return f'webData2:{ws_msg["data"]["user"].lower()}' elif ws_msg["channel"] == "bbo": return f'bbo:{ws_msg["data"]["coin"].lower()}' - elif ws_msg["channel"] == "activeAssetCtx": + elif ws_msg["channel"] == "activeAssetCtx" or ws_msg["channel"] == "activeSpotAssetCtx": return f'activeAssetCtx:{ws_msg["data"]["coin"].lower()}' - elif ws_msg["channel"] == "activeSpotAssetCtx": - return f'activeAssetCtx:{ws_msg["data"]["coin"].lower()}' - pass class WebsocketManager(threading.Thread):