o
    _�¿j×  ã                   @  sv   d Z ddlmZ ddlmZmZ ddlmZ ddlmZ eddd�G dd	„ d	ƒƒZ	edd
�G dd„ dƒƒZ
dd	gZdS )uº   Data models for option chain results.

Uses :func:`dataclasses.dataclass` with ``slots=True`` for maximum memory
efficiency â€” critical when holding thousands of strike rows in memory.
é    )Úannotations)Ú	dataclassÚfield)Údatetime)ÚAnyT)ÚslotsÚfrozenc                   @  sè   e Zd ZU dZded< dZded< dZded< dZded< dZded	< d
Z	ded< d
Z
ded< d
Zded< d
Zded< d
Zded< d
Zded< d
Zded< d
Zded< d
Zded< d
Zded< eddd„ƒZed dd„ƒZd!dd„Zd
S )"ÚOptionChainRowa  A single strike row in an option chain.

    Both ``call_*`` and ``put_*`` fields can be ``None`` when the exchange
    does not provide data for that side (e.g. deep ITM / OTM strikes with no
    open interest).

    Attributes:
        strike:    Strike price.
        call_oi:   Call open interest (contracts).
        call_coi:  Call change in open interest vs. previous session.
        put_oi:    Put open interest (contracts).
        put_coi:   Put change in open interest vs. previous session.
        call_iv:   Call implied volatility (%).
        put_iv:    Put implied volatility (%).
        call_ltp:  Call last traded price.
        put_ltp:   Put last traded price.
        call_vol:  Call traded volume (contracts), if available.
        put_vol:   Put traded volume (contracts), if available.
        call_bid:  Call best bid price, if available.
        put_bid:   Put best bid price, if available.
        call_ask:  Call best ask price, if available.
        put_ask:   Put best ask price, if available.
    ÚfloatÚstriker   ÚintÚcall_oiÚcall_coiÚput_oiÚput_coiNúfloat | NoneÚcall_ivÚput_ivÚcall_ltpÚput_ltpz
int | NoneÚcall_volÚput_volÚcall_bidÚput_bidÚcall_askÚput_askÚreturnc                 C  s   | j dkrdS | j| j  S )zsPut/Call ratio by open interest.

        Returns ``None`` when call OI is zero to avoid division by zero.
        r   N©r   r   ©Úself© r    úW/home/dinkstrade/pdmp/venv/lib/python3.10/site-packages/indiaopt/models/option_chain.pyÚpcr8   s   
zOptionChainRow.pcrc                 C  s   | j | j S )z1Sum of call and put open interest at this strike.r   r   r    r    r!   Útotal_oiB   s   zOptionChainRow.total_oiúdict[str, Any]c                 C  s„   i d| j “d| j“d| j“d| j“d| j“d| j“d| j“d| j“d	| j“d
| j	“d| j
“d| j“d| j“d| j“d| j“d| j“S )z.Serialize to a plain dict (JSON-serializable).r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r"   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r"   r   r    r    r!   Úto_dictG   sB   ÿþýüûúùø	÷
öõôóòñðzOptionChainRow.to_dict©r   r   ©r   r   ©r   r$   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú__annotations__r   r   r   r   r   r   r   r   r   r   r   r   r   r   Úpropertyr"   r#   r%   r    r    r    r!   r	      s,   
 	r	   )r   c                   @  s¸   e Zd ZU dZded< ded< ded< ded< ded	< d
ed< ded< eed�Zded< ed&dd„ƒZ	ed'dd„ƒZ
ed'dd„ƒZed(dd„ƒZed(dd„ƒZd)d*d d!„Zd+d#d$„Zd%S ),ÚOptionChainResultai  Complete option chain result for a symbol.

    Attributes:
        symbol:      Trading symbol (e.g. ``"NIFTY"``).
        exchange:    Exchange name (``"NSE"`` or ``"BSE"``).
        expiry:      Nearest expiry date string as returned by the exchange.
        spot_price:  Underlying spot price at fetch time.
        atm_strike:  At-the-money strike (closest to spot_price).
        data:        List of :class:`OptionChainRow`, sorted by strike ascending.
        fetched_at:  UTC timestamp when this result was fetched.
        expiry_dates: All available expiry dates for the symbol (raw exchange strings).
    ÚstrÚsymbolÚexchangez
str | NoneÚexpiryr   Ú
spot_priceÚ
atm_strikeúlist[OptionChainRow]Údatar   Ú
fetched_at)Údefault_factoryz	list[str]Úexpiry_datesr   úlist[float]c                 C  s   dd„ | j D ƒS )z+Sorted list of all available strike prices.c                 S  s   g | ]}|j ‘qS r    )r   ©Ú.0Úrowr    r    r!   Ú
<listcomp>z   ó    z-OptionChainResult.strikes.<locals>.<listcomp>)r7   r   r    r    r!   Ústrikesw   s   zOptionChainResult.strikesr   c                 C  ó   t dd„ | jD ƒƒS )z1Sum of all call open interest across all strikes.c                 s  ó   � | ]}|j V  qd S ©N)r   r<   r    r    r!   Ú	<genexpr>   ó   € z2OptionChainResult.total_call_oi.<locals>.<genexpr>©Úsumr7   r   r    r    r!   Útotal_call_oi|   ó   zOptionChainResult.total_call_oic                 C  rB   )z0Sum of all put open interest across all strikes.c                 s  rC   rD   )r   r<   r    r    r!   rE   „   rF   z1OptionChainResult.total_put_oi.<locals>.<genexpr>rG   r   r    r    r!   Útotal_put_oi�   rJ   zOptionChainResult.total_put_oic                 C  s   | j }|dkr	dS | j| S )zTOverall Put/Call ratio.

        Returns ``None`` if total call OI is zero.
        r   N)rI   rK   )r   Ú
total_callr    r    r!   r"   †   s   
zOptionChainResult.pcrc                 C  s   | j sdS t| j dd„ d�jS )u#  Max pain strike â€” the strike with the highest total OI.

        This is a simplified max pain calculation based on total open interest
        (call OI + put OI). A full max pain calculation requires pricing each
        option at expiry, which is beyond the scope of this model.
        Nc                 S  s   | j S rD   )r#   )Úrr    r    r!   Ú<lambda>›   s    z3OptionChainResult.max_pain_strike.<locals>.<lambda>©Úkey)r7   Úmaxr   r   r    r    r!   Úmax_pain_strike‘   s   z!OptionChainResult.max_pain_strikeé   Únc                   s–   ˆ j du sˆ jstˆ jƒS ˆ j‰zˆ ˆ j ¡}W n ty0   tttˆƒƒ‡ ‡fdd„d�}Y nw t	d|| ƒ}ttˆ jƒ|| d ƒ}ˆ j||… S )zÖReturn the ``n`` strikes above and below the ATM strike.

        Args:
            n: Number of strikes on each side of ATM.

        Returns:
            Up to ``2*n + 1`` rows centred on the ATM strike.
        Nc                   s   t ˆ|  ˆ j ƒS rD   )Úabsr5   )Úi©r   rA   r    r!   rN   ­   r@   z.OptionChainResult.atm_window.<locals>.<lambda>rO   r   é   )
r5   r7   ÚlistrA   ÚindexÚ
ValueErrorÚminÚrangeÚlenrQ   )r   rT   Úatm_idxÚloÚhir    rW   r!   Ú
atm_window�   s   	
"þzOptionChainResult.atm_windowr$   c                 C  sD   | j | j| j| j| j| j| j| j| j| j	 
¡ | jdd„ | jD ƒdœS )z,Serialize to a plain JSON-serializable dict.c                 S  s   g | ]}|  ¡ ‘qS r    )r%   r<   r    r    r!   r?   À   s    z-OptionChainResult.to_dict.<locals>.<listcomp>)r1   r2   r3   r4   r5   r"   rR   rI   rK   r8   r:   r7   )r1   r2   r3   r4   r5   r"   rR   rI   rK   r8   Ú	isoformatr:   r7   r   r    r    r!   r%   ²   s   ôzOptionChainResult.to_dictN)r   r;   r'   r&   )rS   )rT   r   r   r6   r(   )r)   r*   r+   r,   r-   r   rY   r:   r.   rA   rI   rK   r"   rR   rb   r%   r    r    r    r!   r/   ]   s,   
 
r/   N)r,   Ú
__future__r   Údataclassesr   r   r   Útypingr   r	   r/   Ú__all__r    r    r    r!   Ú<module>   s    
Nf