
    iI              	      2   d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlmZ ddlmZ ddlmZmZ ddlZddlZddlmZ ddlmZmZ erdd	lmZ  ej<                  e      Z  G d
 dejB                        Z" G d d      Z#edk(  r ejH                  ejJ                          e#       Z& e'e&jQ                  ddd              e'e&jQ                  ddd              e'e&jQ                  dde"jR                  dd             yy)zFTradingView data feed client for historical and real-time market data.    )annotationsN)contextmanager)Path)ClassVarTYPE_CHECKING)connect)create_connection	WebSocket)	Generatorc                  P    e Zd ZdZdZdZdZdZdZdZ	dZ
d	Zd
ZdZdZdZdZdZdZdZy)Intervalz)Supported time intervals for market data.1351530451H2H3H4H1D1W1M3M6M12MN)__name__
__module____qualname____doc__in_1_minutein_3_minutein_5_minutein_15_minutein_30_minutein_45_minute	in_1_hour	in_2_hour	in_3_hour	in_4_hourin_daily	in_weekly
in_monthlyin_3_monthlyin_6_monthly	in_yearly     H/home/work/apex_v16/venv/lib/python3.12/site-packages/tvDatafeed/main.pyr   r      sU    3KKKLLLIIIIHIJLLIr3   r   c                     e Zd ZU dZdZded<   dZded<   dZded<   d	d
iZded<   ddiZ	ded<   dZ
ded<   	 	 	 d3	 	 	 	 	 	 	 d4dZd5dZd6dZd7dZd8dZd9dZd5dZd:dZed;d       Zed<d       Zed=d       Zed=d       Zed>d        Zed?d!       Zd?d"Zd@d#ZedAd$       ZedBd%       ZedCdDd&       Zd'e jB                  d(dd)f	 	 	 	 	 	 	 	 	 	 	 	 	 dEd*Z"	 dC	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dFd+Z#	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dGd,Z$d'e jB                  d(d-dd)d.f	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dHd/Z%d'e jB                  d(d-dd)d.f	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dId0Z&dJdKd1Z'd5d2Z(y)L
TvDatafeeda  TradingView data feed client for downloading historical market data.

    Supports both authenticated and anonymous access to TradingView data.
    Authenticated access provides more data and fewer restrictions.

    Args:
        username: TradingView username (optional for anonymous access)
        password: TradingView password (optional for anonymous access)
        token_cache_file: Path to cache authentication token
    z-https://www.tradingview.com/accounts/current/zClassVar[str]_TvDatafeed__user_url,https://www.tradingview.com/accounts/signin/_TvDatafeed__sign_in_urlzmhttps://symbol-search.tradingview.com/symbol_search/?text={}&hl=1&exchange={}&lang=en&type=&domain=production_TvDatafeed__search_urlOriginhttps://data.tradingview.comzClassVar[dict[str, str]]_TvDatafeed__ws_headersRefererzhttps://www.tradingview.com_TvDatafeed__signin_headers   zClassVar[int]_TvDatafeed__ws_timeoutNc                   d| _         t        |      j                         | _        t	        j
                         | _        t	        j
                         | _        | j                         }|r|| _	        t        j                  d       y|rJ|rH| j                  ||      | _	        | j                  | j                         t        j                  d       yd| _	        t        j                  d       y)z(Initialize TradingView data feed client.Fz!Using cached authentication tokenz'Logged in successfully and cached tokenNz,Using anonymous access - data may be limited)ws_debugr   
expandusertoken_cache_file	threadingLock_lock_ws_lock_load_tokentokenloggerinfo_login_and_get_token_save_tokenwarning)selfusernamepasswordrE   rK   s        r4   __init__zTvDatafeed.__init__F   s     $ $%5 6 A A C^^%
!(   "%*DJKK;<(228XFDJTZZ(KKABDJNNIJr3   c                   | j                   j                         sy	 t        j                  | j                   j	                               }|j                  d      }|r| j                  |      r|S t        j                  d       | j                   j                  d       y# t        $ r }t        j                  d|       Y d}~yd}~ww xY w)zwLoad authentication token from cache file.

        Returns:
            Cached token if valid, None otherwise
        NrK   zCached token expired, removingT)
missing_okzFailed to load token cache: %s)rE   existsjsonloads	read_textget_is_token_validrL   rM   unlink	Exceptiondebug)rQ   datarK   es       r4   rJ   zTvDatafeed._load_token`   s     $$++-	::d33==?@DHHW%E--e4<=%%,,,= 	LL91=	s   AB" 01B" "	C+CCc                   	 ddl }|j                  d      }t        |      dk7  rt        j	                  d       y|d   }dt        |      dz  z
  }|dk7  r|d	|z  z  }|j                  |      }t        j                  |      }|j                  d
      }|st        j	                  d       yt        j                  j                  |t        j                  j                        }	t        j                  j                  t        j                  j                        }
|
|	k  }|st        j	                  d|	       |S # t        $ r }t        j	                  d|       Y d}~yd}~ww xY w)zValidate authentication token by checking JWT expiration.

        Args:
            token: Authentication token to validate

        Returns:
            True if token is valid and not expired, False otherwise
        r   N.   zInvalid JWT formatF      =expzToken has no expiration claimtzzToken expired at %szToken validation failed: %s)base64splitlenrL   r_   urlsafe_b64decoderX   rY   r[   datetimefromtimestamptimezoneutcnowr^   )rQ   rK   rk   partspayloadpaddingdecodedr`   rh   exp_timers   is_validra   s                r4   r\   zTvDatafeed._is_token_validw   s7   &	 KK$E5zQ12AhG #g,**G!|3=( ..w7G::g&D ((5/C<=  ((66sx?P?P?T?T6UH##''(9(9(=(=>CX~H2H=O 	LL6:	s$   8D< A1D< -BD< <	E%E  E%c                   	 | j                   j                  j                  dd       | j                   j                  t	        j
                  d|i             y# t        $ r }t        j                  d|       Y d}~yd}~ww xY w)zqSave authentication token to cache file.

        Args:
            token: Authentication token to cache
        T)parentsexist_okrK   zFailed to save token: %sN)	rE   parentmkdir
write_textrX   dumpsr^   rL   rP   )rQ   rK   ra   s      r4   rO   zTvDatafeed._save_token   sj    	:!!((..td.K!!,,TZZ%8H-IJ 	:NN5q99	:s   AA 	B#A>>Bc                D    | j                  ||      }|st        d      |S )a  Authenticate with TradingView and get token.

        Args:
            username: TradingView username
            password: TradingView password

        Returns:
            Authentication token

        Raises:
            ValueError: If login fails
        z%Login failed - check your credentials)_TvDatafeed__auth
ValueError)rQ   rR   rS   rK   s       r4   rN   zTvDatafeed._login_and_get_token   s(     Hh/DEEr3   c                "   t         j                  d       d}	 t        j                  |       t         j                  d       | j                         }|rt         j                  d       |S t        d       t        d	       t        d
       t        d       t        d       t        d       t        d|        t        d       t        d       t        d       t        d       t        d       t        d       t        d       t        d       t        d       t        d       t        d       t        d       t        d       t        d       t                t        d       t        d       t        d       t        d        t        d!       t        d"       t        d#       t        d$       t        d%       t        d&       t        d'       t        d(       t        d!       t        d)       t        d*       t        d$       t        d+       t        d&       t        d'       t        d(       t        d!       t        d,       t        d-       t                t        d.       t        d/       t        d0       t                t        d1       t        d2       t        d3       t        d4       t        d5       	 t        d6      j                         }|rkt        |      d7kD  rG|j                  d8d9      j                  d:d9      j                         rt         j                  d;       |S t         j                  d<       yt         j                  d=       | j                         }|rt         j                  d>       |S t         j                  d?       y# t        $ r7}t         j                  d|       t         j                  d|       Y d}~d}~ww xY w# t        t        f$ r t         j                  d@       Y yw xY w)Aa?  Handle login when CAPTCHA is required.

        Opens browser for user to complete CAPTCHA and login manually.
        Attempts to extract token from browser cookies or prompts user.

        Args:
            username: TradingView username

        Returns:
            Authentication token or None on failure
        z0Opening browser for manual login with CAPTCHA...r8   z3Browser opened. Please complete login with CAPTCHA.z(Failed to open browser automatically: %sz!Please open this URL manually: %sNz*Successfully extracted token from browser!zG
======================================================================z/CAPTCHA REQUIRED - Manual Authentication NeededzF======================================================================uF   
⚠️  NOTE: Browser sessionid does NOT work for API authentication!z?You need to extract the auth_token from the login API response.z>
A browser window has been opened (or open this URL manually):z  z)
Option 1: Use Network Tab (Recommended):z-  1. Open browser DevTools BEFORE logging in:zC     - Chrome/Edge: Press F12 or Ctrl+Shift+I (Cmd+Option+I on Mac)z?     - Firefox: Press F12 or Ctrl+Shift+I (Cmd+Option+I on Mac)z  2. Go to the 'Network' tabz4  3. Keep DevTools open and complete CAPTCHA + loginz:  4. After login, find the 'signin' request in Network tabz#  5. Click it, go to 'Response' tabz*  6. Look for: {"user":{"auth_token":"..."z,  7. Copy the auth_token value (long string)z3
Option 2: Use Console (if login already complete):z  1. Open browser DevToolsz  2. Go to the 'Console' tabz   3. Paste and run this command:z     (function() {z       // Check cookieszF       const cookieMatch = document.cookie.match(/authToken=([^;]+)/);z.       if (cookieMatch) return cookieMatch[1];z       z       // Check localStoragez3       for (let key of Object.keys(localStorage)) {zY         if (key.toLowerCase().includes("auth") || key.toLowerCase().includes("token")) {z1           const val = localStorage.getItem(key);z2           if (val && val.length > 50) return val;z
         }z       }z       // Check sessionStoragez5       for (let key of Object.keys(sessionStorage)) {z3           const val = sessionStorage.getItem(key);zL       return "Token not found. Run the commands below to see all storage.";z
     })();z6  5. If token not found, run these to see all storage:z     Object.keys(localStorage);z!     Object.keys(sessionStorage);z.  6. Copy the token (long string) that appearszI     (If you see 'Token not found', look for keys with 'auth' or 'token')z6
Alternatively, if you have browser_cookie3 installed,z:the token will be automatically extracted after you login.zG======================================================================
z<Enter auth token (or press Enter to retry auto-extraction):    - _zToken received from user inputzInvalid token formatz)Retrying token extraction from browser...z&Successfully extracted token on retry!z1Failed to extract token. Please try manual entry.zLogin cancelled by user)rL   rM   
webbrowseropenr^   rP   _extract_token_from_browserprintinputstriprm   replaceisalnumerrorKeyboardInterruptEOFError)rQ   rR   	login_urlra   rK   
user_inputs         r4   _handle_captcha_loginz TvDatafeed._handle_captcha_login   sL    	FG C		HOOI&KKMN 002KKDEL 	m?@fWXOPOP9+:;=>STOP,-DEJK34@A<=DE*+,-01"#'(VW>?i,-CDijABBClji./EFijCDBClji\]lFG/012>?YZGHJKm	]^ddfJz?R'J,>,>sB,G,O,OPSUW,X,`,`,bKK @A%%LL!78 GH88:KK HI LLL!TUq  	HNNEqIKK;YGG	Ht "8, 	NN45	s<   *N$ 
A/O' :O' =O' O' $	O$-,OO$'$PPc                   	 ddl }d|j                  fd|j                  fd|j                  fd|j                  fg}|D ]  \  }}	 t
        j                  d| d        |d	
      }i }|D ]  }|j                  ||j                  <    d|v r t
        j                  d| d       |d   c S d|v r t
        j                  d| d       |d   c S  t
        j                  d       y# t        $ r%}t
        j                  d| d|        Y d}~d}~ww xY w# t        $ r t
        j                  d       Y yt        $ r"}t
        j                  d|        Y d}~yd}~ww xY w)a  Extract TradingView auth token from browser cookies.

        Requires browser_cookie3 package (optional dependency).
        Looks for: authToken or auth_token cookies.

        NOTE: sessionid is NOT extracted as it only works for browser sessions,
        not for API/WebSocket authentication. The API requires a specific
        auth_token which is only available in the POST response body.

        Returns:
            Auth token if found, None otherwise
        r   NChromeFirefoxEdgeSafarizTrying to extract token from z...z.tradingview.com)domain_name	authTokenzFound authToken in z cookies
auth_tokenzFound auth_token in zCould not access z
 cookies: z(No auth-related cookies found in browserzHbrowser_cookie3 not installed. Install with: pip install browser-cookie3z%Error extracting token from browser: )browser_cookie3chromefirefoxedgesafarirL   r_   valuenamerM   r^   ImportError)	rQ   r   browsersbrowser_namebrowser_funccookiesauth_cookiescookiera   s	            r4   r   z&TvDatafeed._extract_token_from_browser7  s   -	" ?112O334--.?112	H /7 *lLL#@c!RS*7IJG $&L") A4:LLV[[1A
 #l2&9,x$PQ+K88%5&:<.$QR+L99 6. LLCD ! LL#4\N*QC!PQ  	LL.  	LL@DE	s[   AD A%C)*D -!C)D D )	D2DD DD E$:E$EE$c                   	 t        j                  | j                  ||dd| j                  d      }|j	                          |j                         }d|v rQdt        |j                  dd            j                         v r&t        j                  d       | j                  |      S d	|vsd
|d	   vr't        j                  d|       | j                  |      S |d	   d
   S # t         j                  $ r }t        j                  d|       Y d}~yd}~wt        t        f$ r }t        j                  d|       Y d}~yd}~ww xY w)zAuthenticate with TradingView.

        Args:
            username: TradingView username
            password: TradingView password

        Returns:
            Authentication token or None on failure
        on)rR   rS   remember
   )r`   headerstimeoutr   captchar   zCAPTCHA required for loginuserr   z!Invalid login response format: %sz'Network error during authentication: %sNzAuthentication failed: %s)requestspostr9   r?   raise_for_statusrX   strr[   lowerrL   rP   r   r   RequestExceptionKeyErrorr   )rQ   rR   rS   responser`   ra   s         r4   __authzTvDatafeed.__auths  s   	}}"""*dS--	H %%'==?D $9DHHWb4I0J0P0P0R#R;<11(;;T!\f%E@$G11(;;<--(( 	LLBAF*% 	LL4a8	s0   B%C" (1C" C" "E5DE"D==Ec              #    K   d}	 | j                   5  t        j                  d       t        d| j                  | j
                        }ddd       | |r	 |j                          yy# 1 sw Y   "xY w# t        $ r }t        j                  d|       Y d}~yd}~ww xY w# |r>	 |j                          w # t        $ r }t        j                  d|       Y d}~w d}~ww xY ww xY ww)zCreate and manage WebSocket connection lifecycle.

        Yields:
            Active WebSocket connection

        Example:
            with self._websocket_connection() as ws:
                ws.send(message)
        NzCreating WebSocket connection.wss://data.tradingview.com/socket.io/websocket)headerr   zError closing WebSocket: %s)rI   rL   r_   r	   r=   rA   closer^   )rQ   wsra   s      r4   _websocket_connectionz TvDatafeed._websocket_connection  s      	C <=&D,, -- HCHHJ   ! CLL!>BBC CHHJ  CLL!>BBC s   C(B# 8A+
B# C(A7 )C(+A40B# 7	B  BC(B  C(#C%'B87C%8	C!CC%C!!C%%C(c                    	 t        j                  d|       j                  d      }t        j                  d|       j                  d      }||fS # t        $ r t        j                  d       Y yw xY w)zFilter and extract message components from raw WebSocket data.

        Args:
            text: Raw WebSocket message

        Returns:
            Tuple of (message_type, payload) or None on error
        z"m":"(.+?)",re   z"p":(.+?"}"])}zError parsing WebSocket messageN)researchgroupAttributeErrorrL   r   )textfoundfound2s      r4   __filter_raw_messagezTvDatafeed.__filter_raw_message  sg    	IInd399!<EYY/6<<Q?F&=  	LL:;	s   AA A10A1c                 N    dj                  d t        d      D              } d|  S )z|Generate random session ID for quote session.

        Returns:
            Session ID string (format: qs_<random>)
        r   c              3  b   K   | ]'  }t        j                  t        j                         ) y wNrandomchoicestringascii_lowercase.0r   s     r4   	<genexpr>z0TvDatafeed.__generate_session.<locals>.<genexpr>       Y!f.D.D EY   -/   qs_joinrangerandom_strings    r4   __generate_sessionzTvDatafeed.__generate_session  *     YuUWyYY]O$$r3   c                 N    dj                  d t        d      D              } d|  S )zGenerate random session ID for chart session.

        Returns:
            Chart session ID string (format: cs_<random>)
        r   c              3  b   K   | ]'  }t        j                  t        j                         ) y wr   r   r   s     r4   r   z6TvDatafeed.__generate_chart_session.<locals>.<genexpr>  r   r   r   cs_r   r   s    r4   __generate_chart_sessionz#TvDatafeed.__generate_chart_session  r   r3   c                $    dt        |        d|  S )zPrepend TradingView protocol header to message.

        Args:
            st: Message string

        Returns:
            Message with protocol header
        z~m~)rm   )sts    r4   __prepend_headerzTvDatafeed.__prepend_header  s     SWIS%%r3   c                6    t        j                  | |dd      S )zConstruct JSON message for WebSocket.

        Args:
            func: Function name
            param_list: List of parameters

        Returns:
            JSON-encoded message
        )mp),:)
separators)rX   r   )func
param_lists     r4   __construct_messagezTvDatafeed.__construct_message  s     zz:6:NNr3   c                D    | j                  | j                  ||            S )zCreate complete WebSocket message with header.

        Args:
            func: Function name
            param_list: List of parameters

        Returns:
            Complete message ready to send
        )_TvDatafeed__prepend_header_TvDatafeed__construct_message)rQ   r   r   s      r4   __create_messagezTvDatafeed.__create_message  s"     $$T%=%=dJ%OPPr3   c                ~    | j                  ||      }| j                  rt        d|        |j                  |       y)zSend message through WebSocket.

        Args:
            ws: WebSocket connection
            func: Function name
            args: Message arguments
        z	Sending: N)_TvDatafeed__create_messagerC   r   send)rQ   r   r   argsmessages        r4   __send_messagezTvDatafeed.__send_message  s8     ''d3==IgY'(
r3   c                   t        j                  d|       j                  d      }|j                  d      }g }d}|D ]  }t        j                  d|      }|rEt        j                  j                  t        |d         t        j                  j                        nt        |d   j                  d      d	         }|g}t        d
d      D ]9  }	|s|	dk(  r|j                  d       	 |j                  t        ||	                ; |j                  |        |S # t        t        f$ r+ d}|j                  d       t        j                  d       Y w xY w)ah  Parse raw WebSocket data into list of OHLCV rows.

        Args:
            raw_data: Raw WebSocket response data
            is_return_dataframe: Whether to format timestamp for DataFrame

        Returns:
            List of [timestamp, open, high, low, close, volume] rows

        Raises:
            AttributeError: If raw_data format is invalid
        z"s":\[(.+?)\}\]re   z,{"Tz	\[|:|,|\]rf   ri   rc   r      r   	   g        FzNo volume data available)r   r   r   rl   ro   rp   floatrq   rr   intr   appendr   
IndexErrorrL   r_   )
raw_datais_return_dataframeoutxr`   volume_dataxitsrowis
             r4   __parse_datazTvDatafeed.__parse_data  s@    ii,h7==a@IIe 	B-,B ' !!//beARARAVAV/WAS)!,-  $C1b\ 
="qAvJJsO=JJuRU|,
= KK-	0  #J/ ="'KJJsOLL!;<=s   )D7EEc                    	 t        j                  | g d      j                  d      }|j                  dd|       |S # t        t
        f$ r }t        j                  d|       Y d}~yd}~ww xY w)	a  Create pandas DataFrame from parsed OHLCV data.

        Args:
            parsed_data: List of [timestamp, open, high, low, close, volume] rows
            symbol: Symbol name for the data

        Returns:
            DataFrame with OHLCV data or None on error
        )ro   r   highlowr   volume)columnsro   r   symbol)r   z:Failed to create DataFrame - check exchange and symbol: %sN)pd	DataFrame	set_indexinsertr   r  rL   r   )parsed_datar  dfra   s       r4   __create_dfzTvDatafeed.__create_df<  sk    
	N i
#  IIaI0I
+ 	LLUWXY	s   =A   A/A**A/c                    | |fx  r dk(  r\  } d|v r |S  x  r dk(  r\  c	} | d| S    r# dk(  r\  }}t        |t              r| d| | dS  	 t        d      )a:  Format symbol string for TradingView.

        Args:
            symbol: Symbol name
            exchange: Exchange name
            contract: Futures contract number (None for spot)

        Returns:
            Formatted symbol string

        Raises:
            ValueError: If contract type is invalid
           r   !z&Invalid contract - must be int or None)
isinstancer  r   )r  exchangecontractscs        r4   __format_symbolzTvDatafeed.__format_symbolS  s     x Q3!8 !T"1QC(( :a-"1QCs!,,  !IJJr3   NSEr   Fc                   | j                  |||      }|j                  }| j                         }| j                         }		 | j	                         5 }
| j
                  r| j
                  nd}| j                  |
d|g       | j                  |
d|	dg       | j                  |
d|g       | j                  |
d|dd	d
ddddddddddddddddddddg       | j                  |
d||d d!gig       | j                  |
d"||g       |sd#nd$}d%| d&| d'}| j                  |
d(|	d)|g       | j                  |
d*|	d+d+d)||g       | j                  |
d,|	dg       d}t        j                  d-|       	 	 |
j                         }||d/z   z  }d0|v rn	  |rd0|vr t        j                  d3|       	 d2d2d2       y2| j                  |d.4      }| j                  ||      cd2d2d2       S # t        $ r2}t        j                  d1||       d0|vrY d2}~d2d2d2       y2Y d2}~d2}~ww xY w# 1 sw Y   y2xY w# t        $ r!}t        j                  d5||       Y d2}~y2d2}~ww xY w)6a  Get historical market data from TradingView.

        Args:
            symbol: Symbol name (e.g., 'NIFTY', 'AAPL')
            exchange: Exchange name (e.g., 'NSE', 'NASDAQ')
            interval: Time interval for bars
            n_bars: Number of bars to fetch
            fut_contract: Futures contract number (None for spot, 1 for front month)
            extended_session: Include extended trading hours

        Returns:
            DataFrame with columns: symbol, open, high, low, close, volume
            Returns None on error

        Raises:

        Example:
            >>> tv = TvDatafeed(username='user', password='pass')
            >>> data = tv.get_hist('AAPL', 'NASDAQ', Interval.in_1_hour, n_bars=100)
        )r  r  r   unauthorized_user_tokenset_auth_tokenchart_create_sessionr   quote_create_sessionquote_set_fieldschchpcurrent_sessiondescriptionlocal_descriptionlanguager  
fractionalis_tradablelplp_timeminmovminmove2original_name
pricescalepro_name
short_nametypeupdate_moder  currency_coderchprtcquote_add_symbolsflagsforce_permissionquote_fast_symbolsregularextended={"symbol":"#","adjustment":"splits","session":""}resolve_symbolsymbol_1create_seriess1switch_timezonezFetching data for %s...T
series_completed"WebSocket receive error for %s: %sNNo valid data received for %s)r  z(Failed to get historical data for %s: %s)_TvDatafeed__format_symbolr   _TvDatafeed__generate_session#_TvDatafeed__generate_chart_sessionr   rK   _TvDatafeed__send_messagerL   r_   recvr^   r   _TvDatafeed__parse_data_TvDatafeed__create_df)rQ   r  r  intervaln_barsfut_contractextended_sessioninterval_valuesessionchart_sessionr   r   session_typesymbol_configr  resultra   r  s                     r4   get_histzTvDatafeed.get_histl  s   : %%H| & 
 " ))+557K	++- F=+/::TZZ;T
##B(8:,G##B(>PR@ST##B(>	J ##&e%6+Z\%tY*'z<x&RW ##'fw1C0D&EF
 ##B(<w>OP 1Ayj"/x7Z[gZhhk l##$"J>
 ###"D$
NFS
 ##B(9M:;VW 6?!# FTM1-7! 8   #5X#ELL!@&IEF= F=J #//d/S''V<MF= F=r % %I6STU-X=#'yF= F=z 	sF= F=P  	LLCVQO	sy   H- DH!0G# H!,H- 5$H!	H- #	H,HH!H- H!HH!!H*&H- *H- -	I6IIc	           
        K   |r;|4 d{    | j                  |||||||       d{   cddd      d{    S | j                  |||||||       d{   S 7 S7 67 (# 1 d{  7  sw Y   yxY w7 w)a"  Asynchronously fetch historical data for a single symbol.

        Args:
            symbol: Symbol name
            exchange: Exchange name
            interval: Time interval
            n_bars: Number of bars to fetch
            fut_contract: Futures contract number
            extended_session: Include extended trading hours
            dataFrame: Return as DataFrame (True) or list (False)
            semaphore: Optional semaphore for rate limiting

        Returns:
            DataFrame or list of OHLCV data, or None on error
        N)_do_fetch_symbol_data)	rQ   r  r  rY  rZ  r[  r\  	dataFrame	semaphores	            r4   __fetch_symbol_datazTvDatafeed.__fetch_symbol_data  s     6    !77HhFVXa   
 33(FLBRT]     
s]   	A<AA<A%A!A%A<A#A<A:A<!A%#A<%A7+A.,A73A<c                  K   	 | j                  |||      }|j                  }	| j                         }
| j                         }t	        dd      4 d{   }| j
                  r| j
                  nd}|j                  | j                  d|g             d{    |j                  | j                  d|dg             d{    |j                  | j                  d	|
g             d{    |j                  | j                  d
|
dddddddddddddddddddddd d!g             d{    |j                  | j                  d"|
|d#d$gig             d{    |j                  | j                  d%|
|g             d{    |sd&nd'}d(| d)| d*}|j                  | j                  d+|d,|g             d{    |j                  | j                  d-|d.d.d,|	|g             d{    |j                  | j                  d/|dg             d{    d}t        j                  d0|       	 	 |j                          d{   }||d1z   z  }d3|v rn'|rd3|vr(t        j                  d4|       	 ddd      d{    y| j                  ||      }|r#| j                  ||      cddd      d{    S |cddd      d{    S 7 7 E7 7 7 7 7 d7 ,7 7 7 # t        $ r!}t        j                  d2||       Y d}~d}~ww xY w7 7 e7 T# 1 d{  7  sw Y   yxY w# t        $ r%}t        j                  d5| d6|        Y d}~yd}~ww xY ww)7z.Internal method to actually fetch symbol data.r   r<   )originNr&  r'  r(  r   r)  r*  r+  r,  r-  r.  r/  r0  r  r1  r2  r3  r4  r5  r6  r7  r8  r9  r:  r;  r<  r  r=  r>  r?  r@  rA  rB  rC  rD  rE  rF  rG  rH  rI  rJ  rK  rL  rM  zFetching async data for %s...rN  rP  rO  rQ  zError fetching async data for z: )rR  r   rS  rT  r   rK   r   r   rL   r_   rV  r^   r   rW  rX  )rQ   r  r  rY  rZ  r[  r\  rf  symbol_formattedr]  r^  r_  	websocketr   r`  ra  r  rb  ra   r  s                       r4   re  z TvDatafeed._do_fetch_symbol_data  s    Q	#33FHlS%^^N --/G 99;M@5 E' E' +/::TZZ;T
nnT%:%:;Kj\%Z[[[nnT%:%:;QTaceSf%ghhhnnT%:%:;QT[S\%]^^^  nnT%:%:&e%6+Z\%tY*'z<x&RW
& 
 
 
  nnT%:%:'.;M:N0OP&     nnT%:%:;ORY[kQl%mnnn 1Ayj"/0@/AAdeqdrru vnnT%:%:$"J>&     nnT%:%:#"D$
NFS&     nnT%:%:;L}^hNi%jkkk <fE'0~~'7!7 FTM1
 *V3   #5X#ELL!@&I}E' E' E'B #//)D++K9IJGE' E' E'J 'KE' E' E' \h^
 o l "8$ %I6STUiE' E' E' E' E' E'N  	LL9&A3GH	s  M1AM  KM  A L+K*L+K )L+-K#.A L+.K&/.L+K)*L+K,	:L+K/.L+2K23*L+K4L+<K8K6K8#L+?M  
L%M  M1%L+5M  L'M  M1L+M  L)M  M1M  L+ L+#L+&L+)L+,L+/L+2L+4L+6K88	L"LL+L""L+%M  'M  )M  +L=1L42L=9M  <M1=M   	M.	M)$M1)M..M1Tr   c	                V  K   t        j                  |      }	t        j                  dt	        |       d| d       |D 
cg c]  }
| j                  |
|||||||	       }}
t        j                  |  d{   }t        ||      D ci c]  \  }}||
 c}}S c c}
w 7 )c c}}w w)a  Fetch historical data for multiple symbols asynchronously.

        This method fetches data for all symbols concurrently, which is much
        faster than fetching them sequentially. Rate limiting prevents overwhelming
        the server or hitting API limits.

        Args:
            symbols: List of symbol names
            exchange: Exchange name (applies to all symbols)
            interval: Time interval for bars
            n_bars: Number of bars to fetch
            dataFrame: Return as DataFrame (True) or list (False)
            fut_contract: Futures contract number
            extended_session: Include extended trading hours
            max_concurrent: Maximum number of concurrent connections (default: 20)
                           Recommended values:
                           - Conservative: 10-15 (safest, unlikely to hit limits)
                           - Moderate: 20-30 (balanced, good for most use cases)
                           - Aggressive: 40-50 (faster but higher risk of rate limiting)

        Returns:
            Dictionary mapping symbol names to their DataFrames or lists

        Example:
            >>> tv = TvDatafeed()
            >>> symbols = ['AAPL', 'GOOGL', 'MSFT']
            >>> # Default rate limiting (20 concurrent)
            >>> data = asyncio.run(tv.get_hist_async(symbols, 'NASDAQ', n_bars=100))
            >>>
            >>> # Conservative rate limiting (10 concurrent)
            >>> data = asyncio.run(tv.get_hist_async(symbols, 'NASDAQ', n_bars=100, max_concurrent=10))
            >>>
            >>> # Or use the synchronous wrapper:
            >>> data = tv.get_hist_multi(symbols, 'NASDAQ', n_bars=100, max_concurrent=15)
        z	Fetching z symbols with max z concurrent connectionsN)asyncio	SemaphorerL   rM   rm   _TvDatafeed__fetch_symbol_datagatherzip)rQ   symbolsr  rY  rZ  rf  r[  r\  max_concurrentrg  r  tasksresultssymr`   s                  r4   get_hist_asynczTvDatafeed.get_hist_asyncb  s     ^ %%n5	iG~-??OOfgh "	
  $$(FLBRT]_h
 
  ..+.w+@Aic4T	AA
 /As/   ?B)B B)7B!8B)B#
B)#B)c	                    t        |t              r*t        j                  | j	                  |||||||            S t        j                  | j                  ||||||||            S )ao  Get historical data for single or multiple symbols.

        This method supports both single symbol and multiple symbols. When
        multiple symbols are provided, data is fetched concurrently for better
        performance with rate limiting to prevent API throttling.

        Args:
            symbols: Single symbol name or list of symbol names
            exchange: Exchange name (applies to all symbols)
            interval: Time interval for bars
            n_bars: Number of bars to fetch
            dataFrame: Return as DataFrame (True) or list (False)
            fut_contract: Futures contract number
            extended_session: Include extended trading hours
            max_concurrent: Maximum concurrent connections (default: 20)
                           **Recommended Settings:**
                           - **Conservative (10-15)**: Safest, unlikely to hit limits
                           - **Moderate (20-30)**: Balanced, good for most use cases
                           - **Aggressive (40-50)**: Faster but higher risk

        Returns:
            - Single symbol: DataFrame or list
            - Multiple symbols: Dict mapping symbol names to DataFrames or lists

        Raises:

        Examples:
            >>> tv = TvDatafeed()
            >>> # Single symbol
            >>> data = tv.get_hist_multi('AAPL', 'NASDAQ', n_bars=100)
            >>>
            >>> # Multiple symbols with default rate limiting (20 concurrent)
            >>> symbols = ['AAPL', 'GOOGL', 'MSFT', 'TSLA', 'AMZN']
            >>> data = tv.get_hist_multi(symbols, 'NASDAQ', n_bars=100)
            >>> # Returns: {'AAPL': DataFrame, 'GOOGL': DataFrame, ...}
            >>>
            >>> # Conservative rate limiting for large batches
            >>> symbols = [f'SYM{i}' for i in range(100)]
            >>> data = tv.get_hist_multi(symbols, 'NASDAQ', n_bars=100, max_concurrent=15)
            >>>
            >>> # Return as lists instead of DataFrames
            >>> data = tv.get_hist_multi(symbols, 'NASDAQ', n_bars=100, dataFrame=False)
            >>> # Returns: {'AAPL': [[ts, o, h, l, c, v], ...], 'GOOGL': [...], ...}
        )r  r   rn  runrp  rx  )	rQ   rs  r  rY  rZ  rf  r[  r\  rt  s	            r4   get_hist_multizTvDatafeed.get_hist_multi  ss    p gs#;;((XxGWYb  {{8VYN^`n
 	
r3   c                   | j                   j                  ||      }	 t        j                  |d      }|j	                          |j
                  j                  dd      j                  dd      }t        j                  |      S # t        j                  $ r"}t        j                  d|       g cY d}~S d}~wt        j                  $ r"}t        j                  d|       g cY d}~S d}~ww xY w)	a@  Search for symbols on TradingView.

        Args:
            text: Search text
            exchange: Filter by exchange (optional)

        Returns:
            List of matching symbols with metadata

        Example:
            >>> tv = TvDatafeed()
            >>> results = tv.search_symbol('CRUDE', 'MCX')
        r   )r   z</em>r   z<em>zSymbol search failed: %sNz"Failed to parse search results: %s)r:   formatr   r[   r   r   r   rX   rY   r   rL   r   JSONDecodeError)rQ   r   r  urlresp
clean_textra   s          r4   search_symbolzTvDatafeed.search_symbol  s     &&tX6	<<R0D!!# **7B7??KJ::j))(( 	LL3Q7I## 	LL=qAI	s0   A'B C.B60C.6C.C)#C.)C.c                    | j                   S )zzGet current authentication token.

        Returns:
            Authentication token or None if not authenticated
        )rK   )rQ   s    r4   	get_tokenzTvDatafeed.get_token  s     zzr3   )NNz~/.tv_token.json)rR   
str | NonerS   r  rE   z
str | PathreturnNone)r  r  )rK   r   r  bool)rK   r   r  r  )rR   r   rS   r   r  r   )rR   r   r  r  )rR   r   rS   r   r  r  )r  z Generator[WebSocket, None, None])r   r   r  ztuple[str, str] | None)r  r   )r   r   r  r   )r   r   r   listr  r   )r   r
   r   r   r   r  r  r  )r  r   r  r  r  
list[list])r  r  r  r   r  pd.DataFrame | Noner   )r  r   r  r   r   
int | Noner  r   )r  r   r  r   rY  r   rZ  r  r[  r  r\  r  r  r  )r  r   r  r   rY  r   rZ  r  r[  r  r\  r  rf  r  rg  zasyncio.Semaphore | Noner   pd.DataFrame | list[list] | None)r  r   r  r   rY  r   rZ  r  r[  r  r\  r  rf  r  r  r  )rs  z	list[str]r  r   rY  r   rZ  r  rf  r  r[  r  r\  r  rt  r  r  z+dict[str, pd.DataFrame | list[list] | None])rs  zlist[str] | strr  r   rY  r   rZ  r  rf  r  r[  r  r\  r  rt  r  r  zNpd.DataFrame | dict[str, pd.DataFrame | list[list] | None] | list[list] | None)r   )r   r   r  r   r  z
list[dict]))r   r   r    r!   r7   __annotations__r9   r:   r=   r?   rA   rT   rJ   r\   rO   rN   r   r   r   r   r   staticmethod_TvDatafeed__filter_raw_messagerS  rT  r   r   r   rU  rW  rX  rR  r   r,   rc  rp  re  rx  r{  r  r  r2   r3   r4   r6   r6   3   s   	 !PJO#QM=Q #RL-  R.68V-WL*W2;=Z1[.["$L-$  $#'9	KK K %	K
 
K4./b
:$ob:x&P C C6  " % % % % 	& 	& 
O 
O
Q * *X  , K K6 %..#'!&qq q 	q
 q !q q 
qx /3## # 	#
 # !# # # ,# 
*#J\\ \ 	\
 \ !\ \ \ 
*\B %..#'!& :B:B :B 	:B
 :B :B !:B :B :B 
5:B~ %..#'!& D
 D
 D
 	D

 D
 D
 !D
 D
 D
 
XD
L>r3   r6   __main__)levelCRUDEOILMCXre   )r[  NIFTYr$  	EICHERMOTi  F)rY  rZ  r\  )*r!   
__future__r   rn  ro   enumrX   loggingr   r   r   rF   r   
contextlibr   pathlibr   typingr   r   pandasr  r   
websocketsr   rl  r	   r
   collections.abcr   	getLoggerr   rL   Enumr   r6   basicConfigDEBUGtvr   rc  r(   r2   r3   r4   <module>r     s    L "       	    %  *    2)			8	$tyy *V Vr zGgmm,	B	"++j%a+
89	"++gu1+
56	
''" 	 	
 r3   