o
    _�¿j‰  ã                   @  sÈ   d Z ddlmZ ddlZddlmZm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mZ e d	¡Zd
ZdZdZdZdZdZdZdZdZdZd%dd„Zd&dd „Zd&d!d"„Zd'd#d$„Z d gZ!dS )(uí  BSE option chain response parser.

Transforms raw JSON from BSE's ``DerivOptionChain_IV`` endpoint into a typed
:class:`~indiaopt.models.option_chain.OptionChainResult`.

BSE response schema (approximate â€” field names differ from NSE)::

    {
        "Table": [
            {
                "StrikePrice": 74000,
                "CE_OpenInterest": 1234,
                "CE_ChgInOI": 56,
                "CE_IV": 12.5,
                "CE_LTP": 45.0,
                "PE_OpenInterest": 789,
                "PE_ChgInOI": -10,
                "PE_IV": 11.0,
                "PE_LTP": 60.5,
                ...
            }
        ],
        "Table1": [
            {"UnderlyingValue": 74250.3, "ExpiryDate": "2024-06-27T00:00:00"}
        ]
    }

.. note::
    BSE's API schema is not officially documented. This parser is a
    best-effort implementation based on observed responses. If you have
    access to official BSE API documentation, adjust field names in
    :func:`_map_row` accordingly.
é    )ÚannotationsN)ÚdatetimeÚtimezone)ÚAny)Ú
ParseError)ÚOptionChainResultÚOptionChainRow)Ú
safe_floatÚsafe_intÚsafe_int_or_zerozindiaopt.parsers.bseÚBSE)ÚStrikePriceÚstrikePriceÚStrikeÚstrike)ÚCE_OpenInterestÚCE_OIÚCallOI)Ú
CE_ChgInOIÚCE_ChangeInOIÚ	CallChgOI)ÚCE_IVÚCallIVÚCE_ImpliedVolatility)ÚCE_LTPÚCallLTPÚCE_LastTradedPrice)ÚPE_OpenInterestÚPE_OIÚPutOI)Ú
PE_ChgInOIÚPE_ChangeInOIÚPutChgOI)ÚPE_IVÚPutIVÚPE_ImpliedVolatility)ÚPE_LTPÚPutLTPÚPE_LastTradedPriceÚdúdict[str, Any]ÚkeysÚstrÚreturnr   c                 G  s.   |D ]}|| v r| | dur| |   S qdS )z?Return the first non-None value found in *d* for any of *keys*.N© )r)   r+   Úkr.   r.   úO/home/dinkstrade/pdmp/venv/lib/python3.10/site-packages/indiaopt/parsers/bse.pyÚ_first@   s
   €r1   ÚrawÚsymbolr   c              
   C  s^   zt | |ƒW S  ty   ‚  ty. } ztd|› d|› �|tt| ƒdd… d�|‚d}~ww )aq  Parse a BSE option chain response into :class:`OptionChainResult`.

    Args:
        raw:    Raw JSON dict from BSE API.
        symbol: The trading symbol (BSE scrip code or name).

    Returns:
        Fully typed :class:`OptionChainResult`.

    Raises:
        :class:`~indiaopt.exceptions.ParseError`: If the response structure
            is unrecognisable.
    z*Unexpected error parsing BSE response for z: NéÈ   )r3   ÚexchangeÚraw_preview)Ú_parser   Ú	ExceptionÚEXCHANGEr,   )r2   r3   Úexcr.   r.   r0   Úparse_option_chainH   s   üû€ÿr;   c                   s>  |   d¡p|   d¡p|   di ¡  d¡pg }|st d|¡ |   d¡p(|   d¡p(g }d ‰ d }|D ]-}ˆ d u r?tt|ddd	d
ƒƒ‰ |d u rRt|dddƒ}|rRtt|ƒƒ}ˆ d ur\|d ur\ nq/g }d}|D ]}}	t|	tƒso|d7 }qctt|	gt	¢R Ž ƒ}
|
d u r‚|d7 }qc| 
t|
tt|	gt¢R Ž ƒtt|	gt¢R Ž ƒtt|	gt¢R Ž ƒtt|	gt¢R Ž ƒtt|	gt¢R Ž ƒtt|	gt¢R Ž ƒtt|	gt¢R Ž ƒtt|	gt¢R Ž ƒtt|	ddƒƒtt|	ddƒƒd�¡ qc|rêt d||¡ |jdd„ d� d }ˆ d u�r|�rt|‡ fdd„d�j}t|t|ˆ ||t tj¡|�r|gd�S g d�S )NÚTableÚdataÚrecordsz]BSE response for %s has no data table. Exchange may be closed or scrip code may be incorrect.ÚTable1ÚmetaÚUnderlyingValueÚ	SpotPriceÚLTPÚunderlyingValueÚ
ExpiryDateÚExpiryÚ
expiryDater   é   Ú	CE_VolumeÚ
CallVolumeÚ	PE_VolumeÚ	PutVolume)r   Úcall_oiÚcall_coiÚput_oiÚput_coiÚcall_ivÚput_ivÚcall_ltpÚput_ltpÚcall_volÚput_volz%Skipped %d malformed rows for BSE/%s.c                 S  s   | j S ©N)r   ©Úrr.   r.   r0   Ú<lambda>£   s    z_parse.<locals>.<lambda>)Úkeyc                   s   t | jˆ  ƒS rW   )Úabsr   rX   ©Ú
spot_pricer.   r0   rZ   §   s    )r3   r5   Úexpiryr^   Ú
atm_striker=   Ú
fetched_atÚexpiry_dates) ÚgetÚloggerÚwarningr	   r1   Ú_normalise_expiryr,   Ú
isinstanceÚdictÚ_STRIKE_FIELDSÚappendr   r   Ú_CALL_OI_FIELDSÚ_CALL_COI_FIELDSÚ_PUT_OI_FIELDSÚ_PUT_COI_FIELDSÚ_CALL_IV_FIELDSÚ_PUT_IV_FIELDSÚ_CALL_LTP_FIELDSÚ_PUT_LTP_FIELDSr
   ÚdebugÚsortÚminr   r   r9   r   Únowr   Úutc)r2   r3   ÚtableÚ
meta_tabler_   Úmeta_rowÚ
raw_expiryÚrowsÚskippedÚitemr   r`   r.   r]   r0   r7   c   sŒ   
ÿþüýÿ€
õÿ

øør7   c                 C  st   ddddddddd	d
dddœ}zt  |  d¡d ¡}||jd› }|jd›d|› d|j› �W S  ty9   |  Y S w )uê   Attempt to convert BSE expiry strings to ``DD-Mon-YYYY`` format.

    Handles:
    - ``"2024-06-27T00:00:00"`` â†’ ``"27-Jun-2024"``
    - ``"27-06-2024"`` â†’ ``"27-Jun-2024"``
    - Already-formatted strings are returned as-is.
    ÚJanÚFebÚMarÚAprÚMayÚJunÚJulÚAugÚSepÚOctÚNovÚDec)Ú01Ú02Ú03Ú04Ú05Ú06Ú07Ú08Ú09Ú10Ú11Ú12ÚTr   Ú02dú-)r   ÚfromisoformatÚsplitÚmonthÚdayÚyearr8   )r2   Ú_MONTH_ABBRÚdtÚ
month_abbrr.   r.   r0   rf   µ   s   	ýÿrf   )r)   r*   r+   r,   r-   r   )r2   r*   r3   r,   r-   r   )r2   r,   r-   r,   )"Ú__doc__Ú
__future__r   Úloggingr   r   Útypingr   Úindiaopt.exceptionsr   Úindiaopt.models.option_chainr   r   Úindiaopt.utils.coercer	   r
   r   Ú	getLoggerrd   r9   ri   rk   rl   ro   rq   rm   rn   rp   rr   r1   r;   r7   rf   Ú__all__r.   r.   r.   r0   Ú<module>   s0    "




R
