o
    _�¿jä)  ã                   @  sÞ   d Z ddlm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mZmZ ddlmZmZmZ dd	lmZmZmZmZmZ dd
lmZ ddlmZ ddlmZ ddlm Z! e "d¡Z#dZ$G dd„ dƒZ%dgZ&dS )u»  BSEClient â€” async client for BSE option chain data.

Usage::

    import asyncio
    from indiaopt import BSEClient

    async def main():
        async with BSEClient() as client:
            # BSE uses numeric scrip codes, e.g. "999920" for SENSEX derivatives
            result = await client.fetch_option_chain("999920", is_index=True)
            print(f"Spot: {result.spot_price}, ATM: {result.atm_strike}")

    asyncio.run(main())

.. note::
    BSE's option chain API uses scrip codes rather than symbol names.
    The mapping between names (e.g. "SENSEX") and scrip codes is not
    part of this library â€” you'll need to maintain your own mapping or
    use BSE's instrument list API.
é    )ÚannotationsN)ÚThreadPoolExecutor)ÚAny)ÚCircuitBreakerÚget_default_breaker)ÚSettingsÚget_settings)ÚBSE_BASE_URLÚBSE_OPTION_CHAIN_PATHÚRATE_LIMIT_STATUS_CODES)Ú
FetchErrorÚFetchTimeoutErrorÚNetworkErrorÚ
ParseErrorÚRateLimitError)ÚRetryPolicy)Úcreate_bse_session)ÚOptionChainResult)Úbsezindiaopt.exchanges.bseÚBSEc                   @  s”   e Zd ZdZ		d.d/d	d
„Zd0dd„Zd1dd„Zd2dd„Zdddœd3dd„Zdddœd4dd „Z	d5d"d#„Z
d6d$d%„Zd7d'd(„Zd8d*d+„Zd3d,d-„ZdS )9Ú	BSEClienta?  Async client for BSE option chain data.

    Mirrors the :class:`~indiaopt.exchanges.nse.NSEClient` interface exactly
    so the two are interchangeable when accessed through the
    :class:`~indiaopt.exchanges.base.ExchangeClient` Protocol.

    Args:
        settings: Optional :class:`~indiaopt.config.settings.Settings` override.
        breaker:  Optional :class:`~indiaopt.circuit.CircuitBreaker` override.

    Context manager (recommended)::

        async with BSEClient() as client:
            result = await client.fetch_option_chain("999920", is_index=True)
    NÚsettingsúSettings | NoneÚbreakerúCircuitBreaker | NoneÚreturnÚNonec                 C  sP   |pt ƒ | _|pt| jj| jjd�| _t | j¡| _t	| jj
dd�| _d | _d S )N)Úfailure_thresholdÚbackoff_secondszindiaopt-bse)Úmax_workersÚthread_name_prefix)r   Ú	_settingsr   Úcircuit_failure_thresholdÚcircuit_backoff_secondsÚ_breakerr   Úfrom_settingsÚ_retry_policyr   Úthread_pool_workersÚ_poolÚ_session)Úselfr   r   © r+   úQ/home/dinkstrade/pdmp/venv/lib/python3.10/site-packages/indiaopt/exchanges/bse.pyÚ__init__G   s   þþ
zBSEClient.__init__c                 Ã  s   �| S ©Nr+   ©r*   r+   r+   r,   Ú
__aenter__X   s   €zBSEClient.__aenter__Ú_Úobjectc                 Ç  s   �|   ¡ I d H  d S r.   )Úclose)r*   r1   r+   r+   r,   Ú	__aexit__[   s   €zBSEClient.__aexit__c                 Ã  sF   �| j durz| j  ¡  W n	 ty   Y nw d| _ | jjdd� dS )z-Release all resources (session, thread pool).NF)Úwait)r)   r3   Ú	Exceptionr(   Úshutdownr/   r+   r+   r,   r3   ^   s   €
ÿzBSEClient.closeT)Úis_indexÚexpiryÚsymbolÚstrr8   Úboolr9   ú
str | Noneúdict[str, Any]c                Ã  s~   �|  ¡ }| j t|¡ t ¡ }ztj| | j| j	|||¡| j
jd�I dH W S  tjy>   | j t|¡ t|| j
jtd�‚w )z=Fetch the unparsed raw JSON dictionary for *symbol* from BSE.©ÚtimeoutN©r:   Ú	timeout_sÚexchange)Ústripr$   Úraise_if_openÚEXCHANGEÚasyncioÚget_running_loopÚwait_forÚrun_in_executorr(   Ú_fetch_syncr!   Úasync_timeoutÚTimeoutErrorÚrecord_failurer   )r*   r:   r8   r9   Úloopr+   r+   r,   Úfetch_raw_option_chainh   s.   €ûø
ýþz BSEClient.fetch_raw_option_chainr   c                Ã  sŒ   �|  ¡ }| j t|¡ t ¡ }ztj| | j| j	|||¡| j
jd�I dH }W n tjy?   | j t|¡ t|| j
jtd�‚w t ||¡S )a˜  Fetch the full option chain for *symbol* from BSE.

        Args:
            symbol:   BSE scrip code (e.g. ``"999920"`` for SENSEX derivatives).
            is_index: ``True`` for index instruments, ``False`` for equities.
            expiry:   Specific expiry date string. Uses today's date when not provided.

        Returns:
            :class:`~indiaopt.models.option_chain.OptionChainResult`
        r?   NrA   )rD   r$   rE   rF   rG   rH   rI   rJ   r(   rK   r!   rL   rM   rN   r   Ú
bse_parserÚparse_option_chain)r*   r:   r8   r9   rO   Úrawr+   r+   r,   Úfetch_option_chain‡   s0   €ûø
ýþzBSEClient.fetch_option_chainú	list[str]c                 Ã  s   �t  d¡ g S )u£   Return available expiry dates for *symbol*.

        BSE does not have a standard public expiry endpoint â€” returns
        an empty list with a warning.
        zgBSE does not expose a public expiry-dates API. Pass the expiry date explicitly to fetch_option_chain().)ÚloggerÚwarning©r*   r:   r+   r+   r,   Úget_expiry_dates±   s
   €ÿzBSEClient.get_expiry_datesc                 C  s   | j  t|¡ dS )z0Manually reset the circuit breaker for *symbol*.N)r$   ÚresetrF   rX   r+   r+   r,   Úreset_circuit½   s   zBSEClient.reset_circuitúdict[str, dict[str, object]]c                 C  s
   | j  ¡ S )z?Return a snapshot of all circuit breaker states for monitoring.)r$   Ústatsr/   r+   r+   r,   Úcircuit_statsÁ   s   
zBSEClient.circuit_statsr   c                 C  s&   | j d u rt| jj| jjd�| _ | j S )N)Ú
proxy_urlsÚwarmup_timeout)r)   r   r!   r_   r`   r/   r+   r+   r,   Ú_get_or_create_sessionÇ   s   
þz BSEClient._get_or_create_sessionc                 C  sŒ  ddl m } |  ¡ }|rdnd}|p| ¡  d¡}t› t› d|› d|› d|› �}d }t| jjƒD ]û}	z•|j	|| j
jd	�}
|
jd
krz|
 ¡ }W n+ tyr } zt d||	d |¡ d | _|  ¡ }td|› �|t|	d d�|‚d }~ww | j t|¡ |W   S |
jtv rµtd|
j› d|› �|t|
j|	d d�}t d||	d | jj|
j¡ |	| jjd k r³| j |	¡ W q0td|
j› d|› �|t|
j|	d d�‚ ttfyÑ   ‚  t�y } z+td|› d|› �|t|	d d�}d | _|  ¡ }|	| jjd k rþ| j |	¡ W Y d }~q0d }~w t�y+ } z|}|	| jjd k �r!| j |	¡ W Y d }~q0d }~ww | j t|¡ td| jj› d|› �|t| jjd�|‚)Nr   )ÚdatetimeÚIndicesÚEquitiesz%d-%b-%Yz?Scripcode=z&ExpiryDate=z&Type=r?   éÈ   zCJSON decode failed for BSE/%s (attempt %d): %s. Refreshing session.é   zInvalid JSON from BSE: )r:   rC   ÚattemptszHTTP z from BSE for )r:   rC   Ústatus_coderg   z4Rate-limited by BSE for %s (attempt %d/%d, HTTP %d).zUnexpected HTTP zNetwork error for BSE/z: zAll z attempts failed for BSE/)rb   ra   ÚnowÚstrftimer	   r
   Úranger&   Úmax_retriesÚgetr!   Úfetch_timeoutrh   Újsonr6   rV   rW   r)   r   rF   r$   Úrecord_successr   r   Ú	sleep_forr   ÚOSErrorr   rN   )r*   r:   r8   r9   rb   ÚsessionÚtype_strÚurlÚlast_excÚattemptÚrespÚdataÚjson_excÚexcr+   r+   r,   rK   Ï   s¼   
ÿÿÿÿ
üüû€÷

ûûûü€€ýüûzBSEClient._fetch_sync)NN)r   r   r   r   r   r   )r   r   )r1   r2   r   r   )r   r   )r:   r;   r8   r<   r9   r=   r   r>   )r:   r;   r8   r<   r9   r=   r   r   )r:   r;   r   rU   )r:   r;   r   r   )r   r\   )r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r-   r0   r4   r3   rP   rT   rY   r[   r^   ra   rK   r+   r+   r+   r,   r   6   s&    ý


û#û
*


r   )'r   Ú
__future__r   rG   ÚloggingÚconcurrent.futuresr   Útypingr   Úindiaopt.circuitr   r   Úindiaopt.config.settingsr   r   Úindiaopt.constantsr	   r
   r   Úindiaopt.exceptionsr   r   r   r   r   Úindiaopt.http.retryr   Úindiaopt.http.sessionr   Úindiaopt.models.option_chainr   Úindiaopt.parsersr   rQ   Ú	getLoggerrV   rF   r   Ú__all__r+   r+   r+   r,   Ú<module>   s&    
 
{