+
    iO                       a  0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
HtHtHt ^ RIHtHt ^RIHtHt ]'       d   ^RIHt ]P,                  ! ]4      tRtRtR	t ! R
 R]4      t ! R R]4      t ! R R]4      t ! R R]4      t ! R R]4      t  ! R R]4      t! ! R R]4      t" ! R R]4      t#]],          t$R]R]R]R]R] R]!R ]"R!]#/t%R"]&R#&   RRRRRRRRRRRR$R R R!R%/t'R&]&R'&    ! R( R)4      t(R# )*zoReal-time data feed via WebSocket.

This module provides streaming market data through Kalshi's WebSocket API.
)annotationsN)AnyCallableTYPE_CHECKING)	BaseModel
ConfigDict)normalize_tickernormalize_tickers)KalshiClientz.wss://api.elections.kalshi.com/trade-api/ws/v2z(wss://demo-api.kalshi.co/trade-api/ws/v2z/trade-api/ws/v2c                      ] tR t^"t$ RtR]R&   RtR]R&   RtR]R&   RtR]R&   Rt	R]R	&   Rt
R]R
&   RtR]R&   RtR]R&   RtR]R&   ]! RR7      tRtR# )TickerMessagezlReal-time market ticker update.

Sent when price, volume, or open interest changes for a subscribed market.
strmarket_tickerN
int | Nonepriceyes_bidyes_askvolumeopen_interestdollar_volumedollar_open_interesttsignoreextra )__name__
__module____qualname____firstlineno____doc____annotations__r   r   r   r   r   r   r   r   r   model_config__static_attributes__r       T/home/wkmabra/.openclaw/workspace/venv/lib/python3.14/site-packages/pykalshi/feed.pyr   r   "   sj    
 E:GZGZFJ $M:$ $M:$'+*+B
H-Lr$   r   c                  T    ] tR t^5t$ RtR]R&   RtR]R&   RtR]R&   ]! RR	7      t	R
t
R# )OrderbookSnapshotMessagezFull orderbook state received on initial subscription.

Contains all current price levels. After this, you'll receive
OrderbookDeltaMessage for incremental updates.
r   r   Nzlist[tuple[int, int]] | Noneyesnor   r   r   )r   r   r   r   r    r!   r(   r)   r   r"   r#   r   r$   r%   r'   r'   5   s/     (,C	%,'+B$+H-Lr$   r'   c                  V    ] tR t^Ct$ RtR]R&   R]R&   R]R&   R]R&   ]! RR	7      tR
tR# )OrderbookDeltaMessagezlIncremental orderbook update.

Represents a change at a single price level. Apply to local orderbook state.
r   r   intr   deltasider   r   r   N)	r   r   r   r   r    r!   r   r"   r#   r   r$   r%   r+   r+   C   s(    
 JJ
IH-Lr$   r+   c                      ] tR t^Qt$ RtRtR]R&   RtR]R&   RtR]R&   Rt	R]R&   Rt
R]R	&   RtR]R
&   RtR]R&   RtR]R&   ]! RR7      tRtR# )TradeMessagezKPublic trade execution.

Sent when any trade occurs on subscribed markets.
N
str | Noner   tickertrade_idr   count	yes_priceno_price
taker_sider   r   r   r   )r   r   r   r   r    r   r!   r2   r3   r4   r5   r6   r7   r   r   r"   r#   r   r$   r%   r0   r0   Q   sc    
 !%M:$FJHjE: Iz Hj!J
!B
H-Lr$   r0   c                      ] tR t^ct$ RtRtR]R&   RtR]R&   RtR]R&   Rt	R]R&   Rt
R]R&   RtR	]R
&   RtR	]R&   RtR	]R&   RtR]R&   RtR	]R&   ]! RR7      tRtR# )FillMessagezMUser fill notification (private channel).

Sent when your orders are filled.
Nr1   r3   r2   order_idr.   actionr   r4   r5   r6   zbool | Noneis_takerr   r   r   r   )r   r   r   r   r    r3   r!   r2   r:   r.   r;   r4   r5   r6   r<   r   r   r"   r#   r   r$   r%   r9   r9   c   sw    
  HjFJHjD*FJE: Iz Hj Hk B
H-Lr$   r9   c                      ] tR t^wt$ RtR]R&   RtR]R&   RtR]R&   RtR]R&   Rt	R]R	&   Rt
R]R
&   RtR]R&   RtR]R&   ]! RR7      tRtR# )PositionMessagezReal-time position update (private channel).

Sent when your position in a market changes (after fills settle).
Includes realized P&L and current exposure.
r   r2   Nr   positionmarket_exposurerealized_pnltotal_tradedresting_orders_count	fees_paidr   r   r   r   )r   r   r   r   r    r!   r?   r@   rA   rB   rC   rD   r   r   r"   r#   r   r$   r%   r>   r>   w   s_     KHj"&OZ&#L*##L*#'+*+ Iz B
H-Lr$   r>   c                  b    ] tR t^t$ RtR]R&   RtR]R&   RtR]R&   RtR]R	&   ]	! R
R7      t
RtR# )MarketLifecycleMessageztMarket lifecycle state change (public channel).

Sent when a market's status changes (open, closed, settled, etc.).
r   r   Nr1   statusresultr   r   r   r   r   )r   r   r   r   r    r!   rG   rH   r   r   r"   r#   r   r$   r%   rF   rF      s7    
 FJFJB
H-Lr$   rF   c                  T    ] tR t^t$ RtR]R&   RtR]R&   RtR]R&   ]! R	R
7      t	Rt
R# )OrderGroupUpdateMessagezxOrder group lifecycle update (private channel).

Sent when an order group's status changes (triggered, canceled, etc.).
r   order_group_idNr1   rG   r   r   r   r   r   )r   r   r   r   r    r!   rG   r   r   r"   r#   r   r$   r%   rJ   rJ      s-    
 FJB
H-Lr$   rJ   r2   orderbook_snapshotorderbook_deltatradefillmarket_positionmarket_lifecycleorder_group_updatezdict[str, type[BaseModel]]_MESSAGE_MODELSmarket_positionsorder_group_updatesdict[str, str]_TYPE_TO_CHANNELc                  b   ] tR t^tRtR R ltR.R R lltRRRR/R	 R
 lltRRRR/R R lltR R lt	R R lt
]R R l4       t]R R l4       t]R R l4       t]R R l4       t]R R l4       t]R R l4       tR R ltR R  ltR! R" ltR# R$ ltR% R& ltR' R( ltR) tR* tR+ R, ltR-tR# )/Feeda  Real-time streaming data feed via WebSocket.

Provides a clean interface to Kalshi's WebSocket API with automatic
reconnection, typed message models, and callback-based handling.

Usage:
    feed = client.feed()

    @feed.on("ticker")
    def handle_ticker(msg: TickerMessage):
        print(f"{msg.market_ticker}: {msg.yes_bid}/{msg.yes_ask}")

    @feed.on("orderbook_delta")
    def handle_orderbook(msg: OrderbookMessage):
        if isinstance(msg, OrderbookSnapshotMessage):
            # Initialize local orderbook
            pass
        else:
            # Apply delta
            pass

    feed.subscribe("ticker", market_ticker="KXBTC-26JAN")
    feed.subscribe("orderbook_delta", market_ticker="KXBTC-26JAN")

    feed.start()  # Runs in background thread
    # ... do other work ...
    feed.stop()

    # Or use as context manager:
    with client.feed() as feed:
        feed.on("ticker", my_handler)
        feed.subscribe("ticker", market_ticker="KXBTC-26JAN")
        time.sleep(60)

Available channels:
    - "ticker": Market price/volume updates (public)
    - "trade": Public trade executions (public)
    - "orderbook_delta": Orderbook snapshots and deltas (requires auth)
    - "fill": Your order fills (requires auth, no market filter)
    - "market_positions": Real-time position updates with P&L (requires auth, no market filter)
    - "market_lifecycle": Market state changes (public)
    - "order_group_updates": Order group lifecycle changes (requires auth)
c                    V ^8  d   QhRRRR/# )   clientr
   returnNoner   )formats   "r%   __annotate__Feed.__annotate__   s     V V| V Vr$   c                   Wn         / V n        . V n        RV n        RV n        RV n        RV n        \        P                  ! ^4      V n	        \        P                  ! 4       V n        \        P                  ! 4       V n        \        P                  ! 4       V n        RV n        RV n        RV n        ^ V n        ^ V n        RVP*                  9   d   \,        V n        R# \.        V n        R# )zMInitialize the feed.

Args:
    client: Authenticated KalshiClient instance.
NFdemo)_client	_handlers_active_subs_ws_loop_thread_running	itertoolsr4   _cmd_id_counter	threadingEvent
_connectedLock_lock_metrics_lock_connected_at_last_message_at_last_server_ts_message_count_reconnect_countapi_baseDEMO_WS_BASEDEFAULT_WS_BASE_ws_url)selfr\   s   &&r%   __init__Feed.__init__   s     46(*7;
04(q1#//+^^%
&^^- ,0.2+/#$%& (.'@|or$   Nc               $    V ^8  d   QhRRRRRR/# )r[   channelr   handlerzCallable | Noner]   r   r   )r_   s   "r%   r`   ra   
  s$      %4	r$   c                   a a Ve.   S P                   P                  S. 4      P                  V4       V# R VV 3R llpV# )a  Register a handler for a channel.

Can be used as a decorator or called directly:

    @feed.on("ticker")
    def handle(msg: TickerMessage):
        ...

    # or
    feed.on("ticker", my_handler)

Args:
    channel: Channel name ("ticker", "orderbook_delta", "trade", "fill", "market_positions").
    handler: Optional handler function. If None, returns a decorator.

Returns:
    The handler function (for decorator chaining).
c                    V ^8  d   QhRRRR/# )r[   fnr   r]   r   )r_   s   "r%   r`   Feed.on.<locals>.__annotate__#  s     	 	( 	x 	r$   c                ^   < SP                   P                  S. 4      P                  V 4       V # Nre   
setdefaultappend)r   r   r|   s   &r%   	decoratorFeed.on.<locals>.decorator#  s'    NN%%gr299"=Ir$   r   )r|   r   r   r   s   ff& r%   onFeed.on
  sA    * NN%%gr299'BN	 	 r$   r   market_tickersc               (    V ^8  d   QhRRRRRRRR/# 	r[   r   r   r   r1   r   zlist[str] | Noner]   r^   r   )r_   s   "r%   r`   ra   )  s2     ! !! "	!
 )! 
!r$   c                  RV./pVe   VP                  4       VR&   Ve   \        V4      VR&   V P                  ;_uu_ 4        V P                  P	                  V4       RRR4       V P
                  '       dV   V P                  P                  4       '       d4   \        P                  ! V P                  RV4      V P
                  4       R# R# R#   + '       g   i     Ly; i)a  Subscribe to a channel.

Args:
    channel: Channel name ("ticker", "orderbook_delta", "trade", "fill", "market_positions").
    market_ticker: Filter to a single market.
    market_tickers: Filter to multiple markets.

Note:
    - For "fill" and "market_positions" channels, market filters are ignored
      (you get all your fills/positions).
    - Can be called before or after start(). If called after, subscription
      is sent immediately.
channelsNr   r   	subscribe)upperr	   rq   rf   r   rh   ro   is_setasynciorun_coroutine_threadsafe	_send_cmd)r|   r   r   r   paramss   &&$$ r%   r   Feed.subscribe)  s    ( #-wi!8$&3&9&9&;F?#%'8'HF#$ZZZ$$V,  :::$//0022,,{F3TZZ 3:	 Zs   CC 	c               (    V ^8  d   QhRRRRRRRR/# r   r   )r_   s   "r%   r`   ra   L  s2     # ## "	#
 )# 
#r$   c               f   RV./pVe   VP                  4       VR&   Ve   \        V4      VR&   V P                  ;_uu_ 4        V P                   Uu. uFJ  pVP	                  R4      V.8X  d/   VP	                  R4      V8X  d   VP	                  R4      V8X  d   KH  VNKL  	  upV n        RRR4       V P
                  '       dV   V P                  P                  4       '       d4   \        P                  ! V P                  RV4      V P
                  4       R# R# R# u upi   + '       g   i     L~; i)zUnsubscribe from a channel.

Args:
    channel: Channel name.
    market_ticker: Single market to unsubscribe from.
    market_tickers: Multiple markets to unsubscribe from.
r   Nr   r   unsubscribe)r   r	   rq   rf   getrh   ro   r   r   r   r   )r|   r   r   r   r   ss   &&$$  r%   r   Feed.unsubscribeL  s    #-wi!8$&3&9&9&;F?#%'8'HF#$ ZZZ **!*AEE*%'2o.-?./>A *!D  :::$//0022,,}f5tzz 3:! Zs%   D ADD"D D  D0	c                   V ^8  d   QhRR/# r[   r]   r^   r   )r_   s   "r%   r`   ra   q  s     ) )t )r$   c                   V P                   ;_uu_ 4        V P                  '       d    RRR4       R# RV n        V P                  P                  4        \        P
                  ! V P                  RRR7      V n        V P                  P                  4        RRR4       V P                  P                  ^
R7       R#   + '       g   i     L.; i)zStart the feed in a background thread.

Blocks briefly (up to 10s) until the initial connection is established.
If connection fails, the feed continues retrying in the background.
NTzkalshi-feed)targetnamedaemontimeout)
rq   rj   ro   clearrm   Thread_runri   startwaitr|   s   &r%   r   
Feed.startq  s     ZZZ}}} Z !DMOO!!#$++yy}TDL LL   	R( Zs   B<A#B<<C	c                   V ^8  d   QhRR/# r   r   )r_   s   "r%   r`   ra     s     " "d "r$   c                H  a  S P                   ;_uu_ 4        S P                  '       g    RRR4       R# RS n        RRR4       S P                  '       dr   S P                  '       d`   S P                  P	                  4       '       d@   V 3R lp\
        P                  ! V! 4       S P                  4      p VP                  ^R7       S P                  '       dP   S P                  P	                  4       '       d0   S P                  P                  S P                  P                  4       S P                  '       d$   S P                  P                  ^R7       RS n        S P                  P                  4        RS n        R#   + '       g   i     ELM; i  \         d     Li ; i)zStop the feed and disconnect.NFc                 ~   <"    S P                   P                  4       G R j  xL
  R #  L  \         d     R # i ; i5ir   )rg   close	Exceptionr   s   r%   close_wsFeed.stop.<locals>.close_ws  s0     ((..***  s(   =+ )+ =+ :=:=r   )rq   rj   rg   rh   
is_runningr   r   rH   r   call_soon_threadsafestopri   joinro   r   rs   )r|   r   futures   f  r%   r   	Feed.stop  s   ZZZ=== Z "DM  888


tzz'<'<'>'>
 55hj$**MFa(
 :::$**//11JJ++DJJOO<<<<LLa(DL!5 ZZ  s"   E?E?4F ?F	F! F!c                   V ^8  d   QhRR/# )r[   r]   boolr   )r_   s   "r%   r`   ra     s     ( (d (r$   c                6    V P                   P                  4       # )z-Whether the WebSocket is currently connected.)ro   r   r   s   &r%   is_connectedFeed.is_connected  s     %%''r$   c                   V ^8  d   QhRR/# r[   r]   zfloat | Noner   )r_   s   "r%   r`   ra     s     3 3L 3r$   c                    V P                   ;_uu_ 4        V P                  e   V P                  f    RRR4       R# V P                  R,          pWP                  ,
          uuRRR4       #   + '       g   i     R# ; i)a  Estimated latency in milliseconds based on last message timestamp.

Returns None if no messages with timestamps have been received.
This measures the difference between the server's timestamp and
when we received the message locally. Assumes clocks are synchronized.
Ni  )rr   ru   rt   )r|   local_mss   & r%   
latency_msFeed.latency_ms  s_     ##+t/D/D/L   ,,t3H222	  s   A,$A,,A=	c                   V ^8  d   QhRR/# r[   r]   r,   r   )r_   s   "r%   r`   ra     s     ' '3 'r$   c                    V P                   ;_uu_ 4        V P                  uuRRR4       #   + '       g   i     R# ; i)z5Total number of messages received since feed started.N)rr   rv   r   s   &r%   messages_receivedFeed.messages_received  s(     &&     ,=	c                   V ^8  d   QhRR/# r   r   )r_   s   "r%   r`   ra     s     4 4 4r$   c                
   V P                   ;_uu_ 4        V P                  e   V P                  '       g    RRR4       R# \        P                  ! 4       V P                  ,
          uuRRR4       #   + '       g   i     R# ; i)z@Seconds since connection was established. None if not connected.N)rr   rs   r   timer   s   &r%   uptime_secondsFeed.uptime_seconds  sW     !!)1B1B1B   99;!3!33  s    A1A1%A11B	c                   V ^8  d   QhRR/# r   r   )r_   s   "r%   r`   ra     s     7 7L 7r$   c                    V P                   ;_uu_ 4        V P                  f    RRR4       R# \        P                  ! 4       V P                  ,
          uuRRR4       #   + '       g   i     R# ; i)zASeconds since last message was received. None if no messages yet.N)rr   rt   r   r   s   &r%   seconds_since_last_messageFeed.seconds_since_last_message  sL     $$,   99;!6!66  s   A%AA0	c                   V ^8  d   QhRR/# r   r   )r_   s   "r%   r`   ra     s     ) ) )r$   c                    V P                   ;_uu_ 4        V P                  uuRRR4       #   + '       g   i     R# ; i)zANumber of times the feed has reconnected (0 on first connection).N)rr   rw   r   s   &r%   reconnect_countFeed.reconnect_count  s(     ((  r   c                   V ^8  d   QhRR/# r   r   )r_   s   "r%   r`   ra     s      d r$   c           	     x   \         P                  ! 4       V n        \         P                  ! V P                  4        V P                  P	                  V P                  4       4       \         P                  ! V P                  4      pV F  pVP                  4        K  	  V'       d0   V P                  P	                  \         P                  ! VRR/ 4       V P                  P                  4        RV n        R#   \         d!   p\        P                  RT4        Rp?LRp?ii ; i  \         P                  ! T P                  4      pT F  pTP                  4        K  	  T'       d0   T P                  P	                  \         P                  ! TRR/ 4       T P                  P                  4        RT n        i ; i)zBackground thread entry point.zFeed loop crashed: %sNreturn_exceptionsT)r   new_event_looprh   set_event_looprun_until_complete_connect_loopr   loggererror	all_taskscancelgatherr   )r|   ependingtasks   &   r%   r   	Feed._run  s9   ++-
tzz*	JJ))$*<*<*>?
 ''

3G  

--NNGDtD JJDJ  	5LL0!44	5 ''

3G  

--NNGDtD JJDJs1   )C8 8D#DD& D##D& &AF9(AF9c                   V ^8  d   QhRR/# r   r   )r_   s   "r%   r`   ra     s     : :T :r$   c           	       "    ^ RI pRp^pT P                  '       EdV    T P                  4       pTP	                  T P
                  T^^
R7      ;_uu_4       GRj  xL
 pYPn        RpT P                  ;_uu_ 4        T P                  e   T ;P                  ^,          un	        \        P                  ! 4       T n        RRR4       T P                  ;_uu_ 4        \        T P                  4      pRRR4       X F  pT P                  RT4      G Rj  xL
  K  	  T P                  P!                  4        \"        P%                  RT P
                  4       T  Rj  xL
  pT P'                  T4       K  T P                  P/                  4        RT n        R#   \         d    \        R4      hi ; i ELV  + '       g   i     L; i  + '       g   i     L; i L LDRRR4      GRj  xL 
  EK    + GRj  xL 
 '       g   i     EK  ; i  \(        P*                   d     K  \,         d   p	T P                  P/                  4        RT n        T P                  '       g    Rp	?	K  \"        P1                  R\3        T	4      P4                  T4       \(        P6                  ! T4      G Rj  xL 
  \9        T^,          T4      p Rp	?	EK  Rp	?	ii ; i5i)z)Main connection loop with auto-reconnect.NzEwebsockets is required for Feed. Install with: pip install websocketsg      ?)additional_headersping_intervalping_timeoutr   zFeed connected to %sz-Feed disconnected (%s), reconnecting in %.1fs)
websocketsImportErrorrj   _auth_headersconnectr{   rg   rr   rs   rw   r   rq   listrf   r   ro   setr   info	_dispatchr   CancelledErrorr   r   warningtyper   sleepmin)
r|   r   backoffmax_backoffheaderswssubsr   raw_msgr   s
   &         r%   r   Feed._connect_loop  s1    	 mmm*8,,.%--LL'."$!#	 .   
 !H!G +++--9 11Q61-1YY[* , #D$5$56 $"&"nn[&AAA #' OO'')KK 6E)+ 0 0gw/" 	m  	W 	 ,+ $ B
01     6 ))  8%%'}}}CG$$
 mmG,,,gk;78s+  KF K;H F1H G3<AF4	>G3G	0"G3G
AG3GG
GG34#KF..K1H 4G?G3G	G3GG3H *G-+H 0K3H	9G<:
H	H	H KH K&K)K2K33K&K,AK/J20KKKKc                   V ^8  d   QhRR/# )r[   r]   rV   r   )r_   s   "r%   r`   ra     s     
 
~ 
r$   c                ~    V P                   P                  R\        4      w  rRV P                   P                  RVRV/# )z8Generate authentication headers for WebSocket handshake.GETzKALSHI-ACCESS-KEYzKALSHI-ACCESS-SIGNATUREzKALSHI-ACCESS-TIMESTAMP)rd   _sign_request_WS_SIGN_PATH
api_key_id)r|   	timestamp	signatures   &  r%   r   Feed._auth_headers  s>    #||99%O	!8!8%y%y
 	
r$   c                   V ^8  d   QhRR/# r   r   )r_   s   "r%   r`   ra   (  s     * *# *r$   c                ,    \        V P                  4      # )z"Get next command ID (thread-safe).)nextrl   r   s   &r%   _next_idFeed._next_id(  s    D(())r$   c               $    V ^8  d   QhRRRRRR/# )r[   cmdr   r   dictr]   r^   r   )r_   s   "r%   r`   ra   ,  s!     2 23 2 2 2r$   c                   "   V P                   '       df   \        P                  ! RV P                  4       RVRV/4      pV P                   P	                  V4      G Rj  xL
  \
        P                  RW4       R# R#  L5i)z"Send a command over the WebSocket.idr  r   NzSent %s: %s)rg   jsondumpsr  sendr   debug)r|   r  r   msgs   &&& r%   r   Feed._send_cmd,  s[     888**dDMMOUC6RSC((--$$$LL1 $s   AA>A<A>c                    V ^8  d   QhRRRR/# )r[   rawzstr | bytesr]   r^   r   )r_   s   "r%   r`   ra   3  s     .I .I[ .IT .Ir$   c                (   \         P                   ! 4       pV P                  ;_uu_ 4        W n        V ;P                  ^,          un        RRR4        \        P
                  ! V4      pTP                  R4      pT'       g   R# TP                  RT4      p\        T\        4      '       d9   TP                  R4      pTe$   T P                  ;_uu_ 4        Y`n        RRR4       \        P                  YD4      pT P                  P                  T4      pT'       g   R# \         P                  T4      p	T	'       d    T	P#                  T4      p
MTp
T F  p T! T
4       K  	  R#   + '       g   i     EL#; i  \        P                  \        3 d    \        P                  RT4        R# i ; i  + '       g   i     L; i  \$         d    \        P'                  RT4       Tp
 Li ; i  \$         d    \        P)                  RT4        K  i ; i)z0Parse incoming message and dispatch to handlers.NzMalformed message: %.200sr   r  r   z$Failed to parse %s, passing raw dictzHandler error on channel %s)r   rr   rt   rv   r  loadsJSONDecodeError	TypeErrorr   r   r   
isinstancer  ru   rW   re   rS   model_validater   r  	exception)r|   r  receive_timedatamsg_typepayloadr   r   handlers	model_clsparsedr   s   &&          r%   r   Feed._dispatch3  s   yy{$0!1$  	::c?D
 88F# ((5$'gt$$T"B~'''+-( ( #&&x:>>%%g. $''1	!"11':
 FGI  O   $$i0 	NN6<	 ('  !CXN !  I  !>HIsM    E$E8 F0<G G,$E5	81F-,F-0G 	#G)(G),!HHc                	&    V P                  4        V # r   )r   r   s   &r%   	__enter__Feed.__enter__c  s    

r$   c                	&    V P                  4        R # r   )r   )r|   argss   &*r%   __exit__Feed.__exit__g  s    		r$   c                   V ^8  d   QhRR/# )r[   r]   r   r   )r_   s   "r%   r`   ra   j  s     S S# Sr$   c                	    V P                   '       d   R MRp\        V P                  4      pV P                  pVe   RVR R2MRpRV RV RV P                   V R	2# )
	connecteddisconnectedz	 latency=z.1fms z<Feed z subs=z msgs=>)r   lenrf   r   rv   )r|   rG   nlatencylatency_strs   &    r%   __repr__Feed.__repr__j  sk     $ 1 1 1~!!"//5<5H	'#b1bxvaSt/B/B.CK=PQRRr$   )rf   rd   rl   ro   rs   re   rt   ru   rq   rh   rv   rr   rw   rj   ri   rg   r{   r   )r   r   r   r   r    r}   r   r   r   r   r   propertyr   r   r   r   r   r   r   r   r   r  r   r   r0  r4  rA  r#   r   r$   r%   rY   rY      s    *XV8>! %)	!
 ,0!F# %)	#
 ,0#J)""< ( ( 3 3 ' '
 4 4 7 7 ) )
(:x
*2.I`S Sr$   rY   ))__conditional_annotations__r    
__future__r   r   rk   r  loggingrm   r   typingr   r   r   pydanticr   r   _utilsr   r	   r\   r
   	getLoggerr   r   rz   ry   r	  r   r'   r+   r0   r9   r>   rF   rJ   OrderbookMessagerS   r!   rW   rY   )rD  s   @r%   <module>rL     sM  
 #       / / * 7$			8	$ C9".I .&.y ..I ..9 .$.) .(.i .&.Y .
.i 
. ,.CC  m2,\
K.1	/+ 	 +(hW
F)*/	$ . 	nS nSr$   